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/qdsp6v2/Makefile b/arch/arm/mach-msm/qdsp6v2/Makefile
new file mode 100644
index 0000000..eaf9e69
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/Makefile
@@ -0,0 +1,17 @@
+ifdef CONFIG_ARCH_MSM8X60
+obj-$(CONFIG_MSM8X60_RTAC) += rtac.o
+obj-y += audio_dev_ctl.o
+obj-y += board-msm8x60-audio.o
+obj-$(CONFIG_TIMPANI_CODEC) += snddev_icodec.o
+obj-y += snddev_ecodec.o snddev_mi2s.o snddev_virtual.o
+obj-y += pcm_out.o pcm_in.o fm.o
+obj-y += audio_lpa.o
+obj-y += q6voice.o
+obj-y += snddev_hdmi.o
+obj-y += audio_mvs.o
+obj-$(CONFIG_FB_MSM_HDMI_MSM_PANEL) += lpa_if_hdmi.o
+endif
+obj-$(CONFIG_MSM_QDSP6_APR) += apr.o apr_tal.o q6core.o dsp_debug.o
+obj-y += audio_acdb.o
+obj-y += aac_in.o qcelp_in.o evrc_in.o amrnb_in.o audio_utils.o
+obj-y += audio_wma.o audio_wmapro.o audio_aac.o audio_multi_aac.o
\ No newline at end of file
diff --git a/arch/arm/mach-msm/qdsp6v2/aac_in.c b/arch/arm/mach-msm/qdsp6v2/aac_in.c
new file mode 100644
index 0000000..ff25d32
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/aac_in.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_aac.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <sound/q6asm.h>
+#include <sound/apr_audio.h>
+#include "audio_utils.h"
+
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE		(4096 + sizeof(struct meta_in))
+
+/* Maximum 5 frames in buffer with meta */
+#define FRAME_SIZE		(1 + ((1536+sizeof(struct meta_out_dsp)) * 5))
+
+#define AAC_FORMAT_ADTS 65535
+
+void q6asm_aac_in_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv)
+{
+	struct q6audio_in * audio = (struct q6audio_in *)priv;
+	unsigned long flags;
+
+	pr_debug("%s:session id %d: opcode[0x%x]\n", __func__,
+			audio->ac->session, opcode);
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	switch (opcode) {
+	case ASM_DATA_EVENT_READ_DONE:
+		audio_in_get_dsp_frames(audio, token, payload);
+		break;
+	case ASM_DATA_EVENT_WRITE_DONE:
+		atomic_inc(&audio->in_count);
+		wake_up(&audio->write_wait);
+		break;
+	case ASM_DATA_CMDRSP_EOS:
+		audio->eos_rsp = 1;
+		wake_up(&audio->read_wait);
+		break;
+	case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
+		break;
+	case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
+		break;
+	case ASM_SESSION_EVENT_TX_OVERFLOW:
+		pr_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
+			__func__, audio->ac->session);
+		break;
+	default:
+		pr_debug("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
+			audio->ac->session, opcode);
+		break;
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+/* ------------------- device --------------------- */
+static long aac_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_in  *audio = file->private_data;
+	int rc = 0;
+	int cnt = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		struct msm_audio_aac_enc_config *enc_cfg;
+		struct msm_audio_aac_config *aac_config;
+		uint32_t aac_mode = AAC_ENC_MODE_AAC_LC;
+
+		enc_cfg = audio->enc_cfg;
+		aac_config = audio->codec_cfg;
+		/* ENCODE CFG (after new set of API's are published )bharath*/
+		pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+				audio->ac->session, audio->buf_alloc);
+		if (audio->enabled == 1) {
+			pr_info("%s:AUDIO_START already over\n", __func__);
+			rc = 0;
+			break;
+		}
+
+		rc = audio_in_buf_alloc(audio);
+		if (rc < 0) {
+			pr_err("%s:session id %d: buffer allocation failed\n",
+				__func__, audio->ac->session);
+			break;
+		}
+
+		pr_debug("%s:sbr_ps_flag = %d, sbr_flag = %d\n", __func__,
+			aac_config->sbr_ps_on_flag, aac_config->sbr_on_flag);
+		if (aac_config->sbr_ps_on_flag)
+			aac_mode = AAC_ENC_MODE_EAAC_P;
+		else if (aac_config->sbr_on_flag)
+			aac_mode = AAC_ENC_MODE_AAC_P;
+		else
+			aac_mode = AAC_ENC_MODE_AAC_LC;
+
+		rc = q6asm_enc_cfg_blk_aac(audio->ac,
+					audio->buf_cfg.frames_per_buf,
+					enc_cfg->sample_rate,
+					enc_cfg->channels,
+					enc_cfg->bit_rate,
+					aac_mode,
+					enc_cfg->stream_format);
+		if (rc < 0) {
+			pr_err("%s:session id %d: cmd media format block\
+				failed\n", __func__, audio->ac->session);
+			break;
+		}
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			rc = q6asm_media_format_block_pcm(audio->ac,
+						audio->pcm_cfg.sample_rate,
+						audio->pcm_cfg.channel_count);
+			if (rc < 0) {
+				pr_err("%s:session id %d: media format block\
+				failed\n", __func__, audio->ac->session);
+				break;
+			}
+		}
+		rc = audio_in_enable(audio);
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("%s:session id %d: Audio Start procedure\
+			failed rc=%d\n", __func__, audio->ac->session, rc);
+			break;
+		}
+		while (cnt++ < audio->str_cfg.buffer_count)
+			q6asm_read(audio->ac);
+		pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+				__func__, audio->ac->session, audio->enabled);
+		break;
+	}
+	case AUDIO_STOP: {
+		pr_debug("%s:session id %d: Rxed AUDIO_STOP\n", __func__,
+				audio->ac->session);
+		rc = audio_in_disable(audio);
+		if (rc  < 0) {
+			pr_err("%s:session id %d: Audio Stop procedure failed\
+				rc=%d\n", __func__, audio->ac->session, rc);
+			break;
+		}
+		break;
+	}
+	case AUDIO_GET_AAC_ENC_CONFIG: {
+		struct msm_audio_aac_enc_config cfg;
+		struct msm_audio_aac_enc_config *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		if (enc_cfg->channels == CH_MODE_MONO)
+			cfg.channels = 1;
+		else
+			cfg.channels = 2;
+		cfg.sample_rate = enc_cfg->sample_rate;
+		cfg.bit_rate = enc_cfg->bit_rate;
+		/* ADTS(-1) to ADTS(0x00), RAW(0x00) to RAW(0x03) */
+		cfg.stream_format = ((enc_cfg->stream_format == \
+			0x00) ? AUDIO_AAC_FORMAT_ADTS : AUDIO_AAC_FORMAT_RAW);
+		pr_debug("%s:session id %d: Get-aac-cfg: format=%d sr=%d\
+			bitrate=%d\n", __func__, audio->ac->session,
+			cfg.stream_format, cfg.sample_rate, cfg.bit_rate);
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_AAC_ENC_CONFIG: {
+		struct msm_audio_aac_enc_config cfg;
+		struct msm_audio_aac_enc_config *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s:session id %d: Set-aac-cfg: stream=%d\n", __func__,
+					audio->ac->session, cfg.stream_format);
+
+		if ((cfg.stream_format != AUDIO_AAC_FORMAT_RAW)  &&
+			(cfg.stream_format != AAC_FORMAT_ADTS)) {
+			pr_err("%s:session id %d: unsupported AAC format\n",
+				__func__, audio->ac->session);
+			rc = -EINVAL;
+			break;
+		}
+
+		if (cfg.channels == 1) {
+			cfg.channels = CH_MODE_MONO;
+		} else if (cfg.channels == 2) {
+			cfg.channels = CH_MODE_STEREO;
+		} else {
+			rc = -EINVAL;
+			break;
+		}
+		if ((cfg.sample_rate < 8000) && (cfg.sample_rate > 48000)) {
+			pr_err("%s: ERROR in setting samplerate = %d\n",
+				__func__, cfg.sample_rate);
+			rc = -EINVAL;
+			break;
+		}
+		enc_cfg->sample_rate = cfg.sample_rate;
+		enc_cfg->channels = cfg.channels;
+		enc_cfg->bit_rate = cfg.bit_rate;
+		enc_cfg->stream_format =
+			((cfg.stream_format == AUDIO_AAC_FORMAT_RAW) ? \
+								0x03 : 0x00);
+		pr_debug("%s:session id %d: Set-aac-cfg:SR= 0x%x ch=0x%x\
+			bitrate=0x%x, format(adts/raw) = %d\n",
+			__func__, audio->ac->session, enc_cfg->sample_rate,
+			enc_cfg->channels, enc_cfg->bit_rate,
+			enc_cfg->stream_format);
+		break;
+	}
+	case AUDIO_GET_AAC_CONFIG: {
+		if (copy_to_user((void *)arg, &audio->codec_cfg,
+				 sizeof(struct msm_audio_aac_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case AUDIO_SET_AAC_CONFIG: {
+		struct msm_audio_aac_config aac_cfg;
+		struct msm_audio_aac_config *audio_aac_cfg;
+		struct msm_audio_aac_enc_config *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		audio_aac_cfg = audio->codec_cfg;
+
+		if (copy_from_user(&aac_cfg, (void *)arg,
+				 sizeof(struct msm_audio_aac_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s:session id %d: AUDIO_SET_AAC_CONFIG: sbr_flag = %d"
+				 " sbr_ps_flag = %d\n", __func__,
+				 audio->ac->session, aac_cfg.sbr_on_flag,
+				 aac_cfg.sbr_ps_on_flag);
+		audio_aac_cfg->sbr_on_flag = aac_cfg.sbr_on_flag;
+		audio_aac_cfg->sbr_ps_on_flag = aac_cfg.sbr_ps_on_flag;
+		if ((audio_aac_cfg->sbr_on_flag == 1) ||
+			 (audio_aac_cfg->sbr_ps_on_flag == 1)) {
+			if (enc_cfg->sample_rate < 24000) {
+				pr_err("%s: ERROR in setting samplerate = %d"
+					"\n", __func__, enc_cfg->sample_rate);
+				rc = -EINVAL;
+				break;
+			}
+		}
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int aac_in_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_in *audio = NULL;
+	struct msm_audio_aac_enc_config *enc_cfg;
+	struct msm_audio_aac_config *aac_config;
+	int rc = 0;
+
+	audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("%s:session id %d: Could not allocate memory for aac\
+				driver\n", __func__, audio->ac->session);
+		return -ENOMEM;
+	}
+	/* Allocate memory for encoder config param */
+	audio->enc_cfg = kzalloc(sizeof(struct msm_audio_aac_enc_config),
+				GFP_KERNEL);
+	if (audio->enc_cfg == NULL) {
+		pr_err("%s:session id %d: Could not allocate memory for aac\
+				config param\n", __func__, audio->ac->session);
+		kfree(audio);
+		return -ENOMEM;
+	}
+	enc_cfg = audio->enc_cfg;
+
+	audio->codec_cfg = kzalloc(sizeof(struct msm_audio_aac_config),
+				GFP_KERNEL);
+	if (audio->codec_cfg == NULL) {
+		pr_err("%s:session id %d: Could not allocate memory for aac\
+				config\n", __func__, audio->ac->session);
+		kfree(audio->enc_cfg);
+		kfree(audio);
+		return -ENOMEM;
+	}
+	aac_config = audio->codec_cfg;
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->write_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->read_wait);
+	init_waitqueue_head(&audio->write_wait);
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	* but at least we need to have initial config
+	*/
+	audio->str_cfg.buffer_size = FRAME_SIZE;
+	audio->str_cfg.buffer_count = FRAME_NUM;
+	audio->min_frame_size = 1536;
+	audio->max_frames_per_buf = 5;
+	enc_cfg->sample_rate = 8000;
+	enc_cfg->channels = 1;
+	enc_cfg->bit_rate = 16000;
+	enc_cfg->stream_format = 0x00;/* 0:ADTS, 3:RAW */
+	audio->buf_cfg.meta_info_enable = 0x01;
+	audio->buf_cfg.frames_per_buf   = 0x01;
+	audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+	audio->pcm_cfg.buffer_size  = PCM_BUF_SIZE;
+	aac_config->format = AUDIO_AAC_FORMAT_ADTS;
+	aac_config->audio_object = AUDIO_AAC_OBJECT_LC;
+	aac_config->sbr_on_flag = 0;
+	aac_config->sbr_ps_on_flag = 0;
+	aac_config->channel_configuration = 1;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_aac_in_cb,
+							(void *)audio);
+
+	if (!audio->ac) {
+		pr_err("%s:session id %d: Could not allocate memory for\
+				audio client\n", __func__, audio->ac->session);
+		kfree(audio->enc_cfg);
+		kfree(audio->codec_cfg);
+		kfree(audio);
+		return -ENOMEM;
+	}
+	/* open aac encoder in tunnel mode */
+	audio->buf_cfg.frames_per_buf = 0x01;
+
+	if ((file->f_mode & FMODE_WRITE) &&
+		(file->f_mode & FMODE_READ)) {
+		audio->feedback = NON_TUNNEL_MODE;
+		rc = q6asm_open_read_write(audio->ac, FORMAT_MPEG4_AAC,
+						FORMAT_LINEAR_PCM);
+
+		if (rc < 0) {
+			pr_err("%s:session id %d: NT Open failed rc=%d\n",
+				__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->buf_cfg.meta_info_enable = 0x01;
+		pr_info("%s:session id %d: NT mode encoder success\n", __func__,
+				audio->ac->session);
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+				(file->f_mode & FMODE_READ)) {
+		audio->feedback = TUNNEL_MODE;
+		rc = q6asm_open_read(audio->ac, FORMAT_MPEG4_AAC);
+
+		if (rc < 0) {
+			pr_err("%s:session id %d: Tunnel Open failed rc=%d\n",
+				__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		/* register for tx overflow (valid for tunnel mode only) */
+		rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+		if (rc < 0) {
+			pr_err("%s:session id %d: TX Overflow registration\
+				failed rc=%d\n", __func__,
+				audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->buf_cfg.meta_info_enable = 0x00;
+		pr_info("%s:session id %d: T mode encoder success\n", __func__,
+			audio->ac->session);
+	} else {
+		pr_err("%s:session id %d: Unexpected mode\n", __func__,
+				audio->ac->session);
+		rc = -EACCES;
+		goto fail;
+	}
+	audio->opened = 1;
+	atomic_set(&audio->in_count, PCM_BUF_COUNT);
+	atomic_set(&audio->out_count, 0x00);
+	audio->enc_ioctl = aac_in_ioctl;
+	file->private_data = audio;
+
+	pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio->enc_cfg);
+	kfree(audio->codec_cfg);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= aac_in_open,
+	.release	= audio_in_release,
+	.read		= audio_in_read,
+	.write		= audio_in_write,
+	.unlocked_ioctl	= audio_in_ioctl,
+};
+
+struct miscdevice audio_aac_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_aac_in",
+	.fops	= &audio_in_fops,
+};
+
+static int __init aac_in_init(void)
+{
+	return misc_register(&audio_aac_in_misc);
+}
+device_initcall(aac_in_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/amrnb_in.c b/arch/arm/mach-msm/qdsp6v2/amrnb_in.c
new file mode 100644
index 0000000..ece44fd
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/amrnb_in.c
@@ -0,0 +1,325 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio_amrnb.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <sound/q6asm.h>
+#include <sound/apr_audio.h>
+#include "audio_utils.h"
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE		(4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE		(1 + ((32+sizeof(struct meta_out_dsp)) * 10))
+
+void q6asm_amrnb_in_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv)
+{
+	struct q6audio_in * audio = (struct q6audio_in *)priv;
+	unsigned long flags;
+
+	pr_debug("%s:session id %d: opcode - %d\n", __func__,
+			audio->ac->session, opcode);
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	switch (opcode) {
+	case ASM_DATA_EVENT_READ_DONE:
+		audio_in_get_dsp_frames(audio, token, payload);
+		break;
+	case ASM_DATA_EVENT_WRITE_DONE:
+		atomic_inc(&audio->in_count);
+		wake_up(&audio->write_wait);
+		break;
+	case ASM_DATA_CMDRSP_EOS:
+		audio->eos_rsp = 1;
+		wake_up(&audio->read_wait);
+		break;
+	case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
+		break;
+	case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
+		break;
+	case ASM_SESSION_EVENT_TX_OVERFLOW:
+		pr_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
+			__func__, audio->ac->session);
+		break;
+	default:
+		pr_err("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
+				audio->ac->session, opcode);
+		break;
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+static long amrnb_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_in  *audio = file->private_data;
+	int rc = 0;
+	int cnt = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+				audio->ac->session, audio->buf_alloc);
+		if (audio->enabled == 1) {
+			pr_info("%s:AUDIO_START already over\n", __func__);
+			rc = 0;
+			break;
+		}
+		rc = audio_in_buf_alloc(audio);
+		if (rc < 0) {
+			pr_err("%s:session id %d: buffer allocation failed\n",
+				__func__, audio->ac->session);
+			break;
+		}
+
+		rc = q6asm_enc_cfg_blk_amrnb(audio->ac,
+			audio->buf_cfg.frames_per_buf,
+			enc_cfg->band_mode,
+			enc_cfg->dtx_enable);
+
+		if (rc < 0) {
+			pr_err("%s:session id %d: cmd amrnb media format block\
+				failed\n", __func__, audio->ac->session);
+			break;
+		}
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			rc = q6asm_media_format_block_pcm(audio->ac,
+				audio->pcm_cfg.sample_rate,
+				audio->pcm_cfg.channel_count);
+
+			if (rc < 0) {
+				pr_err("%s:session id %d: media format block\
+				failed\n", __func__, audio->ac->session);
+				break;
+			}
+		}
+		pr_debug("%s:session id %d: AUDIO_START enable[%d]\n",
+				__func__, audio->ac->session,
+				audio->enabled);
+		rc = audio_in_enable(audio);
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("%s:session id %d: Audio Start procedure failed\
+					rc=%d\n", __func__,
+					audio->ac->session, rc);
+			break;
+		}
+		while (cnt++ < audio->str_cfg.buffer_count)
+			q6asm_read(audio->ac); /* Push buffer to DSP */
+		rc = 0;
+		pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+				__func__, audio->ac->session, audio->enabled);
+		break;
+	}
+	case AUDIO_STOP: {
+		pr_debug("%s:AUDIO_STOP\n", __func__);
+		rc = audio_in_disable(audio);
+		if (rc  < 0) {
+			pr_err("%s:session id %d: Audio Stop procedure failed\
+				rc=%d\n", __func__,
+				audio->ac->session, rc);
+			break;
+		}
+		break;
+	}
+	case AUDIO_GET_AMRNB_ENC_CONFIG_V2: {
+		if (copy_to_user((void *)arg, audio->enc_cfg,
+			sizeof(struct msm_audio_amrnb_enc_config_v2)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_AMRNB_ENC_CONFIG_V2: {
+		struct msm_audio_amrnb_enc_config_v2 cfg;
+		struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		if (copy_from_user(&cfg, (void *) arg,
+				sizeof(struct msm_audio_amrnb_enc_config_v2))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (cfg.band_mode > 8 ||
+			 cfg.band_mode < 1) {
+			pr_err("%s:session id %d: invalid band mode\n",
+				__func__, audio->ac->session);
+			rc = -EINVAL;
+			break;
+		}
+		/* AMR NB encoder accepts values between 0-7
+		   while openmax provides value between 1-8
+		   as per spec */
+		enc_cfg->band_mode = (cfg.band_mode - 1);
+		enc_cfg->dtx_enable = (cfg.dtx_enable ? 1 : 0);
+		enc_cfg->frame_format = 0;
+		pr_debug("%s:session id %d: band_mode = 0x%x dtx_enable=0x%x\n",
+				__func__, audio->ac->session,
+				enc_cfg->band_mode, enc_cfg->dtx_enable);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int amrnb_in_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_in *audio = NULL;
+	struct msm_audio_amrnb_enc_config_v2 *enc_cfg;
+	int rc = 0;
+
+	audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("%s:session id %d: Could not allocate memory for amrnb\
+			driver\n", __func__, audio->ac->session);
+		return -ENOMEM;
+	}
+	/* Allocate memory for encoder config param */
+	audio->enc_cfg = kzalloc(sizeof(struct msm_audio_amrnb_enc_config_v2),
+				GFP_KERNEL);
+	if (audio->enc_cfg == NULL) {
+		pr_err("%s:session id %d: Could not allocate memory for aac\
+				config param\n", __func__, audio->ac->session);
+		kfree(audio);
+		return -ENOMEM;
+	}
+	enc_cfg = audio->enc_cfg;
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->write_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->read_wait);
+	init_waitqueue_head(&audio->write_wait);
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	* but at least we need to have initial config
+	*/
+	audio->str_cfg.buffer_size = FRAME_SIZE;
+	audio->str_cfg.buffer_count = FRAME_NUM;
+	audio->min_frame_size = 32;
+	audio->max_frames_per_buf = 10;
+	audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+	audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+	enc_cfg->band_mode = 7;
+	enc_cfg->dtx_enable = 0;
+	audio->pcm_cfg.channel_count = 1;
+	audio->pcm_cfg.sample_rate = 8000;
+	audio->buf_cfg.meta_info_enable = 0x01;
+	audio->buf_cfg.frames_per_buf = 0x01;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_amrnb_in_cb,
+				(void *)audio);
+
+	if (!audio->ac) {
+		pr_err("%s:session id %d: Could not allocate memory for audio\
+				client\n", __func__, audio->ac->session);
+		kfree(audio->enc_cfg);
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	/* open amrnb encoder in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) &&
+		(file->f_mode & FMODE_READ)) {
+		audio->feedback = NON_TUNNEL_MODE;
+		rc = q6asm_open_read_write(audio->ac, FORMAT_AMRNB,
+					FORMAT_LINEAR_PCM);
+		if (rc < 0) {
+			pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
+				__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		pr_info("%s:session id %d: NT mode encoder success\n",
+				__func__, audio->ac->session);
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+				(file->f_mode & FMODE_READ)) {
+		audio->feedback = TUNNEL_MODE;
+		rc = q6asm_open_read(audio->ac, FORMAT_AMRNB);
+		if (rc < 0) {
+			pr_err("%s:session id %d: T mode Open failed rc=%d\n",
+				__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		/* register for tx overflow (valid for tunnel mode only) */
+		rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+		if (rc < 0) {
+			pr_err("%s:session id %d: TX Overflow registration\
+				failed rc=%d\n", __func__, audio->ac->session,
+				rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		pr_info("%s:session id %d: T mode encoder success\n",
+				__func__, audio->ac->session);
+	} else {
+		pr_err("%s:session id %d: Unexpected mode\n", __func__,
+				audio->ac->session);
+		rc = -EACCES;
+		goto fail;
+	}
+
+	audio->opened = 1;
+	atomic_set(&audio->in_count, PCM_BUF_COUNT);
+	atomic_set(&audio->out_count, 0x00);
+	audio->enc_ioctl = amrnb_in_ioctl;
+	file->private_data = audio;
+
+	pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio->enc_cfg);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= amrnb_in_open,
+	.release	= audio_in_release,
+	.read		= audio_in_read,
+	.write		= audio_in_write,
+	.unlocked_ioctl	= audio_in_ioctl,
+};
+
+struct miscdevice audio_amrnb_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_amrnb_in",
+	.fops	= &audio_in_fops,
+};
+
+static int __init amrnb_in_init(void)
+{
+	return misc_register(&audio_amrnb_in_misc);
+}
+
+device_initcall(amrnb_in_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr.c b/arch/arm/mach-msm/qdsp6v2/apr.c
new file mode 100644
index 0000000..f405457
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/apr.c
@@ -0,0 +1,673 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <mach/peripheral-loader.h>
+#include <mach/msm_smd.h>
+#include <mach/qdsp6v2/apr.h>
+#include <mach/qdsp6v2/apr_tal.h>
+#include <mach/qdsp6v2/dsp_debug.h>
+#include <mach/subsystem_notif.h>
+#include <mach/subsystem_restart.h>
+
+struct apr_q6 q6;
+struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
+static atomic_t dsp_state;
+static atomic_t modem_state;
+
+static wait_queue_head_t  dsp_wait;
+static wait_queue_head_t  modem_wait;
+/* Subsystem restart: QDSP6 data, functions */
+static struct workqueue_struct *apr_reset_workqueue;
+static void apr_reset_deregister(struct work_struct *work);
+struct apr_reset_work {
+	void *handle;
+	struct work_struct work;
+};
+
+
+int apr_send_pkt(void *handle, uint32_t *buf)
+{
+	struct apr_svc *svc = handle;
+	struct apr_client *clnt;
+	struct apr_hdr *hdr;
+	uint16_t dest_id;
+	uint16_t client_id;
+	uint16_t w_len;
+	unsigned long flags;
+
+	if (!handle || !buf) {
+		pr_err("APR: Wrong parameters\n");
+		return -EINVAL;
+	}
+	if (svc->need_reset) {
+		pr_err("apr: send_pkt service need reset\n");
+		return -ENETRESET;
+	}
+
+	if ((svc->dest_id == APR_DEST_QDSP6) &&
+					(atomic_read(&dsp_state) == 0)) {
+		pr_err("apr: Still dsp is not Up\n");
+		return -ENETRESET;
+	} else if ((svc->dest_id == APR_DEST_MODEM) &&
+					(atomic_read(&modem_state) == 0)) {
+		pr_err("apr: Still Modem is not Up\n");
+		return -ENETRESET;
+	}
+
+
+	spin_lock_irqsave(&svc->w_lock, flags);
+	dest_id = svc->dest_id;
+	client_id = svc->client_id;
+	clnt = &client[dest_id][client_id];
+
+	if (!client[dest_id][client_id].handle) {
+		pr_err("APR: Still service is not yet opened\n");
+		spin_unlock_irqrestore(&svc->w_lock, flags);
+		return -EINVAL;
+	}
+	hdr = (struct apr_hdr *)buf;
+
+	hdr->src_domain = APR_DOMAIN_APPS;
+	hdr->src_svc = svc->id;
+	if (dest_id == APR_DEST_MODEM)
+		hdr->dest_domain = APR_DOMAIN_MODEM;
+	else if (dest_id == APR_DEST_QDSP6)
+		hdr->dest_domain = APR_DOMAIN_ADSP;
+
+	hdr->dest_svc = svc->id;
+
+	w_len = apr_tal_write(clnt->handle, buf, hdr->pkt_size);
+	if (w_len != hdr->pkt_size)
+		pr_err("Unable to write APR pkt successfully: %d\n", w_len);
+	spin_unlock_irqrestore(&svc->w_lock, flags);
+
+	return w_len;
+}
+
+static void apr_cb_func(void *buf, int len, void *priv)
+{
+	struct apr_client_data data;
+	struct apr_client *apr_client;
+	struct apr_svc *c_svc;
+	struct apr_hdr *hdr;
+	uint16_t hdr_size;
+	uint16_t msg_type;
+	uint16_t ver;
+	uint16_t src;
+	uint16_t svc;
+	uint16_t clnt;
+	int i;
+	int temp_port = 0;
+	uint32_t *ptr;
+
+	pr_debug("APR2: len = %d\n", len);
+	ptr = buf;
+	pr_debug("\n*****************\n");
+	for (i = 0; i < len/4; i++)
+		pr_debug("%x  ", ptr[i]);
+	pr_debug("\n");
+	pr_debug("\n*****************\n");
+
+	if (!buf || len <= APR_HDR_SIZE) {
+		pr_err("APR: Improper apr pkt received:%p %d\n",
+								buf, len);
+		return;
+	}
+	hdr = buf;
+
+	ver = hdr->hdr_field;
+	ver = (ver & 0x000F);
+	if (ver > APR_PKT_VER + 1) {
+		pr_err("APR: Wrong version: %d\n", ver);
+		return;
+	}
+
+	hdr_size = hdr->hdr_field;
+	hdr_size = ((hdr_size & 0x00F0) >> 0x4) * 4;
+	if (hdr_size < APR_HDR_SIZE) {
+		pr_err("APR: Wrong hdr size:%d\n", hdr_size);
+		return;
+	}
+
+	if (hdr->pkt_size < APR_HDR_SIZE) {
+		pr_err("APR: Wrong paket size\n");
+		return;
+	}
+	msg_type = hdr->hdr_field;
+	msg_type = (msg_type >> 0x08) & 0x0003;
+	if (msg_type >= APR_MSG_TYPE_MAX &&
+			msg_type != APR_BASIC_RSP_RESULT) {
+		pr_err("APR: Wrong message type: %d\n", msg_type);
+		return;
+	}
+
+	if (hdr->src_domain >= APR_DOMAIN_MAX ||
+		hdr->dest_domain >= APR_DOMAIN_MAX ||
+		hdr->src_svc >= APR_SVC_MAX ||
+		hdr->dest_svc >= APR_SVC_MAX) {
+		pr_err("APR: Wrong APR header\n");
+		return;
+	}
+
+	svc = hdr->dest_svc;
+	if (hdr->src_domain == APR_DOMAIN_MODEM) {
+		src = APR_DEST_MODEM;
+		if (svc == APR_SVC_MVS || svc == APR_SVC_MVM ||
+			svc == APR_SVC_CVS || svc == APR_SVC_CVP ||
+			svc == APR_SVC_TEST_CLIENT)
+			clnt = APR_CLIENT_VOICE;
+		else {
+			pr_err("APR: Wrong svc :%d\n", svc);
+			return;
+		}
+	} else if (hdr->src_domain == APR_DOMAIN_ADSP) {
+		src = APR_DEST_QDSP6;
+		if (svc == APR_SVC_AFE || svc == APR_SVC_ASM ||
+			svc == APR_SVC_VSM || svc == APR_SVC_VPM ||
+			svc == APR_SVC_ADM || svc == APR_SVC_ADSP_CORE ||
+			svc == APR_SVC_TEST_CLIENT || svc == APR_SVC_ADSP_MVM ||
+			svc == APR_SVC_ADSP_CVS || svc == APR_SVC_ADSP_CVP)
+			clnt = APR_CLIENT_AUDIO;
+		else {
+			pr_err("APR: Wrong svc :%d\n", svc);
+			return;
+		}
+	} else {
+		pr_err("APR: Pkt from wrong source: %d\n", hdr->src_domain);
+		return;
+	}
+
+	pr_debug("src =%d clnt = %d\n", src, clnt);
+	apr_client = &client[src][clnt];
+	for (i = 0; i < APR_SVC_MAX; i++)
+		if (apr_client->svc[i].id == svc) {
+			pr_debug("%d\n", apr_client->svc[i].id);
+			c_svc = &apr_client->svc[i];
+			break;
+		}
+
+	if (i == APR_SVC_MAX) {
+		pr_err("APR: service is not registered\n");
+		return;
+	}
+	pr_debug("svc_idx = %d\n", i);
+	pr_debug("%x %x %x %p %p\n", c_svc->id, c_svc->dest_id,
+			c_svc->client_id, c_svc->fn, c_svc->priv);
+	data.payload_size = hdr->pkt_size - hdr_size;
+	data.opcode = hdr->opcode;
+	data.src = src;
+	data.src_port = hdr->src_port;
+	data.dest_port = hdr->dest_port;
+	data.token = hdr->token;
+	data.msg_type = msg_type;
+	if (data.payload_size > 0)
+		data.payload = (char *)hdr + hdr_size;
+
+	temp_port = ((data.src_port >> 8) * 8) + (data.src_port & 0xFF);
+	pr_debug("port = %d t_port = %d\n", data.src_port, temp_port);
+	if (c_svc->port_cnt && c_svc->port_fn[temp_port])
+		c_svc->port_fn[temp_port](&data,  c_svc->port_priv[temp_port]);
+	else if (c_svc->fn)
+		c_svc->fn(&data, c_svc->priv);
+	else
+		pr_err("APR: Rxed a packet for NULL callback\n");
+}
+
+struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
+					uint32_t src_port, void *priv)
+{
+	int client_id = 0;
+	int svc_idx = 0;
+	int svc_id = 0;
+	int dest_id = 0;
+	int temp_port = 0;
+	struct apr_svc *svc = NULL;
+	int rc = 0;
+
+	if (!dest || !svc_name || !svc_fn)
+		return NULL;
+
+	if (!strcmp(dest, "ADSP"))
+		dest_id = APR_DEST_QDSP6;
+	else if (!strcmp(dest, "MODEM")) {
+		dest_id = APR_DEST_MODEM;
+	} else {
+		pr_err("APR: wrong destination\n");
+		goto done;
+	}
+
+	if ((dest_id == APR_DEST_QDSP6) &&
+				(atomic_read(&dsp_state) == 0)) {
+		rc = wait_event_timeout(dsp_wait,
+				(atomic_read(&dsp_state) == 1), 5*HZ);
+		if (rc == 0) {
+			pr_err("apr: Still dsp is not Up\n");
+			return NULL;
+		}
+	} else if ((dest_id == APR_DEST_MODEM) &&
+					(atomic_read(&modem_state) == 0)) {
+		rc = wait_event_timeout(modem_wait,
+			(atomic_read(&modem_state) == 1), 5*HZ);
+		if (rc == 0) {
+			pr_err("apr: Still Modem is not Up\n");
+			return NULL;
+		}
+	}
+
+	if (!strcmp(svc_name, "AFE")) {
+		client_id = APR_CLIENT_AUDIO;
+		svc_idx = 0;
+		svc_id = APR_SVC_AFE;
+	} else if (!strcmp(svc_name, "ASM")) {
+		client_id = APR_CLIENT_AUDIO;
+		svc_idx = 1;
+		svc_id = APR_SVC_ASM;
+	} else if (!strcmp(svc_name, "ADM")) {
+		client_id = APR_CLIENT_AUDIO;
+		svc_idx = 2;
+		svc_id = APR_SVC_ADM;
+	} else if (!strcmp(svc_name, "CORE")) {
+		client_id = APR_CLIENT_AUDIO;
+		svc_idx = 3;
+		svc_id = APR_SVC_ADSP_CORE;
+	} else if (!strcmp(svc_name, "TEST")) {
+		if (dest_id == APR_DEST_QDSP6) {
+			client_id = APR_CLIENT_AUDIO;
+			svc_idx = 4;
+		} else {
+			client_id = APR_CLIENT_VOICE;
+			svc_idx = 7;
+		}
+		svc_id = APR_SVC_TEST_CLIENT;
+	} else if (!strcmp(svc_name, "VSM")) {
+		client_id = APR_CLIENT_VOICE;
+		svc_idx = 0;
+		svc_id = APR_SVC_VSM;
+	} else if (!strcmp(svc_name, "VPM")) {
+		client_id = APR_CLIENT_VOICE;
+		svc_idx = 1;
+		svc_id = APR_SVC_VPM;
+	} else if (!strcmp(svc_name, "MVS")) {
+		client_id = APR_CLIENT_VOICE;
+		svc_idx = 2;
+		svc_id = APR_SVC_MVS;
+	} else if (!strcmp(svc_name, "MVM")) {
+		if (dest_id == APR_DEST_MODEM) {
+			client_id = APR_CLIENT_VOICE;
+			svc_idx = 3;
+			svc_id = APR_SVC_MVM;
+		} else {
+			client_id = APR_CLIENT_AUDIO;
+			svc_idx = 5;
+			svc_id = APR_SVC_ADSP_MVM;
+		}
+	} else if (!strcmp(svc_name, "CVS")) {
+		if (dest_id == APR_DEST_MODEM) {
+			client_id = APR_CLIENT_VOICE;
+			svc_idx = 4;
+			svc_id = APR_SVC_CVS;
+		} else {
+			client_id = APR_CLIENT_AUDIO;
+			svc_idx = 6;
+			svc_id = APR_SVC_ADSP_CVS;
+		}
+	} else if (!strcmp(svc_name, "CVP")) {
+		if (dest_id == APR_DEST_MODEM) {
+			client_id = APR_CLIENT_VOICE;
+			svc_idx = 5;
+			svc_id = APR_SVC_CVP;
+		} else {
+			client_id = APR_CLIENT_AUDIO;
+			svc_idx = 7;
+			svc_id = APR_SVC_ADSP_CVP;
+		}
+	} else if (!strcmp(svc_name, "SRD")) {
+		client_id = APR_CLIENT_VOICE;
+		svc_idx = 6;
+		svc_id = APR_SVC_SRD;
+	} else {
+		pr_err("APR: Wrong svc name\n");
+		goto done;
+	}
+
+	pr_debug("svc name = %s c_id = %d dest_id = %d\n",
+				svc_name, client_id, dest_id);
+	mutex_lock(&q6.lock);
+	if (q6.state == APR_Q6_NOIMG) {
+		q6.pil = pil_get("q6");
+		if (!q6.pil) {
+			pr_err("APR: Unable to load q6 image\n");
+			mutex_unlock(&q6.lock);
+			return svc;
+		}
+		q6.state = APR_Q6_LOADED;
+	}
+	mutex_unlock(&q6.lock);
+	mutex_lock(&client[dest_id][client_id].m_lock);
+	if (!client[dest_id][client_id].handle) {
+		client[dest_id][client_id].handle = apr_tal_open(client_id,
+				dest_id, APR_DL_SMD, apr_cb_func, NULL);
+		if (!client[dest_id][client_id].handle) {
+			svc = NULL;
+			pr_err("APR: Unable to open handle\n");
+			mutex_unlock(&client[dest_id][client_id].m_lock);
+			goto done;
+		}
+	}
+	mutex_unlock(&client[dest_id][client_id].m_lock);
+	svc = &client[dest_id][client_id].svc[svc_idx];
+	mutex_lock(&svc->m_lock);
+	client[dest_id][client_id].id = client_id;
+	if (svc->need_reset) {
+		mutex_unlock(&svc->m_lock);
+		pr_err("APR: Service needs reset\n");
+		goto done;
+	}
+	svc->priv = priv;
+	svc->id = svc_id;
+	svc->dest_id = dest_id;
+	svc->client_id = client_id;
+	if (src_port != 0xFFFFFFFF) {
+		temp_port = ((src_port >> 8) * 8) + (src_port & 0xFF);
+		pr_debug("port = %d t_port = %d\n", src_port, temp_port);
+		if (temp_port > APR_MAX_PORTS || temp_port < 0) {
+			pr_err("APR: temp_port out of bounds\n");
+			mutex_unlock(&svc->m_lock);
+			return NULL;
+		}
+		if (!svc->port_cnt && !svc->svc_cnt)
+			client[dest_id][client_id].svc_cnt++;
+		svc->port_cnt++;
+		svc->port_fn[temp_port] = svc_fn;
+		svc->port_priv[temp_port] = priv;
+	} else {
+		if (!svc->fn) {
+			if (!svc->port_cnt && !svc->svc_cnt)
+				client[dest_id][client_id].svc_cnt++;
+			svc->fn = svc_fn;
+			if (svc->port_cnt)
+				svc->svc_cnt++;
+		}
+	}
+
+	mutex_unlock(&svc->m_lock);
+done:
+	return svc;
+}
+
+static void apr_reset_deregister(struct work_struct *work)
+{
+	struct apr_svc *handle = NULL;
+	struct apr_reset_work *apr_reset =
+			container_of(work, struct apr_reset_work, work);
+
+	handle = apr_reset->handle;
+	pr_debug("%s:handle[%p]\n", __func__, handle);
+	apr_deregister(handle);
+	kfree(apr_reset);
+}
+
+int apr_deregister(void *handle)
+{
+	struct apr_svc *svc = handle;
+	struct apr_client *clnt;
+	uint16_t dest_id;
+	uint16_t client_id;
+
+	if (!handle)
+		return -EINVAL;
+
+	mutex_lock(&svc->m_lock);
+	dest_id = svc->dest_id;
+	client_id = svc->client_id;
+	clnt = &client[dest_id][client_id];
+
+	if (svc->port_cnt > 0 || svc->svc_cnt > 0) {
+		if (svc->port_cnt)
+			svc->port_cnt--;
+		else if (svc->svc_cnt)
+			svc->svc_cnt--;
+		if (!svc->port_cnt && !svc->svc_cnt) {
+			client[dest_id][client_id].svc_cnt--;
+			svc->need_reset = 0x0;
+		}
+	} else if (client[dest_id][client_id].svc_cnt > 0) {
+		client[dest_id][client_id].svc_cnt--;
+		if (!client[dest_id][client_id].svc_cnt) {
+			svc->need_reset = 0x0;
+			pr_debug("%s: service is reset %p\n", __func__, svc);
+		}
+	}
+
+	if (!svc->port_cnt && !svc->svc_cnt) {
+		svc->priv = NULL;
+		svc->id = 0;
+		svc->fn = NULL;
+		svc->dest_id = 0;
+		svc->client_id = 0;
+		svc->need_reset = 0x0;
+	}
+	if (client[dest_id][client_id].handle &&
+		!client[dest_id][client_id].svc_cnt) {
+		apr_tal_close(client[dest_id][client_id].handle);
+		client[dest_id][client_id].handle = NULL;
+	}
+	mutex_unlock(&svc->m_lock);
+
+	return 0;
+}
+
+void apr_reset(void *handle)
+{
+	struct apr_reset_work *apr_reset_worker = NULL;
+
+	if (!handle)
+		return;
+	pr_debug("%s: handle[%p]\n", __func__, handle);
+
+	apr_reset_worker = kzalloc(sizeof(struct apr_reset_work),
+					GFP_ATOMIC);
+	if (apr_reset_worker == NULL || apr_reset_workqueue == NULL) {
+		pr_err("%s: mem failure\n", __func__);
+		return;
+	}
+	apr_reset_worker->handle = handle;
+	INIT_WORK(&apr_reset_worker->work, apr_reset_deregister);
+	queue_work(apr_reset_workqueue, &apr_reset_worker->work);
+}
+
+void change_q6_state(int state)
+{
+	mutex_lock(&q6.lock);
+	q6.state = state;
+	mutex_unlock(&q6.lock);
+}
+
+int adsp_state(int state)
+{
+	pr_info("dsp state = %d\n", state);
+	return 0;
+}
+
+/* Dispatch the Reset events to Modem and audio clients */
+void dispatch_event(unsigned long code, unsigned short proc)
+{
+	struct apr_client *apr_client;
+	struct apr_client_data data;
+	struct apr_svc *svc;
+	uint16_t clnt;
+	int i, j;
+
+	data.opcode = RESET_EVENTS;
+	data.reset_event = code;
+	data.reset_proc = proc;
+
+	clnt = APR_CLIENT_AUDIO;
+	apr_client = &client[proc][clnt];
+	for (i = 0; i < APR_SVC_MAX; i++) {
+		mutex_lock(&apr_client->svc[i].m_lock);
+		if (apr_client->svc[i].fn) {
+			apr_client->svc[i].need_reset = 0x1;
+			apr_client->svc[i].fn(&data, apr_client->svc[i].priv);
+		}
+		if (apr_client->svc[i].port_cnt) {
+			svc = &(apr_client->svc[i]);
+			svc->need_reset = 0x1;
+			for (j = 0; j < APR_MAX_PORTS; j++)
+				if (svc->port_fn[j])
+					svc->port_fn[j](&data,
+						svc->port_priv[j]);
+		}
+		mutex_unlock(&apr_client->svc[i].m_lock);
+	}
+
+	clnt = APR_CLIENT_VOICE;
+	apr_client = &client[proc][clnt];
+	for (i = 0; i < APR_SVC_MAX; i++) {
+		mutex_lock(&apr_client->svc[i].m_lock);
+		if (apr_client->svc[i].fn) {
+			apr_client->svc[i].need_reset = 0x1;
+			apr_client->svc[i].fn(&data, apr_client->svc[i].priv);
+		}
+		if (apr_client->svc[i].port_cnt) {
+			svc = &(apr_client->svc[i]);
+			svc->need_reset = 0x1;
+			for (j = 0; j < APR_MAX_PORTS; j++)
+				if (svc->port_fn[j])
+					svc->port_fn[j](&data,
+						svc->port_priv[j]);
+		}
+		mutex_unlock(&apr_client->svc[i].m_lock);
+	}
+}
+
+static int modem_notifier_cb(struct notifier_block *this, unsigned long code,
+								void *_cmd)
+{
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+		pr_debug("M-Notify: Shutdown started\n");
+		atomic_set(&modem_state, 0);
+		dispatch_event(code, APR_DEST_MODEM);
+		break;
+	case SUBSYS_AFTER_SHUTDOWN:
+		pr_debug("M-Notify: Shutdown Completed\n");
+		break;
+	case SUBSYS_BEFORE_POWERUP:
+		pr_debug("M-notify: Bootup started\n");
+		break;
+	case SUBSYS_AFTER_POWERUP:
+		if (atomic_read(&modem_state) == 0) {
+			atomic_set(&modem_state, 1);
+			wake_up(&modem_wait);
+		}
+		pr_debug("M-Notify: Bootup Completed\n");
+		break;
+	default:
+		pr_err("M-Notify: General: %lu\n", code);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block mnb = {
+	.notifier_call = modem_notifier_cb,
+};
+
+static int lpass_notifier_cb(struct notifier_block *this, unsigned long code,
+								void *_cmd)
+{
+	switch (code) {
+	case SUBSYS_BEFORE_SHUTDOWN:
+		pr_debug("L-Notify: Shutdown started\n");
+		atomic_set(&dsp_state, 0);
+		dispatch_event(code, APR_DEST_QDSP6);
+		break;
+	case SUBSYS_AFTER_SHUTDOWN:
+		pr_debug("L-Notify: Shutdown Completed\n");
+		break;
+	case SUBSYS_BEFORE_POWERUP:
+		pr_debug("L-notify: Bootup started\n");
+		break;
+	case SUBSYS_AFTER_POWERUP:
+		if (atomic_read(&dsp_state) == 0) {
+			atomic_set(&dsp_state, 1);
+			wake_up(&dsp_wait);
+		}
+		pr_debug("L-Notify: Bootup Completed\n");
+		break;
+	default:
+		pr_err("L-Notify: Generel: %lu\n", code);
+		break;
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block lnb = {
+	.notifier_call = lpass_notifier_cb,
+};
+
+
+static int __init apr_init(void)
+{
+	int i, j, k;
+
+	for (i = 0; i < APR_DEST_MAX; i++)
+		for (j = 0; j < APR_CLIENT_MAX; j++) {
+			mutex_init(&client[i][j].m_lock);
+			for (k = 0; k < APR_SVC_MAX; k++) {
+				mutex_init(&client[i][j].svc[k].m_lock);
+				spin_lock_init(&client[i][j].svc[k].w_lock);
+			}
+		}
+	mutex_init(&q6.lock);
+	dsp_debug_register(adsp_state);
+	apr_reset_workqueue =
+		create_singlethread_workqueue("apr_driver");
+	if (!apr_reset_workqueue)
+		return -ENOMEM;
+	return 0;
+}
+device_initcall(apr_init);
+
+static int __init apr_late_init(void)
+{
+	void *ret;
+	init_waitqueue_head(&dsp_wait);
+	init_waitqueue_head(&modem_wait);
+	atomic_set(&dsp_state, 1);
+	atomic_set(&modem_state, 1);
+	ret = subsys_notif_register_notifier("modem", &mnb);
+	pr_debug("subsys_register_notifier: ret1 = %p\n", ret);
+	ret = subsys_notif_register_notifier("lpass", &lnb);
+	pr_debug("subsys_register_notifier: ret2 = %p\n", ret);
+
+	return 0;
+}
+late_initcall(apr_late_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/apr_tal.c b/arch/arm/mach-msm/qdsp6v2/apr_tal.c
new file mode 100644
index 0000000..418da4d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/apr_tal.c
@@ -0,0 +1,279 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <mach/msm_smd.h>
+#include <mach/qdsp6v2/apr_tal.h>
+
+static char *svc_names[APR_DEST_MAX][APR_CLIENT_MAX] = {
+	{
+		"apr_audio_svc",
+		"apr_voice_svc",
+	},
+	{
+		"apr_audio_svc",
+		"apr_voice_svc",
+	},
+};
+
+struct apr_svc_ch_dev apr_svc_ch[APR_DL_MAX][APR_DEST_MAX][APR_CLIENT_MAX];
+
+int __apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data, int len)
+{
+	int w_len;
+	unsigned long flags;
+
+
+	spin_lock_irqsave(&apr_ch->w_lock, flags);
+	if (smd_write_avail(apr_ch->ch) < len) {
+		spin_unlock_irqrestore(&apr_ch->w_lock, flags);
+		return -EAGAIN;
+	}
+
+	w_len = smd_write(apr_ch->ch, data, len);
+	spin_unlock_irqrestore(&apr_ch->w_lock, flags);
+	pr_debug("apr_tal:w_len = %d\n", w_len);
+
+	if (w_len != len) {
+		pr_err("apr_tal: Error in write\n");
+		return -ENETRESET;
+	}
+	return w_len;
+}
+
+int apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data, int len)
+{
+	int rc = 0, retries = 0;
+
+	if (!apr_ch->ch)
+		return -EINVAL;
+
+	do {
+		if (rc == -EAGAIN)
+			udelay(50);
+
+		rc = __apr_tal_write(apr_ch, data, len);
+	} while (rc == -EAGAIN && retries++ < 300);
+
+	if (rc == -EAGAIN)
+		pr_err("apr_tal: TIMEOUT for write\n");
+
+	return rc;
+}
+
+static void apr_tal_notify(void *priv, unsigned event)
+{
+	struct apr_svc_ch_dev *apr_ch = priv;
+	int len, r_len, sz;
+	int pkt_cnt = 0;
+	unsigned long flags;
+
+	pr_debug("event = %d\n", event);
+	switch (event) {
+	case SMD_EVENT_DATA:
+		pkt_cnt = 0;
+		spin_lock_irqsave(&apr_ch->lock, flags);
+check_pending:
+		len = smd_read_avail(apr_ch->ch);
+		if (len < 0) {
+			pr_err("apr_tal: Invalid Read Event :%d\n", len);
+			spin_unlock_irqrestore(&apr_ch->lock, flags);
+			return;
+		}
+		sz = smd_cur_packet_size(apr_ch->ch);
+		if (sz < 0) {
+			pr_debug("pkt size is zero\n");
+			spin_unlock_irqrestore(&apr_ch->lock, flags);
+			return;
+		}
+		if (!len && !sz && !pkt_cnt)
+			goto check_write_avail;
+		if (!len) {
+			pr_debug("len = %d pkt_cnt = %d\n", len, pkt_cnt);
+			spin_unlock_irqrestore(&apr_ch->lock, flags);
+			return;
+		}
+		r_len = smd_read_from_cb(apr_ch->ch, apr_ch->data, len);
+		if (len != r_len) {
+			pr_err("apr_tal: Invalid Read\n");
+			spin_unlock_irqrestore(&apr_ch->lock, flags);
+			return;
+		}
+		pkt_cnt++;
+		pr_debug("%d %d %d\n", len, sz, pkt_cnt);
+		if (apr_ch->func)
+			apr_ch->func(apr_ch->data, r_len, apr_ch->priv);
+		goto check_pending;
+check_write_avail:
+		if (smd_write_avail(apr_ch->ch))
+			wake_up(&apr_ch->wait);
+		spin_unlock_irqrestore(&apr_ch->lock, flags);
+		break;
+	case SMD_EVENT_OPEN:
+		pr_info("apr_tal: SMD_EVENT_OPEN\n");
+		apr_ch->smd_state = 1;
+		wake_up(&apr_ch->wait);
+		break;
+	case SMD_EVENT_CLOSE:
+		pr_info("apr_tal: SMD_EVENT_CLOSE\n");
+		break;
+	}
+}
+
+struct apr_svc_ch_dev *apr_tal_open(uint32_t svc, uint32_t dest,
+				uint32_t dl, apr_svc_cb_fn func, void *priv)
+{
+	int rc;
+
+	if ((svc >= APR_CLIENT_MAX) || (dest >= APR_DEST_MAX) ||
+						(dl >= APR_DL_MAX)) {
+		pr_err("apr_tal: Invalid params\n");
+		return NULL;
+	}
+
+	if (apr_svc_ch[dl][dest][svc].ch) {
+		pr_err("apr_tal: This channel alreday openend\n");
+		return NULL;
+	}
+
+	mutex_lock(&apr_svc_ch[dl][dest][svc].m_lock);
+	if (!apr_svc_ch[dl][dest][svc].dest_state) {
+		rc = wait_event_timeout(apr_svc_ch[dl][dest][svc].dest,
+			apr_svc_ch[dl][dest][svc].dest_state,
+				msecs_to_jiffies(APR_OPEN_TIMEOUT_MS));
+		if (rc == 0) {
+			pr_debug("apr_tal:Open timeout\n");
+			mutex_unlock(&apr_svc_ch[dl][dest][svc].m_lock);
+			return NULL;
+		}
+		pr_debug("apr_tal:Wakeup done\n");
+		apr_svc_ch[dl][dest][svc].dest_state = 0;
+	}
+	rc = smd_named_open_on_edge(svc_names[dest][svc], dest,
+			&apr_svc_ch[dl][dest][svc].ch,
+			&apr_svc_ch[dl][dest][svc],
+			apr_tal_notify);
+	if (rc < 0) {
+		pr_err("apr_tal: smd_open failed %s\n",
+					svc_names[dest][svc]);
+		mutex_unlock(&apr_svc_ch[dl][dest][svc].m_lock);
+		return NULL;
+	}
+	rc = wait_event_timeout(apr_svc_ch[dl][dest][svc].wait,
+		(apr_svc_ch[dl][dest][svc].smd_state == 1), 5 * HZ);
+	if (rc == 0) {
+		pr_err("apr_tal:TIMEOUT for OPEN event\n");
+		mutex_unlock(&apr_svc_ch[dl][dest][svc].m_lock);
+		return NULL;
+	}
+	if (!apr_svc_ch[dl][dest][svc].dest_state) {
+		apr_svc_ch[dl][dest][svc].dest_state = 1;
+		pr_debug("apr_tal:Waiting for apr svc init\n");
+		msleep(200);
+		pr_debug("apr_tal:apr svc init done\n");
+	}
+	apr_svc_ch[dl][dest][svc].smd_state = 0;
+
+	apr_svc_ch[dl][dest][svc].func = func;
+	apr_svc_ch[dl][dest][svc].priv = priv;
+	mutex_unlock(&apr_svc_ch[dl][dest][svc].m_lock);
+
+	return &apr_svc_ch[dl][dest][svc];
+}
+
+int apr_tal_close(struct apr_svc_ch_dev *apr_ch)
+{
+	int r;
+
+	if (!apr_ch->ch)
+		return -EINVAL;
+
+	mutex_lock(&apr_ch->m_lock);
+	r = smd_close(apr_ch->ch);
+	apr_ch->ch = NULL;
+	apr_ch->func = NULL;
+	apr_ch->priv = NULL;
+	mutex_unlock(&apr_ch->m_lock);
+	return r;
+}
+
+static int apr_smd_probe(struct platform_device *pdev)
+{
+	int dest;
+	int clnt;
+
+	if (pdev->id == APR_DEST_MODEM) {
+		pr_info("apr_tal:Modem Is Up\n");
+		dest = APR_DEST_MODEM;
+		clnt = APR_CLIENT_VOICE;
+		apr_svc_ch[APR_DL_SMD][dest][clnt].dest_state = 1;
+		wake_up(&apr_svc_ch[APR_DL_SMD][dest][clnt].dest);
+	} else if (pdev->id == APR_DEST_QDSP6) {
+		pr_info("apr_tal:Q6 Is Up\n");
+		dest = APR_DEST_QDSP6;
+		clnt = APR_CLIENT_AUDIO;
+		apr_svc_ch[APR_DL_SMD][dest][clnt].dest_state = 1;
+		wake_up(&apr_svc_ch[APR_DL_SMD][dest][clnt].dest);
+	} else
+		pr_err("apr_tal:Invalid Dest Id: %d\n", pdev->id);
+
+	return 0;
+}
+
+static struct platform_driver apr_q6_driver = {
+	.probe = apr_smd_probe,
+	.driver = {
+		.name = "apr_audio_svc",
+		.owner = THIS_MODULE,
+	},
+};
+
+static struct platform_driver apr_modem_driver = {
+	.probe = apr_smd_probe,
+	.driver = {
+		.name = "apr_voice_svc",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init apr_tal_init(void)
+{
+	int i, j, k;
+
+	for (i = 0; i < APR_DL_MAX; i++)
+		for (j = 0; j < APR_DEST_MAX; j++)
+			for (k = 0; k < APR_CLIENT_MAX; k++) {
+				init_waitqueue_head(&apr_svc_ch[i][j][k].wait);
+				init_waitqueue_head(&apr_svc_ch[i][j][k].dest);
+				spin_lock_init(&apr_svc_ch[i][j][k].lock);
+				spin_lock_init(&apr_svc_ch[i][j][k].w_lock);
+				mutex_init(&apr_svc_ch[i][j][k].m_lock);
+			}
+	platform_driver_register(&apr_q6_driver);
+	platform_driver_register(&apr_modem_driver);
+	return 0;
+}
+device_initcall(apr_tal_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
new file mode 100644
index 0000000..4c9a9b4
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_aac.c
@@ -0,0 +1,1674 @@
+/* aac audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_aac.h>
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <asm/ioctls.h>
+#include <asm/atomic.h>
+#include <sound/apr_audio.h>
+#include <sound/q6asm.h>
+
+#define ADRV_STATUS_AIO_INTF 0x00000001	/* AIO interface */
+#define ADRV_STATUS_FSYNC 0x00000008
+#define ADRV_STATUS_PAUSE 0x00000010
+
+#define TUNNEL_MODE     0x0000
+#define NON_TUNNEL_MODE 0x0001
+#define AUDAAC_EOS_SET  0x00000001
+
+/* Default number of pre-allocated event packets */
+#define AUDAAC_EVENT_NUM 10
+
+#define __CONTAINS(r, v, l) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = ((__v >= __r->vaddr) &&			\
+		(__e <= __r->vaddr + __r->len));		\
+	res;							\
+})
+
+#define CONTAINS(r1, r2) ({					\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->vaddr, __r2->len);			\
+})
+
+#define IN_RANGE(r, v) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->vaddr) &&			\
+		(__vv < (__r->vaddr + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2) ({					\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->vaddr) __v = __r2->vaddr;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
+	res;							\
+})
+
+struct timestamp {
+	unsigned long lowpart;
+	unsigned long highpart;
+} __attribute__ ((packed));
+
+struct meta_in {
+	unsigned char reserved[18];
+	unsigned short offset;
+	struct timestamp ntimestamp;
+	unsigned int nflags;
+} __attribute__ ((packed));
+
+struct meta_out_dsp{
+	u32 offset_to_frame;
+	u32 frame_size;
+	u32 encoded_pcm_samples;
+	u32 msw_ts;
+	u32 lsw_ts;
+	u32 nflags;
+} __attribute__ ((packed));
+
+struct dec_meta_out{
+	unsigned int reserved[7];
+	unsigned int num_of_frames;
+	struct meta_out_dsp meta_out_dsp[];
+} __attribute__ ((packed));
+
+/* General meta field to store meta info
+locally */
+union  meta_data {
+	struct dec_meta_out meta_out;
+	struct meta_in meta_in;
+} __attribute__ ((packed));
+
+struct audaac_event {
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audaac_pmem_region {
+	struct list_head list;
+	struct file *file;
+	int fd;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	unsigned ref_cnt;
+};
+
+struct audaac_buffer_node {
+	struct list_head list;
+	struct msm_audio_aio_buf buf;
+	unsigned long paddr;
+	unsigned long token;
+	void		*kvaddr;
+	union meta_data meta_info;
+};
+
+struct q6audio;
+
+struct audaac_drv_operations {
+	void (*out_flush) (struct q6audio *);
+	void (*in_flush) (struct q6audio *);
+	int (*fsync)(struct q6audio *);
+};
+
+#define PCM_BUF_COUNT		(2)
+/* Buffer with meta */
+#define PCM_BUFSZ_MIN		((8192) + sizeof(struct dec_meta_out))
+
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM		(2)
+#define FRAME_SIZE		((4*1536) + sizeof(struct meta_in))
+
+struct q6audio {
+	atomic_t in_bytes;
+	atomic_t in_samples;
+
+	struct msm_audio_stream_config str_cfg;
+	struct msm_audio_buf_cfg        buf_cfg;
+	struct msm_audio_config pcm_cfg;
+	struct msm_audio_aac_config aac_config;
+
+	struct audio_client *ac;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	struct mutex write_lock;
+	struct mutex get_event_lock;
+	wait_queue_head_t cmd_wait;
+	wait_queue_head_t write_wait;
+	wait_queue_head_t event_wait;
+	spinlock_t dsp_lock;
+	spinlock_t event_queue_lock;
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+	struct list_head out_queue;	/* queue to retain output buffers */
+	struct list_head in_queue;	/* queue to retain input buffers */
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	struct list_head pmem_region_queue;	/* protected by lock */
+	struct audaac_drv_operations drv_ops;
+	union msm_audio_event_payload eos_write_payload;
+
+	uint32_t drv_status;
+	int event_abort;
+	int eos_rsp;
+	int eos_flag;
+	int opened;
+	int enabled;
+	int stopped;
+	int feedback;
+	int rflush;		/* Read  flush */
+	int wflush;		/* Write flush */
+};
+
+static int insert_eos_buf(struct q6audio *audio,
+	struct audaac_buffer_node *buf_node) {
+	struct dec_meta_out *eos_buf = buf_node->kvaddr;
+	eos_buf->num_of_frames = 0xFFFFFFFF;
+	eos_buf->meta_out_dsp[0].offset_to_frame = 0x0;
+	eos_buf->meta_out_dsp[0].nflags = AUDAAC_EOS_SET;
+	return sizeof(struct dec_meta_out) +
+		sizeof(eos_buf->meta_out_dsp[0]);
+}
+
+/* Routine which updates read buffers of driver/dsp,
+   for flush operation as DSP output might not have proper
+   value set */
+static int insert_meta_data(struct q6audio *audio,
+	struct audaac_buffer_node *buf_node) {
+	struct dec_meta_out *meta_data = buf_node->kvaddr;
+	meta_data->num_of_frames = 0x0;
+	meta_data->meta_out_dsp[0].offset_to_frame = 0x0;
+	meta_data->meta_out_dsp[0].nflags = 0x0;
+	return sizeof(struct dec_meta_out) +
+		sizeof(meta_data->meta_out_dsp[0]);
+}
+
+static void extract_meta_info(struct q6audio *audio,
+	struct audaac_buffer_node *buf_node, int dir)
+{
+	if (dir) { /* input buffer - Write */
+		if (audio->buf_cfg.meta_info_enable)
+			memcpy(&buf_node->meta_info.meta_in,
+			(char *)buf_node->kvaddr, sizeof(struct meta_in));
+		else
+			memset(&buf_node->meta_info.meta_in,
+			0, sizeof(struct meta_in));
+		pr_debug("i/p: msw_ts 0x%lx lsw_ts 0x%lx nflags 0x%8x\n",
+			buf_node->meta_info.meta_in.ntimestamp.highpart,
+			buf_node->meta_info.meta_in.ntimestamp.lowpart,
+			buf_node->meta_info.meta_in.nflags);
+	} else { /* output buffer - Read */
+		memcpy((char *)buf_node->kvaddr,
+			&buf_node->meta_info.meta_out,
+			sizeof(struct dec_meta_out));
+		pr_debug("o/p: msw_ts 0x%8x lsw_ts 0x%8x nflags 0x%8x,"
+				 "num_frames = %d\n",
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].msw_ts,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].lsw_ts,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].nflags,
+		((struct dec_meta_out *)buf_node->kvaddr)->num_of_frames);
+	}
+}
+
+static int audaac_pmem_lookup_vaddr(struct q6audio *audio, void *addr,
+	unsigned long len, struct audaac_pmem_region **region)
+{
+	struct audaac_pmem_region *region_elt;
+
+	int match_count = 0;
+
+	*region = NULL;
+
+	/* returns physical address or zero */
+	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+		if (addr >= region_elt->vaddr &&
+		    addr < region_elt->vaddr + region_elt->len &&
+		    addr + len <= region_elt->vaddr + region_elt->len) {
+			/* offset since we could pass vaddr inside a registerd
+			 * pmem buffer
+			 */
+
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		pr_err("multiple hits for vaddr %p, len %ld\n", addr, len);
+		list_for_each_entry(region_elt, &audio->pmem_region_queue,
+					list) {
+			if (addr >= region_elt->vaddr &&
+			    addr < region_elt->vaddr + region_elt->len &&
+			    addr + len <= region_elt->vaddr + region_elt->len)
+				pr_err("\t%p, %ld --> %p\n", region_elt->vaddr,
+				       region_elt->len,
+				       (void *)region_elt->paddr);
+		}
+	}
+
+	return *region ? 0 : -1;
+}
+
+static unsigned long audaac_pmem_fixup(struct q6audio *audio, void *addr,
+	unsigned long len, int ref_up, void **kvaddr)
+{
+	struct audaac_pmem_region *region;
+	unsigned long paddr;
+	int ret;
+
+	ret = audaac_pmem_lookup_vaddr(audio, addr, len, &region);
+	if (ret) {
+		pr_err("lookup (%p, %ld) failed\n", addr, len);
+		return 0;
+	}
+	if (ref_up)
+		region->ref_cnt++;
+	else
+		region->ref_cnt--;
+	pr_debug("found region %p ref_cnt %d\n", region, region->ref_cnt);
+	paddr = region->paddr + (addr - region->vaddr);
+	/* provide kernel virtual address for accessing meta information */
+	if (kvaddr)
+		*kvaddr = (void *) (region->kvaddr + (addr - region->vaddr));
+	return paddr;
+}
+
+static void audaac_post_event(struct q6audio *audio, int type,
+			      union msm_audio_event_payload payload)
+{
+	struct audaac_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+					  struct audaac_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audaac_event), GFP_ATOMIC);
+		if (!e_node) {
+			pr_err("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static int audaac_enable(struct q6audio *audio)
+{
+	/* 2nd arg: 0 -> run immediately
+	   3rd arg: 0 -> msw_ts, 4th arg: 0 ->lsw_ts */
+	return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
+}
+
+static int audaac_disable(struct q6audio *audio)
+{
+	int rc = 0;
+	if (audio->opened) {
+		audio->enabled = 0;
+		audio->opened = 0;
+		pr_debug("%s: inbytes[%d] insamples[%d]\n", __func__,
+			 atomic_read(&audio->in_bytes),
+			 atomic_read(&audio->in_samples));
+		/* Close the session */
+		rc = q6asm_cmd(audio->ac, CMD_CLOSE);
+		if (rc < 0)
+			pr_err("Failed to close the session rc=%d\n", rc);
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->cmd_wait);
+	}
+	pr_debug("enabled[%d]\n", audio->enabled);
+	return rc;
+}
+
+static int audaac_pause(struct q6audio *audio)
+{
+	int rc = 0;
+
+	pr_debug("%s, enabled = %d\n", __func__,
+			audio->enabled);
+	if (audio->enabled) {
+		rc = q6asm_cmd(audio->ac, CMD_PAUSE);
+		if (rc < 0)
+			pr_err("%s: pause cmd failed rc=%d\n", __func__, rc);
+
+	} else
+		pr_err("%s: Driver not enabled\n", __func__);
+	return rc;
+}
+
+static int audaac_flush(struct q6audio *audio)
+{
+	int rc;
+
+	if (audio->enabled) {
+		/* Implicitly issue a pause to the decoder before flushing if
+		   it is not in pause state */
+		if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
+			rc = audaac_pause(audio);
+			if (rc < 0)
+				pr_err("%s: pause cmd failed rc=%d\n", __func__,
+					rc);
+			else
+				audio->drv_status |= ADRV_STATUS_PAUSE;
+		}
+		rc = q6asm_cmd(audio->ac, CMD_FLUSH);
+		if (rc < 0)
+			pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
+		/* Not in stop state, reenable the stream */
+		if (audio->stopped == 0) {
+			rc = audaac_enable(audio);
+			if (rc)
+				pr_err("%s:audio re-enable failed\n", __func__);
+			else {
+				audio->enabled = 1;
+				if (audio->drv_status & ADRV_STATUS_PAUSE)
+					audio->drv_status &= ~ADRV_STATUS_PAUSE;
+			}
+		}
+	}
+	pr_debug("in_bytes %d\n", atomic_read(&audio->in_bytes));
+	pr_debug("in_samples %d\n", atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+	return 0;
+}
+
+static int audaac_outport_flush(struct q6audio *audio)
+{
+	int rc;
+
+	rc = q6asm_cmd(audio->ac, CMD_OUT_FLUSH);
+	if (rc < 0)
+		pr_err("%s: output port flush cmd failed rc=%d\n", __func__,
+			rc);
+	return rc;
+}
+
+static void audaac_async_read(struct q6audio *audio,
+		struct audaac_buffer_node *buf_node)
+{
+	struct audio_client *ac;
+	struct audio_aio_read_param param;
+	int rc;
+
+	pr_debug("%s: Send read buff %p phy %lx len %d\n", __func__, buf_node,
+			buf_node->paddr, buf_node->buf.buf_len);
+	ac = audio->ac;
+	/* Provide address so driver can append nr frames information */
+	param.paddr = buf_node->paddr +
+			sizeof(struct dec_meta_out);
+	param.len = buf_node->buf.buf_len -
+			sizeof(struct dec_meta_out);
+	param.uid = param.paddr;
+	/* Write command will populate paddr as token */
+	buf_node->token = param.paddr;
+	rc = q6asm_async_read(ac, &param);
+	if (rc < 0)
+		pr_err("%s:failed\n", __func__);
+}
+
+static void audaac_async_write(struct q6audio *audio,
+		struct audaac_buffer_node *buf_node)
+{
+	int rc;
+	struct audio_client *ac;
+	struct audio_aio_write_param param;
+
+	pr_debug("%s: Send write buff %p phy %lx len %d, meta_enable = %d\n",
+		__func__, buf_node, buf_node->paddr, buf_node->buf.data_len,
+		audio->buf_cfg.meta_info_enable);
+
+	ac = audio->ac;
+	/* Offset with  appropriate meta */
+	param.paddr = buf_node->paddr + sizeof(struct meta_in);
+	param.len = buf_node->buf.data_len - sizeof(struct meta_in);
+	param.msw_ts = buf_node->meta_info.meta_in.ntimestamp.highpart;
+	param.lsw_ts = buf_node->meta_info.meta_in.ntimestamp.lowpart;
+	/* If no meta_info enaled, indicate no time stamp valid */
+	if (audio->buf_cfg.meta_info_enable)
+		param.flags = 0;
+	else
+		param.flags = 0xFF00;
+	param.uid = param.paddr;
+	/* Read command will populate paddr as token */
+	buf_node->token = param.paddr;
+	rc = q6asm_async_write(ac, &param);
+	if (rc < 0)
+		pr_err("%s:failed\n", __func__);
+}
+
+/* Write buffer to DSP / Handle Ack from DSP */
+static void audaac_async_write_ack(struct q6audio *audio, uint32_t token,
+		uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload event_payload;
+	struct audaac_buffer_node *used_buf;
+
+	/* No active flush in progress */
+	if (audio->wflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	BUG_ON(list_empty(&audio->out_queue));
+	used_buf = list_first_entry(&audio->out_queue,
+				    struct audaac_buffer_node, list);
+	if (token == used_buf->token) {
+		list_del(&used_buf->list);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		pr_debug("consumed buffer\n");
+		event_payload.aio_buf = used_buf->buf;
+		audaac_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				  event_payload);
+		kfree(used_buf);
+		if (list_empty(&audio->out_queue) &&
+			   (audio->drv_status & ADRV_STATUS_FSYNC)) {
+			pr_debug("%s: list is empty, reached EOS in\
+				Tunnel\n", __func__);
+			wake_up(&audio->write_wait);
+		}
+	} else {
+		pr_err("expected=%lx ret=%x\n", used_buf->token, token);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	}
+}
+
+/* Read buffer from DSP / Handle Ack from DSP */
+static void audaac_async_read_ack(struct q6audio *audio, uint32_t token,
+		uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload event_payload;
+	struct audaac_buffer_node *filled_buf;
+
+	/* No active flush in progress */
+	if (audio->rflush)
+		return;
+
+	/* Statistics of read */
+	atomic_add(payload[2], &audio->in_bytes);
+	atomic_add(payload[7], &audio->in_samples);
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	BUG_ON(list_empty(&audio->in_queue));
+	filled_buf = list_first_entry(&audio->in_queue,
+				      struct audaac_buffer_node, list);
+	if (token == (filled_buf->token)) {
+		list_del(&filled_buf->list);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		event_payload.aio_buf = filled_buf->buf;
+		/* Read done Buffer due to flush/normal condition
+		   after EOS event, so append EOS buffer */
+		if (audio->eos_rsp == 0x1) {
+			event_payload.aio_buf.data_len =
+					insert_eos_buf(audio, filled_buf);
+			/* Reset flag back to indicate eos intimated */
+			audio->eos_rsp = 0;
+		} else {
+			filled_buf->meta_info.meta_out.num_of_frames =
+				payload[7];
+			event_payload.aio_buf.data_len = payload[2] + \
+			payload[3] + \
+			sizeof(struct dec_meta_out);
+			pr_debug("nr of frames 0x%8x len=%d\n",
+				filled_buf->meta_info.meta_out.num_of_frames,
+				event_payload.aio_buf.data_len);
+			extract_meta_info(audio, filled_buf, 0);
+			audio->eos_rsp = 0;
+		}
+		audaac_post_event(audio, AUDIO_EVENT_READ_DONE, event_payload);
+		kfree(filled_buf);
+	} else {
+		pr_err("expected=%lx ret=%x\n", filled_buf->token, token);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	}
+}
+
+static void q6_audaac_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv)
+{
+	struct q6audio *audio = (struct q6audio *)priv;
+	union msm_audio_event_payload e_payload;
+
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE:
+		pr_debug("%s:ASM_DATA_EVENT_WRITE_DONE token = 0x%x\n",
+			 __func__, token);
+		audaac_async_write_ack(audio, token, payload);
+		break;
+	case ASM_DATA_EVENT_READ_DONE:
+		pr_debug("%s:ASM_DATA_EVENT_READ_DONE token = 0x%x\n",
+			 __func__, token);
+		audaac_async_read_ack(audio, token, payload);
+		break;
+	case ASM_DATA_CMDRSP_EOS:
+		/* EOS Handle */
+		pr_debug("%s:ASM_DATA_CMDRSP_EOS\n", __func__);
+		if (audio->feedback) { /* Non-Tunnel mode */
+			audio->eos_rsp = 1;
+			/* propagate input EOS i/p buffer,
+			   after receiving DSP acknowledgement */
+			if (audio->eos_flag &&
+				(audio->eos_write_payload.aio_buf.buf_addr)) {
+				audaac_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+						audio->eos_write_payload);
+				memset(&audio->eos_write_payload , 0,
+					sizeof(union msm_audio_event_payload));
+				audio->eos_flag = 0;
+			}
+		} else { /* Tunnel mode */
+			audio->eos_rsp = 1;
+			wake_up(&audio->write_wait);
+			wake_up(&audio->cmd_wait);
+		}
+		break;
+	case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
+	case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+		pr_debug("%s:payload0[%x] payloa1d[%x]opcode= 0x%x\n",
+			 __func__, payload[0], payload[1], opcode);
+		break;
+
+	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+		pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
+				"payload[0]-sr = %d, payload[1]-chl = %d, "
+				"payload[2] = %d, payload[3] = %d\n", __func__,
+				payload[0], payload[1], payload[2],
+				payload[3]);
+		pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
+				"sr(prev) = %d, chl(prev) = %d,",
+				__func__, audio->pcm_cfg.sample_rate,
+				audio->pcm_cfg.channel_count);
+		audio->pcm_cfg.sample_rate = payload[0];
+		audio->pcm_cfg.channel_count = payload[1] & 0xFFFF;
+		e_payload.stream_info.chan_info = audio->pcm_cfg.channel_count;
+		e_payload.stream_info.sample_rate = audio->pcm_cfg.sample_rate;
+		audaac_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
+		break;
+	default:
+		pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
+		break;
+	}
+}
+
+/* ------------------- device --------------------- */
+static void audaac_async_out_flush(struct q6audio *audio)
+{
+	struct audaac_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+	unsigned long flags;
+
+	pr_debug("%s\n", __func__);
+	/* EOS followed by flush, EOS response not guranteed, free EOS i/p
+	   buffer */
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (audio->eos_flag && (audio->eos_write_payload.aio_buf.buf_addr)) {
+		pr_debug("%s: EOS followed by flush received,acknowledge eos"\
+			" i/p buffer immediately\n", __func__);
+		audaac_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+					audio->eos_write_payload);
+		memset(&audio->eos_write_payload , 0,
+			sizeof(union msm_audio_event_payload));
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+	list_for_each_safe(ptr, next, &audio->out_queue) {
+		buf_node = list_entry(ptr, struct audaac_buffer_node, list);
+		list_del(&buf_node->list);
+		payload.aio_buf = buf_node->buf;
+		audaac_post_event(audio, AUDIO_EVENT_WRITE_DONE, payload);
+		kfree(buf_node);
+		pr_debug("%s: Propagate WRITE_DONE during flush\n", __func__);
+	}
+}
+
+static void audaac_async_in_flush(struct q6audio *audio)
+{
+	struct audaac_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+
+	pr_debug("%s\n", __func__);
+	list_for_each_safe(ptr, next, &audio->in_queue) {
+		buf_node = list_entry(ptr, struct audaac_buffer_node, list);
+		list_del(&buf_node->list);
+		/* Forcefull send o/p eos buffer after flush, if no eos response
+		 * received by dsp even after sending eos command */
+		if ((audio->eos_rsp != 1) && audio->eos_flag) {
+			pr_debug("%s: send eos on o/p buffer during flush\n",\
+				__func__);
+			payload.aio_buf = buf_node->buf;
+			payload.aio_buf.data_len =
+					insert_eos_buf(audio, buf_node);
+			audio->eos_flag = 0;
+		} else {
+			payload.aio_buf = buf_node->buf;
+			payload.aio_buf.data_len =
+					insert_meta_data(audio, buf_node);
+		}
+		audaac_post_event(audio, AUDIO_EVENT_READ_DONE, payload);
+		kfree(buf_node);
+		pr_debug("%s: Propagate READ_DONE during flush\n", __func__);
+	}
+}
+
+static void audaac_ioport_reset(struct q6audio *audio)
+{
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
+		/* If fsync is in progress, make sure
+		 * return value of fsync indicates
+		 * abort due to flush
+		 */
+		if (audio->drv_status & ADRV_STATUS_FSYNC) {
+			pr_debug("fsync in progress\n");
+			audio->drv_ops.out_flush(audio);
+		} else
+			audio->drv_ops.out_flush(audio);
+		audio->drv_ops.in_flush(audio);
+	}
+}
+
+static int audaac_events_pending(struct q6audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audaac_reset_event_queue(struct q6audio *audio)
+{
+	unsigned long flags;
+	struct audaac_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+					   struct audaac_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+					   struct audaac_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audaac_process_event_req(struct q6audio *audio, void __user * arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audaac_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int)usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(audio->event_wait,
+						      audaac_events_pending
+						      (audio),
+						      msecs_to_jiffies
+						      (timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(audio->event_wait,
+					      audaac_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+					   struct audaac_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else {
+		pr_err("Unexpected path\n");
+		spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+		return -EPERM;
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
+		pr_debug("posted AUDIO_EVENT_WRITE_DONE to user\n");
+		mutex_lock(&audio->write_lock);
+		audaac_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0, 0);
+		mutex_unlock(&audio->write_lock);
+	} else if (drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
+		pr_debug("posted AUDIO_EVENT_READ_DONE to user\n");
+		mutex_lock(&audio->read_lock);
+		audaac_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0, 0);
+		mutex_unlock(&audio->read_lock);
+	}
+
+	/* Some read buffer might be held up in DSP, release all
+	 * once EOS indicated
+	 */
+	if (audio->eos_rsp && !list_empty(&audio->in_queue)) {
+		pr_debug("Send flush command to release read buffers"\
+		"held up in DSP\n");
+		audaac_flush(audio);
+	}
+
+	if (copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audaac_pmem_check(struct q6audio *audio,
+			     void *vaddr, unsigned long len)
+{
+	struct audaac_pmem_region *region_elt;
+	struct audaac_pmem_region t = {.vaddr = vaddr, .len = len };
+
+	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+		    OVERLAPS(region_elt, &t)) {
+			pr_err("region (vaddr %p len %ld)"
+			       " clashes with registered region"
+			       " (vaddr %p paddr %p len %ld)\n",
+			       vaddr, len,
+			       region_elt->vaddr,
+			       (void *)region_elt->paddr, region_elt->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int audaac_pmem_add(struct q6audio *audio,
+			   struct msm_audio_pmem_info *info)
+{
+	unsigned long paddr, kvaddr, len;
+	struct file *file;
+	struct audaac_pmem_region *region;
+	int rc = -EINVAL;
+
+	pr_debug("%s:\n", __func__);
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+
+	if (!region) {
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+		kfree(region);
+		goto end;
+	}
+
+	rc = audaac_pmem_check(audio, info->vaddr, len);
+	if (rc < 0) {
+		put_pmem_file(file);
+		kfree(region);
+		goto end;
+	}
+
+	region->vaddr = info->vaddr;
+	region->fd = info->fd;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->file = file;
+	region->ref_cnt = 0;
+	pr_debug("add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+		region->paddr, region->vaddr, region->len, region->kvaddr);
+	list_add_tail(&region->list, &audio->pmem_region_queue);
+
+	rc = q6asm_memory_map(audio->ac, (uint32_t) paddr, IN, (uint32_t) len,
+			1);
+	if (rc < 0)
+		pr_err("%s: memory map failed\n", __func__);
+end:
+	return rc;
+}
+
+static int audaac_pmem_remove(struct q6audio *audio,
+			      struct msm_audio_pmem_info *info)
+{
+	struct audaac_pmem_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	pr_debug("info fd %d vaddr %p\n", info->fd, info->vaddr);
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audaac_pmem_region, list);
+
+		if ((region->fd == info->fd) &&
+			(region->vaddr == info->vaddr)) {
+			if (region->ref_cnt) {
+				pr_debug("region %p in use ref_cnt %d\n",
+					 region, region->ref_cnt);
+				break;
+			}
+			pr_debug("remove region fd %d vaddr %p\n",
+					info->fd, info->vaddr);
+			rc = q6asm_memory_unmap(audio->ac,
+						(uint32_t) region->paddr, IN);
+			if (rc < 0)
+				pr_err("%s: memory unmap failed\n", __func__);
+
+			list_del(&region->list);
+			put_pmem_file(region->file);
+			kfree(region);
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+/* audio -> lock must be held at this point */
+static int audaac_aio_buf_add(struct q6audio *audio, unsigned dir,
+			      void __user *arg)
+{
+	unsigned long flags;
+	struct audaac_buffer_node *buf_node;
+
+	buf_node = kzalloc(sizeof(*buf_node), GFP_KERNEL);
+
+	if (!buf_node)
+		return -ENOMEM;
+
+	if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
+		kfree(buf_node);
+		return -EFAULT;
+	}
+
+	pr_debug("node %p dir %x buf_addr %p buf_len %d data_len \
+			%d\n", buf_node, dir, buf_node->buf.buf_addr,
+			buf_node->buf.buf_len, buf_node->buf.data_len);
+
+	buf_node->paddr = audaac_pmem_fixup(audio, buf_node->buf.buf_addr,
+					    buf_node->buf.buf_len, 1,
+					    &buf_node->kvaddr);
+	if (dir) {
+		/* write */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (!audio->feedback && !buf_node->buf.data_len)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		extract_meta_info(audio, buf_node, 1);
+		/* Not a EOS buffer */
+		if (!(buf_node->meta_info.meta_in.nflags & AUDAAC_EOS_SET)) {
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			audaac_async_write(audio, buf_node);
+			/* EOS buffer handled in driver */
+			list_add_tail(&buf_node->list, &audio->out_queue);
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		}
+		if (buf_node->meta_info.meta_in.nflags & AUDAAC_EOS_SET) {
+			if (!audio->wflush) {
+				pr_debug("%s:Send EOS cmd at i/p\n", __func__);
+				/* Driver will forcefully post writedone event
+				 *	once eos ack recived from DSP
+				 */
+				audio->eos_write_payload.aio_buf =
+								buf_node->buf;
+				audio->eos_flag = 1;
+				audio->eos_rsp = 0;
+				q6asm_cmd(audio->ac, CMD_EOS);
+				kfree(buf_node);
+			} else {/* Flush in progress, send back i/p
+				 * EOS buffer as is
+				 */
+				union msm_audio_event_payload event_payload;
+				event_payload.aio_buf = buf_node->buf;
+				audaac_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+						event_payload);
+				kfree(buf_node);
+			}
+
+		}
+	} else {
+		/* read */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (buf_node->buf.buf_len < PCM_BUFSZ_MIN)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		/* No EOS reached */
+		if (!audio->eos_rsp) {
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			audaac_async_read(audio, buf_node);
+			/* EOS buffer handled in driver */
+			list_add_tail(&buf_node->list, &audio->in_queue);
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		} else {
+		/* EOS reached at input side fake all upcoming read buffer to
+		 * indicate the same
+		 */
+			union msm_audio_event_payload event_payload;
+			event_payload.aio_buf = buf_node->buf;
+			event_payload.aio_buf.data_len =
+				insert_eos_buf(audio, buf_node);
+			pr_debug("%s: propagate READ_DONE as EOS done\n",
+				__func__);
+			audaac_post_event(audio, AUDIO_EVENT_READ_DONE,
+					event_payload);
+			kfree(buf_node);
+		}
+	}
+	return 0;
+}
+
+/* TBD: Only useful in tunnel-mode */
+int audaac_async_fsync(struct q6audio *audio)
+{
+	int rc = 0;
+
+	/* Blocking client sends more data */
+	mutex_lock(&audio->lock);
+	audio->drv_status |= ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	pr_debug("%s:\n", __func__);
+
+	mutex_lock(&audio->write_lock);
+	audio->eos_rsp = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+					(list_empty(&audio->out_queue)) ||
+					audio->wflush || audio->stopped);
+
+	if (rc < 0) {
+		pr_err("%s: wait event for list_empty failed, rc = %d\n",
+			__func__, rc);
+		goto done;
+	}
+
+	rc = q6asm_cmd(audio->ac, CMD_EOS);
+
+	if (rc < 0)
+		pr_err("%s: q6asm_cmd failed, rc = %d", __func__, rc);
+
+	rc = wait_event_interruptible(audio->write_wait,
+				  (audio->eos_rsp || audio->wflush ||
+				  audio->stopped));
+
+	if (rc < 0) {
+		pr_err("%s: wait event for eos_rsp failed, rc = %d\n", __func__,
+			rc);
+		goto done;
+	}
+
+	if (audio->eos_rsp == 1) {
+		rc = audaac_enable(audio);
+		if (rc)
+			pr_err("%s: audio enable failed\n", __func__);
+		else {
+			audio->drv_status &= ~ADRV_STATUS_PAUSE;
+			audio->enabled = 1;
+		}
+	}
+
+	if (audio->stopped || audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+	mutex_lock(&audio->lock);
+	audio->drv_status &= ~ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	return rc;
+}
+
+int audaac_fsync(struct file *file, int datasync)
+{
+	struct q6audio *audio = file->private_data;
+
+	if (!audio->enabled || audio->feedback)
+		return -EINVAL;
+
+	return audio->drv_ops.fsync(audio);
+}
+
+static void audaac_reset_pmem_region(struct q6audio *audio)
+{
+	struct audaac_pmem_region *region;
+	struct list_head *ptr, *next;
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audaac_pmem_region, list);
+		list_del(&region->list);
+		put_pmem_file(region->file);
+		kfree(region);
+	}
+
+	return;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audaac_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audaac_debug_read(struct file *file, char __user * buf,
+				 size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0;
+	struct q6audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "feedback %d\n", audio->feedback);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "inqueue empty %d\n", list_empty(&audio->in_queue));
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "outqueue empty %d\n", list_empty(&audio->out_queue));
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audaac_debug_fops = {
+	.read = audaac_debug_read,
+	.open = audaac_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct q6audio *audio = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return rc;
+	}
+
+	if (cmd == AUDIO_GET_EVENT) {
+		pr_debug("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audaac_process_event_req(audio,
+						      (void __user *)arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ASYNC_WRITE) {
+		mutex_lock(&audio->write_lock);
+		if (audio->drv_status & ADRV_STATUS_FSYNC)
+			rc = -EBUSY;
+		else {
+			if (audio->enabled)
+				rc = audaac_aio_buf_add(audio, 1,
+						(void __user *)arg);
+			else
+				rc = -EPERM;
+		}
+		mutex_unlock(&audio->write_lock);
+		return rc;
+	}
+
+	if (cmd == AUDIO_ASYNC_READ) {
+		mutex_lock(&audio->read_lock);
+		if ((audio->feedback) && (audio->enabled))
+			rc = audaac_aio_buf_add(audio, 0,
+					(void __user *)arg);
+		else
+			rc = -EPERM;
+		mutex_unlock(&audio->read_lock);
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		struct asm_aac_cfg aac_cfg;
+		uint32_t sbr_ps = 0x00;
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			/* Configure PCM output block */
+			rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+					audio->pcm_cfg.sample_rate,
+					audio->pcm_cfg.channel_count);
+			if (rc < 0) {
+				pr_err("pcm output block config failed\n");
+				break;
+			}
+		}
+		/* turn on both sbr and ps */
+		rc = q6asm_enable_sbrps(audio->ac, sbr_ps);
+		if (rc < 0)
+			pr_err("sbr-ps enable failed\n");
+		if (audio->aac_config.sbr_ps_on_flag)
+			aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
+		else if (audio->aac_config.sbr_on_flag)
+			aac_cfg.aot = AAC_ENC_MODE_AAC_P;
+		else
+			aac_cfg.aot = AAC_ENC_MODE_AAC_LC;
+
+		switch (audio->aac_config.format) {
+		case AUDIO_AAC_FORMAT_ADTS:
+			aac_cfg.format = 0x00;
+			break;
+		case AUDIO_AAC_FORMAT_LOAS:
+			aac_cfg.format = 0x01;
+			break;
+		/* ADIF, use it as RAW */
+		default:
+		case AUDIO_AAC_FORMAT_RAW:
+			aac_cfg.format = 0x03;
+		}
+		aac_cfg.ep_config = audio->aac_config.ep_config;
+		aac_cfg.section_data_resilience =
+			audio->aac_config.aac_section_data_resilience_flag;
+		aac_cfg.scalefactor_data_resilience =
+			audio->aac_config.aac_scalefactor_data_resilience_flag;
+		aac_cfg.spectral_data_resilience =
+			audio->aac_config.aac_spectral_data_resilience_flag;
+		aac_cfg.ch_cfg = audio->pcm_cfg.channel_count;
+		aac_cfg.sample_rate =  audio->pcm_cfg.sample_rate;
+
+		pr_debug("%s:format=%x aot=%d  ch=%d sr=%d\n",
+			__func__, aac_cfg.format,
+			aac_cfg.aot, aac_cfg.ch_cfg,
+			aac_cfg.sample_rate);
+
+		/* Configure Media format block */
+		rc = q6asm_media_format_block_aac(audio->ac, &aac_cfg);
+		if (rc < 0) {
+			pr_err("cmd media format block failed\n");
+			break;
+		}
+		rc = audaac_enable(audio);
+		audio->eos_rsp = 0;
+		audio->eos_flag = 0;
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("Audio Start procedure failed rc=%d\n", rc);
+			break;
+		}
+		pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+						audio->ac->session,
+						audio->enabled);
+		if (audio->stopped == 1)
+			audio->stopped = 0;
+		break;
+	}
+	case AUDIO_STOP: {
+		pr_debug("%s: AUDIO_STOP sessionid[%d]\n", __func__,
+						audio->ac->session);
+		audio->stopped = 1;
+		audaac_flush(audio);
+		audio->enabled = 0;
+		audio->drv_status &= ~ADRV_STATUS_PAUSE;
+		if (rc < 0) {
+			pr_err("Audio Stop procedure failed rc=%d\n", rc);
+			break;
+		}
+		break;
+	}
+	case AUDIO_PAUSE: {
+		pr_debug("AUDIO_PAUSE %ld\n", arg);
+		if (arg == 1) {
+			rc = audaac_pause(audio);
+			if (rc < 0)
+				pr_err("%s: pause FAILED rc=%d\n", __func__,
+						rc);
+				audio->drv_status |= ADRV_STATUS_PAUSE;
+		} else if (arg == 0) {
+			if (audio->drv_status & ADRV_STATUS_PAUSE) {
+				rc = audaac_enable(audio);
+				if (rc)
+					pr_err("%s: audio enable failed\n",
+						__func__);
+				else {
+					audio->drv_status &= ~ADRV_STATUS_PAUSE;
+					audio->enabled = 1;
+				}
+			}
+		}
+		break;
+	}
+	case AUDIO_FLUSH: {
+		pr_debug("%s: AUDIO_FLUSH sessionid[%d]\n", __func__,
+						audio->ac->session);
+		audio->rflush = 1;
+		audio->wflush = 1;
+		/* Flush DSP */
+		rc = audaac_flush(audio);
+		/* Flush input / Output buffer in software*/
+		audaac_ioport_reset(audio);
+		if (rc < 0) {
+			pr_err("AUDIO_FLUSH interrupted\n");
+			rc = -EINTR;
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		audio->eos_flag = 0;
+		audio->eos_rsp = 0;
+		break;
+	}
+	case AUDIO_OUTPORT_FLUSH:
+	{
+		pr_debug("AUDIO_OUTPORT_FLUSH\n");
+		rc = audaac_outport_flush(audio);
+		if (rc < 0) {
+			pr_err("%s: AUDIO_OUTPORT_FLUSH failed\n", __func__);
+			rc = -EINTR;
+		}
+		break;
+	}
+	case AUDIO_REGISTER_PMEM: {
+		struct msm_audio_pmem_info info;
+		pr_debug("AUDIO_REGISTER_PMEM\n");
+		if (copy_from_user(&info, (void *)arg, sizeof(info)))
+			rc = -EFAULT;
+		else
+			rc = audaac_pmem_add(audio, &info);
+		break;
+	}
+	case AUDIO_DEREGISTER_PMEM: {
+		struct msm_audio_pmem_info info;
+		pr_debug("AUDIO_DEREGISTER_PMEM\n");
+		if (copy_from_user(&info, (void *)arg, sizeof(info)))
+			rc = -EFAULT;
+		else
+			rc = audaac_pmem_remove(audio, &info);
+		break;
+	}
+	case AUDIO_GET_AAC_CONFIG: {
+		if (copy_to_user((void *)arg, &audio->aac_config,
+				 sizeof(struct msm_audio_aac_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case AUDIO_SET_AAC_CONFIG: {
+		if (copy_from_user(&audio->aac_config, (void *)arg,
+				 sizeof(struct msm_audio_aac_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = audio->str_cfg.buffer_size;
+		cfg.buffer_count = audio->str_cfg.buffer_count;
+		pr_debug("GET STREAM CFG %d %d\n", cfg.buffer_size,
+			 cfg.buffer_count);
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		pr_debug("SET STREAM CONFIG\n");
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->str_cfg.buffer_size = FRAME_SIZE;
+		audio->str_cfg.buffer_count = FRAME_NUM;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config cfg;
+		if (copy_to_user((void *)arg, &audio->pcm_cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+		}
+		if (audio->feedback != NON_TUNNEL_MODE) {
+			pr_err("Not sufficient permission to"
+				       "change the playback mode\n");
+			rc = -EACCES;
+			break;
+		}
+		if ((config.buffer_count > PCM_BUF_COUNT) ||
+		    (config.buffer_count == 1))
+			config.buffer_count = PCM_BUF_COUNT;
+
+		if (config.buffer_size < PCM_BUFSZ_MIN)
+			config.buffer_size = PCM_BUFSZ_MIN;
+
+		audio->pcm_cfg.buffer_count = config.buffer_count;
+		audio->pcm_cfg.buffer_size = config.buffer_size;
+		audio->pcm_cfg.channel_count = config.channel_count;
+		audio->pcm_cfg.sample_rate = config.sample_rate;
+		rc = 0;
+		break;
+		}
+	case AUDIO_SET_BUF_CFG: {
+		struct msm_audio_buf_cfg  cfg;
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if ((audio->feedback == NON_TUNNEL_MODE) &&
+			!cfg.meta_info_enable) {
+			rc = -EFAULT;
+			break;
+		}
+
+		audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
+		pr_debug("%s:session id %d: Set-buf-cfg: meta[%d]", __func__,
+				audio->ac->session, cfg.meta_info_enable);
+		break;
+	}
+	case AUDIO_GET_BUF_CFG: {
+		pr_debug("%s:session id %d: Get-buf-cfg: meta[%d]\
+			framesperbuf[%d]\n", __func__,
+			audio->ac->session, audio->buf_cfg.meta_info_enable,
+			audio->buf_cfg.frames_per_buf);
+
+		if (copy_to_user((void *)arg, &audio->buf_cfg,
+					sizeof(struct msm_audio_buf_cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+			if (copy_to_user((void *)arg, &audio->ac->session,
+					 sizeof(unsigned short))) {
+				rc = -EFAULT;
+			}
+			break;
+		}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct q6audio *audio = file->private_data;
+	pr_debug("%s: aac dec\n", __func__);
+	mutex_lock(&audio->lock);
+	audaac_disable(audio);
+	audio->drv_ops.out_flush(audio);
+	audio->drv_ops.in_flush(audio);
+	audaac_reset_pmem_region(audio);
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audaac_reset_event_queue(audio);
+	q6asm_audio_client_free(audio->ac);
+	mutex_unlock(&audio->lock);
+	mutex_destroy(&audio->lock);
+	mutex_destroy(&audio->read_lock);
+	mutex_destroy(&audio->write_lock);
+	mutex_destroy(&audio->get_event_lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	pr_info("%s:aac dec success\n", __func__);
+	return 0;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct q6audio *audio = NULL;
+	int rc = 0;
+	int i;
+	struct audaac_event *e_node = NULL;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_aac_" + 5];
+#endif
+	audio = kzalloc(sizeof(struct q6audio), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("Could not allocate memory for aac decode driver\n");
+		return -ENOMEM;
+	}
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->str_cfg.buffer_size = FRAME_SIZE;
+	audio->str_cfg.buffer_count = FRAME_NUM;
+	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+	audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+	audio->pcm_cfg.sample_rate = 48000;
+	audio->pcm_cfg.channel_count = 2;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audaac_cb,
+					     (void *)audio);
+
+	if (!audio->ac) {
+		pr_err("Could not allocate memory for audio client\n");
+		kfree(audio);
+		return -ENOMEM;
+	}
+	/* Only AIO interface */
+	if (file->f_flags & O_NONBLOCK) {
+		pr_debug("set to aio interface\n");
+		audio->drv_status |= ADRV_STATUS_AIO_INTF;
+		audio->drv_ops.out_flush = audaac_async_out_flush;
+		audio->drv_ops.in_flush = audaac_async_in_flush;
+		audio->drv_ops.fsync = audaac_async_fsync;
+		q6asm_set_io_mode(audio->ac, ASYNC_IO_MODE);
+	} else {
+		pr_err("SIO interface not supported\n");
+		rc = -EACCES;
+		goto fail;
+	}
+
+	/* open in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+					   FORMAT_MPEG4_AAC);
+		if (rc < 0) {
+			pr_err("NT mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = NON_TUNNEL_MODE;
+		/* open AAC decoder, expected frames is always 1
+		audio->buf_cfg.frames_per_buf = 0x01;*/
+		audio->buf_cfg.meta_info_enable = 0x01;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_write(audio->ac, FORMAT_MPEG4_AAC);
+		if (rc < 0) {
+			pr_err("T mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = TUNNEL_MODE;
+		audio->buf_cfg.meta_info_enable = 0x00;
+	} else {
+		pr_err("Not supported mode\n");
+		rc = -EACCES;
+		goto fail;
+	}
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	spin_lock_init(&audio->event_queue_lock);
+	init_waitqueue_head(&audio->cmd_wait);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->event_wait);
+	INIT_LIST_HEAD(&audio->out_queue);
+	INIT_LIST_HEAD(&audio->in_queue);
+	INIT_LIST_HEAD(&audio->pmem_region_queue);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+
+	audio->drv_ops.out_flush(audio);
+	audio->opened = 1;
+	file->private_data = audio;
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_aac_%04x", audio->ac->session);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+					    NULL, (void *)audio,
+					    &audaac_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		pr_debug("debugfs_create_file failed\n");
+#endif
+	for (i = 0; i < AUDAAC_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audaac_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			pr_err("event pkt alloc failed\n");
+			break;
+		}
+	}
+	pr_info("%s:aacdec success mode[%d]session[%d]\n", __func__,
+						audio->feedback,
+						audio->ac->session);
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_aac_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_release,
+	.unlocked_ioctl = audio_ioctl,
+	.fsync = audaac_fsync,
+};
+
+struct miscdevice audaac_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_aac",
+	.fops = &audio_aac_fops,
+};
+
+static int __init audio_aac_init(void)
+{
+	return misc_register(&audaac_misc);
+}
+
+device_initcall(audio_aac_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_acdb.c b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
new file mode 100644
index 0000000..7ce070c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_acdb.c
@@ -0,0 +1,905 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+#include <linux/android_pmem.h>
+#include <linux/mm.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+
+
+#define MAX_NETWORKS		9
+#define NUM_ACTIVE_NETWORKS	6
+#define VOCPROC_STREAM_OFFSET	NUM_ACTIVE_NETWORKS
+#define VOCPROC_VOL_OFFSET	(NUM_ACTIVE_NETWORKS * 2)
+#define NUM_VOCPROC_CAL_TYPES	(NUM_ACTIVE_NETWORKS * 3)
+#define NUM_AUDPROC_CAL_TYPES	3
+#define ACDB_BLOCK_SIZE		4096
+#define NUM_VOCPROC_BLOCKS	18
+
+enum {
+	RX_CAL,
+	TX_CAL,
+	MAX_AUDPROC_TYPES
+};
+
+struct acdb_data {
+	struct mutex		acdb_mutex;
+
+	/* ANC Cal */
+	struct acdb_cal_block	anc_cal;
+
+	/* AudProc Cal */
+	uint32_t		adm_topology;
+	uint32_t		asm_topology;
+	struct acdb_cal_block	audproc_cal[MAX_AUDPROC_TYPES];
+	struct acdb_cal_block	audstrm_cal[MAX_AUDPROC_TYPES];
+	struct acdb_cal_block	audvol_cal[MAX_AUDPROC_TYPES];
+
+	/* VocProc Cal */
+	uint32_t                voice_rx_topology;
+	uint32_t                voice_tx_topology;
+	struct acdb_cal_block	vocproc_cal[MAX_NETWORKS];
+	struct acdb_cal_block	vocstrm_cal[MAX_NETWORKS];
+	struct acdb_cal_block	vocvol_cal[MAX_NETWORKS];
+	/* size of cal block tables above*/
+	uint32_t		vocproc_cal_size;
+	uint32_t		vocstrm_cal_size;
+	uint32_t		vocvol_cal_size;
+	/* Total size of cal data for all networks */
+	uint32_t		vocproc_total_cal_size;
+	uint32_t		vocstrm_total_cal_size;
+	uint32_t		vocvol_total_cal_size;
+
+	/* Sidetone Cal */
+	struct sidetone_cal	sidetone_cal;
+
+	/* PMEM information */
+	int			pmem_fd;
+	unsigned long		paddr;
+	unsigned long		kvaddr;
+	unsigned long		pmem_len;
+	struct file		*file;
+
+};
+
+static struct acdb_data		acdb_data;
+static atomic_t usage_count;
+
+uint32_t get_voice_rx_topology(void)
+{
+	return acdb_data.voice_rx_topology;
+}
+
+void store_voice_rx_topology(uint32_t topology)
+{
+	acdb_data.voice_rx_topology = topology;
+}
+
+uint32_t get_voice_tx_topology(void)
+{
+	return acdb_data.voice_tx_topology;
+}
+
+void store_voice_tx_topology(uint32_t topology)
+{
+	acdb_data.voice_tx_topology = topology;
+}
+
+uint32_t get_adm_topology(void)
+{
+	return acdb_data.adm_topology;
+}
+
+void store_adm_topology(uint32_t topology)
+{
+	acdb_data.adm_topology = topology;
+}
+
+uint32_t get_asm_topology(void)
+{
+	return acdb_data.asm_topology;
+}
+
+void store_asm_topology(uint32_t topology)
+{
+	acdb_data.asm_topology = topology;
+}
+
+void get_all_voice_cal(struct acdb_cal_block *cal_block)
+{
+	cal_block->cal_kvaddr = acdb_data.vocproc_cal[0].cal_kvaddr;
+	cal_block->cal_paddr = acdb_data.vocproc_cal[0].cal_paddr;
+	cal_block->cal_size = acdb_data.vocproc_total_cal_size +
+				acdb_data.vocstrm_total_cal_size +
+				acdb_data.vocvol_total_cal_size;
+}
+
+void get_all_cvp_cal(struct acdb_cal_block *cal_block)
+{
+	cal_block->cal_kvaddr = acdb_data.vocproc_cal[0].cal_kvaddr;
+	cal_block->cal_paddr = acdb_data.vocproc_cal[0].cal_paddr;
+	cal_block->cal_size = acdb_data.vocproc_total_cal_size +
+				acdb_data.vocvol_total_cal_size;
+}
+
+void get_all_vocproc_cal(struct acdb_cal_block *cal_block)
+{
+	cal_block->cal_kvaddr = acdb_data.vocproc_cal[0].cal_kvaddr;
+	cal_block->cal_paddr = acdb_data.vocproc_cal[0].cal_paddr;
+	cal_block->cal_size = acdb_data.vocproc_total_cal_size;
+}
+
+void get_all_vocstrm_cal(struct acdb_cal_block *cal_block)
+{
+	cal_block->cal_kvaddr = acdb_data.vocstrm_cal[0].cal_kvaddr;
+	cal_block->cal_paddr = acdb_data.vocstrm_cal[0].cal_paddr;
+	cal_block->cal_size = acdb_data.vocstrm_total_cal_size;
+}
+
+void get_all_vocvol_cal(struct acdb_cal_block *cal_block)
+{
+	cal_block->cal_kvaddr = acdb_data.vocvol_cal[0].cal_kvaddr;
+	cal_block->cal_paddr = acdb_data.vocvol_cal[0].cal_paddr;
+	cal_block->cal_size = acdb_data.vocvol_total_cal_size;
+}
+
+void get_anc_cal(struct acdb_cal_block *cal_block)
+{
+	pr_debug("%s\n", __func__);
+
+	if (cal_block == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+
+	mutex_lock(&acdb_data.acdb_mutex);
+
+	cal_block->cal_kvaddr = acdb_data.anc_cal.cal_kvaddr;
+	cal_block->cal_paddr = acdb_data.anc_cal.cal_paddr;
+	cal_block->cal_size = acdb_data.anc_cal.cal_size;
+
+	mutex_unlock(&acdb_data.acdb_mutex);
+done:
+	return;
+}
+
+void store_anc_cal(struct cal_block *cal_block)
+{
+	pr_debug("%s,\n", __func__);
+
+	if (cal_block->cal_offset > acdb_data.pmem_len) {
+		pr_err("%s: offset %d is > pmem_len %ld\n",
+			__func__, cal_block->cal_offset,
+			acdb_data.pmem_len);
+		goto done;
+	}
+
+	mutex_lock(&acdb_data.acdb_mutex);
+
+	acdb_data.anc_cal.cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
+	acdb_data.anc_cal.cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.anc_cal.cal_size =
+		cal_block->cal_size;
+
+	mutex_unlock(&acdb_data.acdb_mutex);
+done:
+	return;
+}
+
+void get_audproc_buffer_data(struct audproc_buffer_data *cal_buffers)
+{
+	int i;
+	pr_debug("%s\n", __func__);
+
+	if (cal_buffers == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+
+	for (i = 0; i < NUM_AUDPROC_BUFFERS; i++) {
+		cal_buffers->phys_addr[i] = (uint32_t)
+			(acdb_data.paddr +
+			(NUM_VOCPROC_BLOCKS + i) * ACDB_BLOCK_SIZE);
+		cal_buffers->buf_size[i] = ACDB_BLOCK_SIZE;
+	}
+done:
+	return;
+}
+
+void store_audproc_cal(int32_t path, struct cal_block *cal_block)
+{
+	pr_debug("%s, path = %d\n", __func__, path);
+
+	mutex_lock(&acdb_data.acdb_mutex);
+
+	if (cal_block->cal_offset > acdb_data.pmem_len) {
+		pr_err("%s: offset %d is > pmem_len %ld\n",
+			__func__, cal_block->cal_offset,
+			acdb_data.pmem_len);
+		goto done;
+	}
+	if (path >= MAX_AUDPROC_TYPES) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+			__func__, path);
+		goto done;
+	}
+
+	acdb_data.audproc_cal[path].cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
+	acdb_data.audproc_cal[path].cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.audproc_cal[path].cal_size =
+		cal_block->cal_size;
+
+done:
+	mutex_unlock(&acdb_data.acdb_mutex);
+	return;
+}
+
+void get_audproc_cal(int32_t path, struct acdb_cal_block *cal_block)
+{
+	pr_debug("%s, path = %d\n", __func__, path);
+
+	if (cal_block == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+	if (path >= MAX_AUDPROC_TYPES) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+			__func__, path);
+		goto done;
+	}
+
+	mutex_lock(&acdb_data.acdb_mutex);
+
+	cal_block->cal_kvaddr = acdb_data.audproc_cal[path].cal_kvaddr;
+	cal_block->cal_paddr = acdb_data.audproc_cal[path].cal_paddr;
+	cal_block->cal_size = acdb_data.audproc_cal[path].cal_size;
+
+	mutex_unlock(&acdb_data.acdb_mutex);
+done:
+	return;
+}
+
+void store_audstrm_cal(int32_t path, struct cal_block *cal_block)
+{
+	pr_debug("%s, path = %d\n", __func__, path);
+
+	mutex_lock(&acdb_data.acdb_mutex);
+
+	if (cal_block->cal_offset > acdb_data.pmem_len) {
+		pr_err("%s: offset %d is > pmem_len %ld\n",
+			__func__, cal_block->cal_offset,
+			acdb_data.pmem_len);
+		goto done;
+	}
+	if (path >= MAX_AUDPROC_TYPES) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+			__func__, path);
+		goto done;
+	}
+
+	acdb_data.audstrm_cal[path].cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
+	acdb_data.audstrm_cal[path].cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.audstrm_cal[path].cal_size =
+		cal_block->cal_size;
+
+done:
+	mutex_unlock(&acdb_data.acdb_mutex);
+	return;
+}
+
+void get_audstrm_cal(int32_t path, struct acdb_cal_block *cal_block)
+{
+	pr_debug("%s, path = %d\n", __func__, path);
+
+	if (cal_block == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+	if (path >= MAX_AUDPROC_TYPES) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+			__func__, path);
+		goto done;
+	}
+
+	mutex_lock(&acdb_data.acdb_mutex);
+
+	cal_block->cal_kvaddr = acdb_data.audstrm_cal[path].cal_kvaddr;
+	cal_block->cal_paddr = acdb_data.audstrm_cal[path].cal_paddr;
+	cal_block->cal_size = acdb_data.audstrm_cal[path].cal_size;
+
+	mutex_unlock(&acdb_data.acdb_mutex);
+done:
+	return;
+}
+
+void store_audvol_cal(int32_t path, struct cal_block *cal_block)
+{
+	pr_debug("%s, path = %d\n", __func__, path);
+
+	mutex_lock(&acdb_data.acdb_mutex);
+
+	if (cal_block->cal_offset > acdb_data.pmem_len) {
+		pr_err("%s: offset %d is > pmem_len %ld\n",
+			__func__, cal_block->cal_offset,
+			acdb_data.pmem_len);
+		goto done;
+	}
+	if (path >= MAX_AUDPROC_TYPES) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+			__func__, path);
+		goto done;
+	}
+
+	acdb_data.audvol_cal[path].cal_kvaddr =
+		cal_block->cal_offset + acdb_data.kvaddr;
+	acdb_data.audvol_cal[path].cal_paddr =
+		cal_block->cal_offset + acdb_data.paddr;
+	acdb_data.audvol_cal[path].cal_size =
+		cal_block->cal_size;
+
+done:
+	mutex_unlock(&acdb_data.acdb_mutex);
+	return;
+}
+
+void get_audvol_cal(int32_t path, struct acdb_cal_block *cal_block)
+{
+	pr_debug("%s, path = %d\n", __func__, path);
+
+	if (cal_block == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+	if (path > MAX_AUDPROC_TYPES || path < 0) {
+		pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+			__func__, path);
+		goto done;
+	}
+
+	mutex_lock(&acdb_data.acdb_mutex);
+
+	cal_block->cal_kvaddr = acdb_data.audvol_cal[path].cal_kvaddr;
+	cal_block->cal_paddr = acdb_data.audvol_cal[path].cal_paddr;
+	cal_block->cal_size = acdb_data.audvol_cal[path].cal_size;
+
+	mutex_unlock(&acdb_data.acdb_mutex);
+done:
+	return;
+}
+
+
+void store_vocproc_cal(int32_t len, struct cal_block *cal_blocks)
+{
+	int i;
+	pr_debug("%s\n", __func__);
+
+	if (len > MAX_NETWORKS) {
+		pr_err("%s: Calibration sent for %d networks, only %d are "
+			"supported!\n", __func__, len, MAX_NETWORKS);
+		goto done;
+	}
+
+
+	mutex_lock(&acdb_data.acdb_mutex);
+
+	acdb_data.vocproc_total_cal_size = 0;
+	for (i = 0; i < len; i++) {
+		if (cal_blocks[i].cal_offset > acdb_data.pmem_len) {
+			pr_err("%s: offset %d is > pmem_len %ld\n",
+				__func__, cal_blocks[i].cal_offset,
+				acdb_data.pmem_len);
+			acdb_data.vocproc_cal[i].cal_size = 0;
+		} else {
+			acdb_data.vocproc_total_cal_size +=
+				cal_blocks[i].cal_size;
+			acdb_data.vocproc_cal[i].cal_size =
+				cal_blocks[i].cal_size;
+			acdb_data.vocproc_cal[i].cal_paddr =
+				cal_blocks[i].cal_offset +
+				acdb_data.paddr;
+			acdb_data.vocproc_cal[i].cal_kvaddr =
+				cal_blocks[i].cal_offset +
+				acdb_data.kvaddr;
+		}
+	}
+	acdb_data.vocproc_cal_size = len;
+	mutex_unlock(&acdb_data.acdb_mutex);
+done:
+	return;
+}
+
+void get_vocproc_cal(struct acdb_cal_data *cal_data)
+{
+	pr_debug("%s\n", __func__);
+
+	if (cal_data == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+
+	mutex_lock(&acdb_data.acdb_mutex);
+
+	cal_data->num_cal_blocks = acdb_data.vocproc_cal_size;
+	cal_data->cal_blocks = &acdb_data.vocproc_cal[0];
+
+	mutex_unlock(&acdb_data.acdb_mutex);
+done:
+	return;
+}
+
+void store_vocstrm_cal(int32_t len, struct cal_block *cal_blocks)
+{
+	int i;
+	pr_debug("%s\n", __func__);
+
+	if (len > MAX_NETWORKS) {
+		pr_err("%s: Calibration sent for %d networks, only %d are "
+			"supported!\n", __func__, len, MAX_NETWORKS);
+		goto done;
+	}
+
+	mutex_lock(&acdb_data.acdb_mutex);
+
+	acdb_data.vocstrm_total_cal_size = 0;
+	for (i = 0; i < len; i++) {
+		if (cal_blocks[i].cal_offset > acdb_data.pmem_len) {
+			pr_err("%s: offset %d is > pmem_len %ld\n",
+				__func__, cal_blocks[i].cal_offset,
+				acdb_data.pmem_len);
+			acdb_data.vocstrm_cal[i].cal_size = 0;
+		} else {
+			acdb_data.vocstrm_total_cal_size +=
+				cal_blocks[i].cal_size;
+			acdb_data.vocstrm_cal[i].cal_size =
+				cal_blocks[i].cal_size;
+			acdb_data.vocstrm_cal[i].cal_paddr =
+				cal_blocks[i].cal_offset +
+				acdb_data.paddr;
+			acdb_data.vocstrm_cal[i].cal_kvaddr =
+				cal_blocks[i].cal_offset +
+				acdb_data.kvaddr;
+		}
+	}
+	acdb_data.vocstrm_cal_size = len;
+	mutex_unlock(&acdb_data.acdb_mutex);
+done:
+	return;
+}
+
+void get_vocstrm_cal(struct acdb_cal_data *cal_data)
+{
+	pr_debug("%s\n", __func__);
+
+	if (cal_data == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+
+	mutex_lock(&acdb_data.acdb_mutex);
+
+	cal_data->num_cal_blocks = acdb_data.vocstrm_cal_size;
+	cal_data->cal_blocks = &acdb_data.vocstrm_cal[0];
+
+	mutex_unlock(&acdb_data.acdb_mutex);
+done:
+	return;
+}
+
+void store_vocvol_cal(int32_t len, struct cal_block *cal_blocks)
+{
+	int i;
+	pr_debug("%s\n", __func__);
+
+	if (len > MAX_NETWORKS) {
+		pr_err("%s: Calibration sent for %d networks, only %d are "
+			"supported!\n", __func__, len, MAX_NETWORKS);
+		goto done;
+	}
+
+	mutex_lock(&acdb_data.acdb_mutex);
+
+	acdb_data.vocvol_total_cal_size = 0;
+	for (i = 0; i < len; i++) {
+		if (cal_blocks[i].cal_offset > acdb_data.pmem_len) {
+			pr_err("%s: offset %d is > pmem_len %ld\n",
+				__func__, cal_blocks[i].cal_offset,
+				acdb_data.pmem_len);
+			acdb_data.vocvol_cal[i].cal_size = 0;
+		} else {
+			acdb_data.vocvol_total_cal_size +=
+				cal_blocks[i].cal_size;
+			acdb_data.vocvol_cal[i].cal_size =
+				cal_blocks[i].cal_size;
+			acdb_data.vocvol_cal[i].cal_paddr =
+				cal_blocks[i].cal_offset +
+				acdb_data.paddr;
+			acdb_data.vocvol_cal[i].cal_kvaddr =
+				cal_blocks[i].cal_offset +
+				acdb_data.kvaddr;
+		}
+	}
+	acdb_data.vocvol_cal_size = len;
+	mutex_unlock(&acdb_data.acdb_mutex);
+done:
+	return;
+}
+
+void get_vocvol_cal(struct acdb_cal_data *cal_data)
+{
+	pr_debug("%s\n", __func__);
+
+	if (cal_data == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+
+	mutex_lock(&acdb_data.acdb_mutex);
+
+	cal_data->num_cal_blocks = acdb_data.vocvol_cal_size;
+	cal_data->cal_blocks = &acdb_data.vocvol_cal[0];
+
+	mutex_unlock(&acdb_data.acdb_mutex);
+done:
+	return;
+}
+
+void store_sidetone_cal(struct sidetone_cal *cal_data)
+{
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&acdb_data.acdb_mutex);
+
+	acdb_data.sidetone_cal.enable = cal_data->enable;
+	acdb_data.sidetone_cal.gain = cal_data->gain;
+
+	mutex_unlock(&acdb_data.acdb_mutex);
+}
+
+
+void get_sidetone_cal(struct sidetone_cal *cal_data)
+{
+	pr_debug("%s\n", __func__);
+
+	if (cal_data == NULL) {
+		pr_err("ACDB=> NULL pointer sent to %s\n", __func__);
+		goto done;
+	}
+
+	mutex_lock(&acdb_data.acdb_mutex);
+
+	cal_data->enable = acdb_data.sidetone_cal.enable;
+	cal_data->gain = acdb_data.sidetone_cal.gain;
+
+	mutex_unlock(&acdb_data.acdb_mutex);
+done:
+	return;
+}
+
+static int acdb_open(struct inode *inode, struct file *f)
+{
+	s32 result = 0;
+	pr_info("%s\n", __func__);
+
+	mutex_lock(&acdb_data.acdb_mutex);
+	if (acdb_data.pmem_fd) {
+		pr_info("%s: ACDB opened but PMEM allocated, using existing PMEM!\n",
+			__func__);
+	}
+	mutex_unlock(&acdb_data.acdb_mutex);
+
+	atomic_inc(&usage_count);
+	return result;
+}
+
+static int deregister_pmem(void)
+{
+	int result;
+	struct audproc_buffer_data buffer;
+
+	get_audproc_buffer_data(&buffer);
+
+	result = adm_memory_unmap_regions(buffer.phys_addr,
+			buffer.buf_size, NUM_AUDPROC_BUFFERS);
+
+	if (result < 0)
+		pr_err("Audcal unmap did not work!\n");
+
+	if (acdb_data.pmem_fd) {
+		put_pmem_file(acdb_data.file);
+		acdb_data.pmem_fd = 0;
+	}
+	return result;
+}
+
+static int register_pmem(void)
+{
+	int result;
+	struct audproc_buffer_data buffer;
+
+	result = get_pmem_file(acdb_data.pmem_fd, &acdb_data.paddr,
+				&acdb_data.kvaddr, &acdb_data.pmem_len,
+				&acdb_data.file);
+	if (result != 0) {
+		acdb_data.pmem_fd = 0;
+		pr_err("%s: Could not register PMEM!!!\n", __func__);
+		goto done;
+	}
+
+	pr_debug("AUDIO_REGISTER_PMEM done! paddr = 0x%lx, "
+		"kvaddr = 0x%lx, len = x%lx\n", acdb_data.paddr,
+		acdb_data.kvaddr, acdb_data.pmem_len);
+	get_audproc_buffer_data(&buffer);
+	result = adm_memory_map_regions(buffer.phys_addr, 0,
+			buffer.buf_size,
+			NUM_AUDPROC_BUFFERS);
+	if (result < 0)
+		pr_err("Audcal mmap did not work!\n");
+	goto done;
+
+done:
+	return result;
+}
+static long acdb_ioctl(struct file *f,
+		unsigned int cmd, unsigned long arg)
+{
+	s32			result = 0;
+	s32			audproc_path;
+	s32			size;
+	u32			topology;
+	struct cal_block	data[MAX_NETWORKS];
+	pr_debug("%s\n", __func__);
+
+	switch (cmd) {
+	case AUDIO_REGISTER_PMEM:
+		pr_debug("AUDIO_REGISTER_PMEM\n");
+		mutex_lock(&acdb_data.acdb_mutex);
+		if (acdb_data.pmem_fd) {
+			deregister_pmem();
+			pr_info("Remove the existing PMEM\n");
+		}
+
+		if (copy_from_user(&acdb_data.pmem_fd, (void *)arg,
+					sizeof(acdb_data.pmem_fd))) {
+			pr_err("%s: fail to copy pmem handle!\n", __func__);
+			result = -EFAULT;
+		} else {
+			result = register_pmem();
+		}
+		mutex_unlock(&acdb_data.acdb_mutex);
+		goto done;
+
+	case AUDIO_DEREGISTER_PMEM:
+		pr_debug("AUDIO_DEREGISTER_PMEM\n");
+		mutex_lock(&acdb_data.acdb_mutex);
+		deregister_pmem();
+		mutex_unlock(&acdb_data.acdb_mutex);
+		goto done;
+	case AUDIO_SET_VOICE_RX_TOPOLOGY:
+		if (copy_from_user(&topology, (void *)arg,
+				sizeof(topology))) {
+			pr_err("%s: fail to copy topology!\n", __func__);
+			result = -EFAULT;
+		}
+		store_voice_rx_topology(topology);
+		goto done;
+	case AUDIO_SET_VOICE_TX_TOPOLOGY:
+		if (copy_from_user(&topology, (void *)arg,
+				sizeof(topology))) {
+			pr_err("%s: fail to copy topology!\n", __func__);
+			result = -EFAULT;
+		}
+		store_voice_tx_topology(topology);
+		goto done;
+	case AUDIO_SET_ADM_TOPOLOGY:
+		if (copy_from_user(&topology, (void *)arg,
+				sizeof(topology))) {
+			pr_err("%s: fail to copy topology!\n", __func__);
+			result = -EFAULT;
+		}
+		store_adm_topology(topology);
+		goto done;
+	case AUDIO_SET_ASM_TOPOLOGY:
+		if (copy_from_user(&topology, (void *)arg,
+				sizeof(topology))) {
+			pr_err("%s: fail to copy topology!\n", __func__);
+			result = -EFAULT;
+		}
+		store_asm_topology(topology);
+		goto done;
+	}
+
+	if (copy_from_user(&size, (void *) arg, sizeof(size))) {
+
+		result = -EFAULT;
+		goto done;
+	}
+
+	if (size <= 0) {
+		pr_err("%s: Invalid size sent to driver: %d\n",
+			__func__, size);
+		result = -EFAULT;
+		goto done;
+	}
+
+	if (copy_from_user(data, (void *)(arg + sizeof(size)), size)) {
+
+		pr_err("%s: fail to copy table size %d\n", __func__, size);
+		result = -EFAULT;
+		goto done;
+	}
+
+	if (data == NULL) {
+		pr_err("%s: NULL pointer sent to driver!\n", __func__);
+		result = -EFAULT;
+		goto done;
+	}
+
+	switch (cmd) {
+	case AUDIO_SET_AUDPROC_TX_CAL:
+		audproc_path = TX_CAL;
+		if (size > sizeof(struct cal_block))
+			pr_err("%s: More Audproc Cal then expected, "
+				"size received: %d\n", __func__, size);
+		store_audproc_cal(audproc_path, data);
+		break;
+	case AUDIO_SET_AUDPROC_RX_CAL:
+		audproc_path = RX_CAL;
+		if (size > sizeof(struct cal_block))
+			pr_err("%s: More Audproc Cal then expected, "
+				"size received: %d\n", __func__, size);
+		store_audproc_cal(audproc_path, data);
+		break;
+	case AUDIO_SET_AUDPROC_TX_STREAM_CAL:
+		audproc_path = TX_CAL;
+		if (size > sizeof(struct cal_block))
+			pr_err("%s: More Audproc Cal then expected, "
+				"size received: %d\n", __func__, size);
+		store_audstrm_cal(audproc_path, data);
+		break;
+	case AUDIO_SET_AUDPROC_RX_STREAM_CAL:
+		audproc_path = RX_CAL;
+		if (size > sizeof(struct cal_block))
+			pr_err("%s: More Audproc Cal then expected, "
+				"size received: %d\n", __func__, size);
+		store_audstrm_cal(audproc_path, data);
+		break;
+	case AUDIO_SET_AUDPROC_TX_VOL_CAL:
+		audproc_path = TX_CAL;
+		if (size > sizeof(struct cal_block))
+			pr_err("%s: More Audproc Cal then expected, "
+				"size received: %d\n", __func__, size);
+		store_audvol_cal(audproc_path, data);
+	case AUDIO_SET_AUDPROC_RX_VOL_CAL:
+		audproc_path = RX_CAL;
+		if (size > sizeof(struct cal_block))
+			pr_err("%s: More Audproc Cal then expected, "
+				"size received: %d\n", __func__, size);
+		store_audvol_cal(audproc_path, data);
+		break;
+	case AUDIO_SET_VOCPROC_CAL:
+		store_vocproc_cal(size / sizeof(struct cal_block), data);
+		break;
+	case AUDIO_SET_VOCPROC_STREAM_CAL:
+		store_vocstrm_cal(size / sizeof(struct cal_block), data);
+		break;
+	case AUDIO_SET_VOCPROC_VOL_CAL:
+		store_vocvol_cal(size / sizeof(struct cal_block), data);
+		break;
+	case AUDIO_SET_SIDETONE_CAL:
+		if (size > sizeof(struct sidetone_cal))
+			pr_err("%s: More sidetone cal then expected, "
+				"size received: %d\n", __func__, size);
+		store_sidetone_cal((struct sidetone_cal *)data);
+		break;
+	case AUDIO_SET_ANC_CAL:
+		store_anc_cal(data);
+		break;
+	default:
+		pr_err("ACDB=> ACDB ioctl not found!\n");
+	}
+
+done:
+	return result;
+}
+
+static int acdb_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	int result = 0;
+	int size = vma->vm_end - vma->vm_start;
+
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&acdb_data.acdb_mutex);
+	if (acdb_data.pmem_fd) {
+		if (size <= acdb_data.pmem_len) {
+			vma->vm_page_prot = pgprot_noncached(
+						vma->vm_page_prot);
+			result = remap_pfn_range(vma,
+				vma->vm_start,
+				acdb_data.paddr >> PAGE_SHIFT,
+				size,
+				vma->vm_page_prot);
+		} else {
+			pr_err("%s: Not enough PMEM memory!\n", __func__);
+			result = -ENOMEM;
+		}
+	} else {
+		pr_err("%s: PMEM is not allocated, yet!\n", __func__);
+		result = -ENODEV;
+	}
+	mutex_unlock(&acdb_data.acdb_mutex);
+
+	return result;
+}
+
+static int acdb_release(struct inode *inode, struct file *f)
+{
+	s32 result = 0;
+
+	atomic_dec(&usage_count);
+	atomic_read(&usage_count);
+
+	pr_info("%s: ref count %d!\n", __func__,
+		atomic_read(&usage_count));
+
+	if (atomic_read(&usage_count) >= 1) {
+		result = -EBUSY;
+	} else {
+		mutex_lock(&acdb_data.acdb_mutex);
+		result = deregister_pmem();
+		mutex_unlock(&acdb_data.acdb_mutex);
+	}
+
+	return result;
+}
+
+static const struct file_operations acdb_fops = {
+	.owner = THIS_MODULE,
+	.open = acdb_open,
+	.release = acdb_release,
+	.unlocked_ioctl = acdb_ioctl,
+	.mmap = acdb_mmap,
+};
+
+struct miscdevice acdb_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_acdb",
+	.fops	= &acdb_fops,
+};
+
+static int __init acdb_init(void)
+{
+	memset(&acdb_data, 0, sizeof(acdb_data));
+	mutex_init(&acdb_data.acdb_mutex);
+	atomic_set(&usage_count, 0);
+	return misc_register(&acdb_misc);
+}
+
+static void __exit acdb_exit(void)
+{
+}
+
+module_init(acdb_init);
+module_exit(acdb_exit);
+
+MODULE_DESCRIPTION("MSM 8x60 Audio ACDB driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c b/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c
new file mode 100644
index 0000000..08e5266
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_dev_ctl.c
@@ -0,0 +1,1701 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/msm_audio.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <mach/debug_mm.h>
+#include <mach/qdsp6v2/q6voice.h>
+#include <mach/qdsp6v2/rtac.h>
+#include <sound/apr_audio.h>
+#include <sound/q6adm.h>
+
+#ifndef MAX
+#define  MAX(x, y) (((x) > (y)) ? (x) : (y))
+#endif
+
+
+static DEFINE_MUTEX(session_lock);
+
+struct audio_dev_ctrl_state {
+	struct msm_snddev_info *devs[AUDIO_DEV_CTL_MAX_DEV];
+	u32 num_dev;
+	atomic_t opened;
+	struct msm_snddev_info *voice_rx_dev;
+	struct msm_snddev_info *voice_tx_dev;
+	wait_queue_head_t      wait;
+};
+
+static struct audio_dev_ctrl_state audio_dev_ctrl;
+struct event_listner event;
+
+#define PLAYBACK 0x1
+#define LIVE_RECORDING 0x2
+#define NON_LIVE_RECORDING 0x3
+#define MAX_COPP_DEVICES 4
+
+struct session_freq {
+	int freq;
+	int evt;
+};
+
+struct audio_routing_info {
+	unsigned short mixer_mask[MAX_SESSIONS];
+	unsigned short audrec_mixer_mask[MAX_SESSIONS];
+	struct session_freq dec_freq[MAX_SESSIONS];
+	struct session_freq enc_freq[MAX_SESSIONS];
+	unsigned int copp_list[MAX_SESSIONS][AFE_MAX_PORTS];
+	int voice_tx_dev_id;
+	int voice_rx_dev_id;
+	int voice_tx_sample_rate;
+	int voice_rx_sample_rate;
+	signed int voice_tx_vol;
+	signed int voice_rx_vol;
+	int tx_mute;
+	int rx_mute;
+	int voice_state;
+	struct mutex copp_list_mutex;
+	struct mutex adm_mutex;
+};
+
+static struct audio_routing_info routing_info;
+
+struct audio_copp_topology {
+	struct mutex lock;
+	int session_cnt;
+	int session_id[MAX_SESSIONS];
+	int topolog_id[MAX_SESSIONS];
+};
+static struct audio_copp_topology adm_tx_topology_tbl;
+
+int msm_reset_all_device(void)
+{
+	int rc = 0;
+	int dev_id = 0;
+	struct msm_snddev_info *dev_info = NULL;
+
+	for (dev_id = 0; dev_id < audio_dev_ctrl.num_dev; dev_id++) {
+		dev_info = audio_dev_ctrl_find_dev(dev_id);
+		if (IS_ERR(dev_info)) {
+			pr_err("%s:pass invalid dev_id\n", __func__);
+			rc = PTR_ERR(dev_info);
+			return rc;
+		}
+		if (!dev_info->opened)
+			continue;
+		pr_debug("%s:Resetting device %d active on COPP %d"
+			"with  %lld as routing\n", __func__,
+				dev_id, dev_info->copp_id, dev_info->sessions);
+		broadcast_event(AUDDEV_EVT_REL_PENDING,
+					dev_id,
+					SESSION_IGNORE);
+		rc = dev_info->dev_ops.close(dev_info);
+		if (rc < 0) {
+			pr_err("%s:Snd device failed close!\n", __func__);
+			return rc;
+		} else {
+			dev_info->opened = 0;
+			broadcast_event(AUDDEV_EVT_DEV_RLS,
+				dev_id,
+				SESSION_IGNORE);
+
+			if (dev_info->copp_id == VOICE_PLAYBACK_TX)
+				voice_start_playback(0);
+		}
+		dev_info->sessions = 0;
+	}
+	msm_clear_all_session();
+	return 0;
+}
+EXPORT_SYMBOL(msm_reset_all_device);
+
+int msm_set_copp_id(int session_id, int copp_id)
+{
+	int rc = 0;
+	int index;
+
+	if (session_id < 1 || session_id > 8)
+		return -EINVAL;
+	if (afe_validate_port(copp_id) < 0)
+		return -EINVAL;
+
+	index = afe_get_port_index(copp_id);
+	if (index < 0 || index > AFE_MAX_PORTS)
+		return -EINVAL;
+	pr_debug("%s: session[%d] copp_id[%d] index[%d]\n", __func__,
+			session_id, copp_id, index);
+	mutex_lock(&routing_info.copp_list_mutex);
+	if (routing_info.copp_list[session_id][index] == DEVICE_IGNORE)
+		routing_info.copp_list[session_id][index] = copp_id;
+	mutex_unlock(&routing_info.copp_list_mutex);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_set_copp_id);
+
+int msm_clear_copp_id(int session_id, int copp_id)
+{
+	int rc = 0;
+	int index = afe_get_port_index(copp_id);
+
+	if (session_id < 1 || session_id > 8)
+		return -EINVAL;
+	pr_debug("%s: session[%d] copp_id[%d] index[%d]\n", __func__,
+			session_id, copp_id, index);
+	mutex_lock(&routing_info.copp_list_mutex);
+	if (routing_info.copp_list[session_id][index] == copp_id)
+		routing_info.copp_list[session_id][index] = DEVICE_IGNORE;
+	mutex_unlock(&routing_info.copp_list_mutex);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_clear_copp_id);
+
+int msm_clear_session_id(int session_id)
+{
+	int rc = 0;
+	int i = 0;
+	if (session_id < 1 || session_id > 8)
+		return -EINVAL;
+	pr_debug("%s: session[%d]\n", __func__, session_id);
+	mutex_lock(&routing_info.adm_mutex);
+	mutex_lock(&routing_info.copp_list_mutex);
+	for (i = 0; i < AFE_MAX_PORTS; i++) {
+		if (routing_info.copp_list[session_id][i] != DEVICE_IGNORE) {
+			rc = adm_close(routing_info.copp_list[session_id][i]);
+			if (rc < 0) {
+				pr_err("%s: adm close fail port[%d] rc[%d]\n",
+					__func__,
+					routing_info.copp_list[session_id][i],
+					rc);
+				continue;
+			}
+			routing_info.copp_list[session_id][i] = DEVICE_IGNORE;
+			rc = 0;
+		}
+	}
+	mutex_unlock(&routing_info.copp_list_mutex);
+	mutex_unlock(&routing_info.adm_mutex);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_clear_session_id);
+
+int msm_clear_all_session()
+{
+	int rc = 0;
+	int i = 0, j = 0;
+	pr_info("%s:\n", __func__);
+	mutex_lock(&routing_info.adm_mutex);
+	mutex_lock(&routing_info.copp_list_mutex);
+	for (j = 1; j < MAX_SESSIONS; j++) {
+		for (i = 0; i < AFE_MAX_PORTS; i++) {
+			if (routing_info.copp_list[j][i] != DEVICE_IGNORE) {
+				rc = adm_close(
+					routing_info.copp_list[j][i]);
+				if (rc < 0) {
+					pr_err("%s: adm close fail copp[%d]"
+					"session[%d] rc[%d]\n",
+					__func__,
+					routing_info.copp_list[j][i],
+					j, rc);
+					continue;
+				}
+				routing_info.copp_list[j][i] = DEVICE_IGNORE;
+				rc = 0;
+			}
+		}
+	}
+	mutex_unlock(&routing_info.copp_list_mutex);
+	mutex_unlock(&routing_info.adm_mutex);
+	return rc;
+}
+EXPORT_SYMBOL(msm_clear_all_session);
+
+int msm_get_voice_state(void)
+{
+	pr_debug("voice state %d\n", routing_info.voice_state);
+	return routing_info.voice_state;
+}
+EXPORT_SYMBOL(msm_get_voice_state);
+
+int msm_set_voice_mute(int dir, int mute)
+{
+	pr_debug("dir %x mute %x\n", dir, mute);
+	if (dir == DIR_TX) {
+		routing_info.tx_mute = mute;
+		broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
+			routing_info.voice_tx_dev_id, SESSION_IGNORE);
+	} else
+		return -EPERM;
+	return 0;
+}
+EXPORT_SYMBOL(msm_set_voice_mute);
+
+int msm_set_voice_vol(int dir, s32 volume)
+{
+	if (dir == DIR_TX) {
+		routing_info.voice_tx_vol = volume;
+		broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
+					routing_info.voice_tx_dev_id,
+					SESSION_IGNORE);
+	} else if (dir == DIR_RX) {
+		routing_info.voice_rx_vol = volume;
+		broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG,
+					routing_info.voice_rx_dev_id,
+					SESSION_IGNORE);
+	} else
+		return -EINVAL;
+	return 0;
+}
+EXPORT_SYMBOL(msm_set_voice_vol);
+
+void msm_snddev_register(struct msm_snddev_info *dev_info)
+{
+	mutex_lock(&session_lock);
+	if (audio_dev_ctrl.num_dev < AUDIO_DEV_CTL_MAX_DEV) {
+		audio_dev_ctrl.devs[audio_dev_ctrl.num_dev] = dev_info;
+		/* roughly 0 DB for digital gain
+		 * If default gain is not desirable, it is expected that
+		 * application sets desired gain before activating sound
+		 * device
+		 */
+		dev_info->dev_volume = 75;
+		dev_info->sessions = 0x0;
+		dev_info->usage_count = 0;
+		audio_dev_ctrl.num_dev++;
+	} else
+		pr_err("%s: device registry max out\n", __func__);
+	mutex_unlock(&session_lock);
+}
+EXPORT_SYMBOL(msm_snddev_register);
+
+int msm_snddev_devcount(void)
+{
+	return audio_dev_ctrl.num_dev;
+}
+EXPORT_SYMBOL(msm_snddev_devcount);
+
+int msm_snddev_query(int dev_id)
+{
+	if (dev_id <= audio_dev_ctrl.num_dev)
+			return 0;
+	return -ENODEV;
+}
+EXPORT_SYMBOL(msm_snddev_query);
+
+int msm_snddev_is_set(int popp_id, int copp_id)
+{
+	return routing_info.mixer_mask[popp_id] & (0x1 << copp_id);
+}
+EXPORT_SYMBOL(msm_snddev_is_set);
+
+unsigned short msm_snddev_route_enc(int enc_id)
+{
+	if (enc_id >= MAX_SESSIONS)
+		return -EINVAL;
+	return routing_info.audrec_mixer_mask[enc_id];
+}
+EXPORT_SYMBOL(msm_snddev_route_enc);
+
+unsigned short msm_snddev_route_dec(int popp_id)
+{
+	if (popp_id >= MAX_SESSIONS)
+		return -EINVAL;
+	return routing_info.mixer_mask[popp_id];
+}
+EXPORT_SYMBOL(msm_snddev_route_dec);
+
+/*To check one->many case*/
+int msm_check_multicopp_per_stream(int session_id,
+				struct route_payload *payload)
+{
+	int i = 0;
+	int flag = 0;
+	pr_debug("%s: session_id=%d\n", __func__, session_id);
+	mutex_lock(&routing_info.copp_list_mutex);
+	for (i = 0; i < AFE_MAX_PORTS; i++) {
+		if (routing_info.copp_list[session_id][i] == DEVICE_IGNORE)
+			continue;
+		else {
+			pr_debug("Device enabled\n");
+			payload->copp_ids[flag++] =
+				routing_info.copp_list[session_id][i];
+		}
+	}
+	mutex_unlock(&routing_info.copp_list_mutex);
+	if (flag > 1) {
+		pr_debug("Multiple copp per stream case num_copps=%d\n", flag);
+	} else {
+		pr_debug("Stream routed to single copp\n");
+	}
+	payload->num_copps = flag;
+	return flag;
+}
+
+int msm_snddev_set_dec(int popp_id, int copp_id, int set,
+					int rate, int mode)
+{
+	int rc = 0, i = 0;
+	struct route_payload payload;
+
+	if ((popp_id >= MAX_SESSIONS) || (popp_id <= 0)) {
+		pr_err("%s: Invalid session id %d\n", __func__, popp_id);
+		return 0;
+	}
+
+	mutex_lock(&routing_info.adm_mutex);
+	if (set) {
+		rc = adm_open(copp_id, PLAYBACK, rate, mode,
+			DEFAULT_COPP_TOPOLOGY);
+		if (rc < 0) {
+			pr_err("%s: adm open fail rc[%d]\n", __func__, rc);
+			rc = -EINVAL;
+			mutex_unlock(&routing_info.adm_mutex);
+			return rc;
+		}
+		msm_set_copp_id(popp_id, copp_id);
+		pr_debug("%s:Session id=%d copp_id=%d\n",
+			__func__, popp_id, copp_id);
+		memset(payload.copp_ids, DEVICE_IGNORE,
+				(sizeof(unsigned int) * AFE_MAX_PORTS));
+		rc = msm_check_multicopp_per_stream(popp_id, &payload);
+		/* Multiple streams per copp is handled, one stream at a time */
+		rc = adm_matrix_map(popp_id, PLAYBACK, rc,
+					payload.copp_ids, copp_id);
+		if (rc < 0) {
+			pr_err("%s: matrix map failed rc[%d]\n",
+				__func__, rc);
+			adm_close(copp_id);
+			rc = -EINVAL;
+			mutex_unlock(&routing_info.adm_mutex);
+			return rc;
+		}
+	} else {
+		for (i = 0; i < AFE_MAX_PORTS; i++) {
+			if (routing_info.copp_list[popp_id][i] == copp_id) {
+				rc = adm_close(copp_id);
+				if (rc < 0) {
+					pr_err("%s: adm close fail copp[%d]"
+						"rc[%d]\n",
+						__func__, copp_id, rc);
+					rc = -EINVAL;
+					mutex_unlock(&routing_info.adm_mutex);
+					return rc;
+				}
+				msm_clear_copp_id(popp_id, copp_id);
+				break;
+			}
+		}
+	}
+
+	if (copp_id == VOICE_PLAYBACK_TX) {
+		/* Signal uplink playback. */
+		rc = voice_start_playback(set);
+	}
+	mutex_unlock(&routing_info.adm_mutex);
+	return rc;
+}
+EXPORT_SYMBOL(msm_snddev_set_dec);
+
+
+static int check_tx_copp_topology(int session_id)
+{
+	int cnt;
+	int ret_val = -ENOENT;
+
+	cnt = adm_tx_topology_tbl.session_cnt;
+	if (cnt) {
+		do {
+			if (adm_tx_topology_tbl.session_id[cnt-1]
+				== session_id)
+				ret_val = cnt-1;
+		} while (--cnt);
+	}
+
+	return ret_val;
+}
+
+static int add_to_tx_topology_lists(int session_id, int topology)
+{
+	int idx = 0, tbl_idx;
+	int ret_val = -ENOSPC;
+
+	mutex_lock(&adm_tx_topology_tbl.lock);
+
+	tbl_idx = check_tx_copp_topology(session_id);
+	if (tbl_idx == -ENOENT) {
+		while (adm_tx_topology_tbl.session_id[idx++])
+			;
+		tbl_idx = idx-1;
+	}
+
+	if (tbl_idx < MAX_SESSIONS) {
+		adm_tx_topology_tbl.session_id[tbl_idx] = session_id;
+		adm_tx_topology_tbl.topolog_id[tbl_idx] = topology;
+		adm_tx_topology_tbl.session_cnt++;
+
+		ret_val = 0;
+	}
+	mutex_unlock(&adm_tx_topology_tbl.lock);
+	return ret_val;
+}
+
+static void remove_from_tx_topology_lists(int session_id)
+{
+	int tbl_idx;
+
+	mutex_lock(&adm_tx_topology_tbl.lock);
+	tbl_idx = check_tx_copp_topology(session_id);
+	if (tbl_idx != -ENOENT) {
+
+		adm_tx_topology_tbl.session_cnt--;
+		adm_tx_topology_tbl.session_id[tbl_idx] = 0;
+		adm_tx_topology_tbl.topolog_id[tbl_idx] = 0;
+	}
+	mutex_unlock(&adm_tx_topology_tbl.lock);
+}
+
+int auddev_cfg_tx_copp_topology(int session_id, int cfg)
+{
+	int ret = 0;
+
+	if (cfg == DEFAULT_COPP_TOPOLOGY)
+		remove_from_tx_topology_lists(session_id);
+	else {
+		switch (cfg) {
+		case VPM_TX_SM_ECNS_COPP_TOPOLOGY:
+		case VPM_TX_DM_FLUENCE_COPP_TOPOLOGY:
+			ret = add_to_tx_topology_lists(session_id, cfg);
+			break;
+
+		default:
+			ret = -ENODEV;
+			break;
+		}
+	}
+	return ret;
+}
+
+int msm_snddev_set_enc(int popp_id, int copp_id, int set,
+					int rate, int mode)
+{
+	int topology;
+	int tbl_idx;
+	int rc = 0, i = 0;
+	mutex_lock(&routing_info.adm_mutex);
+	if (set) {
+		mutex_lock(&adm_tx_topology_tbl.lock);
+		tbl_idx = check_tx_copp_topology(popp_id);
+		if (tbl_idx == -ENOENT)
+			topology = DEFAULT_COPP_TOPOLOGY;
+		else {
+			topology = adm_tx_topology_tbl.topolog_id[tbl_idx];
+			rate = 16000;
+		}
+		mutex_unlock(&adm_tx_topology_tbl.lock);
+		rc = adm_open(copp_id, LIVE_RECORDING, rate, mode, topology);
+		if (rc < 0) {
+			pr_err("%s: adm open fail rc[%d]\n", __func__, rc);
+			rc = -EINVAL;
+			goto fail_cmd;
+		}
+
+		rc = adm_matrix_map(popp_id, LIVE_RECORDING, 1,
+					(unsigned int *)&copp_id, copp_id);
+		if (rc < 0) {
+			pr_err("%s: matrix map failed rc[%d]\n", __func__, rc);
+			adm_close(copp_id);
+			rc = -EINVAL;
+			goto fail_cmd;
+		}
+		msm_set_copp_id(popp_id, copp_id);
+	} else {
+		for (i = 0; i < AFE_MAX_PORTS; i++) {
+			if (routing_info.copp_list[popp_id][i] == copp_id) {
+				rc = adm_close(copp_id);
+				if (rc < 0) {
+					pr_err("%s: adm close fail copp[%d]"
+					"rc[%d]\n",
+							__func__, copp_id, rc);
+					rc = -EINVAL;
+					goto fail_cmd;
+				}
+				msm_clear_copp_id(popp_id, copp_id);
+				break;
+			}
+		}
+	}
+fail_cmd:
+	mutex_unlock(&routing_info.adm_mutex);
+	return rc;
+}
+EXPORT_SYMBOL(msm_snddev_set_enc);
+
+int msm_device_is_voice(int dev_id)
+{
+	if ((dev_id == routing_info.voice_rx_dev_id)
+		|| (dev_id == routing_info.voice_tx_dev_id))
+		return 0;
+	else
+		return -EINVAL;
+}
+EXPORT_SYMBOL(msm_device_is_voice);
+
+int msm_set_voc_route(struct msm_snddev_info *dev_info,
+			int stream_type, int dev_id)
+{
+	int rc = 0;
+	u64 session_mask = 0;
+
+	mutex_lock(&session_lock);
+	switch (stream_type) {
+	case AUDIO_ROUTE_STREAM_VOICE_RX:
+		if (audio_dev_ctrl.voice_rx_dev)
+			audio_dev_ctrl.voice_rx_dev->sessions &= ~0xFFFF;
+
+		if (!(dev_info->capability & SNDDEV_CAP_RX) |
+		    !(dev_info->capability & SNDDEV_CAP_VOICE)) {
+			rc = -EINVAL;
+			break;
+		}
+		audio_dev_ctrl.voice_rx_dev = dev_info;
+		if (audio_dev_ctrl.voice_rx_dev) {
+			session_mask =
+				((u64)0x1) << (MAX_BIT_PER_CLIENT * \
+				((int)AUDDEV_CLNT_VOC-1));
+			audio_dev_ctrl.voice_rx_dev->sessions |=
+				session_mask;
+		}
+		routing_info.voice_rx_dev_id = dev_id;
+		break;
+	case AUDIO_ROUTE_STREAM_VOICE_TX:
+		if (audio_dev_ctrl.voice_tx_dev)
+			audio_dev_ctrl.voice_tx_dev->sessions &= ~0xFFFF;
+
+		if (!(dev_info->capability & SNDDEV_CAP_TX) |
+		    !(dev_info->capability & SNDDEV_CAP_VOICE)) {
+			rc = -EINVAL;
+			break;
+		}
+
+		audio_dev_ctrl.voice_tx_dev = dev_info;
+		if (audio_dev_ctrl.voice_rx_dev) {
+			session_mask =
+				((u64)0x1) << (MAX_BIT_PER_CLIENT * \
+					((int)AUDDEV_CLNT_VOC-1));
+			audio_dev_ctrl.voice_tx_dev->sessions |=
+				session_mask;
+		}
+		routing_info.voice_tx_dev_id = dev_id;
+		break;
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&session_lock);
+	return rc;
+}
+EXPORT_SYMBOL(msm_set_voc_route);
+
+void msm_release_voc_thread(void)
+{
+	wake_up(&audio_dev_ctrl.wait);
+}
+EXPORT_SYMBOL(msm_release_voc_thread);
+
+int msm_snddev_get_enc_freq(session_id)
+{
+	return routing_info.enc_freq[session_id].freq;
+}
+EXPORT_SYMBOL(msm_snddev_get_enc_freq);
+
+int msm_get_voc_freq(int *tx_freq, int *rx_freq)
+{
+	*tx_freq = routing_info.voice_tx_sample_rate;
+	*rx_freq = routing_info.voice_rx_sample_rate;
+	return 0;
+}
+EXPORT_SYMBOL(msm_get_voc_freq);
+
+int msm_get_voc_route(u32 *rx_id, u32 *tx_id)
+{
+	int rc = 0;
+
+	if (!rx_id || !tx_id)
+		return -EINVAL;
+
+	mutex_lock(&session_lock);
+	if (!audio_dev_ctrl.voice_rx_dev || !audio_dev_ctrl.voice_tx_dev) {
+		rc = -ENODEV;
+		mutex_unlock(&session_lock);
+		return rc;
+	}
+
+	*rx_id = audio_dev_ctrl.voice_rx_dev->acdb_id;
+	*tx_id = audio_dev_ctrl.voice_tx_dev->acdb_id;
+
+	mutex_unlock(&session_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_get_voc_route);
+
+struct msm_snddev_info *audio_dev_ctrl_find_dev(u32 dev_id)
+{
+	struct msm_snddev_info *info;
+
+	if ((audio_dev_ctrl.num_dev - 1) < dev_id) {
+		info = ERR_PTR(-ENODEV);
+		goto error;
+	}
+
+	info = audio_dev_ctrl.devs[dev_id];
+error:
+	return info;
+
+}
+EXPORT_SYMBOL(audio_dev_ctrl_find_dev);
+
+int snddev_voice_set_volume(int vol, int path)
+{
+	if (audio_dev_ctrl.voice_rx_dev
+		&& audio_dev_ctrl.voice_tx_dev) {
+		if (path)
+			audio_dev_ctrl.voice_tx_dev->dev_volume = vol;
+		else
+			audio_dev_ctrl.voice_rx_dev->dev_volume = vol;
+	} else
+		return -ENODEV;
+	return 0;
+}
+EXPORT_SYMBOL(snddev_voice_set_volume);
+
+static int audio_dev_ctrl_get_devices(struct audio_dev_ctrl_state *dev_ctrl,
+				      void __user *arg)
+{
+	int rc = 0;
+	u32 index;
+	struct msm_snd_device_list work_list;
+	struct msm_snd_device_info *work_tbl;
+
+	if (copy_from_user(&work_list, arg, sizeof(work_list))) {
+		rc = -EFAULT;
+		goto error;
+	}
+
+	if (work_list.num_dev > dev_ctrl->num_dev) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	work_tbl = kmalloc(work_list.num_dev *
+		sizeof(struct msm_snd_device_info), GFP_KERNEL);
+	if (!work_tbl) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	for (index = 0; index < dev_ctrl->num_dev; index++) {
+		work_tbl[index].dev_id = index;
+		work_tbl[index].dev_cap = dev_ctrl->devs[index]->capability;
+		strlcpy(work_tbl[index].dev_name, dev_ctrl->devs[index]->name,
+		64);
+	}
+
+	if (copy_to_user((void *) (work_list.list), work_tbl,
+		 work_list.num_dev * sizeof(struct msm_snd_device_info)))
+		rc = -EFAULT;
+	kfree(work_tbl);
+error:
+	return rc;
+}
+
+
+int auddev_register_evt_listner(u32 evt_id, u32 clnt_type, u32 clnt_id,
+		void (*listner)(u32 evt_id,
+			union auddev_evt_data *evt_payload,
+			void *private_data),
+		void *private_data)
+{
+	int rc;
+	struct msm_snd_evt_listner *callback = NULL;
+	struct msm_snd_evt_listner *new_cb;
+
+	new_cb = kzalloc(sizeof(struct msm_snd_evt_listner), GFP_KERNEL);
+	if (!new_cb) {
+		pr_err("No memory to add new listener node\n");
+		return -ENOMEM;
+	}
+
+	mutex_lock(&session_lock);
+	new_cb->cb_next = NULL;
+	new_cb->auddev_evt_listener = listner;
+	new_cb->evt_id = evt_id;
+	new_cb->clnt_type = clnt_type;
+	new_cb->clnt_id = clnt_id;
+	new_cb->private_data = private_data;
+	if (event.cb == NULL) {
+		event.cb = new_cb;
+		new_cb->cb_prev = NULL;
+	} else {
+		callback = event.cb;
+		for (; ;) {
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+		callback->cb_next = new_cb;
+		new_cb->cb_prev = callback;
+	}
+	event.num_listner++;
+	mutex_unlock(&session_lock);
+	rc = 0;
+	return rc;
+}
+EXPORT_SYMBOL(auddev_register_evt_listner);
+
+int auddev_unregister_evt_listner(u32 clnt_type, u32 clnt_id)
+{
+	struct msm_snd_evt_listner *callback = event.cb;
+	struct msm_snddev_info *info;
+	u64 session_mask = 0;
+	int i = 0;
+
+	mutex_lock(&session_lock);
+	while (callback != NULL) {
+		if ((callback->clnt_type == clnt_type)
+			&& (callback->clnt_id == clnt_id))
+			break;
+		 callback = callback->cb_next;
+	}
+	if (callback == NULL) {
+		mutex_unlock(&session_lock);
+		return -EINVAL;
+	}
+
+	if ((callback->cb_next == NULL) && (callback->cb_prev == NULL))
+		event.cb = NULL;
+	else if (callback->cb_next == NULL)
+		callback->cb_prev->cb_next = NULL;
+	else if (callback->cb_prev == NULL) {
+		callback->cb_next->cb_prev = NULL;
+		event.cb = callback->cb_next;
+	} else {
+		callback->cb_prev->cb_next = callback->cb_next;
+		callback->cb_next->cb_prev = callback->cb_prev;
+	}
+	kfree(callback);
+
+	session_mask = (((u64)0x1) << clnt_id) << (MAX_BIT_PER_CLIENT * \
+				((int)clnt_type-1));
+	for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
+		info = audio_dev_ctrl.devs[i];
+		info->sessions &= ~session_mask;
+	}
+	mutex_unlock(&session_lock);
+	return 0;
+}
+EXPORT_SYMBOL(auddev_unregister_evt_listner);
+
+int msm_snddev_withdraw_freq(u32 session_id, u32 capability, u32 clnt_type)
+{
+	int i = 0;
+	struct msm_snddev_info *info;
+	u64 session_mask = 0;
+
+	if ((clnt_type == AUDDEV_CLNT_VOC) && (session_id != 0))
+		return -EINVAL;
+	if ((clnt_type == AUDDEV_CLNT_DEC)
+			&& (session_id >= MAX_SESSIONS))
+		return -EINVAL;
+	if ((clnt_type == AUDDEV_CLNT_ENC)
+			&& (session_id >= MAX_SESSIONS))
+		return -EINVAL;
+
+	session_mask = (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
+				((int)clnt_type-1));
+
+	for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
+		info = audio_dev_ctrl.devs[i];
+		if ((info->sessions & session_mask)
+			&& (info->capability & capability)) {
+			if (!(info->sessions & ~(session_mask)))
+				info->set_sample_rate = 0;
+		}
+	}
+	if (clnt_type == AUDDEV_CLNT_DEC)
+		routing_info.dec_freq[session_id].freq
+					= 0;
+	else if (clnt_type == AUDDEV_CLNT_ENC)
+		routing_info.enc_freq[session_id].freq
+					= 0;
+	else if (capability == SNDDEV_CAP_TX)
+		routing_info.voice_tx_sample_rate = 0;
+	else
+		routing_info.voice_rx_sample_rate = 48000;
+	return 0;
+}
+
+int msm_snddev_request_freq(int *freq, u32 session_id,
+			u32 capability, u32 clnt_type)
+{
+	int i = 0;
+	int rc = 0;
+	struct msm_snddev_info *info;
+	u32 set_freq;
+	u64 session_mask = 0;
+	u64 clnt_type_mask = 0;
+
+	pr_debug(": clnt_type 0x%08x\n", clnt_type);
+
+	if ((clnt_type == AUDDEV_CLNT_VOC) && (session_id != 0))
+		return -EINVAL;
+	if ((clnt_type == AUDDEV_CLNT_DEC)
+			&& (session_id >= MAX_SESSIONS))
+		return -EINVAL;
+	if ((clnt_type == AUDDEV_CLNT_ENC)
+			&& (session_id >= MAX_SESSIONS))
+		return -EINVAL;
+	session_mask = (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
+				((int)clnt_type-1));
+	clnt_type_mask = (0xFFFF << (MAX_BIT_PER_CLIENT * (clnt_type-1)));
+	if (!(*freq == 8000) && !(*freq == 11025) &&
+		!(*freq == 12000) && !(*freq == 16000) &&
+		!(*freq == 22050) && !(*freq == 24000) &&
+		!(*freq == 32000) && !(*freq == 44100) &&
+		!(*freq == 48000))
+		return -EINVAL;
+
+	for (i = 0; i < audio_dev_ctrl.num_dev; i++) {
+		info = audio_dev_ctrl.devs[i];
+		if ((info->sessions & session_mask)
+			&& (info->capability & capability)) {
+			rc = 0;
+			if ((info->sessions & ~clnt_type_mask)
+				&& ((*freq != 8000) && (*freq != 16000)
+					&& (*freq != 48000))) {
+				if (clnt_type == AUDDEV_CLNT_ENC) {
+					routing_info.enc_freq[session_id].freq
+							= 0;
+					return -EPERM;
+				} else if (clnt_type == AUDDEV_CLNT_DEC) {
+					routing_info.dec_freq[session_id].freq
+							= 0;
+					return -EPERM;
+				}
+			}
+			if (*freq == info->set_sample_rate) {
+				rc = info->set_sample_rate;
+				continue;
+			}
+			set_freq = MAX(*freq, info->set_sample_rate);
+
+
+			if (clnt_type == AUDDEV_CLNT_DEC) {
+				routing_info.dec_freq[session_id].evt = 1;
+				routing_info.dec_freq[session_id].freq
+						= set_freq;
+			} else if (clnt_type == AUDDEV_CLNT_ENC) {
+				routing_info.enc_freq[session_id].evt = 1;
+				routing_info.enc_freq[session_id].freq
+						= set_freq;
+			} else if (capability == SNDDEV_CAP_TX)
+				routing_info.voice_tx_sample_rate = set_freq;
+
+			rc = set_freq;
+			info->set_sample_rate = set_freq;
+			*freq = info->set_sample_rate;
+
+			if (info->opened) {
+				broadcast_event(AUDDEV_EVT_FREQ_CHG, i,
+							SESSION_IGNORE);
+				set_freq = info->dev_ops.set_freq(info,
+								set_freq);
+				broadcast_event(AUDDEV_EVT_DEV_RDY, i,
+							SESSION_IGNORE);
+			}
+		}
+		pr_debug("info->set_sample_rate = %d\n", info->set_sample_rate);
+		pr_debug("routing_info.enc_freq.freq = %d\n",
+					routing_info.enc_freq[session_id].freq);
+	}
+	return rc;
+}
+EXPORT_SYMBOL(msm_snddev_request_freq);
+
+int msm_snddev_enable_sidetone(u32 dev_id, u32 enable, uint16_t gain)
+{
+	int rc;
+	struct msm_snddev_info *dev_info;
+
+	pr_debug("dev_id %d enable %d\n", dev_id, enable);
+
+	dev_info = audio_dev_ctrl_find_dev(dev_id);
+
+	if (IS_ERR(dev_info)) {
+		pr_err("bad dev_id %d\n", dev_id);
+		rc = -EINVAL;
+	} else if (!dev_info->dev_ops.enable_sidetone) {
+		pr_debug("dev %d no sidetone support\n", dev_id);
+		rc = -EPERM;
+	} else
+		rc = dev_info->dev_ops.enable_sidetone(dev_info, enable, gain);
+
+	return rc;
+}
+EXPORT_SYMBOL(msm_snddev_enable_sidetone);
+
+int msm_enable_incall_recording(int popp_id, int rec_mode, int rate,
+				int channel_mode)
+{
+	int rc = 0;
+	unsigned int port_id[2];
+	port_id[0] = VOICE_RECORD_TX;
+	port_id[1] = VOICE_RECORD_RX;
+
+	pr_debug("%s: popp_id %d, rec_mode %d, rate %d, channel_mode %d\n",
+		 __func__, popp_id, rec_mode, rate, channel_mode);
+
+	mutex_lock(&routing_info.adm_mutex);
+
+	if (rec_mode == VOC_REC_UPLINK) {
+		rc = afe_start_pseudo_port(port_id[0]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in Tx pseudo port start\n",
+			       __func__, rc);
+
+			goto fail_cmd;
+		}
+
+		rc = adm_open(port_id[0], LIVE_RECORDING, rate, channel_mode,
+				DEFAULT_COPP_TOPOLOGY);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM open %d\n",
+			       __func__, rc, port_id[0]);
+
+			goto fail_cmd;
+		}
+
+		rc = adm_matrix_map(popp_id, LIVE_RECORDING, 1,
+				&port_id[0], port_id[0]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM matrix map %d\n",
+			       __func__, rc, port_id[0]);
+
+			goto fail_cmd;
+		}
+
+		msm_set_copp_id(popp_id, port_id[0]);
+
+	} else if (rec_mode == VOC_REC_DOWNLINK) {
+		rc = afe_start_pseudo_port(port_id[1]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in Rx pseudo port start\n",
+			       __func__, rc);
+
+			goto fail_cmd;
+		}
+
+		rc = adm_open(port_id[1], LIVE_RECORDING, rate, channel_mode,
+				DEFAULT_COPP_TOPOLOGY);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM open %d\n",
+			       __func__, rc, port_id[1]);
+
+			goto fail_cmd;
+		}
+
+		rc = adm_matrix_map(popp_id, LIVE_RECORDING, 1,
+				&port_id[1], port_id[1]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM matrix map %d\n",
+			       __func__, rc, port_id[1]);
+
+			goto fail_cmd;
+		}
+
+		msm_set_copp_id(popp_id, port_id[1]);
+
+	} else if (rec_mode == VOC_REC_BOTH) {
+		rc = afe_start_pseudo_port(port_id[0]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in Tx pseudo port start\n",
+			       __func__, rc);
+
+			goto fail_cmd;
+		}
+
+		rc = adm_open(port_id[0], LIVE_RECORDING, rate, channel_mode,
+				DEFAULT_COPP_TOPOLOGY);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM open %d\n",
+			       __func__, rc, port_id[0]);
+
+			goto fail_cmd;
+		}
+
+		msm_set_copp_id(popp_id, port_id[0]);
+
+		rc = afe_start_pseudo_port(port_id[1]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in Rx pseudo port start\n",
+			       __func__, rc);
+
+			goto fail_cmd;
+		}
+
+		rc = adm_open(port_id[1], LIVE_RECORDING, rate, channel_mode,
+				DEFAULT_COPP_TOPOLOGY);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM open %d\n",
+			       __func__, rc, port_id[0]);
+
+			goto fail_cmd;
+		}
+
+		rc = adm_matrix_map(popp_id, LIVE_RECORDING, 2,
+				&port_id[0], port_id[1]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM matrix map\n",
+			       __func__, rc);
+
+			goto fail_cmd;
+		}
+
+		msm_set_copp_id(popp_id, port_id[1]);
+	} else {
+		pr_err("%s Unknown rec_mode %d\n", __func__, rec_mode);
+
+		goto fail_cmd;
+	}
+
+	rc = voice_start_record(rec_mode, 1);
+
+fail_cmd:
+	mutex_unlock(&routing_info.adm_mutex);
+	return rc;
+}
+
+int msm_disable_incall_recording(uint32_t popp_id, uint32_t rec_mode)
+{
+	int rc = 0;
+	uint32_t port_id[2];
+	port_id[0] = VOICE_RECORD_TX;
+	port_id[1] = VOICE_RECORD_RX;
+
+	pr_debug("%s: popp_id %d, rec_mode %d\n", __func__, popp_id, rec_mode);
+
+	mutex_lock(&routing_info.adm_mutex);
+
+	rc = voice_start_record(rec_mode, 0);
+	if (rc < 0) {
+		pr_err("%s: Error %d stopping record\n", __func__, rc);
+
+		goto fail_cmd;
+	}
+
+	if (rec_mode == VOC_REC_UPLINK) {
+		rc = adm_close(port_id[0]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM close %d\n",
+			       __func__, rc, port_id[0]);
+
+			goto fail_cmd;
+		}
+
+		msm_clear_copp_id(popp_id, port_id[0]);
+
+		rc = afe_stop_pseudo_port(port_id[0]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in Tx pseudo port stop\n",
+			       __func__, rc);
+			goto fail_cmd;
+		}
+
+	} else if (rec_mode == VOC_REC_DOWNLINK) {
+		rc = adm_close(port_id[1]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM close %d\n",
+			       __func__, rc, port_id[1]);
+
+			goto fail_cmd;
+		}
+
+		msm_clear_copp_id(popp_id, port_id[1]);
+
+		rc = afe_stop_pseudo_port(port_id[1]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in Rx pseudo port stop\n",
+			       __func__, rc);
+			goto fail_cmd;
+		}
+	} else if (rec_mode == VOC_REC_BOTH) {
+		rc = adm_close(port_id[0]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM close %d\n",
+			       __func__, rc, port_id[0]);
+
+			goto fail_cmd;
+		}
+
+		msm_clear_copp_id(popp_id, port_id[0]);
+
+		rc = afe_stop_pseudo_port(port_id[0]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in Tx pseudo port stop\n",
+			       __func__, rc);
+			goto fail_cmd;
+		}
+
+		rc = adm_close(port_id[1]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in ADM close %d\n",
+			       __func__, rc, port_id[1]);
+
+			goto fail_cmd;
+		}
+
+		msm_clear_copp_id(popp_id, port_id[1]);
+
+		rc = afe_stop_pseudo_port(port_id[1]);
+		if (rc < 0) {
+			pr_err("%s: Error %d in Rx pseudo port stop\n",
+			       __func__, rc);
+			goto fail_cmd;
+		}
+	} else {
+		pr_err("%s Unknown rec_mode %d\n", __func__, rec_mode);
+
+		goto fail_cmd;
+	}
+
+fail_cmd:
+	mutex_unlock(&routing_info.adm_mutex);
+	return rc;
+}
+
+static long audio_dev_ctrl_ioctl(struct file *file,
+	unsigned int cmd, unsigned long arg)
+{
+	int rc = 0;
+	struct audio_dev_ctrl_state *dev_ctrl = file->private_data;
+
+	mutex_lock(&session_lock);
+	switch (cmd) {
+	case AUDIO_GET_NUM_SND_DEVICE:
+		rc = put_user(dev_ctrl->num_dev, (uint32_t __user *) arg);
+		break;
+	case AUDIO_GET_SND_DEVICES:
+		rc = audio_dev_ctrl_get_devices(dev_ctrl, (void __user *) arg);
+		break;
+	case AUDIO_ENABLE_SND_DEVICE: {
+		struct msm_snddev_info *dev_info;
+		u32 dev_id;
+
+		if (get_user(dev_id, (u32 __user *) arg)) {
+			rc = -EFAULT;
+			break;
+		}
+		dev_info = audio_dev_ctrl_find_dev(dev_id);
+		if (IS_ERR(dev_info))
+			rc = PTR_ERR(dev_info);
+		else {
+			rc = dev_info->dev_ops.open(dev_info);
+			if (!rc)
+				dev_info->opened = 1;
+			wake_up(&audio_dev_ctrl.wait);
+		}
+		break;
+
+	}
+
+	case AUDIO_DISABLE_SND_DEVICE: {
+		struct msm_snddev_info *dev_info;
+		u32 dev_id;
+
+		if (get_user(dev_id, (u32 __user *) arg)) {
+			rc = -EFAULT;
+			break;
+		}
+		dev_info = audio_dev_ctrl_find_dev(dev_id);
+		if (IS_ERR(dev_info))
+			rc = PTR_ERR(dev_info);
+		else {
+			rc = dev_info->dev_ops.close(dev_info);
+			dev_info->opened = 0;
+		}
+		break;
+	}
+
+	case AUDIO_ROUTE_STREAM: {
+		struct msm_audio_route_config route_cfg;
+		struct msm_snddev_info *dev_info;
+
+		if (copy_from_user(&route_cfg, (void __user *) arg,
+			sizeof(struct msm_audio_route_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: route cfg %d %d type\n", __func__,
+		route_cfg.dev_id, route_cfg.stream_type);
+		dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
+		if (IS_ERR(dev_info)) {
+			pr_err("%s: pass invalid dev_id\n", __func__);
+			rc = PTR_ERR(dev_info);
+			break;
+		}
+
+		switch (route_cfg.stream_type) {
+
+		case AUDIO_ROUTE_STREAM_VOICE_RX:
+			if (!(dev_info->capability & SNDDEV_CAP_RX) |
+			    !(dev_info->capability & SNDDEV_CAP_VOICE)) {
+				rc = -EINVAL;
+				break;
+			}
+			dev_ctrl->voice_rx_dev = dev_info;
+			break;
+		case AUDIO_ROUTE_STREAM_VOICE_TX:
+			if (!(dev_info->capability & SNDDEV_CAP_TX) |
+			    !(dev_info->capability & SNDDEV_CAP_VOICE)) {
+				rc = -EINVAL;
+				break;
+			}
+			dev_ctrl->voice_tx_dev = dev_info;
+			break;
+		}
+		break;
+	}
+
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&session_lock);
+	return rc;
+}
+
+static int audio_dev_ctrl_open(struct inode *inode, struct file *file)
+{
+	pr_debug("open audio_dev_ctrl\n");
+	atomic_inc(&audio_dev_ctrl.opened);
+	file->private_data = &audio_dev_ctrl;
+	return 0;
+}
+
+static int audio_dev_ctrl_release(struct inode *inode, struct file *file)
+{
+	pr_debug("release audio_dev_ctrl\n");
+	atomic_dec(&audio_dev_ctrl.opened);
+	return 0;
+}
+
+static const struct file_operations audio_dev_ctrl_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_dev_ctrl_open,
+	.release = audio_dev_ctrl_release,
+	.unlocked_ioctl = audio_dev_ctrl_ioctl,
+};
+
+
+struct miscdevice audio_dev_ctrl_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_audio_dev_ctrl",
+	.fops	= &audio_dev_ctrl_fops,
+};
+
+/* session id is 64 bit routing mask per device
+ * 0-15 for voice clients
+ * 16-31 for Decoder clients
+ * 32-47 for Encoder clients
+ * 48-63 Do not care
+ */
+void broadcast_event(u32 evt_id, u32 dev_id, u64 session_id)
+{
+	int clnt_id = 0, i;
+	union auddev_evt_data *evt_payload;
+	struct msm_snd_evt_listner *callback;
+	struct msm_snddev_info *dev_info = NULL;
+	u64 session_mask = 0;
+	static int pending_sent;
+
+	pr_debug(": evt_id = %d\n", evt_id);
+
+	if ((evt_id != AUDDEV_EVT_START_VOICE)
+		&& (evt_id != AUDDEV_EVT_END_VOICE)
+		&& (evt_id != AUDDEV_EVT_STREAM_VOL_CHG)
+		&& (evt_id != AUDDEV_EVT_VOICE_STATE_CHG)) {
+		dev_info = audio_dev_ctrl_find_dev(dev_id);
+		if (IS_ERR(dev_info)) {
+			pr_err("%s: pass invalid dev_id(%d)\n",
+					 __func__, dev_id);
+			return;
+		}
+	}
+
+#ifdef CONFIG_MSM8X60_RTAC
+	update_rtac(evt_id, dev_id, dev_info);
+#endif
+
+	if (event.cb != NULL)
+		callback = event.cb;
+	else
+		return;
+	mutex_lock(&session_lock);
+
+	if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+		routing_info.voice_state = dev_id;
+
+	evt_payload = kzalloc(sizeof(union auddev_evt_data),
+			GFP_KERNEL);
+
+	if (evt_payload == NULL) {
+		pr_err("broadcast_event: cannot allocate memory\n");
+		mutex_unlock(&session_lock);
+		return;
+	}
+	for (; ;) {
+		if (!(evt_id & callback->evt_id)) {
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+		clnt_id = callback->clnt_id;
+		memset(evt_payload, 0, sizeof(union auddev_evt_data));
+
+		if ((evt_id == AUDDEV_EVT_START_VOICE)
+			|| (evt_id == AUDDEV_EVT_END_VOICE))
+			goto skip_check;
+		if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL)
+			goto aud_cal;
+
+		session_mask = (((u64)0x1) << clnt_id)
+				<< (MAX_BIT_PER_CLIENT * \
+				((int)callback->clnt_type-1));
+
+		if ((evt_id == AUDDEV_EVT_STREAM_VOL_CHG) || \
+			(evt_id == AUDDEV_EVT_VOICE_STATE_CHG)) {
+			pr_debug("AUDDEV_EVT_STREAM_VOL_CHG or\
+				AUDDEV_EVT_VOICE_STATE_CHG\n");
+			goto volume_strm;
+		}
+
+		pr_debug("dev_info->sessions = %llu\n", dev_info->sessions);
+
+		if ((!session_id && !(dev_info->sessions & session_mask)) ||
+			(session_id && ((dev_info->sessions & session_mask) !=
+						session_id))) {
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+		if (evt_id == AUDDEV_EVT_DEV_CHG_VOICE)
+			goto voc_events;
+
+volume_strm:
+		if (callback->clnt_type == AUDDEV_CLNT_DEC) {
+			pr_debug("AUDDEV_CLNT_DEC\n");
+			if (evt_id == AUDDEV_EVT_STREAM_VOL_CHG) {
+				pr_debug("clnt_id = %d, session_id = %llu\n",
+					clnt_id, session_id);
+				if (session_mask != session_id)
+					goto sent_dec;
+				else
+					evt_payload->session_vol =
+						msm_vol_ctl.volume;
+			} else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
+				if (routing_info.dec_freq[clnt_id].evt) {
+					routing_info.dec_freq[clnt_id].evt
+							= 0;
+					goto sent_dec;
+				} else if (routing_info.dec_freq[clnt_id].freq
+					== dev_info->set_sample_rate)
+					goto sent_dec;
+				else {
+					evt_payload->freq_info.sample_rate
+						= dev_info->set_sample_rate;
+					evt_payload->freq_info.dev_type
+						= dev_info->capability;
+					evt_payload->freq_info.acdb_dev_id
+						= dev_info->acdb_id;
+				}
+			} else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+				evt_payload->voice_state =
+					routing_info.voice_state;
+			else
+				evt_payload->routing_id = dev_info->copp_id;
+			callback->auddev_evt_listener(
+					evt_id,
+					evt_payload,
+					callback->private_data);
+sent_dec:
+			if ((evt_id != AUDDEV_EVT_STREAM_VOL_CHG) &&
+				(evt_id != AUDDEV_EVT_VOICE_STATE_CHG))
+				routing_info.dec_freq[clnt_id].freq
+						= dev_info->set_sample_rate;
+
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+		if (callback->clnt_type == AUDDEV_CLNT_ENC) {
+			pr_debug("AUDDEV_CLNT_ENC\n");
+			if (evt_id == AUDDEV_EVT_FREQ_CHG) {
+				if (routing_info.enc_freq[clnt_id].evt) {
+					routing_info.enc_freq[clnt_id].evt
+							= 0;
+					goto sent_enc;
+				 } else {
+					evt_payload->freq_info.sample_rate
+						= dev_info->set_sample_rate;
+					evt_payload->freq_info.dev_type
+						= dev_info->capability;
+					evt_payload->freq_info.acdb_dev_id
+						= dev_info->acdb_id;
+				}
+			} else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+				evt_payload->voice_state =
+					routing_info.voice_state;
+			else
+				evt_payload->routing_id = dev_info->copp_id;
+			callback->auddev_evt_listener(
+					evt_id,
+					evt_payload,
+					callback->private_data);
+sent_enc:
+			if (callback->cb_next == NULL)
+					break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+aud_cal:
+		if (callback->clnt_type == AUDDEV_CLNT_AUDIOCAL) {
+			pr_debug("AUDDEV_CLNT_AUDIOCAL\n");
+			if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+				evt_payload->voice_state =
+					routing_info.voice_state;
+			else if (!dev_info->sessions)
+				goto sent_aud_cal;
+			else {
+				evt_payload->audcal_info.dev_id =
+						dev_info->copp_id;
+				evt_payload->audcal_info.acdb_id =
+						dev_info->acdb_id;
+				evt_payload->audcal_info.dev_type =
+					(dev_info->capability & SNDDEV_CAP_TX) ?
+					SNDDEV_CAP_TX : SNDDEV_CAP_RX;
+				evt_payload->audcal_info.sample_rate =
+					dev_info->set_sample_rate ?
+					dev_info->set_sample_rate :
+					dev_info->sample_rate;
+			}
+			callback->auddev_evt_listener(
+				evt_id,
+				evt_payload,
+				callback->private_data);
+
+sent_aud_cal:
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+skip_check:
+voc_events:
+		if (callback->clnt_type == AUDDEV_CLNT_VOC) {
+			pr_debug("AUDDEV_CLNT_VOC\n");
+			if (evt_id == AUDDEV_EVT_DEV_RLS) {
+				if (!pending_sent)
+					goto sent_voc;
+				else
+					pending_sent = 0;
+			}
+			if (evt_id == AUDDEV_EVT_REL_PENDING)
+				pending_sent = 1;
+
+			if (evt_id == AUDDEV_EVT_DEVICE_VOL_MUTE_CHG) {
+				if (dev_info->capability & SNDDEV_CAP_TX) {
+					evt_payload->voc_vm_info.dev_type =
+						SNDDEV_CAP_TX;
+					evt_payload->voc_vm_info.acdb_dev_id =
+						dev_info->acdb_id;
+					evt_payload->
+					voc_vm_info.dev_vm_val.mute =
+						routing_info.tx_mute;
+				} else {
+					evt_payload->voc_vm_info.dev_type =
+						SNDDEV_CAP_RX;
+					evt_payload->voc_vm_info.acdb_dev_id =
+						dev_info->acdb_id;
+					evt_payload->
+					voc_vm_info.dev_vm_val.vol =
+						routing_info.voice_rx_vol;
+				}
+			} else if ((evt_id == AUDDEV_EVT_START_VOICE)
+					|| (evt_id == AUDDEV_EVT_END_VOICE))
+				memset(evt_payload, 0,
+					sizeof(union auddev_evt_data));
+			else if (evt_id == AUDDEV_EVT_FREQ_CHG) {
+				if (routing_info.voice_tx_sample_rate
+						!= dev_info->set_sample_rate) {
+					routing_info.voice_tx_sample_rate
+						= dev_info->set_sample_rate;
+					evt_payload->freq_info.sample_rate
+						= dev_info->set_sample_rate;
+					evt_payload->freq_info.dev_type
+						= dev_info->capability;
+					evt_payload->freq_info.acdb_dev_id
+						= dev_info->acdb_id;
+				} else
+					goto sent_voc;
+			} else if (evt_id == AUDDEV_EVT_VOICE_STATE_CHG)
+				evt_payload->voice_state =
+						routing_info.voice_state;
+			else {
+				evt_payload->voc_devinfo.dev_type =
+					(dev_info->capability & SNDDEV_CAP_TX) ?
+					SNDDEV_CAP_TX : SNDDEV_CAP_RX;
+				evt_payload->voc_devinfo.acdb_dev_id =
+					dev_info->acdb_id;
+				evt_payload->voc_devinfo.dev_port_id =
+					dev_info->copp_id;
+				evt_payload->voc_devinfo.dev_sample =
+					dev_info->set_sample_rate ?
+					dev_info->set_sample_rate :
+					dev_info->sample_rate;
+				evt_payload->voc_devinfo.dev_id = dev_id;
+				if (dev_info->capability & SNDDEV_CAP_RX) {
+					for (i = 0; i < VOC_RX_VOL_ARRAY_NUM;
+						i++) {
+						evt_payload->
+						voc_devinfo.max_rx_vol[i] =
+						dev_info->max_voc_rx_vol[i];
+						evt_payload
+						->voc_devinfo.min_rx_vol[i] =
+						dev_info->min_voc_rx_vol[i];
+					}
+				}
+			}
+			callback->auddev_evt_listener(
+				evt_id,
+				evt_payload,
+				callback->private_data);
+			if (evt_id == AUDDEV_EVT_DEV_RLS)
+				dev_info->sessions &= ~(0xFFFF);
+sent_voc:
+			if (callback->cb_next == NULL)
+				break;
+			else {
+				callback = callback->cb_next;
+				continue;
+			}
+		}
+	}
+	kfree(evt_payload);
+	mutex_unlock(&session_lock);
+}
+EXPORT_SYMBOL(broadcast_event);
+
+
+void mixer_post_event(u32 evt_id, u32 id)
+{
+
+	pr_debug("evt_id = %d\n", evt_id);
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_CHG_VOICE: /* Called from Voice_route */
+		broadcast_event(AUDDEV_EVT_DEV_CHG_VOICE, id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_DEV_RDY:
+		broadcast_event(AUDDEV_EVT_DEV_RDY, id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		broadcast_event(AUDDEV_EVT_DEV_RLS, id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_REL_PENDING:
+		broadcast_event(AUDDEV_EVT_REL_PENDING, id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_DEVICE_VOL_MUTE_CHG:
+		broadcast_event(AUDDEV_EVT_DEVICE_VOL_MUTE_CHG, id,
+							SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		broadcast_event(AUDDEV_EVT_STREAM_VOL_CHG, id,
+							SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_START_VOICE:
+		broadcast_event(AUDDEV_EVT_START_VOICE,
+				id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_END_VOICE:
+		broadcast_event(AUDDEV_EVT_END_VOICE,
+				id, SESSION_IGNORE);
+		break;
+	case AUDDEV_EVT_FREQ_CHG:
+		broadcast_event(AUDDEV_EVT_FREQ_CHG, id, SESSION_IGNORE);
+		break;
+	default:
+		break;
+	}
+}
+EXPORT_SYMBOL(mixer_post_event);
+
+static int __init audio_dev_ctrl_init(void)
+{
+	init_waitqueue_head(&audio_dev_ctrl.wait);
+
+	event.cb = NULL;
+
+	atomic_set(&audio_dev_ctrl.opened, 0);
+	audio_dev_ctrl.num_dev = 0;
+	audio_dev_ctrl.voice_tx_dev = NULL;
+	audio_dev_ctrl.voice_rx_dev = NULL;
+	routing_info.voice_state = VOICE_STATE_INVALID;
+
+	mutex_init(&adm_tx_topology_tbl.lock);
+	mutex_init(&routing_info.copp_list_mutex);
+	mutex_init(&routing_info.adm_mutex);
+
+	memset(routing_info.copp_list, DEVICE_IGNORE,
+		(sizeof(unsigned int) * MAX_SESSIONS * AFE_MAX_PORTS));
+	return misc_register(&audio_dev_ctrl_misc);
+}
+
+static void __exit audio_dev_ctrl_exit(void)
+{
+}
+module_init(audio_dev_ctrl_init);
+module_exit(audio_dev_ctrl_exit);
+
+MODULE_DESCRIPTION("MSM 8K Audio Device Control driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_lpa.c b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
new file mode 100644
index 0000000..52434bf
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_lpa.c
@@ -0,0 +1,1420 @@
+/* low power audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/earlysuspend.h>
+#include <linux/list.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+#include <sound/q6asm.h>
+#include <sound/apr_audio.h>
+#include "audio_lpa.h"
+
+#include <linux/msm_audio.h>
+#include <linux/wakelock.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+
+#include <mach/debug_mm.h>
+#include <linux/fs.h>
+
+#define MAX_BUF 3
+#define BUFSZ (524288)
+
+#define AUDDEC_DEC_PCM 0
+
+#define AUDLPA_EVENT_NUM 10 /* Default number of pre-allocated event packets */
+
+#define __CONTAINS(r, v, l) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = ((__v >= __r->vaddr) &&			\
+		(__e <= __r->vaddr + __r->len));		\
+	res;							\
+})
+
+#define CONTAINS(r1, r2) ({					\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->vaddr, __r2->len);			\
+})
+
+#define IN_RANGE(r, v) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->vaddr) &&			\
+		(__vv < (__r->vaddr + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2) ({					\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->vaddr) __v = __r2->vaddr;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
+	res;							\
+})
+
+struct audlpa_event {
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audlpa_pmem_region {
+	struct list_head list;
+	struct file *file;
+	int fd;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	unsigned ref_cnt;
+};
+
+struct audlpa_buffer_node {
+	struct list_head list;
+	struct msm_audio_aio_buf buf;
+	unsigned long paddr;
+};
+
+struct audlpa_dec {
+	char *name;
+	int dec_attrb;
+	long (*ioctl)(struct file *, unsigned int, unsigned long);
+	int (*set_params)(void *);
+};
+
+static void audlpa_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload);
+static unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+				unsigned long len, int ref_up);
+static void audlpa_async_send_data(struct audio *audio, unsigned needed,
+				uint32_t token);
+static int audlpa_pause(struct audio *audio);
+static void audlpa_unmap_pmem_region(struct audio *audio);
+static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+static int audlpa_set_pcm_params(void *data);
+
+struct audlpa_dec audlpa_decs[] = {
+	{"msm_pcm_lp_dec", AUDDEC_DEC_PCM, &pcm_ioctl,
+		&audlpa_set_pcm_params},
+};
+
+static void lpa_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct audio *audio = (struct audio *) private_data;
+	int rc  = 0;
+
+	switch (evt_id) {
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		audio->volume = evt_payload->session_vol;
+		pr_debug("%s: AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d, "
+				 "enabled = %d\n", __func__, audio->volume,
+				 audio->out_enabled);
+		if (audio->out_enabled == 1) {
+			if (audio->ac) {
+				rc = q6asm_set_volume(audio->ac, audio->volume);
+				if (rc < 0) {
+					pr_err("%s: Send Volume command failed"
+						" rc=%d\n", __func__, rc);
+				}
+			}
+		}
+		break;
+	default:
+		pr_err("%s:ERROR:wrong event\n", __func__);
+		break;
+	}
+}
+
+static void audlpa_prevent_sleep(struct audio *audio)
+{
+	pr_debug("%s:\n", __func__);
+	wake_lock(&audio->wakelock);
+}
+
+static void audlpa_allow_sleep(struct audio *audio)
+{
+	pr_debug("%s:\n", __func__);
+	wake_unlock(&audio->wakelock);
+}
+
+/* must be called with audio->lock held */
+static int audio_enable(struct audio *audio)
+{
+	pr_debug("%s\n", __func__);
+
+	return q6asm_run(audio->ac, 0, 0, 0);
+
+}
+
+static void audlpa_async_flush(struct audio *audio)
+{
+	struct audlpa_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+	int rc = 0;
+
+	pr_debug("%s:out_enabled = %d, drv_status = 0x%x\n", __func__,
+			audio->out_enabled, audio->drv_status);
+	if (audio->out_enabled) {
+		list_for_each_safe(ptr, next, &audio->out_queue) {
+			buf_node = list_entry(ptr, struct audlpa_buffer_node,
+						list);
+			list_del(&buf_node->list);
+			payload.aio_buf = buf_node->buf;
+				audlpa_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+								  payload);
+				kfree(buf_node);
+		}
+		/* Implicitly issue a pause to the decoder before flushing if
+		   it is not in pause state */
+		if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
+			rc = audlpa_pause(audio);
+			if (rc < 0)
+				pr_err("%s: pause cmd failed rc=%d\n", __func__,
+					rc);
+		}
+
+		rc = q6asm_cmd(audio->ac, CMD_FLUSH);
+		if (rc < 0)
+			pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
+
+		audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+		audio->out_needed = 0;
+
+		if (audio->stopped == 0) {
+			rc = audio_enable(audio);
+			if (rc < 0)
+				pr_err("%s: audio enable failed\n", __func__);
+			else {
+				audio->out_enabled = 1;
+				audio->out_needed = 1;
+				if (audio->drv_status & ADRV_STATUS_PAUSE)
+					audio->drv_status &= ~ADRV_STATUS_PAUSE;
+			}
+		}
+		wake_up(&audio->write_wait);
+	}
+}
+
+/* must be called with audio->lock held */
+static int audio_disable(struct audio *audio)
+{
+	int rc = 0;
+
+	pr_debug("%s:%d %d\n", __func__, audio->opened, audio->out_enabled);
+
+	if (audio->opened) {
+		audio->out_enabled = 0;
+		audio->opened = 0;
+		rc = q6asm_cmd(audio->ac, CMD_CLOSE);
+		if (rc < 0)
+			pr_err("%s: CLOSE cmd failed\n", __func__);
+		else
+			pr_debug("%s: rxed CLOSE resp\n", __func__);
+		audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+		wake_up(&audio->write_wait);
+		audio->out_needed = 0;
+	}
+	return rc;
+}
+static int audlpa_pause(struct audio *audio)
+{
+	int rc = 0;
+
+	pr_debug("%s, enabled = %d\n", __func__,
+			audio->out_enabled);
+	if (audio->out_enabled) {
+		rc = q6asm_cmd(audio->ac, CMD_PAUSE);
+		if (rc < 0)
+			pr_err("%s: pause cmd failed rc=%d\n", __func__, rc);
+
+	} else
+		pr_err("%s: Driver not enabled\n", __func__);
+	return rc;
+}
+
+/* ------------------- dsp --------------------- */
+static void audlpa_async_send_data(struct audio *audio, unsigned needed,
+				uint32_t token)
+{
+	unsigned long flags;
+	struct audio_client *ac;
+	int rc = 0;
+
+	pr_debug("%s:\n", __func__);
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+
+	pr_debug("%s: needed = %d, out_needed = %d, token = 0x%x\n",
+			  __func__, needed, audio->out_needed, token);
+	if (needed && !audio->wflush) {
+		audio->out_needed = 1;
+		if (audio->drv_status & ADRV_STATUS_OBUF_GIVEN) {
+			/* pop one node out of queue */
+			union msm_audio_event_payload evt_payload;
+			struct audlpa_buffer_node *used_buf;
+
+			used_buf = list_first_entry(&audio->out_queue,
+				struct audlpa_buffer_node, list);
+			if (token == used_buf->paddr) {
+				pr_debug("%s, Release: addr: %lx,"
+					" token = 0x%x\n", __func__,
+					used_buf->paddr, token);
+				list_del(&used_buf->list);
+				evt_payload.aio_buf = used_buf->buf;
+				audlpa_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+								  evt_payload);
+				kfree(used_buf);
+				audio->drv_status &= ~ADRV_STATUS_OBUF_GIVEN;
+			}
+		}
+	}
+	pr_debug("%s: out_needed = %d, stopped = %d, drv_status = 0x%x\n",
+			 __func__, audio->out_needed, audio->stopped,
+			 audio->drv_status);
+	if (audio->out_needed && (audio->stopped == 0)) {
+		struct audlpa_buffer_node *next_buf;
+		struct audio_aio_write_param param;
+		if (!list_empty(&audio->out_queue)) {
+			pr_debug("%s: list not empty\n", __func__);
+			next_buf = list_first_entry(&audio->out_queue,
+					struct audlpa_buffer_node, list);
+			if (next_buf) {
+				pr_debug("%s: Send: addr: %lx\n", __func__,
+						 next_buf->paddr);
+				ac = audio->ac;
+				param.paddr = next_buf->paddr;
+				param.len = next_buf->buf.data_len;
+				param.msw_ts = 0;
+				param.lsw_ts = 0;
+				/* No time stamp valid */
+				param.flags = NO_TIMESTAMP;
+				param.uid = next_buf->paddr;
+				rc = q6asm_async_write(ac, &param);
+				if (rc < 0)
+					pr_err("%s:q6asm_async_write failed\n",
+						__func__);
+				audio->out_needed = 0;
+				audio->drv_status |= ADRV_STATUS_OBUF_GIVEN;
+			}
+		} else if (list_empty(&audio->out_queue) &&
+				   (audio->drv_status & ADRV_STATUS_FSYNC)) {
+			pr_debug("%s: list is empty, reached EOS\n", __func__);
+			wake_up(&audio->write_wait);
+		}
+	}
+
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+static int audlpa_events_pending(struct audio *audio)
+{
+	int empty;
+
+	spin_lock(&audio->event_queue_lock);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock(&audio->event_queue_lock);
+	return empty || audio->event_abort;
+}
+
+static void audlpa_reset_event_queue(struct audio *audio)
+{
+	struct audlpa_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock(&audio->event_queue_lock);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audlpa_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+			struct audlpa_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock(&audio->event_queue_lock);
+
+	return;
+}
+
+static long audlpa_process_event_req(struct audio *audio, void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audlpa_event *drv_evt = NULL;
+	int timeout;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int) usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(
+			audio->event_wait, audlpa_events_pending(audio),
+			msecs_to_jiffies(timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(
+			audio->event_wait, audlpa_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock(&audio->event_queue_lock);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+			struct audlpa_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else
+		rc = -1;
+	spin_unlock(&audio->event_queue_lock);
+
+	if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE ||
+	    drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
+		pr_debug("%s: AUDIO_EVENT_WRITE_DONE completing\n", __func__);
+		mutex_lock(&audio->lock);
+		audlpa_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0);
+		mutex_unlock(&audio->lock);
+	}
+	if (!rc && copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audlpa_pmem_check(struct audio *audio,
+		void *vaddr, unsigned long len)
+{
+	struct audlpa_pmem_region *region_elt;
+	struct audlpa_pmem_region t = { .vaddr = vaddr, .len = len };
+
+	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+		    OVERLAPS(region_elt, &t)) {
+			pr_err("%s: region (vaddr %p len %ld)"
+				" clashes with registered region"
+				" (vaddr %p paddr %p len %ld)\n",
+				__func__, vaddr, len,
+				region_elt->vaddr,
+				(void *)region_elt->paddr,
+				region_elt->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int audlpa_pmem_add(struct audio *audio,
+	struct msm_audio_pmem_info *info)
+{
+	unsigned long paddr, kvaddr, len;
+	struct file *file;
+	struct audlpa_pmem_region *region;
+	int rc = -EINVAL;
+
+	pr_debug("%s:\n", __func__);
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+
+	if (!region) {
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+		kfree(region);
+		goto end;
+	}
+
+	rc = audlpa_pmem_check(audio, info->vaddr, len);
+	if (rc < 0) {
+		put_pmem_file(file);
+		kfree(region);
+		goto end;
+	}
+
+	region->vaddr = info->vaddr;
+	region->fd = info->fd;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->file = file;
+	region->ref_cnt = 0;
+	pr_debug("%s: add region paddr %lx vaddr %p, len %lu\n", __func__,
+			 region->paddr, region->vaddr,
+			 region->len);
+	list_add_tail(&region->list, &audio->pmem_region_queue);
+	rc = q6asm_memory_map(audio->ac, (uint32_t)paddr, IN, (uint32_t)len, 1);
+	if (rc < 0)
+		pr_err("%s: memory map failed\n", __func__);
+end:
+	return rc;
+}
+
+static int audlpa_pmem_remove(struct audio *audio,
+	struct msm_audio_pmem_info *info)
+{
+	struct audlpa_pmem_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audlpa_pmem_region, list);
+
+		if ((region != NULL) && (region->fd == info->fd) &&
+		    (region->vaddr == info->vaddr)) {
+			if (region->ref_cnt) {
+				pr_debug("%s: region %p in use ref_cnt %d\n",
+					__func__, region, region->ref_cnt);
+				break;
+			}
+			rc = q6asm_memory_unmap(audio->ac,
+						(uint32_t)region->paddr,
+						IN);
+			if (rc < 0)
+				pr_err("%s: memory unmap failed\n", __func__);
+
+			list_del(&region->list);
+			put_pmem_file(region->file);
+			kfree(region);
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int audlpa_pmem_lookup_vaddr(struct audio *audio, void *addr,
+		     unsigned long len, struct audlpa_pmem_region **region)
+{
+	struct audlpa_pmem_region *region_elt;
+
+	int match_count = 0;
+
+	*region = NULL;
+
+	/* returns physical address or zero */
+	list_for_each_entry(region_elt, &audio->pmem_region_queue,
+		list) {
+		if (addr >= region_elt->vaddr &&
+		    addr < region_elt->vaddr + region_elt->len &&
+		    addr + len <= region_elt->vaddr + region_elt->len) {
+			/* offset since we could pass vaddr inside a registerd
+			 * pmem buffer
+			 */
+
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		pr_err("%s: multiple hits for vaddr %p, len %ld\n", __func__,
+			   addr, len);
+		list_for_each_entry(region_elt,
+		  &audio->pmem_region_queue, list) {
+			if (addr >= region_elt->vaddr &&
+			    addr < region_elt->vaddr + region_elt->len &&
+			    addr + len <= region_elt->vaddr + region_elt->len)
+				pr_err("%s: \t%p, %ld --> %p\n", __func__,
+					   region_elt->vaddr, region_elt->len,
+					   (void *)region_elt->paddr);
+		}
+	}
+
+	return *region ? 0 : -1;
+}
+
+unsigned long audlpa_pmem_fixup(struct audio *audio, void *addr,
+		    unsigned long len, int ref_up)
+{
+	struct audlpa_pmem_region *region;
+	unsigned long paddr;
+	int ret;
+
+	ret = audlpa_pmem_lookup_vaddr(audio, addr, len, &region);
+	if (ret) {
+		pr_err("%s: lookup (%p, %ld) failed\n", __func__, addr, len);
+		return 0;
+	}
+	if (ref_up)
+		region->ref_cnt++;
+	else
+		region->ref_cnt--;
+	paddr = region->paddr + (addr - region->vaddr);
+	return paddr;
+}
+
+/* audio -> lock must be held at this point */
+static int audlpa_aio_buf_add(struct audio *audio, unsigned dir,
+	void __user *arg)
+{
+	struct audlpa_buffer_node *buf_node;
+
+	buf_node = kmalloc(sizeof(*buf_node), GFP_KERNEL);
+
+	if (!buf_node)
+		return -ENOMEM;
+
+	if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
+		kfree(buf_node);
+		return -EFAULT;
+	}
+
+	buf_node->paddr = audlpa_pmem_fixup(
+		audio, buf_node->buf.buf_addr,
+		buf_node->buf.buf_len, 1);
+	if (dir) {
+		/* write */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (buf_node->buf.data_len & 0x1)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		list_add_tail(&buf_node->list, &audio->out_queue);
+		pr_debug("%s, Added to list: addr: %lx, length = %d\n",
+			__func__, buf_node->paddr, buf_node->buf.data_len);
+		audlpa_async_send_data(audio, 0, 0);
+	} else {
+		/* read */
+	}
+	return 0;
+}
+
+static int config(struct audio *audio)
+{
+	int rc = 0;
+	if (!audio->out_prefill) {
+		if (audio->codec_ops.set_params != NULL) {
+			rc = audio->codec_ops.set_params(audio);
+			audio->out_prefill = 1;
+		}
+	}
+	return rc;
+}
+
+void q6_audlpa_out_cb(uint32_t opcode, uint32_t token,
+			uint32_t *payload, void *priv)
+{
+	struct audio *audio = (struct audio *) priv;
+
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE:
+		pr_debug("%s: ASM_DATA_EVENT_WRITE_DONE, token = 0x%x\n",
+				 __func__, token);
+		audlpa_async_send_data(audio, 1, token);
+		break;
+	case ASM_DATA_EVENT_EOS:
+	case ASM_DATA_CMDRSP_EOS:
+		pr_debug("%s: ASM_DATA_CMDRSP_EOS, teos = %d\n", __func__,
+				 audio->teos);
+		if (audio->teos == 0) {
+			audio->teos = 1;
+			wake_up(&audio->write_wait);
+		}
+		break;
+	case ASM_SESSION_CMDRSP_GET_SESSION_TIME:
+		break;
+	default:
+		break;
+	}
+}
+
+static long pcm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	pr_debug("%s: cmd = %d\n", __func__, cmd);
+	return -EINVAL;
+}
+
+static int audlpa_set_pcm_params(void *data)
+{
+	struct audio *audio = (struct audio *)data;
+	int rc;
+
+	rc = q6asm_media_format_block_pcm(audio->ac, audio->out_sample_rate,
+					audio->out_channel_mode);
+	if (rc < 0)
+		pr_err("%s: Format block pcm failed\n", __func__);
+	return rc;
+}
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+	uint64_t timestamp;
+	uint64_t temp;
+
+	pr_debug("%s: audio_ioctl() cmd = %d\n", __func__, cmd);
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+
+		pr_debug("%s: AUDIO_GET_STATS cmd\n", __func__);
+		memset(&stats, 0, sizeof(stats));
+		timestamp = q6asm_get_session_time(audio->ac);
+		if (timestamp < 0) {
+			pr_err("%s: Get Session Time return value =%lld\n",
+				__func__, timestamp);
+			return -EAGAIN;
+		}
+		temp = (timestamp * 2 * audio->out_channel_mode);
+		temp = temp * (audio->out_sample_rate/1000);
+		temp = div_u64(temp, 1000);
+		audio->bytes_consumed = (uint32_t)(temp & 0xFFFFFFFF);
+		stats.byte_count = audio->bytes_consumed;
+		stats.unused[0]  = (uint32_t)((temp >> 32) & 0xFFFFFFFF);
+		pr_debug("%s: bytes_consumed:lsb = %d, msb = %d,"
+			"timestamp = %lld\n", __func__,
+			audio->bytes_consumed, stats.unused[0], timestamp);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+				return -EFAULT;
+		return 0;
+	}
+
+	switch (cmd) {
+	case AUDIO_ENABLE_AUDPP:
+		break;
+
+	case AUDIO_SET_VOLUME:
+		break;
+
+	case AUDIO_SET_PAN:
+		break;
+
+	case AUDIO_SET_EQ:
+		break;
+	}
+
+	if (cmd == AUDIO_GET_EVENT) {
+		pr_debug("%s: AUDIO_GET_EVENT\n", __func__);
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audlpa_process_event_req(audio,
+				(void __user *) arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		pr_info("%s: AUDIO_START: Session %d\n", __func__,
+			audio->ac->session);
+		if (!audio->opened) {
+			pr_err("%s: Driver not opened\n", __func__);
+			rc = -EFAULT;
+			goto fail;
+		}
+		rc = config(audio);
+		if (rc) {
+			pr_err("%s: Out Configuration failed\n", __func__);
+			rc = -EFAULT;
+			goto fail;
+		}
+
+		rc = audio_enable(audio);
+		if (rc) {
+			pr_err("%s: audio enable failed\n", __func__);
+			rc = -EFAULT;
+			goto fail;
+		} else {
+			struct asm_softpause_params param = {
+				.enable = SOFT_PAUSE_ENABLE,
+				.period = SOFT_PAUSE_PERIOD,
+				.step = SOFT_PAUSE_STEP,
+				.rampingcurve = SOFT_PAUSE_CURVE_LINEAR,
+			};
+			audio->out_enabled = 1;
+			audio->out_needed = 1;
+			rc = q6asm_set_volume(audio->ac, audio->volume);
+			if (rc < 0)
+				pr_err("%s: Send Volume command failed rc=%d\n",
+					__func__, rc);
+			rc = q6asm_set_softpause(audio->ac, &param);
+			if (rc < 0)
+				pr_err("%s: Send SoftPause Param failed rc=%d\n",
+					__func__, rc);
+			rc = q6asm_set_lrgain(audio->ac, 0x2000, 0x2000);
+			if (rc < 0)
+				pr_err("%s: Send channel gain failed rc=%d\n",
+					__func__, rc);
+			/* disable mute by default */
+			rc = q6asm_set_mute(audio->ac, 0);
+			if (rc < 0)
+				pr_err("%s: Send mute command failed rc=%d\n",
+					__func__, rc);
+			if (!list_empty(&audio->out_queue))
+				pr_err("%s: write_list is not empty!!!\n",
+					__func__);
+			if (audio->stopped == 1)
+				audio->stopped = 0;
+			audlpa_prevent_sleep(audio);
+		}
+		break;
+
+	case AUDIO_STOP:
+		pr_info("%s: AUDIO_STOP: session_id:%d\n", __func__,
+			audio->ac->session);
+		audio->stopped = 1;
+		audlpa_async_flush(audio);
+		audio->out_enabled = 0;
+		audio->out_needed = 0;
+		audio->drv_status &= ~ADRV_STATUS_PAUSE;
+		audlpa_allow_sleep(audio);
+		break;
+
+	case AUDIO_FLUSH:
+		pr_debug("%s: AUDIO_FLUSH: session_id:%d\n", __func__,
+			audio->ac->session);
+		audio->wflush = 1;
+		if (audio->out_enabled)
+			audlpa_async_flush(audio);
+		else
+			audio->wflush = 0;
+		audio->wflush = 0;
+		break;
+
+	case AUDIO_SET_CONFIG:{
+		struct msm_audio_config config;
+		pr_debug("%s: AUDIO_SET_CONFIG\n", __func__);
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			pr_err("%s: ERROR: copy from user\n", __func__);
+			break;
+		}
+		if (!((config.channel_count == 1) ||
+			(config.channel_count == 2))) {
+			rc = -EINVAL;
+			pr_err("%s: ERROR: config.channel_count == %d\n",
+				__func__, config.channel_count);
+			break;
+		}
+
+		if (!((config.bits == 8) || (config.bits == 16) ||
+			  (config.bits == 24))) {
+			rc = -EINVAL;
+			pr_err("%s: ERROR: config.bits = %d\n", __func__,
+				config.bits);
+			break;
+		}
+		audio->out_sample_rate = config.sample_rate;
+		audio->out_channel_mode = config.channel_count;
+		audio->out_bits = config.bits;
+		audio->buffer_count = config.buffer_count;
+		audio->buffer_size = config.buffer_size;
+		rc = 0;
+		break;
+	}
+
+	case AUDIO_GET_CONFIG:{
+		struct msm_audio_config config;
+		config.buffer_count = audio->buffer_count;
+		config.buffer_size = audio->buffer_size;
+		config.sample_rate = audio->out_sample_rate;
+		config.channel_count = audio->out_channel_mode;
+		config.bits = audio->out_bits;
+
+		config.meta_field = 0;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	}
+
+	case AUDIO_PAUSE:
+		pr_debug("%s: AUDIO_PAUSE %ld\n", __func__, arg);
+		if (arg == 1) {
+			rc = audlpa_pause(audio);
+			if (rc < 0)
+				pr_err("%s: pause FAILED rc=%d\n", __func__,
+					rc);
+			audio->drv_status |= ADRV_STATUS_PAUSE;
+		} else if (arg == 0) {
+			if (audio->drv_status & ADRV_STATUS_PAUSE) {
+				rc = audio_enable(audio);
+				if (rc)
+					pr_err("%s: audio enable failed\n",
+						__func__);
+				else {
+					audio->drv_status &= ~ADRV_STATUS_PAUSE;
+					audio->out_enabled = 1;
+				}
+			}
+		}
+		break;
+
+	case AUDIO_REGISTER_PMEM: {
+			struct msm_audio_pmem_info info;
+			pr_debug("%s: AUDIO_REGISTER_PMEM\n", __func__);
+			if (copy_from_user(&info, (void *) arg, sizeof(info)))
+				rc = -EFAULT;
+			else
+				rc = audlpa_pmem_add(audio, &info);
+			break;
+		}
+
+	case AUDIO_DEREGISTER_PMEM: {
+			struct msm_audio_pmem_info info;
+			pr_debug("%s: AUDIO_DEREGISTER_PMEM\n", __func__);
+			if (copy_from_user(&info, (void *) arg, sizeof(info)))
+				rc = -EFAULT;
+			else
+				rc = audlpa_pmem_remove(audio, &info);
+			break;
+		}
+	case AUDIO_ASYNC_WRITE:
+		pr_debug("%s: AUDIO_ASYNC_WRITE\n", __func__);
+		if (audio->drv_status & ADRV_STATUS_FSYNC)
+			rc = -EBUSY;
+		else
+			rc = audlpa_aio_buf_add(audio, 1, (void __user *) arg);
+		break;
+
+	case AUDIO_GET_SESSION_ID:
+		if (copy_to_user((void *) arg, &audio->ac->session,
+					sizeof(unsigned short)))
+			return -EFAULT;
+		rc = 0;
+		break;
+
+	default:
+		rc = audio->codec_ops.ioctl(file, cmd, arg);
+	}
+fail:
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+/* Only useful in tunnel-mode */
+int audlpa_async_fsync(struct audio *audio)
+{
+	int rc = 0;
+
+	pr_info("%s:Session %d\n", __func__, audio->ac->session);
+
+	/* Blocking client sends more data */
+	mutex_lock(&audio->lock);
+	audio->drv_status |= ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	mutex_lock(&audio->write_lock);
+	audio->teos = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+					((list_empty(&audio->out_queue)) ||
+					audio->wflush || audio->stopped));
+
+	if (audio->wflush || audio->stopped)
+		goto flush_event;
+
+	if (rc < 0) {
+		pr_err("%s: wait event for list_empty failed, rc = %d\n",
+			__func__, rc);
+		goto done;
+	}
+
+	rc = q6asm_cmd(audio->ac, CMD_EOS);
+
+	if (rc < 0) {
+		pr_err("%s: q6asm_cmd failed, rc = %d", __func__, rc);
+		goto done;
+	}
+	rc = wait_event_interruptible_timeout(audio->write_wait,
+				  (audio->teos || audio->wflush ||
+				  audio->stopped), 5*HZ);
+
+	if (rc < 0) {
+		pr_err("%s: wait event for teos failed, rc = %d\n", __func__,
+			rc);
+		goto done;
+	}
+
+	if (audio->teos == 1) {
+		rc = audio_enable(audio);
+		if (rc)
+			pr_err("%s: audio enable failed\n", __func__);
+		else {
+			audio->drv_status &= ~ADRV_STATUS_PAUSE;
+			audio->out_enabled = 1;
+			audio->out_needed = 1;
+		}
+	}
+
+flush_event:
+	if (audio->stopped || audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+	mutex_lock(&audio->lock);
+	audio->drv_status &= ~ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	return rc;
+}
+
+int audlpa_fsync(struct file *file, int datasync)
+{
+	struct audio *audio = file->private_data;
+
+	return audlpa_async_fsync(audio);
+}
+
+static void audlpa_reset_pmem_region(struct audio *audio)
+{
+	struct audlpa_pmem_region *region;
+	struct list_head *ptr, *next;
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audlpa_pmem_region, list);
+		list_del(&region->list);
+		put_pmem_file(region->file);
+		kfree(region);
+	}
+
+	return;
+}
+
+static void audlpa_unmap_pmem_region(struct audio *audio)
+{
+	struct audlpa_pmem_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	pr_debug("%s:\n", __func__);
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audlpa_pmem_region, list);
+		pr_debug("%s: phy_address = 0x%lx\n", __func__, region->paddr);
+		if (region != NULL) {
+			rc = q6asm_memory_unmap(audio->ac,
+						(uint32_t)region->paddr, IN);
+			if (rc < 0)
+				pr_err("%s: memory unmap failed\n", __func__);
+		}
+	}
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	pr_info("%s: audio instance 0x%08x freeing, session %d\n", __func__,
+		(int)audio, audio->ac->session);
+
+	mutex_lock(&audio->lock);
+	audio->wflush = 1;
+	if (audio->out_enabled)
+		audlpa_async_flush(audio);
+	audio->wflush = 0;
+	audlpa_unmap_pmem_region(audio);
+	audio_disable(audio);
+	msm_clear_session_id(audio->ac->session);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->ac->session);
+	q6asm_audio_client_free(audio->ac);
+	audlpa_reset_pmem_region(audio);
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	unregister_early_suspend(&audio->suspend_ctl.node);
+#endif
+	audio->opened = 0;
+	audio->out_enabled = 0;
+	audio->out_prefill = 0;
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audlpa_reset_event_queue(audio);
+	pmem_kfree(audio->phys);
+	if (audio->stopped == 0)
+		audlpa_allow_sleep(audio);
+	wake_lock_destroy(&audio->wakelock);
+
+	mutex_unlock(&audio->lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	return 0;
+}
+
+static void audlpa_post_event(struct audio *audio, int type,
+	union msm_audio_event_payload payload)
+{
+	struct audlpa_event *e_node = NULL;
+
+	spin_lock(&audio->event_queue_lock);
+
+	pr_debug("%s:\n", __func__);
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+			struct audlpa_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audlpa_event), GFP_ATOMIC);
+		if (!e_node) {
+			pr_err("%s: No mem to post event %d\n", __func__, type);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock(&audio->event_queue_lock);
+	wake_up(&audio->event_wait);
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void audlpa_suspend(struct early_suspend *h)
+{
+	struct audlpa_suspend_ctl *ctl =
+		container_of(h, struct audlpa_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	pr_debug("%s:\n", __func__);
+	audlpa_post_event(ctl->audio, AUDIO_EVENT_SUSPEND, payload);
+}
+
+static void audlpa_resume(struct early_suspend *h)
+{
+	struct audlpa_suspend_ctl *ctl =
+		container_of(h, struct audlpa_suspend_ctl, node);
+	union msm_audio_event_payload payload;
+
+	pr_debug("%s:\n", __func__);
+	audlpa_post_event(ctl->audio, AUDIO_EVENT_RESUME, payload);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audlpa_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audlpa_debug_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0;
+	struct audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"out_enabled %d\n", audio->out_enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"volume %x\n", audio->volume);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"sample rate %d\n",
+					audio->out_sample_rate);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"channel mode %d\n",
+					audio->out_channel_mode);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"running %d\n", audio->running);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+					"out_needed %d\n", audio->out_needed);
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audlpa_debug_fops = {
+	.read = audlpa_debug_read,
+	.open = audlpa_debug_open,
+};
+#endif
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = NULL;
+	int rc, i, dec_attrb = 0;
+	struct audlpa_event *e_node = NULL;
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_lpa_" + 5];
+#endif
+	char wake_lock_name[24];
+
+	/* Allocate audio instance, set to zero */
+	audio = kzalloc(sizeof(struct audio), GFP_KERNEL);
+	if (!audio) {
+		pr_err("%s: no memory to allocate audio instance\n", __func__);
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	if ((file->f_mode & FMODE_WRITE) && !(file->f_mode & FMODE_READ)) {
+		pr_debug("%s: Tunnel Mode playback\n", __func__);
+	} else {
+		kfree(audio);
+		rc = -EACCES;
+		goto done;
+	}
+
+	/* Allocate the decoder based on inode minor number*/
+	audio->minor_no = iminor(inode);
+	dec_attrb |= audlpa_decs[audio->minor_no].dec_attrb;
+	audio->codec_ops.ioctl = audlpa_decs[audio->minor_no].ioctl;
+	audio->codec_ops.set_params = audlpa_decs[audio->minor_no].set_params;
+	audio->buffer_size = BUFSZ;
+	audio->buffer_count = MAX_BUF;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb)q6_audlpa_out_cb,
+					(void *)audio);
+	if (!audio->ac) {
+		pr_err("%s: Could not allocate memory for lpa client\n",
+								__func__);
+		rc = -ENOMEM;
+		goto err;
+	}
+	rc = q6asm_open_write(audio->ac, FORMAT_LINEAR_PCM);
+	if (rc < 0) {
+		pr_err("%s: lpa out open failed\n", __func__);
+		goto err;
+	}
+
+	pr_debug("%s: Set mode to AIO session[%d]\n",
+						__func__,
+						audio->ac->session);
+	rc = q6asm_set_io_mode(audio->ac, ASYNC_IO_MODE);
+	if (rc < 0)
+		pr_err("%s: Set IO mode failed\n", __func__);
+
+
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->write_wait);
+	INIT_LIST_HEAD(&audio->out_queue);
+	INIT_LIST_HEAD(&audio->pmem_region_queue);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+	init_waitqueue_head(&audio->wait);
+	init_waitqueue_head(&audio->event_wait);
+	spin_lock_init(&audio->event_queue_lock);
+	snprintf(wake_lock_name, sizeof wake_lock_name, "audio_lpa_%x",
+		audio->ac->session);
+	wake_lock_init(&audio->wakelock, WAKE_LOCK_SUSPEND, wake_lock_name);
+
+	audio->out_sample_rate = 44100;
+	audio->out_channel_mode = 2;
+	audio->out_bits = 16;
+	audio->volume = 0x2000;
+
+	file->private_data = audio;
+	audio->opened = 1;
+	audio->out_enabled = 0;
+	audio->out_prefill = 0;
+	audio->bytes_consumed = 0;
+
+	audio->device_events = AUDDEV_EVT_STREAM_VOL_CHG;
+	audio->drv_status &= ~ADRV_STATUS_PAUSE;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->ac->session,
+					lpa_listner,
+					(void *)audio);
+	if (rc) {
+		pr_err("%s: failed to register listner\n", __func__);
+		goto err;
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_lpa_%04x", audio->ac->session);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+			NULL, (void *) audio, &audlpa_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		pr_err("%s: debugfs_create_file failed\n", __func__);
+#endif
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	audio->suspend_ctl.node.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	audio->suspend_ctl.node.resume = audlpa_resume;
+	audio->suspend_ctl.node.suspend = audlpa_suspend;
+	audio->suspend_ctl.audio = audio;
+	register_early_suspend(&audio->suspend_ctl.node);
+#endif
+	for (i = 0; i < AUDLPA_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audlpa_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			pr_err("%s: event pkt alloc failed\n", __func__);
+			break;
+		}
+	}
+	pr_info("%s: audio instance 0x%08x created session[%d]\n", __func__,
+						(int)audio,
+						audio->ac->session);
+done:
+	return rc;
+err:
+	q6asm_audio_client_free(audio->ac);
+	pmem_kfree(audio->phys);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_lpa_fops = {
+	.owner		= THIS_MODULE,
+	.open		= audio_open,
+	.release	= audio_release,
+	.unlocked_ioctl	= audio_ioctl,
+	.fsync		= audlpa_fsync,
+};
+
+static dev_t audlpa_devno;
+static struct class *audlpa_class;
+struct audlpa_device {
+	const char *name;
+	struct device *device;
+	struct cdev cdev;
+};
+
+static struct audlpa_device *audlpa_devices;
+
+static void audlpa_create(struct audlpa_device *adev, const char *name,
+			struct device *parent, dev_t devt)
+{
+	struct device *dev;
+	int rc;
+
+	dev = device_create(audlpa_class, parent, devt, "%s", name);
+	if (IS_ERR(dev))
+		return;
+
+	cdev_init(&adev->cdev, &audio_lpa_fops);
+	adev->cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&adev->cdev, devt, 1);
+	if (rc < 0) {
+		device_destroy(audlpa_class, devt);
+	} else {
+		adev->device = dev;
+		adev->name = name;
+	}
+}
+
+static int __init audio_init(void)
+{
+	int rc;
+	int n = ARRAY_SIZE(audlpa_decs);
+
+	audlpa_devices = kzalloc(sizeof(struct audlpa_device) * n, GFP_KERNEL);
+	if (!audlpa_devices)
+		return -ENOMEM;
+
+	audlpa_class = class_create(THIS_MODULE, "audlpa");
+	if (IS_ERR(audlpa_class))
+		goto fail_create_class;
+
+	rc = alloc_chrdev_region(&audlpa_devno, 0, n, "msm_audio_lpa");
+	if (rc < 0)
+		goto fail_alloc_region;
+
+	for (n = 0; n < ARRAY_SIZE(audlpa_decs); n++) {
+		audlpa_create(audlpa_devices + n,
+				audlpa_decs[n].name, NULL,
+				MKDEV(MAJOR(audlpa_devno), n));
+	}
+
+	return 0;
+
+fail_alloc_region:
+	class_unregister(audlpa_class);
+	return rc;
+fail_create_class:
+	kfree(audlpa_devices);
+	return -ENOMEM;
+}
+
+static void __exit audio_exit(void)
+{
+	class_unregister(audlpa_class);
+	kfree(audlpa_devices);
+}
+
+module_init(audio_init);
+module_exit(audio_exit);
+
+MODULE_DESCRIPTION("MSM LPA driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_lpa.h b/arch/arm/mach-msm/qdsp6v2/audio_lpa.h
new file mode 100644
index 0000000..3c99d08
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_lpa.h
@@ -0,0 +1,112 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef AUDIO_LPA_H
+#define AUDIO_LPA_H
+
+#include <linux/earlysuspend.h>
+#include <linux/wakelock.h>
+
+#define ADRV_STATUS_OBUF_GIVEN 0x00000001
+#define ADRV_STATUS_IBUF_GIVEN 0x00000002
+#define ADRV_STATUS_FSYNC 0x00000004
+#define ADRV_STATUS_PAUSE 0x00000008
+
+#define SOFT_PAUSE_PERIOD       30   /* ramp up/down for 30ms    */
+#define SOFT_PAUSE_STEP         2000 /* Step value 2ms or 2000us */
+enum {
+	SOFT_PAUSE_CURVE_LINEAR = 0,
+	SOFT_PAUSE_CURVE_EXP,
+	SOFT_PAUSE_CURVE_LOG,
+};
+
+struct buffer {
+	void *data;
+	unsigned size;
+	unsigned used;		/* Input usage actual DSP produced PCM size  */
+	unsigned addr;
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+struct audlpa_suspend_ctl {
+	struct early_suspend node;
+	struct audio *audio;
+};
+#endif
+
+struct codec_operations {
+	long (*ioctl)(struct file *, unsigned int, unsigned long);
+	int (*set_params)(void *);
+};
+
+struct audio {
+	spinlock_t dsp_lock;
+
+	uint8_t out_needed; /* number of buffers the dsp is waiting for */
+	struct list_head out_queue; /* queue to retain output buffers */
+
+	struct mutex lock;
+	struct mutex write_lock;
+	wait_queue_head_t write_wait;
+
+	struct audio_client *ac;
+
+	/* configuration to use on next enable */
+	uint32_t out_sample_rate;
+	uint32_t out_channel_mode;
+	uint32_t out_bits; /* bits per sample (used by PCM decoder) */
+
+	int32_t phys; /* physical address of write buffer */
+
+	uint32_t drv_status;
+	int wflush; /* Write flush */
+	int opened;
+	int out_enabled;
+	int out_prefill;
+	int running;
+	int stopped; /* set when stopped, cleared on flush */
+	int buf_refresh;
+	int teos; /* valid only if tunnel mode & no data left for decoder */
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct audlpa_suspend_ctl suspend_ctl;
+#endif
+
+	struct wake_lock wakelock;
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+
+	wait_queue_head_t wait;
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	wait_queue_head_t event_wait;
+	spinlock_t event_queue_lock;
+	struct mutex get_event_lock;
+	int event_abort;
+
+	uint32_t device_events;
+
+	struct list_head pmem_region_queue; /* protected by lock */
+
+	int eq_enable;
+	int eq_needs_commit;
+	uint32_t volume;
+
+	unsigned int minor_no;
+	struct codec_operations codec_ops;
+	uint32_t buffer_size;
+	uint32_t buffer_count;
+	uint32_t bytes_consumed;
+};
+
+#endif /* !AUDIO_LPA_H */
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
new file mode 100644
index 0000000..7423950
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_multi_aac.c
@@ -0,0 +1,1673 @@
+/* aac audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_aac.h>
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <asm/ioctls.h>
+#include <asm/atomic.h>
+#include <sound/apr_audio.h>
+#include <sound/q6asm.h>
+
+#define ADRV_STATUS_AIO_INTF 0x00000001	/* AIO interface */
+#define ADRV_STATUS_FSYNC 0x00000008
+#define ADRV_STATUS_PAUSE 0x00000010
+
+#define TUNNEL_MODE     0x0000
+#define NON_TUNNEL_MODE 0x0001
+#define AUDAAC_EOS_SET  0x00000001
+
+/* Default number of pre-allocated event packets */
+#define AUDAAC_EVENT_NUM 10
+
+#define __CONTAINS(r, v, l) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = ((__v >= __r->vaddr) &&			\
+		(__e <= __r->vaddr + __r->len));		\
+	res;							\
+})
+
+#define CONTAINS(r1, r2) ({					\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->vaddr, __r2->len);			\
+})
+
+#define IN_RANGE(r, v) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->vaddr) &&			\
+		(__vv < (__r->vaddr + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2) ({					\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->vaddr) __v = __r2->vaddr;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
+	res;							\
+})
+
+struct timestamp {
+	unsigned long lowpart;
+	unsigned long highpart;
+} __packed;
+
+struct meta_in {
+	unsigned char reserved[18];
+	unsigned short offset;
+	struct timestamp ntimestamp;
+	unsigned int nflags;
+} __packed;
+
+struct meta_out_dsp {
+	u32 offset_to_frame;
+	u32 frame_size;
+	u32 encoded_pcm_samples;
+	u32 msw_ts;
+	u32 lsw_ts;
+	u32 nflags;
+} __packed;
+
+struct dec_meta_out {
+	unsigned int reserved[7];
+	unsigned int num_of_frames;
+	struct meta_out_dsp meta_out_dsp[];
+} __packed;
+
+/* General meta field to store meta info
+locally */
+union  meta_data {
+	struct dec_meta_out meta_out;
+	struct meta_in meta_in;
+} __packed;
+
+struct audaac_event {
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audaac_pmem_region {
+	struct list_head list;
+	struct file *file;
+	int fd;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	unsigned ref_cnt;
+};
+
+struct audaac_buffer_node {
+	struct list_head list;
+	struct msm_audio_aio_buf buf;
+	unsigned long paddr;
+	unsigned long token;
+	void		*kvaddr;
+	union meta_data meta_info;
+};
+
+struct q6audio;
+
+struct audaac_drv_operations {
+	void (*out_flush) (struct q6audio *);
+	void (*in_flush) (struct q6audio *);
+	int (*fsync)(struct q6audio *);
+};
+
+#define PCM_BUF_COUNT		(2)
+/* Buffer with meta */
+#define PCM_BUFSZ_MIN		((8192) + sizeof(struct dec_meta_out))
+
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM		(2)
+#define FRAME_SIZE		((4*1536) + sizeof(struct meta_in))
+
+struct q6audio {
+	atomic_t in_bytes;
+	atomic_t in_samples;
+
+	struct msm_audio_stream_config str_cfg;
+	struct msm_audio_buf_cfg        buf_cfg;
+	struct msm_audio_config pcm_cfg;
+	struct msm_audio_aac_config aac_config;
+
+	struct audio_client *ac;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	struct mutex write_lock;
+	struct mutex get_event_lock;
+	wait_queue_head_t cmd_wait;
+	wait_queue_head_t write_wait;
+	wait_queue_head_t event_wait;
+	spinlock_t dsp_lock;
+	spinlock_t event_queue_lock;
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+	struct list_head out_queue;	/* queue to retain output buffers */
+	struct list_head in_queue;	/* queue to retain input buffers */
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	struct list_head pmem_region_queue;	/* protected by lock */
+	struct audaac_drv_operations drv_ops;
+	union msm_audio_event_payload eos_write_payload;
+
+	uint32_t drv_status;
+	int event_abort;
+	int eos_rsp;
+	int eos_flag;
+	int opened;
+	int enabled;
+	int stopped;
+	int feedback;
+	int rflush;		/* Read  flush */
+	int wflush;		/* Write flush */
+};
+
+static int insert_eos_buf(struct q6audio *audio,
+	struct audaac_buffer_node *buf_node) {
+	struct dec_meta_out *eos_buf = buf_node->kvaddr;
+	eos_buf->num_of_frames = 0xFFFFFFFF;
+	eos_buf->meta_out_dsp[0].offset_to_frame = 0x0;
+	eos_buf->meta_out_dsp[0].nflags = AUDAAC_EOS_SET;
+	return sizeof(struct dec_meta_out) +
+		sizeof(eos_buf->meta_out_dsp[0]);
+}
+
+/* Routine which updates read buffers of driver/dsp,
+   for flush operation as DSP output might not have proper
+   value set */
+static int insert_meta_data(struct q6audio *audio,
+	struct audaac_buffer_node *buf_node) {
+	struct dec_meta_out *meta_data = buf_node->kvaddr;
+	meta_data->num_of_frames = 0x0;
+	meta_data->meta_out_dsp[0].offset_to_frame = 0x0;
+	meta_data->meta_out_dsp[0].nflags = 0x0;
+	return sizeof(struct dec_meta_out) +
+		sizeof(meta_data->meta_out_dsp[0]);
+}
+
+static void extract_meta_info(struct q6audio *audio,
+	struct audaac_buffer_node *buf_node, int dir)
+{
+	if (dir) { /* input buffer - Write */
+		if (audio->buf_cfg.meta_info_enable)
+			memcpy(&buf_node->meta_info.meta_in,
+			(char *)buf_node->kvaddr, sizeof(struct meta_in));
+		else
+			memset(&buf_node->meta_info.meta_in,
+			0, sizeof(struct meta_in));
+		pr_debug("i/p: msw_ts 0x%lx lsw_ts 0x%lx nflags 0x%8x\n",
+			buf_node->meta_info.meta_in.ntimestamp.highpart,
+			buf_node->meta_info.meta_in.ntimestamp.lowpart,
+			buf_node->meta_info.meta_in.nflags);
+	} else { /* output buffer - Read */
+		memcpy((char *)buf_node->kvaddr,
+			&buf_node->meta_info.meta_out,
+			sizeof(struct dec_meta_out));
+		pr_debug("o/p: msw_ts 0x%8x lsw_ts 0x%8x nflags 0x%8x,"
+				 "num_frames = %d\n",
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].msw_ts,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].lsw_ts,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].nflags,
+		((struct dec_meta_out *)buf_node->kvaddr)->num_of_frames);
+	}
+}
+
+static int audaac_pmem_lookup_vaddr(struct q6audio *audio, void *addr,
+	unsigned long len, struct audaac_pmem_region **region)
+{
+	struct audaac_pmem_region *region_elt;
+
+	int match_count = 0;
+
+	*region = NULL;
+
+	/* returns physical address or zero */
+	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+		if (addr >= region_elt->vaddr &&
+		    addr < region_elt->vaddr + region_elt->len &&
+		    addr + len <= region_elt->vaddr + region_elt->len) {
+			/* offset since we could pass vaddr inside a registerd
+			 * pmem buffer
+			 */
+
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		pr_err("multiple hits for vaddr %p, len %ld\n", addr, len);
+		list_for_each_entry(region_elt, &audio->pmem_region_queue,
+					list) {
+			if (addr >= region_elt->vaddr &&
+			    addr < region_elt->vaddr + region_elt->len &&
+			    addr + len <= region_elt->vaddr + region_elt->len)
+				pr_err("\t%p, %ld --> %p\n", region_elt->vaddr,
+				       region_elt->len,
+				       (void *)region_elt->paddr);
+		}
+	}
+
+	return *region ? 0 : -1;
+}
+
+static unsigned long audaac_pmem_fixup(struct q6audio *audio, void *addr,
+	unsigned long len, int ref_up, void **kvaddr)
+{
+	struct audaac_pmem_region *region;
+	unsigned long paddr;
+	int ret;
+
+	ret = audaac_pmem_lookup_vaddr(audio, addr, len, &region);
+	if (ret) {
+		pr_err("lookup (%p, %ld) failed\n", addr, len);
+		return 0;
+	}
+	if (ref_up)
+		region->ref_cnt++;
+	else
+		region->ref_cnt--;
+	pr_debug("found region %p ref_cnt %d\n", region, region->ref_cnt);
+	paddr = region->paddr + (addr - region->vaddr);
+	/* provide kernel virtual address for accessing meta information */
+	if (kvaddr)
+		*kvaddr = (void *) (region->kvaddr + (addr - region->vaddr));
+	return paddr;
+}
+
+static void audaac_post_event(struct q6audio *audio, int type,
+			      union msm_audio_event_payload payload)
+{
+	struct audaac_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+					  struct audaac_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audaac_event), GFP_ATOMIC);
+		if (!e_node) {
+			pr_err("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static int audaac_enable(struct q6audio *audio)
+{
+	/* 2nd arg: 0 -> run immediately
+	   3rd arg: 0 -> msw_ts, 4th arg: 0 ->lsw_ts */
+	return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
+}
+
+static int audaac_disable(struct q6audio *audio)
+{
+	int rc = 0;
+	if (audio->opened) {
+		audio->enabled = 0;
+		audio->opened = 0;
+		pr_debug("%s: inbytes[%d] insamples[%d]\n", __func__,
+			 atomic_read(&audio->in_bytes),
+			 atomic_read(&audio->in_samples));
+		/* Close the session */
+		rc = q6asm_cmd(audio->ac, CMD_CLOSE);
+		if (rc < 0)
+			pr_err("Failed to close the session rc=%d\n", rc);
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->cmd_wait);
+	}
+	pr_debug("enabled[%d]\n", audio->enabled);
+	return rc;
+}
+
+static int audaac_pause(struct q6audio *audio)
+{
+	int rc = 0;
+
+	pr_debug("%s, enabled = %d\n", __func__,
+			audio->enabled);
+	if (audio->enabled) {
+		rc = q6asm_cmd(audio->ac, CMD_PAUSE);
+		if (rc < 0)
+			pr_err("%s: pause cmd failed rc=%d\n", __func__, rc);
+
+	} else
+		pr_err("%s: Driver not enabled\n", __func__);
+	return rc;
+}
+
+static int audaac_flush(struct q6audio *audio)
+{
+	int rc;
+
+	if (audio->enabled) {
+		/* Implicitly issue a pause to the decoder before flushing if
+		   it is not in pause state */
+		if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
+			rc = audaac_pause(audio);
+			if (rc < 0)
+				pr_err("%s: pause cmd failed rc=%d\n", __func__,
+					rc);
+			else
+				audio->drv_status |= ADRV_STATUS_PAUSE;
+		}
+		rc = q6asm_cmd(audio->ac, CMD_FLUSH);
+		if (rc < 0)
+			pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
+		/* Not in stop state, reenable the stream */
+		if (audio->stopped == 0) {
+			rc = audaac_enable(audio);
+			if (rc)
+				pr_err("%s:audio re-enable failed\n", __func__);
+			else {
+				audio->enabled = 1;
+				if (audio->drv_status & ADRV_STATUS_PAUSE)
+					audio->drv_status &= ~ADRV_STATUS_PAUSE;
+			}
+		}
+	}
+	pr_debug("in_bytes %d\n", atomic_read(&audio->in_bytes));
+	pr_debug("in_samples %d\n", atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+	return 0;
+}
+
+static int audaac_outport_flush(struct q6audio *audio)
+{
+	int rc;
+
+	rc = q6asm_cmd(audio->ac, CMD_OUT_FLUSH);
+	if (rc < 0)
+		pr_err("%s: output port flush cmd failed rc=%d\n", __func__,
+			rc);
+	return rc;
+}
+
+static void audaac_async_read(struct q6audio *audio,
+		struct audaac_buffer_node *buf_node)
+{
+	struct audio_client *ac;
+	struct audio_aio_read_param param;
+	int rc;
+
+	pr_debug("%s: Send read buff %p phy %lx len %d\n", __func__, buf_node,
+			buf_node->paddr, buf_node->buf.buf_len);
+	ac = audio->ac;
+	/* Provide address so driver can append nr frames information */
+	param.paddr = buf_node->paddr +
+			sizeof(struct dec_meta_out);
+	param.len = buf_node->buf.buf_len -
+			sizeof(struct dec_meta_out);
+	param.uid = param.paddr;
+	/* Write command will populate paddr as token */
+	buf_node->token = param.paddr;
+	rc = q6asm_async_read(ac, &param);
+	if (rc < 0)
+		pr_err("%s:failed\n", __func__);
+}
+
+static void audaac_async_write(struct q6audio *audio,
+		struct audaac_buffer_node *buf_node)
+{
+	int rc;
+	struct audio_client *ac;
+	struct audio_aio_write_param param;
+
+	pr_debug("%s: Send write buff %p phy %lx len %d, meta_enable = %d\n",
+		__func__, buf_node, buf_node->paddr, buf_node->buf.data_len,
+		audio->buf_cfg.meta_info_enable);
+
+	ac = audio->ac;
+	/* Offset with  appropriate meta */
+	param.paddr = buf_node->paddr + sizeof(struct meta_in);
+	param.len = buf_node->buf.data_len - sizeof(struct meta_in);
+	param.msw_ts = buf_node->meta_info.meta_in.ntimestamp.highpart;
+	param.lsw_ts = buf_node->meta_info.meta_in.ntimestamp.lowpart;
+	/* If no meta_info enaled, indicate no time stamp valid */
+	if (audio->buf_cfg.meta_info_enable)
+		param.flags = 0;
+	else
+		param.flags = 0xFF00;
+	param.uid = param.paddr;
+	/* Read command will populate paddr as token */
+	buf_node->token = param.paddr;
+	rc = q6asm_async_write(ac, &param);
+	if (rc < 0)
+		pr_err("%s:failed\n", __func__);
+}
+
+/* Write buffer to DSP / Handle Ack from DSP */
+static void audaac_async_write_ack(struct q6audio *audio, uint32_t token,
+		uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload event_payload;
+	struct audaac_buffer_node *used_buf;
+
+	/* No active flush in progress */
+	if (audio->wflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	BUG_ON(list_empty(&audio->out_queue));
+	used_buf = list_first_entry(&audio->out_queue,
+				    struct audaac_buffer_node, list);
+	if (token == used_buf->token) {
+		list_del(&used_buf->list);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		pr_debug("consumed buffer\n");
+		event_payload.aio_buf = used_buf->buf;
+		audaac_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				  event_payload);
+		kfree(used_buf);
+		if (list_empty(&audio->out_queue) &&
+			   (audio->drv_status & ADRV_STATUS_FSYNC)) {
+			pr_debug("%s: list is empty, reached EOS in\
+				Tunnel\n", __func__);
+			wake_up(&audio->write_wait);
+		}
+	} else {
+		pr_err("expected=%lx ret=%x\n", used_buf->token, token);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	}
+}
+
+/* Read buffer from DSP / Handle Ack from DSP */
+static void audaac_async_read_ack(struct q6audio *audio, uint32_t token,
+		uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload event_payload;
+	struct audaac_buffer_node *filled_buf;
+
+	/* No active flush in progress */
+	if (audio->rflush)
+		return;
+
+	/* Statistics of read */
+	atomic_add(payload[2], &audio->in_bytes);
+	atomic_add(payload[7], &audio->in_samples);
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	BUG_ON(list_empty(&audio->in_queue));
+	filled_buf = list_first_entry(&audio->in_queue,
+				      struct audaac_buffer_node, list);
+	if (token == (filled_buf->token)) {
+		list_del(&filled_buf->list);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		event_payload.aio_buf = filled_buf->buf;
+		/* Read done Buffer due to flush/normal condition
+		   after EOS event, so append EOS buffer */
+		if (audio->eos_rsp == 0x1) {
+			event_payload.aio_buf.data_len =
+					insert_eos_buf(audio, filled_buf);
+			/* Reset flag back to indicate eos intimated */
+			audio->eos_rsp = 0;
+		} else {
+			filled_buf->meta_info.meta_out.num_of_frames =
+				payload[7];
+			event_payload.aio_buf.data_len = payload[2] + \
+			payload[3] + \
+			sizeof(struct dec_meta_out);
+			pr_debug("nr of frames 0x%8x len=%d\n",
+				filled_buf->meta_info.meta_out.num_of_frames,
+				event_payload.aio_buf.data_len);
+			extract_meta_info(audio, filled_buf, 0);
+			audio->eos_rsp = 0;
+		}
+		audaac_post_event(audio, AUDIO_EVENT_READ_DONE, event_payload);
+		kfree(filled_buf);
+	} else {
+		pr_err("expected=%lx ret=%x\n", filled_buf->token, token);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	}
+}
+
+static void q6_audaac_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv)
+{
+	struct q6audio *audio = (struct q6audio *)priv;
+	union msm_audio_event_payload e_payload;
+
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE:
+		pr_debug("%s:ASM_DATA_EVENT_WRITE_DONE token = 0x%x\n",
+			 __func__, token);
+		audaac_async_write_ack(audio, token, payload);
+		break;
+	case ASM_DATA_EVENT_READ_DONE:
+		pr_debug("%s:ASM_DATA_EVENT_READ_DONE token = 0x%x\n",
+			 __func__, token);
+		audaac_async_read_ack(audio, token, payload);
+		break;
+	case ASM_DATA_CMDRSP_EOS:
+		/* EOS Handle */
+		pr_debug("%s:ASM_DATA_CMDRSP_EOS\n", __func__);
+		if (audio->feedback) { /* Non-Tunnel mode */
+			audio->eos_rsp = 1;
+			/* propagate input EOS i/p buffer,
+			   after receiving DSP acknowledgement */
+			if (audio->eos_flag &&
+				(audio->eos_write_payload.aio_buf.buf_addr)) {
+				audaac_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+						audio->eos_write_payload);
+				memset(&audio->eos_write_payload , 0,
+					sizeof(union msm_audio_event_payload));
+				audio->eos_flag = 0;
+			}
+		} else { /* Tunnel mode */
+			audio->eos_rsp = 1;
+			wake_up(&audio->write_wait);
+			wake_up(&audio->cmd_wait);
+		}
+		break;
+	case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
+	case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+		pr_debug("%s:payload0[%x] payloa1d[%x]opcode= 0x%x\n",
+			 __func__, payload[0], payload[1], opcode);
+		break;
+
+	case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+		pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
+				"payload[0]-sr = %d, payload[1]-chl = %d, "
+				"payload[2] = %d, payload[3] = %d\n", __func__,
+				payload[0], payload[1], payload[2],
+				payload[3]);
+		pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, "
+				"sr(prev) = %d, chl(prev) = %d,",
+				__func__, audio->pcm_cfg.sample_rate,
+				audio->pcm_cfg.channel_count);
+		audio->pcm_cfg.sample_rate = payload[0];
+		audio->pcm_cfg.channel_count = payload[1] & 0xFFFF;
+		e_payload.stream_info.chan_info = audio->pcm_cfg.channel_count;
+		e_payload.stream_info.sample_rate = audio->pcm_cfg.sample_rate;
+		audaac_post_event(audio, AUDIO_EVENT_STREAM_INFO, e_payload);
+		break;
+	default:
+		pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
+		break;
+	}
+}
+
+/* ------------------- device --------------------- */
+static void audaac_async_out_flush(struct q6audio *audio)
+{
+	struct audaac_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+	unsigned long flags;
+
+	pr_debug("%s\n", __func__);
+	/* EOS followed by flush, EOS response not guranteed, free EOS i/p
+	   buffer */
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (audio->eos_flag && (audio->eos_write_payload.aio_buf.buf_addr)) {
+		pr_debug("%s: EOS followed by flush received,acknowledge eos"\
+			" i/p buffer immediately\n", __func__);
+		audaac_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+					audio->eos_write_payload);
+		memset(&audio->eos_write_payload , 0,
+			sizeof(union msm_audio_event_payload));
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+
+	list_for_each_safe(ptr, next, &audio->out_queue) {
+		buf_node = list_entry(ptr, struct audaac_buffer_node, list);
+		list_del(&buf_node->list);
+		payload.aio_buf = buf_node->buf;
+		audaac_post_event(audio, AUDIO_EVENT_WRITE_DONE, payload);
+		kfree(buf_node);
+		pr_debug("%s: Propagate WRITE_DONE during flush\n", __func__);
+	}
+}
+
+static void audaac_async_in_flush(struct q6audio *audio)
+{
+	struct audaac_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+
+	pr_debug("%s\n", __func__);
+	list_for_each_safe(ptr, next, &audio->in_queue) {
+		buf_node = list_entry(ptr, struct audaac_buffer_node, list);
+		list_del(&buf_node->list);
+		/* Forcefull send o/p eos buffer after flush, if no eos response
+		 * received by dsp even after sending eos command */
+		if ((audio->eos_rsp != 1) && audio->eos_flag) {
+			pr_debug("%s: send eos on o/p buffer during flush\n",\
+				__func__);
+			payload.aio_buf = buf_node->buf;
+			payload.aio_buf.data_len =
+					insert_eos_buf(audio, buf_node);
+			audio->eos_flag = 0;
+		} else {
+			payload.aio_buf = buf_node->buf;
+			payload.aio_buf.data_len =
+					insert_meta_data(audio, buf_node);
+		}
+		audaac_post_event(audio, AUDIO_EVENT_READ_DONE, payload);
+		kfree(buf_node);
+		pr_debug("%s: Propagate READ_DONE during flush\n", __func__);
+	}
+}
+
+static void audaac_ioport_reset(struct q6audio *audio)
+{
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
+		/* If fsync is in progress, make sure
+		 * return value of fsync indicates
+		 * abort due to flush
+		 */
+		if (audio->drv_status & ADRV_STATUS_FSYNC) {
+			pr_debug("fsync in progress\n");
+			audio->drv_ops.out_flush(audio);
+		} else
+			audio->drv_ops.out_flush(audio);
+		audio->drv_ops.in_flush(audio);
+	}
+}
+
+static int audaac_events_pending(struct q6audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audaac_reset_event_queue(struct q6audio *audio)
+{
+	unsigned long flags;
+	struct audaac_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+					   struct audaac_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+					   struct audaac_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audaac_process_event_req(struct q6audio *audio, void __user * arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audaac_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int)usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(audio->event_wait,
+						      audaac_events_pending
+						      (audio),
+						      msecs_to_jiffies
+						      (timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(audio->event_wait,
+					      audaac_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+					   struct audaac_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else {
+		pr_err("Unexpected path\n");
+		spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+		return -EPERM;
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
+		pr_debug("posted AUDIO_EVENT_WRITE_DONE to user\n");
+		mutex_lock(&audio->write_lock);
+		audaac_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0, 0);
+		mutex_unlock(&audio->write_lock);
+	} else if (drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
+		pr_debug("posted AUDIO_EVENT_READ_DONE to user\n");
+		mutex_lock(&audio->read_lock);
+		audaac_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0, 0);
+		mutex_unlock(&audio->read_lock);
+	}
+
+	/* Some read buffer might be held up in DSP, release all
+	 * once EOS indicated
+	 */
+	if (audio->eos_rsp && !list_empty(&audio->in_queue)) {
+		pr_debug("Send flush command to release read buffers"\
+		"held up in DSP\n");
+		audaac_flush(audio);
+	}
+
+	if (copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audaac_pmem_check(struct q6audio *audio,
+			     void *vaddr, unsigned long len)
+{
+	struct audaac_pmem_region *region_elt;
+	struct audaac_pmem_region t = {.vaddr = vaddr, .len = len };
+
+	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+		    OVERLAPS(region_elt, &t)) {
+			pr_err("region (vaddr %p len %ld)"
+			       " clashes with registered region"
+			       " (vaddr %p paddr %p len %ld)\n",
+			       vaddr, len,
+			       region_elt->vaddr,
+			       (void *)region_elt->paddr, region_elt->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int audaac_pmem_add(struct q6audio *audio,
+			   struct msm_audio_pmem_info *info)
+{
+	unsigned long paddr, kvaddr, len;
+	struct file *file;
+	struct audaac_pmem_region *region;
+	int rc = -EINVAL;
+
+	pr_debug("%s:\n", __func__);
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+
+	if (!region) {
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+		kfree(region);
+		goto end;
+	}
+
+	rc = audaac_pmem_check(audio, info->vaddr, len);
+	if (rc < 0) {
+		put_pmem_file(file);
+		kfree(region);
+		goto end;
+	}
+
+	region->vaddr = info->vaddr;
+	region->fd = info->fd;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->file = file;
+	region->ref_cnt = 0;
+	pr_debug("add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+		region->paddr, region->vaddr, region->len, region->kvaddr);
+	list_add_tail(&region->list, &audio->pmem_region_queue);
+
+	rc = q6asm_memory_map(audio->ac, (uint32_t) paddr, IN, (uint32_t) len,
+			1);
+	if (rc < 0)
+		pr_err("%s: memory map failed\n", __func__);
+end:
+	return rc;
+}
+
+static int audaac_pmem_remove(struct q6audio *audio,
+			      struct msm_audio_pmem_info *info)
+{
+	struct audaac_pmem_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	pr_debug("info fd %d vaddr %p\n", info->fd, info->vaddr);
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audaac_pmem_region, list);
+
+		if ((region->fd == info->fd) &&
+			(region->vaddr == info->vaddr)) {
+			if (region->ref_cnt) {
+				pr_debug("region %p in use ref_cnt %d\n",
+					 region, region->ref_cnt);
+				break;
+			}
+			pr_debug("remove region fd %d vaddr %p\n",
+					info->fd, info->vaddr);
+			rc = q6asm_memory_unmap(audio->ac,
+						(uint32_t) region->paddr, IN);
+			if (rc < 0)
+				pr_err("%s: memory unmap failed\n", __func__);
+
+			list_del(&region->list);
+			put_pmem_file(region->file);
+			kfree(region);
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+/* audio -> lock must be held at this point */
+static int audaac_aio_buf_add(struct q6audio *audio, unsigned dir,
+			      void __user *arg)
+{
+	unsigned long flags;
+	struct audaac_buffer_node *buf_node;
+
+	buf_node = kzalloc(sizeof(*buf_node), GFP_KERNEL);
+
+	if (!buf_node)
+		return -ENOMEM;
+
+	if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
+		kfree(buf_node);
+		return -EFAULT;
+	}
+
+	pr_debug("node %p dir %x buf_addr %p buf_len %d data_len \
+			%d\n", buf_node, dir, buf_node->buf.buf_addr,
+			buf_node->buf.buf_len, buf_node->buf.data_len);
+
+	buf_node->paddr = audaac_pmem_fixup(audio, buf_node->buf.buf_addr,
+					    buf_node->buf.buf_len, 1,
+					    &buf_node->kvaddr);
+	if (dir) {
+		/* write */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (!audio->feedback && !buf_node->buf.data_len)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		extract_meta_info(audio, buf_node, 1);
+		/* Not a EOS buffer */
+		if (!(buf_node->meta_info.meta_in.nflags & AUDAAC_EOS_SET)) {
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			audaac_async_write(audio, buf_node);
+			/* EOS buffer handled in driver */
+			list_add_tail(&buf_node->list, &audio->out_queue);
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		}
+		if (buf_node->meta_info.meta_in.nflags & AUDAAC_EOS_SET) {
+			if (!audio->wflush) {
+				pr_debug("%s:Send EOS cmd at i/p\n", __func__);
+				/* Driver will forcefully post writedone event
+				 *	once eos ack recived from DSP
+				 */
+				audio->eos_write_payload.aio_buf =
+								buf_node->buf;
+				audio->eos_flag = 1;
+				audio->eos_rsp = 0;
+				q6asm_cmd(audio->ac, CMD_EOS);
+				kfree(buf_node);
+			} else {/* Flush in progress, send back i/p
+				 * EOS buffer as is
+				 */
+				union msm_audio_event_payload event_payload;
+				event_payload.aio_buf = buf_node->buf;
+				audaac_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+						event_payload);
+				kfree(buf_node);
+			}
+
+		}
+	} else {
+		/* read */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (buf_node->buf.buf_len < PCM_BUFSZ_MIN)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		/* No EOS reached */
+		if (!audio->eos_rsp) {
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			audaac_async_read(audio, buf_node);
+			/* EOS buffer handled in driver */
+			list_add_tail(&buf_node->list, &audio->in_queue);
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		} else {
+		/* EOS reached at input side fake all upcoming read buffer to
+		 * indicate the same
+		 */
+			union msm_audio_event_payload event_payload;
+			event_payload.aio_buf = buf_node->buf;
+			event_payload.aio_buf.data_len =
+				insert_eos_buf(audio, buf_node);
+			pr_debug("%s: propagate READ_DONE as EOS done\n",
+				__func__);
+			audaac_post_event(audio, AUDIO_EVENT_READ_DONE,
+					event_payload);
+			kfree(buf_node);
+		}
+	}
+	return 0;
+}
+
+/* TBD: Only useful in tunnel-mode */
+static int audmultiaac_async_fsync(struct q6audio *audio)
+{
+	int rc = 0;
+
+	/* Blocking client sends more data */
+	mutex_lock(&audio->lock);
+	audio->drv_status |= ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	pr_debug("%s:\n", __func__);
+
+	mutex_lock(&audio->write_lock);
+	audio->eos_rsp = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+					(list_empty(&audio->out_queue)) ||
+					audio->wflush || audio->stopped);
+
+	if (rc < 0) {
+		pr_err("%s: wait event for list_empty failed, rc = %d\n",
+			__func__, rc);
+		goto done;
+	}
+
+	rc = q6asm_cmd(audio->ac, CMD_EOS);
+
+	if (rc < 0)
+		pr_err("%s: q6asm_cmd failed, rc = %d", __func__, rc);
+
+	rc = wait_event_interruptible(audio->write_wait,
+				  (audio->eos_rsp || audio->wflush ||
+				  audio->stopped));
+
+	if (rc < 0) {
+		pr_err("%s: wait event for eos_rsp failed, rc = %d\n", __func__,
+			rc);
+		goto done;
+	}
+
+	if (audio->eos_rsp == 1) {
+		rc = audaac_enable(audio);
+		if (rc)
+			pr_err("%s: audio enable failed\n", __func__);
+		else {
+			audio->drv_status &= ~ADRV_STATUS_PAUSE;
+			audio->enabled = 1;
+		}
+	}
+
+	if (audio->stopped || audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+	mutex_lock(&audio->lock);
+	audio->drv_status &= ~ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	return rc;
+}
+
+static int audmultiaac_fsync(struct file *file, int datasync)
+{
+	struct q6audio *audio = file->private_data;
+
+	if (!audio->enabled || audio->feedback)
+		return -EINVAL;
+
+	return audio->drv_ops.fsync(audio);
+}
+
+static void audaac_reset_pmem_region(struct q6audio *audio)
+{
+	struct audaac_pmem_region *region;
+	struct list_head *ptr, *next;
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audaac_pmem_region, list);
+		list_del(&region->list);
+		put_pmem_file(region->file);
+		kfree(region);
+	}
+
+	return;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audaac_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audaac_debug_read(struct file *file, char __user * buf,
+				 size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0;
+	struct q6audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "feedback %d\n", audio->feedback);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "inqueue empty %d\n", list_empty(&audio->in_queue));
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "outqueue empty %d\n", list_empty(&audio->out_queue));
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audaac_debug_fops = {
+	.read = audaac_debug_read,
+	.open = audaac_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct q6audio *audio = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return rc;
+	}
+
+	if (cmd == AUDIO_GET_EVENT) {
+		pr_debug("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audaac_process_event_req(audio,
+						      (void __user *)arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ASYNC_WRITE) {
+		mutex_lock(&audio->write_lock);
+		if (audio->drv_status & ADRV_STATUS_FSYNC)
+			rc = -EBUSY;
+		else {
+			if (audio->enabled)
+				rc = audaac_aio_buf_add(audio, 1,
+						(void __user *)arg);
+			else
+				rc = -EPERM;
+		}
+		mutex_unlock(&audio->write_lock);
+		return rc;
+	}
+
+	if (cmd == AUDIO_ASYNC_READ) {
+		mutex_lock(&audio->read_lock);
+		if ((audio->feedback) && (audio->enabled))
+			rc = audaac_aio_buf_add(audio, 0,
+					(void __user *)arg);
+		else
+			rc = -EPERM;
+		mutex_unlock(&audio->read_lock);
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		struct asm_aac_cfg aac_cfg;
+		uint32_t sbr_ps = 0x00;
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			/* Configure PCM output block */
+			rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+					audio->pcm_cfg.sample_rate,
+					audio->pcm_cfg.channel_count);
+			if (rc < 0) {
+				pr_err("pcm output block config failed\n");
+				break;
+			}
+		}
+		/* turn on both sbr and ps */
+		rc = q6asm_enable_sbrps(audio->ac, sbr_ps);
+		if (rc < 0)
+			pr_err("sbr-ps enable failed\n");
+		if (audio->aac_config.sbr_ps_on_flag)
+			aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
+		else if (audio->aac_config.sbr_on_flag)
+			aac_cfg.aot = AAC_ENC_MODE_AAC_P;
+		else
+			aac_cfg.aot = AAC_ENC_MODE_AAC_LC;
+
+		switch (audio->aac_config.format) {
+		case AUDIO_AAC_FORMAT_ADTS:
+			aac_cfg.format = 0x00;
+			break;
+		case AUDIO_AAC_FORMAT_LOAS:
+			aac_cfg.format = 0x01;
+			break;
+		/* ADIF, use it as RAW */
+		default:
+		case AUDIO_AAC_FORMAT_RAW:
+			aac_cfg.format = 0x03;
+		}
+		aac_cfg.ep_config = audio->aac_config.ep_config;
+		aac_cfg.section_data_resilience =
+			audio->aac_config.aac_section_data_resilience_flag;
+		aac_cfg.scalefactor_data_resilience =
+			audio->aac_config.aac_scalefactor_data_resilience_flag;
+		aac_cfg.spectral_data_resilience =
+			audio->aac_config.aac_spectral_data_resilience_flag;
+		aac_cfg.ch_cfg = audio->aac_config.channel_configuration;
+		aac_cfg.sample_rate =  audio->pcm_cfg.sample_rate;
+
+		pr_debug("%s:format=%x aot=%d  ch=%d sr=%d\n",
+			__func__, aac_cfg.format,
+			aac_cfg.aot, aac_cfg.ch_cfg,
+			aac_cfg.sample_rate);
+
+		/* Configure Media format block */
+		rc = q6asm_media_format_block_aac(audio->ac, &aac_cfg);
+		if (rc < 0) {
+			pr_err("cmd media format block failed\n");
+			break;
+		}
+		rc = audaac_enable(audio);
+		audio->eos_rsp = 0;
+		audio->eos_flag = 0;
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("Audio Start procedure failed rc=%d\n", rc);
+			break;
+		}
+		pr_info("%s: AUDIO_START sessionid[%d]enable[%d]\n", __func__,
+						audio->ac->session,
+						audio->enabled);
+		if (audio->stopped == 1)
+			audio->stopped = 0;
+		break;
+	}
+	case AUDIO_STOP: {
+		pr_debug("%s: AUDIO_STOP sessionid[%d]\n", __func__,
+						audio->ac->session);
+		audio->stopped = 1;
+		audaac_flush(audio);
+		audio->enabled = 0;
+		audio->drv_status &= ~ADRV_STATUS_PAUSE;
+		if (rc < 0) {
+			pr_err("Audio Stop procedure failed rc=%d\n", rc);
+			break;
+		}
+		break;
+	}
+	case AUDIO_PAUSE: {
+		pr_debug("AUDIO_PAUSE %ld\n", arg);
+		if (arg == 1) {
+			rc = audaac_pause(audio);
+			if (rc < 0)
+				pr_err("%s: pause FAILED rc=%d\n", __func__,
+						rc);
+				audio->drv_status |= ADRV_STATUS_PAUSE;
+		} else if (arg == 0) {
+			if (audio->drv_status & ADRV_STATUS_PAUSE) {
+				rc = audaac_enable(audio);
+				if (rc)
+					pr_err("%s: audio enable failed\n",
+						__func__);
+				else {
+					audio->drv_status &= ~ADRV_STATUS_PAUSE;
+					audio->enabled = 1;
+				}
+			}
+		}
+		break;
+	}
+	case AUDIO_FLUSH: {
+		pr_debug("%s: AUDIO_FLUSH sessionid[%d]\n", __func__,
+						audio->ac->session);
+		audio->rflush = 1;
+		audio->wflush = 1;
+		/* Flush DSP */
+		rc = audaac_flush(audio);
+		/* Flush input / Output buffer in software*/
+		audaac_ioport_reset(audio);
+		if (rc < 0) {
+			pr_err("AUDIO_FLUSH interrupted\n");
+			rc = -EINTR;
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		audio->eos_flag = 0;
+		audio->eos_rsp = 0;
+		break;
+	}
+	case AUDIO_OUTPORT_FLUSH:
+	{
+		pr_debug("AUDIO_OUTPORT_FLUSH\n");
+		rc = audaac_outport_flush(audio);
+		if (rc < 0) {
+			pr_err("%s: AUDIO_OUTPORT_FLUSH failed\n", __func__);
+			rc = -EINTR;
+		}
+		break;
+	}
+	case AUDIO_REGISTER_PMEM: {
+		struct msm_audio_pmem_info info;
+		pr_debug("AUDIO_REGISTER_PMEM\n");
+		if (copy_from_user(&info, (void *)arg, sizeof(info)))
+			rc = -EFAULT;
+		else
+			rc = audaac_pmem_add(audio, &info);
+		break;
+	}
+	case AUDIO_DEREGISTER_PMEM: {
+		struct msm_audio_pmem_info info;
+		pr_debug("AUDIO_DEREGISTER_PMEM\n");
+		if (copy_from_user(&info, (void *)arg, sizeof(info)))
+			rc = -EFAULT;
+		else
+			rc = audaac_pmem_remove(audio, &info);
+		break;
+	}
+	case AUDIO_GET_AAC_CONFIG: {
+		if (copy_to_user((void *)arg, &audio->aac_config,
+				 sizeof(struct msm_audio_aac_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case AUDIO_SET_AAC_CONFIG: {
+		if (copy_from_user(&audio->aac_config, (void *)arg,
+				 sizeof(struct msm_audio_aac_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = audio->str_cfg.buffer_size;
+		cfg.buffer_count = audio->str_cfg.buffer_count;
+		pr_debug("GET STREAM CFG %d %d\n", cfg.buffer_size,
+			 cfg.buffer_count);
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		pr_debug("SET STREAM CONFIG\n");
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->str_cfg.buffer_size = FRAME_SIZE;
+		audio->str_cfg.buffer_count = FRAME_NUM;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config cfg;
+		if (copy_to_user((void *)arg, &audio->pcm_cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+		}
+		if (audio->feedback != NON_TUNNEL_MODE) {
+			pr_err("Not sufficient permission to"
+				       "change the playback mode\n");
+			rc = -EACCES;
+			break;
+		}
+		if ((config.buffer_count > PCM_BUF_COUNT) ||
+		    (config.buffer_count == 1))
+			config.buffer_count = PCM_BUF_COUNT;
+
+		if (config.buffer_size < PCM_BUFSZ_MIN)
+			config.buffer_size = PCM_BUFSZ_MIN;
+
+		audio->pcm_cfg.buffer_count = config.buffer_count;
+		audio->pcm_cfg.buffer_size = config.buffer_size;
+		audio->pcm_cfg.channel_count = config.channel_count;
+		audio->pcm_cfg.sample_rate = config.sample_rate;
+		rc = 0;
+		break;
+		}
+	case AUDIO_SET_BUF_CFG: {
+		struct msm_audio_buf_cfg  cfg;
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if ((audio->feedback == NON_TUNNEL_MODE) &&
+			!cfg.meta_info_enable) {
+			rc = -EFAULT;
+			break;
+		}
+
+		audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
+		pr_debug("%s:session id %d: Set-buf-cfg: meta[%d]", __func__,
+				audio->ac->session, cfg.meta_info_enable);
+		break;
+	}
+	case AUDIO_GET_BUF_CFG: {
+		pr_debug("%s:session id %d: Get-buf-cfg: meta[%d]\
+			framesperbuf[%d]\n", __func__,
+			audio->ac->session, audio->buf_cfg.meta_info_enable,
+			audio->buf_cfg.frames_per_buf);
+
+		if (copy_to_user((void *)arg, &audio->buf_cfg,
+					sizeof(struct msm_audio_buf_cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+			if (copy_to_user((void *)arg, &audio->ac->session,
+					 sizeof(unsigned short))) {
+				rc = -EFAULT;
+			}
+			break;
+		}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct q6audio *audio = file->private_data;
+	pr_debug("%s: multi_aac dec\n", __func__);
+	mutex_lock(&audio->lock);
+	audaac_disable(audio);
+	audio->drv_ops.out_flush(audio);
+	audio->drv_ops.in_flush(audio);
+	audaac_reset_pmem_region(audio);
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audaac_reset_event_queue(audio);
+	q6asm_audio_client_free(audio->ac);
+	mutex_unlock(&audio->lock);
+	mutex_destroy(&audio->lock);
+	mutex_destroy(&audio->read_lock);
+	mutex_destroy(&audio->write_lock);
+	mutex_destroy(&audio->get_event_lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	pr_info("%s:multi_aac dec success\n", __func__);
+	return 0;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct q6audio *audio = NULL;
+	int rc = 0;
+	int i;
+	struct audaac_event *e_node = NULL;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_multi_aac_" + 5];
+#endif
+	audio = kzalloc(sizeof(struct q6audio), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("Could not allocate memory for aac decode driver\n");
+		return -ENOMEM;
+	}
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->str_cfg.buffer_size = FRAME_SIZE;
+	audio->str_cfg.buffer_count = FRAME_NUM;
+	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+	audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+	audio->pcm_cfg.sample_rate = 48000;
+	audio->pcm_cfg.channel_count = 2;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audaac_cb,
+					     (void *)audio);
+
+	if (!audio->ac) {
+		pr_err("Could not allocate memory for audio client\n");
+		kfree(audio);
+		return -ENOMEM;
+	}
+	/* Only AIO interface */
+	if (file->f_flags & O_NONBLOCK) {
+		pr_debug("set to aio interface\n");
+		audio->drv_status |= ADRV_STATUS_AIO_INTF;
+		audio->drv_ops.out_flush = audaac_async_out_flush;
+		audio->drv_ops.in_flush = audaac_async_in_flush;
+		audio->drv_ops.fsync = audmultiaac_async_fsync;
+		q6asm_set_io_mode(audio->ac, ASYNC_IO_MODE);
+	} else {
+		pr_err("SIO interface not supported\n");
+		rc = -EACCES;
+		goto fail;
+	}
+
+	/* open in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+					   FORMAT_MPEG4_AAC);
+		if (rc < 0) {
+			pr_err("NT mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = NON_TUNNEL_MODE;
+		/* open AAC decoder, expected frames is always 1
+		audio->buf_cfg.frames_per_buf = 0x01;*/
+		audio->buf_cfg.meta_info_enable = 0x01;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_write(audio->ac, FORMAT_MPEG4_AAC);
+		if (rc < 0) {
+			pr_err("T mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = TUNNEL_MODE;
+		audio->buf_cfg.meta_info_enable = 0x00;
+	} else {
+		pr_err("Not supported mode\n");
+		rc = -EACCES;
+		goto fail;
+	}
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	spin_lock_init(&audio->event_queue_lock);
+	init_waitqueue_head(&audio->cmd_wait);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->event_wait);
+	INIT_LIST_HEAD(&audio->out_queue);
+	INIT_LIST_HEAD(&audio->in_queue);
+	INIT_LIST_HEAD(&audio->pmem_region_queue);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+
+	audio->drv_ops.out_flush(audio);
+	audio->opened = 1;
+	file->private_data = audio;
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_multi_aac_%04x", audio->ac->session);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+					    NULL, (void *)audio,
+					    &audaac_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		pr_debug("debugfs_create_file failed\n");
+#endif
+	for (i = 0; i < AUDAAC_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audaac_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			pr_err("event pkt alloc failed\n");
+			break;
+		}
+	}
+	pr_info("%s:AAC 5.1 Decoder OPEN success mode[%d]session[%d]\n",
+		__func__, audio->feedback, audio->ac->session);
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_aac_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_release,
+	.unlocked_ioctl = audio_ioctl,
+	.fsync = audmultiaac_fsync,
+};
+
+struct miscdevice audmultiaac_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_multi_aac",
+	.fops = &audio_aac_fops,
+};
+
+static int __init audio_aac_init(void)
+{
+	return misc_register(&audmultiaac_misc);
+}
+
+device_initcall(audio_aac_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_mvs.c b/arch/arm/mach-msm/qdsp6v2/audio_mvs.c
new file mode 100644
index 0000000..13ebaf4
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_mvs.c
@@ -0,0 +1,992 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/wakelock.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/msm_audio_mvs.h>
+#include <mach/qdsp6v2/q6voice.h>
+
+/* Each buffer is 20 ms, queue holds 200 ms of data. */
+#define MVS_MAX_Q_LEN 10
+
+/* Length of the DSP frame info header added to the voc packet. */
+#define DSP_FRAME_HDR_LEN 1
+
+enum audio_mvs_state_type {
+	AUDIO_MVS_CLOSED,
+	AUDIO_MVS_STARTED,
+	AUDIO_MVS_STOPPED
+};
+
+struct audio_mvs_buf_node {
+	struct list_head list;
+	struct msm_audio_mvs_frame frame;
+};
+
+struct audio_mvs_info_type {
+	enum audio_mvs_state_type state;
+
+	uint32_t mvs_mode;
+	uint32_t rate_type;
+	uint32_t dtx_mode;
+
+	struct list_head in_queue;
+	struct list_head free_in_queue;
+
+	struct list_head out_queue;
+	struct list_head free_out_queue;
+
+	wait_queue_head_t out_wait;
+
+	struct mutex lock;
+	struct mutex in_lock;
+	struct mutex out_lock;
+
+	spinlock_t dsp_lock;
+
+	struct wake_lock suspend_lock;
+	struct wake_lock idle_lock;
+
+	void *memory_chunk;
+};
+
+static struct audio_mvs_info_type audio_mvs_info;
+
+static uint32_t audio_mvs_get_rate(uint32_t mvs_mode, uint32_t rate_type)
+{
+	uint32_t cvs_rate;
+
+	if (mvs_mode == MVS_MODE_AMR_WB)
+		cvs_rate = rate_type - MVS_AMR_MODE_0660;
+	else
+		cvs_rate = rate_type;
+
+	pr_debug("%s: CVS rate is %d for MVS mode %d\n",
+		 __func__, cvs_rate, mvs_mode);
+
+	return cvs_rate;
+}
+
+static void audio_mvs_process_ul_pkt(uint8_t *voc_pkt,
+				     uint32_t pkt_len,
+				     void *private_data)
+{
+	struct audio_mvs_buf_node *buf_node = NULL;
+	struct audio_mvs_info_type *audio = private_data;
+	unsigned long dsp_flags;
+
+	/* Copy up-link packet into out_queue. */
+	spin_lock_irqsave(&audio->dsp_lock, dsp_flags);
+
+	if (!list_empty(&audio->free_out_queue)) {
+		buf_node = list_first_entry(&audio->free_out_queue,
+					    struct audio_mvs_buf_node,
+					    list);
+		list_del(&buf_node->list);
+
+		switch (audio->mvs_mode) {
+		case MVS_MODE_AMR:
+		case MVS_MODE_AMR_WB: {
+			/* Remove the DSP frame info header. Header format:
+			 * Bits 0-3: Frame rate
+			 * Bits 4-7: Frame type
+			 */
+			buf_node->frame.frame_type = ((*voc_pkt) & 0xF0) >> 4;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			buf_node->frame.len = pkt_len - DSP_FRAME_HDR_LEN;
+
+			memcpy(&buf_node->frame.voc_pkt[0],
+			       voc_pkt,
+			       buf_node->frame.len);
+
+			list_add_tail(&buf_node->list, &audio->out_queue);
+			break;
+		}
+
+		case MVS_MODE_IS127: {
+			buf_node->frame.frame_type = 0;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			buf_node->frame.len = pkt_len - DSP_FRAME_HDR_LEN;
+
+			memcpy(&buf_node->frame.voc_pkt[0],
+			       voc_pkt,
+			       buf_node->frame.len);
+
+			list_add_tail(&buf_node->list, &audio->out_queue);
+			break;
+		}
+
+		case MVS_MODE_G729A: {
+			/* G729 frames are 10ms each, but the DSP works with
+			 * 20ms frames and sends two 10ms frames per buffer.
+			 * Extract the two frames and put them in separate
+			 * buffers.
+			 */
+			/* Remove the first DSP frame info header.
+			 * Header format:
+			 * Bits 0-1: Frame type
+			 */
+			buf_node->frame.frame_type = (*voc_pkt) & 0x03;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			/* There are two frames in the buffer. Length of the
+			 * first frame:
+			 */
+			buf_node->frame.len = (pkt_len -
+					       2 * DSP_FRAME_HDR_LEN) / 2;
+
+			memcpy(&buf_node->frame.voc_pkt[0],
+			       voc_pkt,
+			       buf_node->frame.len);
+			voc_pkt = voc_pkt + buf_node->frame.len;
+
+			list_add_tail(&buf_node->list, &audio->out_queue);
+
+			/* Get another buffer from the free Q and fill in the
+			 * second frame.
+			 */
+			if (!list_empty(&audio->free_out_queue)) {
+				buf_node =
+					list_first_entry(&audio->free_out_queue,
+						      struct audio_mvs_buf_node,
+						      list);
+				list_del(&buf_node->list);
+
+				/* Remove the second DSP frame info header.
+				 * Header format:
+				 * Bits 0-1: Frame type
+				 */
+				buf_node->frame.frame_type = (*voc_pkt) & 0x03;
+				voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+				/* There are two frames in the buffer. Length
+				 * of the first frame:
+				 */
+				buf_node->frame.len = (pkt_len -
+						     2 * DSP_FRAME_HDR_LEN) / 2;
+
+				memcpy(&buf_node->frame.voc_pkt[0],
+				       voc_pkt,
+				       buf_node->frame.len);
+
+				list_add_tail(&buf_node->list,
+					      &audio->out_queue);
+
+			} else {
+				/* Drop the second frame. */
+				pr_err("%s: UL data dropped, read is slow\n",
+				       __func__);
+			}
+
+			break;
+		}
+
+		case MVS_MODE_G711A: {
+			/* G711 frames are 10ms each, but the DSP works with
+			 * 20ms frames and sends two 10ms frames per buffer.
+			 * Extract the two frames and put them in separate
+			 * buffers.
+			 */
+			/* Remove the first DSP frame info header.
+			 * Header format:
+			 * Bits 0-1: Frame type
+			 * Bits 2-3: Frame rate
+			 */
+			buf_node->frame.frame_type = (*voc_pkt) & 0x03;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			/* There are two frames in the buffer. Length of the
+			 * first frame:
+			 */
+			buf_node->frame.len = (pkt_len -
+					       2 * DSP_FRAME_HDR_LEN) / 2;
+
+			memcpy(&buf_node->frame.voc_pkt[0],
+			       voc_pkt,
+			       buf_node->frame.len);
+			voc_pkt = voc_pkt + buf_node->frame.len;
+
+			list_add_tail(&buf_node->list, &audio->out_queue);
+
+			/* Get another buffer from the free Q and fill in the
+			 * second frame.
+			 */
+			if (!list_empty(&audio->free_out_queue)) {
+				buf_node =
+					list_first_entry(&audio->free_out_queue,
+						      struct audio_mvs_buf_node,
+						      list);
+				list_del(&buf_node->list);
+
+				/* Remove the second DSP frame info header.
+				 * Header format:
+				 * Bits 0-1: Frame type
+				 * Bits 2-3: Frame rate
+				 */
+				buf_node->frame.frame_type = (*voc_pkt) & 0x03;
+				voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+				/* There are two frames in the buffer. Length
+				 * of the second frame:
+				 */
+				buf_node->frame.len = (pkt_len -
+						     2 * DSP_FRAME_HDR_LEN) / 2;
+
+				memcpy(&buf_node->frame.voc_pkt[0],
+				       voc_pkt,
+				       buf_node->frame.len);
+
+				list_add_tail(&buf_node->list,
+					      &audio->out_queue);
+			} else {
+				/* Drop the second frame. */
+				pr_err("%s: UL data dropped, read is slow\n",
+				       __func__);
+			}
+			break;
+		}
+
+		default: {
+			buf_node->frame.frame_type = 0;
+
+			buf_node->frame.len = pkt_len;
+
+			memcpy(&buf_node->frame.voc_pkt[0],
+			       voc_pkt,
+			       buf_node->frame.len);
+
+			list_add_tail(&buf_node->list, &audio->out_queue);
+		}
+		}
+	} else {
+		pr_err("%s: UL data dropped, read is slow\n", __func__);
+	}
+
+	spin_unlock_irqrestore(&audio->dsp_lock, dsp_flags);
+
+	wake_up(&audio->out_wait);
+}
+
+static void audio_mvs_process_dl_pkt(uint8_t *voc_pkt,
+				     uint32_t *pkt_len,
+				     void *private_data)
+{
+	struct audio_mvs_buf_node *buf_node = NULL;
+	struct audio_mvs_info_type *audio = private_data;
+	unsigned long dsp_flags;
+
+	spin_lock_irqsave(&audio->dsp_lock, dsp_flags);
+
+	if (!list_empty(&audio->in_queue)) {
+		uint32_t rate_type = audio_mvs_get_rate(audio->mvs_mode,
+							audio->rate_type);
+
+		buf_node = list_first_entry(&audio->in_queue,
+					    struct audio_mvs_buf_node,
+					    list);
+		list_del(&buf_node->list);
+
+		switch (audio->mvs_mode) {
+		case MVS_MODE_AMR:
+		case MVS_MODE_AMR_WB: {
+			/* Add the DSP frame info header. Header format:
+			 * Bits 0-3: Frame rate
+			 * Bits 4-7: Frame type
+			 */
+			*voc_pkt = ((buf_node->frame.frame_type & 0x0F) << 4) |
+				   (rate_type & 0x0F);
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			*pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+			memcpy(voc_pkt,
+			       &buf_node->frame.voc_pkt[0],
+			       buf_node->frame.len);
+
+			list_add_tail(&buf_node->list, &audio->free_in_queue);
+			break;
+		}
+
+		case MVS_MODE_IS127: {
+			/* Add the DSP frame info header. Header format:
+			 * Bits 0-3: Frame rate
+			 * Bits 4-7: Frame type
+			 */
+			*voc_pkt = rate_type & 0x0F;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			*pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+			memcpy(voc_pkt,
+			       &buf_node->frame.voc_pkt[0],
+			       buf_node->frame.len);
+
+			list_add_tail(&buf_node->list, &audio->free_in_queue);
+			break;
+		}
+
+		case MVS_MODE_G729A: {
+			/* G729 frames are 10ms each but the DSP expects 20ms
+			 * worth of data, so send two 10ms frames per buffer.
+			 */
+			/* Add the first DSP frame info header. Header format:
+			 * Bits 0-1: Frame type
+			 */
+			*voc_pkt = buf_node->frame.frame_type & 0x03;
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			*pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+			memcpy(voc_pkt,
+			       &buf_node->frame.voc_pkt[0],
+			       buf_node->frame.len);
+			voc_pkt = voc_pkt + buf_node->frame.len;
+
+			list_add_tail(&buf_node->list, &audio->free_in_queue);
+
+			if (!list_empty(&audio->in_queue)) {
+				/* Get the second buffer. */
+				buf_node = list_first_entry(&audio->in_queue,
+						      struct audio_mvs_buf_node,
+						      list);
+				list_del(&buf_node->list);
+
+				/* Add the second DSP frame info header.
+				 * Header format:
+				 * Bits 0-1: Frame type
+				 */
+				*voc_pkt = buf_node->frame.frame_type & 0x03;
+				voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+				*pkt_len = *pkt_len +
+					buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+				memcpy(voc_pkt,
+				       &buf_node->frame.voc_pkt[0],
+				       buf_node->frame.len);
+
+				list_add_tail(&buf_node->list,
+					      &audio->free_in_queue);
+			} else {
+				/* Only 10ms worth of data is available, signal
+				 * erasure frame.
+				 */
+				*voc_pkt = MVS_G729A_ERASURE & 0x03;
+
+				*pkt_len = *pkt_len + DSP_FRAME_HDR_LEN;
+			}
+
+			break;
+		}
+
+		case MVS_MODE_G711A: {
+			/* G711 frames are 10ms each but the DSP expects 20ms
+			 * worth of data, so send two 10ms frames per buffer.
+			 */
+			/* Add the first DSP frame info header. Header format:
+			 * Bits 0-1: Frame type
+			 * Bits 2-3: Frame rate
+			 */
+			*voc_pkt = ((rate_type & 0x0F) << 2) |
+				   (buf_node->frame.frame_type & 0x03);
+			voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+			*pkt_len = buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+			memcpy(voc_pkt,
+			       &buf_node->frame.voc_pkt[0],
+			       buf_node->frame.len);
+			voc_pkt = voc_pkt + buf_node->frame.len;
+
+			list_add_tail(&buf_node->list, &audio->free_in_queue);
+
+			if (!list_empty(&audio->in_queue)) {
+				/* Get the second buffer. */
+				buf_node = list_first_entry(&audio->in_queue,
+						      struct audio_mvs_buf_node,
+						      list);
+				list_del(&buf_node->list);
+
+				/* Add the second DSP frame info header.
+				 * Header format:
+				 * Bits 0-1: Frame type
+				 * Bits 2-3: Frame rate
+				 */
+				*voc_pkt = ((rate_type & 0x0F) << 2) |
+					   (buf_node->frame.frame_type & 0x03);
+				voc_pkt = voc_pkt + DSP_FRAME_HDR_LEN;
+
+				*pkt_len = *pkt_len +
+					buf_node->frame.len + DSP_FRAME_HDR_LEN;
+
+				memcpy(voc_pkt,
+				       &buf_node->frame.voc_pkt[0],
+				       buf_node->frame.len);
+
+				list_add_tail(&buf_node->list,
+					      &audio->free_in_queue);
+			} else {
+				/* Only 10ms worth of data is available, signal
+				 * erasure frame.
+				 */
+				*voc_pkt = ((rate_type & 0x0F) << 2) |
+					   (MVS_G711A_ERASURE & 0x03);
+
+				*pkt_len = *pkt_len + DSP_FRAME_HDR_LEN;
+			}
+			break;
+		}
+
+		default: {
+			*pkt_len = buf_node->frame.len;
+
+			memcpy(voc_pkt,
+			       &buf_node->frame.voc_pkt[0],
+			       buf_node->frame.len);
+
+			list_add_tail(&buf_node->list, &audio->free_in_queue);
+		}
+		}
+	} else {
+		*pkt_len = 0;
+
+		pr_info("%s: No DL data available to send to MVS\n", __func__);
+	}
+
+	spin_unlock_irqrestore(&audio->dsp_lock, dsp_flags);
+}
+
+static uint32_t audio_mvs_get_media_type(uint32_t mvs_mode, uint32_t rate_type)
+{
+	uint32_t media_type;
+
+	switch (mvs_mode) {
+	case MVS_MODE_IS127:
+		media_type = VSS_MEDIA_ID_EVRC_MODEM;
+		break;
+
+	case MVS_MODE_AMR:
+		media_type = VSS_MEDIA_ID_AMR_NB_MODEM;
+		break;
+
+	case MVS_MODE_LINEAR_PCM:
+		media_type = VSS_MEDIA_ID_PCM_NB;
+		break;
+
+	case MVS_MODE_PCM:
+		media_type = VSS_MEDIA_ID_PCM_NB;
+		break;
+
+	case MVS_MODE_AMR_WB:
+		media_type = VSS_MEDIA_ID_AMR_WB_MODEM;
+		break;
+
+	case MVS_MODE_G729A:
+		media_type = VSS_MEDIA_ID_G729;
+		break;
+
+	case MVS_MODE_G711A:
+		if (rate_type == MVS_G711A_MODE_MULAW)
+			media_type = VSS_MEDIA_ID_G711_MULAW;
+		else
+			media_type = VSS_MEDIA_ID_G711_ALAW;
+		break;
+
+	default:
+		media_type = VSS_MEDIA_ID_PCM_NB;
+	}
+
+	pr_debug("%s: media_type is 0x%x\n", __func__, media_type);
+
+	return media_type;
+}
+
+static uint32_t audio_mvs_get_network_type(uint32_t mvs_mode)
+{
+	uint32_t network_type;
+
+	switch (mvs_mode) {
+	case MVS_MODE_IS127:
+	case MVS_MODE_AMR:
+	case MVS_MODE_LINEAR_PCM:
+	case MVS_MODE_PCM:
+	case MVS_MODE_G729A:
+	case MVS_MODE_G711A:
+		network_type = VSS_NETWORK_ID_VOIP_NB;
+		break;
+
+	case MVS_MODE_AMR_WB:
+		network_type = VSS_NETWORK_ID_VOIP_WB;
+		break;
+
+	default:
+		network_type = VSS_NETWORK_ID_DEFAULT;
+	}
+
+	pr_debug("%s: network_type is 0x%x\n", __func__, network_type);
+
+	return network_type;
+}
+
+static int audio_mvs_start(struct audio_mvs_info_type *audio)
+{
+	int rc = 0;
+
+	pr_info("%s\n", __func__);
+
+	/* Prevent sleep. */
+	wake_lock(&audio->suspend_lock);
+	wake_lock(&audio->idle_lock);
+
+	rc = voice_set_voc_path_full(1);
+
+	if (rc == 0) {
+		voice_register_mvs_cb(audio_mvs_process_ul_pkt,
+				      audio_mvs_process_dl_pkt,
+				      audio);
+
+		voice_config_vocoder(
+		    audio_mvs_get_media_type(audio->mvs_mode, audio->rate_type),
+		    audio_mvs_get_rate(audio->mvs_mode, audio->rate_type),
+		    audio_mvs_get_network_type(audio->mvs_mode),
+		    audio->dtx_mode);
+
+		audio->state = AUDIO_MVS_STARTED;
+	} else {
+		pr_err("%s: Error %d setting voc path to full\n", __func__, rc);
+	}
+
+	return rc;
+}
+
+static int audio_mvs_stop(struct audio_mvs_info_type *audio)
+{
+	int rc = 0;
+
+	pr_info("%s\n", __func__);
+
+	voice_set_voc_path_full(0);
+
+	audio->state = AUDIO_MVS_STOPPED;
+
+	/* Allow sleep. */
+	wake_unlock(&audio->suspend_lock);
+	wake_unlock(&audio->idle_lock);
+
+	return rc;
+}
+
+static int audio_mvs_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	int i;
+	int offset = 0;
+	struct audio_mvs_buf_node *buf_node = NULL;
+
+	pr_info("%s\n", __func__);
+
+	mutex_lock(&audio_mvs_info.lock);
+
+	/* Allocate input and output buffers. */
+	audio_mvs_info.memory_chunk = kmalloc(2 * MVS_MAX_Q_LEN *
+					      sizeof(struct audio_mvs_buf_node),
+					      GFP_KERNEL);
+
+	if (audio_mvs_info.memory_chunk != NULL) {
+		for (i = 0; i < MVS_MAX_Q_LEN; i++) {
+			buf_node = audio_mvs_info.memory_chunk + offset;
+
+			list_add_tail(&buf_node->list,
+				      &audio_mvs_info.free_in_queue);
+
+			offset = offset + sizeof(struct audio_mvs_buf_node);
+		}
+
+		for (i = 0; i < MVS_MAX_Q_LEN; i++) {
+			buf_node = audio_mvs_info.memory_chunk + offset;
+
+			list_add_tail(&buf_node->list,
+				      &audio_mvs_info.free_out_queue);
+
+			offset = offset + sizeof(struct audio_mvs_buf_node);
+		}
+
+		audio_mvs_info.state = AUDIO_MVS_STOPPED;
+
+		file->private_data = &audio_mvs_info;
+
+	}  else {
+		pr_err("%s: No memory for IO buffers\n", __func__);
+
+		rc = -ENOMEM;
+	}
+
+	mutex_unlock(&audio_mvs_info.lock);
+
+	return rc;
+}
+
+static int audio_mvs_release(struct inode *inode, struct file *file)
+{
+	struct list_head *ptr = NULL;
+	struct list_head *next = NULL;
+	struct audio_mvs_buf_node *buf_node = NULL;
+	struct audio_mvs_info_type *audio = file->private_data;
+
+	pr_info("%s\n", __func__);
+
+	mutex_lock(&audio->lock);
+
+	if (audio->state == AUDIO_MVS_STARTED)
+		audio_mvs_stop(audio);
+
+	/* Free input and output memory. */
+	mutex_lock(&audio->in_lock);
+
+	list_for_each_safe(ptr, next, &audio->in_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+	}
+
+	list_for_each_safe(ptr, next, &audio->free_in_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+	}
+
+	mutex_unlock(&audio->in_lock);
+
+
+	mutex_lock(&audio->out_lock);
+
+	list_for_each_safe(ptr, next, &audio->out_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+	}
+
+	list_for_each_safe(ptr, next, &audio->free_out_queue) {
+		buf_node = list_entry(ptr, struct audio_mvs_buf_node, list);
+		list_del(&buf_node->list);
+	}
+
+	mutex_unlock(&audio->out_lock);
+
+	kfree(audio->memory_chunk);
+	audio->memory_chunk = NULL;
+
+	audio->state = AUDIO_MVS_CLOSED;
+
+	mutex_unlock(&audio->lock);
+
+	return 0;
+}
+
+static ssize_t audio_mvs_read(struct file *file,
+			      char __user *buf,
+			      size_t count,
+			      loff_t *pos)
+{
+	int rc = 0;
+	struct audio_mvs_buf_node *buf_node = NULL;
+	struct audio_mvs_info_type *audio = file->private_data;
+
+	pr_debug("%s:\n", __func__);
+
+	rc = wait_event_interruptible_timeout(audio->out_wait,
+					     (!list_empty(&audio->out_queue) ||
+					     audio->state == AUDIO_MVS_STOPPED),
+					     1 * HZ);
+
+	if (rc > 0) {
+		mutex_lock(&audio->out_lock);
+
+		if ((audio->state == AUDIO_MVS_STARTED) &&
+		    (!list_empty(&audio->out_queue))) {
+
+			if (count >= sizeof(struct msm_audio_mvs_frame)) {
+				buf_node = list_first_entry(&audio->out_queue,
+						struct audio_mvs_buf_node,
+						list);
+				list_del(&buf_node->list);
+
+				rc = copy_to_user(buf,
+					&buf_node->frame,
+					sizeof(struct msm_audio_mvs_frame));
+
+				if (rc == 0) {
+					rc = buf_node->frame.len +
+					    sizeof(buf_node->frame.frame_type) +
+					    sizeof(buf_node->frame.len);
+				} else {
+					pr_err("%s: Copy to user retuned %d",
+					       __func__, rc);
+
+					rc = -EFAULT;
+				}
+
+				list_add_tail(&buf_node->list,
+					      &audio->free_out_queue);
+			} else {
+				pr_err("%s: Read count %d < sizeof(frame) %d",
+				       __func__, count,
+				       sizeof(struct msm_audio_mvs_frame));
+
+				rc = -ENOMEM;
+			}
+		} else {
+			pr_err("%s: Read performed in state %d\n",
+			       __func__, audio->state);
+
+			rc = -EPERM;
+		}
+
+		mutex_unlock(&audio->out_lock);
+
+	} else if (rc == 0) {
+		pr_err("%s: No UL data available\n", __func__);
+
+		rc = -ETIMEDOUT;
+	} else {
+		pr_err("%s: Read was interrupted\n", __func__);
+
+		rc = -ERESTARTSYS;
+	}
+
+	return rc;
+}
+
+static ssize_t audio_mvs_write(struct file *file,
+			       const char __user *buf,
+			       size_t count,
+			       loff_t *pos)
+{
+	int rc = 0;
+	struct audio_mvs_buf_node *buf_node = NULL;
+	struct audio_mvs_info_type *audio = file->private_data;
+
+	pr_debug("%s:\n", __func__);
+
+	mutex_lock(&audio->in_lock);
+
+	if (audio->state == AUDIO_MVS_STARTED) {
+		if (count <= sizeof(struct msm_audio_mvs_frame)) {
+			if (!list_empty(&audio->free_in_queue)) {
+				buf_node =
+					list_first_entry(&audio->free_in_queue,
+						 struct audio_mvs_buf_node,
+						 list);
+				list_del(&buf_node->list);
+
+				rc = copy_from_user(&buf_node->frame,
+						    buf,
+						    count);
+
+				list_add_tail(&buf_node->list,
+					      &audio->in_queue);
+			} else {
+				pr_err("%s: No free DL buffs\n", __func__);
+			}
+		} else {
+			pr_err("%s: Write count %d < sizeof(frame) %d",
+			       __func__, count,
+			       sizeof(struct msm_audio_mvs_frame));
+
+			rc = -ENOMEM;
+		}
+	} else {
+		pr_err("%s: Write performed in invalid state %d\n",
+		       __func__, audio->state);
+
+		rc = -EPERM;
+	}
+
+	mutex_unlock(&audio->in_lock);
+
+	return rc;
+}
+
+static long audio_mvs_ioctl(struct file *file,
+			    unsigned int cmd,
+			    unsigned long arg)
+{
+	int rc = 0;
+	struct audio_mvs_info_type *audio = file->private_data;
+
+	pr_info("%s:\n", __func__);
+
+	switch (cmd) {
+	case AUDIO_GET_MVS_CONFIG: {
+		struct msm_audio_mvs_config config;
+
+		pr_info("%s: IOCTL GET_MVS_CONFIG\n", __func__);
+
+		mutex_lock(&audio->lock);
+
+		config.mvs_mode = audio->mvs_mode;
+		config.rate_type = audio->rate_type;
+		config.dtx_mode = audio->dtx_mode;
+
+		mutex_unlock(&audio->lock);
+
+		rc = copy_to_user((void *)arg, &config, sizeof(config));
+		if (rc == 0)
+			rc = sizeof(config);
+		else
+			pr_err("%s: Config copy failed %d\n", __func__, rc);
+
+		break;
+	}
+
+	case AUDIO_SET_MVS_CONFIG: {
+		struct msm_audio_mvs_config config;
+
+		pr_info("%s: IOCTL SET_MVS_CONFIG\n", __func__);
+
+		rc = copy_from_user(&config, (void *)arg, sizeof(config));
+		if (rc == 0) {
+			mutex_lock(&audio->lock);
+
+			if (audio->state == AUDIO_MVS_STOPPED) {
+				audio->mvs_mode = config.mvs_mode;
+				audio->rate_type = config.rate_type;
+				audio->dtx_mode = config.dtx_mode;
+			} else {
+				pr_err("%s: Set confg called in state %d\n",
+				       __func__, audio->state);
+
+				rc = -EPERM;
+			}
+
+			mutex_unlock(&audio->lock);
+		} else {
+			pr_err("%s: Config copy failed %d\n", __func__, rc);
+		}
+
+		break;
+	}
+
+	case AUDIO_START: {
+		pr_info("%s: IOCTL START\n", __func__);
+
+		mutex_lock(&audio->lock);
+
+		if (audio->state == AUDIO_MVS_STOPPED) {
+			rc = audio_mvs_start(audio);
+
+			if (rc != 0)
+				audio_mvs_stop(audio);
+		} else {
+			pr_err("%s: Start called in invalid state %d\n",
+			       __func__, audio->state);
+
+			rc = -EPERM;
+		}
+
+		mutex_unlock(&audio->lock);
+
+		break;
+	}
+
+	case AUDIO_STOP: {
+		pr_info("%s: IOCTL STOP\n", __func__);
+
+		mutex_lock(&audio->lock);
+
+		if (audio->state == AUDIO_MVS_STARTED) {
+			rc = audio_mvs_stop(audio);
+		} else {
+			pr_err("%s: Stop called in invalid state %d\n",
+			       __func__, audio->state);
+
+			rc = -EPERM;
+		}
+
+		mutex_unlock(&audio->lock);
+
+		break;
+	}
+
+	default: {
+		pr_err("%s: Unknown IOCTL %d\n", __func__, cmd);
+	}
+	}
+
+	return rc;
+}
+
+static const struct file_operations audio_mvs_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_mvs_open,
+	.release = audio_mvs_release,
+	.read = audio_mvs_read,
+	.write = audio_mvs_write,
+	.unlocked_ioctl = audio_mvs_ioctl
+};
+
+struct miscdevice audio_mvs_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_mvs",
+	.fops = &audio_mvs_fops
+};
+
+static int __init audio_mvs_init(void)
+{
+	int rc = 0;
+
+	memset(&audio_mvs_info, 0, sizeof(audio_mvs_info));
+
+	init_waitqueue_head(&audio_mvs_info.out_wait);
+
+	mutex_init(&audio_mvs_info.lock);
+	mutex_init(&audio_mvs_info.in_lock);
+	mutex_init(&audio_mvs_info.out_lock);
+
+	spin_lock_init(&audio_mvs_info.dsp_lock);
+
+	INIT_LIST_HEAD(&audio_mvs_info.in_queue);
+	INIT_LIST_HEAD(&audio_mvs_info.free_in_queue);
+	INIT_LIST_HEAD(&audio_mvs_info.out_queue);
+	INIT_LIST_HEAD(&audio_mvs_info.free_out_queue);
+
+	wake_lock_init(&audio_mvs_info.suspend_lock,
+		       WAKE_LOCK_SUSPEND,
+		       "audio_mvs_suspend");
+	wake_lock_init(&audio_mvs_info.idle_lock,
+		       WAKE_LOCK_IDLE,
+		       "audio_mvs_idle");
+
+	rc = misc_register(&audio_mvs_misc);
+
+	return rc;
+}
+
+static void __exit audio_mvs_exit(void){
+	pr_info("%s:\n", __func__);
+
+	misc_deregister(&audio_mvs_misc);
+}
+
+module_init(audio_mvs_init);
+module_exit(audio_mvs_exit);
+
+MODULE_DESCRIPTION("MSM MVS driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.c b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
new file mode 100644
index 0000000..2e31ba0
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.c
@@ -0,0 +1,639 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <sound/q6asm.h>
+#include <sound/apr_audio.h>
+#include "audio_utils.h"
+
+static int audio_in_pause(struct q6audio_in  *audio)
+{
+	int rc;
+
+	rc = q6asm_cmd(audio->ac, CMD_PAUSE);
+	if (rc < 0)
+		pr_err("%s:session id %d: pause cmd failed rc=%d\n", __func__,
+				audio->ac->session, rc);
+
+	return rc;
+}
+
+static int audio_in_flush(struct q6audio_in  *audio)
+{
+	int rc;
+
+	pr_debug("%s:session id %d: flush\n", __func__, audio->ac->session);
+	/* Implicitly issue a pause to the decoder before flushing */
+	rc = audio_in_pause(audio);
+	if (rc < 0) {
+		pr_err("%s:session id %d: pause cmd failed rc=%d\n", __func__,
+				audio->ac->session, rc);
+		return rc;
+	}
+
+	rc = q6asm_cmd(audio->ac, CMD_FLUSH);
+	if (rc < 0) {
+		pr_err("%s:session id %d: flush cmd failed rc=%d\n", __func__,
+				audio->ac->session, rc);
+		return rc;
+	}
+	audio->rflush = 1;
+	audio->wflush = 1;
+	memset(audio->out_frame_info, 0, sizeof(audio->out_frame_info));
+	wake_up(&audio->read_wait);
+	/* get read_lock to ensure no more waiting read thread */
+	mutex_lock(&audio->read_lock);
+	audio->rflush = 0;
+	mutex_unlock(&audio->read_lock);
+	wake_up(&audio->write_wait);
+	/* get write_lock to ensure no more waiting write thread */
+	mutex_lock(&audio->write_lock);
+	audio->wflush = 0;
+	mutex_unlock(&audio->write_lock);
+	pr_debug("%s:session id %d: in_bytes %d\n", __func__,
+			audio->ac->session, atomic_read(&audio->in_bytes));
+	pr_debug("%s:session id %d: in_samples %d\n", __func__,
+			audio->ac->session, atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+	return 0;
+}
+
+void  audio_in_get_dsp_frames(struct q6audio_in *audio,
+	uint32_t token,	uint32_t *payload)
+{
+	uint32_t index;
+
+	index = token;
+	pr_debug("%s:session id %d: index=%d nr frames=%d offset[%d]\n",
+			__func__, audio->ac->session, token, payload[7],
+			payload[3]);
+	pr_debug("%s:session id %d: timemsw=%d lsw=%d\n", __func__,
+			audio->ac->session, payload[4], payload[5]);
+	pr_debug("%s:session id %d: uflags=0x%8x uid=0x%8x\n", __func__,
+			audio->ac->session, payload[6], payload[8]);
+	pr_debug("%s:session id %d: enc frame size=0x%8x\n", __func__,
+			audio->ac->session, payload[2]);
+
+	audio->out_frame_info[index][0] = payload[7];
+	audio->out_frame_info[index][1] = payload[3];
+
+	/* statistics of read */
+	atomic_add(payload[2], &audio->in_bytes);
+	atomic_add(payload[7], &audio->in_samples);
+
+	if (atomic_read(&audio->out_count) <= audio->str_cfg.buffer_count) {
+		atomic_inc(&audio->out_count);
+		wake_up(&audio->read_wait);
+	}
+}
+
+/* must be called with audio->lock held */
+int audio_in_enable(struct q6audio_in  *audio)
+{
+	if (audio->enabled)
+		return 0;
+
+	/* 2nd arg: 0 -> run immediately
+		3rd arg: 0 -> msw_ts, 4th arg: 0 ->lsw_ts */
+	return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
+}
+
+/* must be called with audio->lock held */
+int audio_in_disable(struct q6audio_in  *audio)
+{
+	int rc = 0;
+	if (audio->opened) {
+		audio->enabled = 0;
+		audio->opened = 0;
+		pr_debug("%s:session id %d: inbytes[%d] insamples[%d]\n",
+				__func__, audio->ac->session,
+				atomic_read(&audio->in_bytes),
+				atomic_read(&audio->in_samples));
+
+		rc = q6asm_cmd(audio->ac, CMD_CLOSE);
+		if (rc < 0)
+			pr_err("%s:session id %d: Failed to close the\
+				session rc=%d\n", __func__, audio->ac->session,
+				rc);
+		audio->stopped = 1;
+		memset(audio->out_frame_info, 0,
+				sizeof(audio->out_frame_info));
+		wake_up(&audio->read_wait);
+		wake_up(&audio->write_wait);
+	}
+	pr_debug("%s:session id %d: enabled[%d]\n", __func__,
+			audio->ac->session, audio->enabled);
+	return rc;
+}
+
+int audio_in_buf_alloc(struct q6audio_in *audio)
+{
+	int rc = 0;
+
+	switch (audio->buf_alloc) {
+	case NO_BUF_ALLOC:
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			rc = q6asm_audio_client_buf_alloc(IN,
+				audio->ac,
+				ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
+				audio->pcm_cfg.buffer_count);
+			if (rc < 0) {
+				pr_err("%s:session id %d: Buffer Alloc\
+						failed\n", __func__,
+						audio->ac->session);
+				rc = -ENOMEM;
+				break;
+			}
+			audio->buf_alloc |= BUF_ALLOC_IN;
+		}
+		rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
+				ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
+				audio->str_cfg.buffer_count);
+		if (rc < 0) {
+			pr_err("%s:session id %d: Buffer Alloc failed rc=%d\n",
+					__func__, audio->ac->session, rc);
+			rc = -ENOMEM;
+			break;
+		}
+		audio->buf_alloc |= BUF_ALLOC_OUT;
+		break;
+	case BUF_ALLOC_IN:
+		rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
+				ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
+				audio->str_cfg.buffer_count);
+		if (rc < 0) {
+			pr_err("%s:session id %d: Buffer Alloc failed rc=%d\n",
+					__func__, audio->ac->session, rc);
+			rc = -ENOMEM;
+			break;
+		}
+		audio->buf_alloc |= BUF_ALLOC_OUT;
+		break;
+	case BUF_ALLOC_OUT:
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			rc = q6asm_audio_client_buf_alloc(IN, audio->ac,
+				ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
+				audio->pcm_cfg.buffer_count);
+			if (rc < 0) {
+				pr_err("%s:session id %d: Buffer Alloc\
+					failed\n", __func__,
+					audio->ac->session);
+				rc = -ENOMEM;
+				break;
+			}
+			audio->buf_alloc |= BUF_ALLOC_IN;
+		}
+		break;
+	default:
+		pr_debug("%s:session id %d: buf[%d]\n", __func__,
+					audio->ac->session, audio->buf_alloc);
+	}
+
+	return rc;
+}
+/* ------------------- device --------------------- */
+long audio_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_in  *audio = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return rc;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_FLUSH: {
+		/* Make sure we're stopped and we wake any threads
+		* that might be blocked holding the read_lock.
+		* While audio->stopped read threads will always
+		* exit immediately.
+		*/
+		rc = audio_in_flush(audio);
+		if (rc < 0)
+			pr_err("%s:session id %d: Flush Fail rc=%d\n",
+					__func__, audio->ac->session, rc);
+		break;
+	}
+	case AUDIO_PAUSE: {
+		pr_debug("%s:session id %d: AUDIO_PAUSE\n", __func__,
+					audio->ac->session);
+		if (audio->enabled)
+			audio_in_pause(audio);
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = audio->str_cfg.buffer_size;
+		cfg.buffer_count = audio->str_cfg.buffer_count;
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		pr_debug("%s:session id %d: AUDIO_GET_STREAM_CONFIG %d %d\n",
+				__func__, audio->ac->session, cfg.buffer_size,
+				cfg.buffer_count);
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		/* Minimum single frame size,
+		   but with in maximum frames number */
+		if ((cfg.buffer_size < (audio->min_frame_size+ \
+			sizeof(struct meta_out_dsp))) ||
+			(cfg.buffer_count < FRAME_NUM)) {
+			rc = -EINVAL;
+			break;
+		}
+		audio->str_cfg.buffer_size = cfg.buffer_size;
+		audio->str_cfg.buffer_count = cfg.buffer_count;
+		rc = q6asm_audio_client_buf_alloc(OUT, audio->ac,
+				ALIGN_BUF_SIZE(audio->str_cfg.buffer_size),
+				audio->str_cfg.buffer_count);
+		if (rc < 0) {
+			pr_err("%s: session id %d: Buffer Alloc failed rc=%d\n",
+					__func__, audio->ac->session, rc);
+			rc = -ENOMEM;
+			break;
+		}
+		audio->buf_alloc |= BUF_ALLOC_OUT;
+		rc = 0;
+		pr_debug("%s:session id %d: AUDIO_SET_STREAM_CONFIG %d %d\n",
+				__func__, audio->ac->session,
+				audio->str_cfg.buffer_size,
+				audio->str_cfg.buffer_count);
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+		if (copy_to_user((void *) arg, &audio->ac->session,
+			sizeof(unsigned short))) {
+			rc = -EFAULT;
+		}
+		break;
+	}
+	case AUDIO_SET_BUF_CFG: {
+		struct msm_audio_buf_cfg  cfg;
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if ((audio->feedback == NON_TUNNEL_MODE) &&
+			!cfg.meta_info_enable) {
+			rc = -EFAULT;
+			break;
+		}
+
+		/* Restrict the num of frames per buf to coincide with
+		 * default buf size */
+		if (cfg.frames_per_buf > audio->max_frames_per_buf) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
+		audio->buf_cfg.frames_per_buf = cfg.frames_per_buf;
+		pr_debug("%s:session id %d: Set-buf-cfg: meta[%d]\
+				framesperbuf[%d]\n", __func__,
+				audio->ac->session, cfg.meta_info_enable,
+				cfg.frames_per_buf);
+		break;
+	}
+	case AUDIO_GET_BUF_CFG: {
+		pr_debug("%s:session id %d: Get-buf-cfg: meta[%d]\
+			framesperbuf[%d]\n", __func__,
+			audio->ac->session, audio->buf_cfg.meta_info_enable,
+			audio->buf_cfg.frames_per_buf);
+
+		if (copy_to_user((void *)arg, &audio->buf_cfg,
+					sizeof(struct msm_audio_buf_cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		if (copy_to_user((void *)arg, &audio->pcm_cfg,
+					sizeof(struct msm_audio_config)))
+			rc = -EFAULT;
+		break;
+
+	}
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config cfg;
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (audio->feedback != NON_TUNNEL_MODE) {
+			pr_err("%s:session id %d: Not sufficient permission to"
+					"change the record mode\n", __func__,
+					audio->ac->session);
+			rc = -EACCES;
+			break;
+		}
+		if ((cfg.buffer_count > PCM_BUF_COUNT) ||
+				(cfg.buffer_count == 1))
+			cfg.buffer_count = PCM_BUF_COUNT;
+
+		audio->pcm_cfg.buffer_count = cfg.buffer_count;
+		audio->pcm_cfg.buffer_size  = cfg.buffer_size;
+		audio->pcm_cfg.channel_count = cfg.channel_count;
+		audio->pcm_cfg.sample_rate = cfg.sample_rate;
+		rc = q6asm_audio_client_buf_alloc(IN, audio->ac,
+			ALIGN_BUF_SIZE(audio->pcm_cfg.buffer_size),
+			audio->pcm_cfg.buffer_count);
+		if (rc < 0) {
+			pr_err("%s:session id %d: Buffer Alloc failed\n",
+				__func__, audio->ac->session);
+			rc = -ENOMEM;
+			break;
+		}
+		audio->buf_alloc |= BUF_ALLOC_IN;
+		rc = 0;
+		pr_debug("%s:session id %d: AUDIO_SET_CONFIG %d %d\n", __func__,
+			audio->ac->session, audio->pcm_cfg.buffer_count,
+			audio->pcm_cfg.buffer_size);
+		break;
+	}
+	default:
+		/* call codec specific ioctl */
+		rc = audio->enc_ioctl(file, cmd, arg);
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+ssize_t audio_in_read(struct file *file,
+				char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct q6audio_in  *audio = file->private_data;
+	const char __user *start = buf;
+	unsigned char *data;
+	uint32_t offset = 0;
+	uint32_t size = 0;
+	int rc = 0;
+	uint32_t idx;
+	struct meta_out_dsp meta;
+	uint32_t bytes_to_copy = 0;
+	uint32_t mfield_size = (audio->buf_cfg.meta_info_enable == 0) ? 0 :
+		(sizeof(unsigned char) +
+		(sizeof(struct meta_out_dsp)*(audio->buf_cfg.frames_per_buf)));
+
+	pr_debug("%s:session id %d: read - %d\n", __func__, audio->ac->session,
+			count);
+	if (!audio->enabled)
+		return -EFAULT;
+	mutex_lock(&audio->read_lock);
+	while (count > 0) {
+		rc = wait_event_interruptible(
+			audio->read_wait,
+			((atomic_read(&audio->out_count) > 0) ||
+			(audio->stopped) ||
+			 audio->rflush || audio->eos_rsp));
+
+		if (rc < 0)
+			break;
+
+		if ((audio->stopped && !(atomic_read(&audio->out_count))) ||
+			audio->rflush) {
+			pr_debug("%s:session id %d: driver in stop state or\
+				flush,No more buf to read", __func__,
+				audio->ac->session);
+			rc = 0;/* End of File */
+			break;
+		}
+		if (!(atomic_read(&audio->out_count)) &&
+			(audio->eos_rsp == 1) &&
+			(count >= (sizeof(unsigned char) +
+				sizeof(struct meta_out_dsp)))) {
+			unsigned char num_of_frames;
+			pr_info("%s:session id %d: eos %d at output\n",
+				__func__, audio->ac->session, audio->eos_rsp);
+			if (buf != start)
+				break;
+			num_of_frames = 0xFF;
+			if (copy_to_user(buf, &num_of_frames,
+					sizeof(unsigned char))) {
+				rc = -EFAULT;
+				break;
+			}
+			buf += sizeof(unsigned char);
+			meta.frame_size = 0xFFFF;
+			meta.encoded_pcm_samples = 0xFFFF;
+			meta.msw_ts = 0x00;
+			meta.lsw_ts = 0x00;
+			meta.nflags = AUD_EOS_SET;
+			audio->eos_rsp = 0;
+			if (copy_to_user(buf, &meta, sizeof(meta))) {
+				rc = -EFAULT;
+				break;
+			}
+			buf += sizeof(meta);
+			break;
+		}
+		data = (unsigned char *)q6asm_is_cpu_buf_avail(OUT, audio->ac,
+						&size, &idx);
+		if ((count >= (size + mfield_size)) && data) {
+			if (audio->buf_cfg.meta_info_enable) {
+				if (copy_to_user(buf,
+					&audio->out_frame_info[idx][0],
+					sizeof(unsigned char))) {
+					rc = -EFAULT;
+					break;
+				}
+				bytes_to_copy =
+					(size + audio->out_frame_info[idx][1]);
+				/* Number of frames information copied */
+				buf += sizeof(unsigned char);
+				count -= sizeof(unsigned char);
+			} else {
+				offset = audio->out_frame_info[idx][1];
+				bytes_to_copy = size;
+			}
+
+			pr_debug("%s:session id %d: offset=%d nr of frames= %d\n",
+					__func__, audio->ac->session,
+					audio->out_frame_info[idx][1],
+					audio->out_frame_info[idx][0]);
+
+			if (copy_to_user(buf, &data[offset], bytes_to_copy)) {
+				rc = -EFAULT;
+				break;
+			}
+			count -= bytes_to_copy;
+			buf += bytes_to_copy;
+		} else {
+			pr_err("%s:session id %d: short read data[%p]\
+				bytesavail[%d]bytesrequest[%d]\n", __func__,
+				audio->ac->session,
+				data, size, count);
+		}
+		atomic_dec(&audio->out_count);
+		q6asm_read(audio->ac);
+		break;
+	}
+	mutex_unlock(&audio->read_lock);
+
+	pr_debug("%s:session id %d: read: %d bytes\n", __func__,
+			audio->ac->session, (buf-start));
+	if (buf > start)
+		return buf - start;
+	return rc;
+}
+
+static int extract_meta_info(char *buf, unsigned long *msw_ts,
+		unsigned long *lsw_ts, unsigned int *flags)
+{
+	struct meta_in *meta = (struct meta_in *)buf;
+	*msw_ts = meta->ntimestamp.highpart;
+	*lsw_ts = meta->ntimestamp.lowpart;
+	*flags = meta->nflags;
+	return 0;
+}
+
+ssize_t audio_in_write(struct file *file,
+		const char __user *buf,
+		size_t count, loff_t *pos)
+{
+	struct q6audio_in *audio = file->private_data;
+	const char __user *start = buf;
+	size_t xfer = 0;
+	char *cpy_ptr;
+	int rc = 0;
+	unsigned char *data;
+	uint32_t size = 0;
+	uint32_t idx = 0;
+	uint32_t nflags = 0;
+	unsigned long msw_ts = 0;
+	unsigned long lsw_ts = 0;
+	uint32_t mfield_size = (audio->buf_cfg.meta_info_enable == 0) ? 0 :
+			sizeof(struct meta_in);
+
+	pr_debug("%s:session id %d: to write[%d]\n", __func__,
+			audio->ac->session, count);
+	if (!audio->enabled)
+		return -EFAULT;
+	mutex_lock(&audio->write_lock);
+
+	while (count > 0) {
+		rc = wait_event_interruptible(audio->write_wait,
+				     ((atomic_read(&audio->in_count) > 0) ||
+				      (audio->stopped) ||
+				      (audio->wflush)));
+		if (rc < 0)
+			break;
+		if (audio->stopped || audio->wflush) {
+			pr_debug("%s: session id %d: stop or flush\n", __func__,
+					audio->ac->session);
+			rc = -EBUSY;
+			break;
+		}
+		data = (unsigned char *)q6asm_is_cpu_buf_avail(IN, audio->ac,
+						&size, &idx);
+		if (!data) {
+			pr_debug("%s:session id %d: No buf available\n",
+				__func__, audio->ac->session);
+			continue;
+		}
+		cpy_ptr = data;
+		if (audio->buf_cfg.meta_info_enable) {
+			if (buf == start) {
+				/* Processing beginning of user buffer */
+				if (copy_from_user(cpy_ptr, buf, mfield_size)) {
+					rc = -EFAULT;
+					break;
+				}
+				/* Check if EOS flag is set and buffer has
+				* contains just meta field
+				*/
+				extract_meta_info(cpy_ptr, &msw_ts, &lsw_ts,
+						&nflags);
+				buf += mfield_size;
+				if (count == mfield_size) {
+					/* send the EOS and return */
+					pr_debug("%s:session id %d: send EOS\
+						0x%8x\n", __func__,
+						audio->ac->session, nflags);
+					break;
+				}
+				count -= mfield_size;
+			} else {
+				pr_debug("%s:session id %d: continuous\
+				buffer\n", __func__, audio->ac->session);
+			}
+		}
+		xfer = (count > (audio->pcm_cfg.buffer_size)) ?
+				(audio->pcm_cfg.buffer_size) : count;
+
+		if (copy_from_user(cpy_ptr, buf, xfer)) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = q6asm_write(audio->ac, xfer, msw_ts, lsw_ts, 0x00);
+		if (rc < 0) {
+			rc = -EFAULT;
+			break;
+		}
+		atomic_dec(&audio->in_count);
+		count -= xfer;
+		buf += xfer;
+	}
+	mutex_unlock(&audio->write_lock);
+	pr_debug("%s:session id %d: eos_condition 0x%8x buf[0x%x]\
+			start[0x%x]\n", __func__, audio->ac->session,
+				nflags,	(int) buf, (int) start);
+	if (nflags & AUD_EOS_SET) {
+		rc = q6asm_cmd(audio->ac, CMD_EOS);
+		pr_info("%s:session id %d: eos %d at input\n", __func__,
+				audio->ac->session, audio->eos_rsp);
+	}
+	pr_debug("%s:session id %d: Written %d Avail Buf[%d]", __func__,
+			audio->ac->session, (buf - start - mfield_size),
+			atomic_read(&audio->in_count));
+	if (!rc) {
+		if (buf > start)
+			return buf - start;
+	}
+	return rc;
+}
+
+int audio_in_release(struct inode *inode, struct file *file)
+{
+	struct q6audio_in  *audio = file->private_data;
+	pr_info("%s: session id %d\n", __func__, audio->ac->session);
+	mutex_lock(&audio->lock);
+	audio_in_disable(audio);
+	q6asm_audio_client_free(audio->ac);
+	mutex_unlock(&audio->lock);
+	kfree(audio->enc_cfg);
+	kfree(audio);
+	return 0;
+}
+
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_utils.h b/arch/arm/mach-msm/qdsp6v2/audio_utils.h
new file mode 100644
index 0000000..7a696ca
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_utils.h
@@ -0,0 +1,104 @@
+/* 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/msm_audio.h>
+
+#define FRAME_NUM	(8)
+
+#define PCM_BUF_COUNT		(2)
+
+#define AUD_EOS_SET  0x01
+#define TUNNEL_MODE     0x0000
+#define NON_TUNNEL_MODE 0x0001
+
+#define NO_BUF_ALLOC	0x00
+#define BUF_ALLOC_IN    0x01
+#define BUF_ALLOC_OUT   0x02
+#define BUF_ALLOC_INOUT 0x03
+#define ALIGN_BUF_SIZE(size) ((size + 4095) & (~4095))
+
+struct timestamp{
+	unsigned long lowpart;
+	unsigned long highpart;
+} __attribute__ ((packed));
+
+struct meta_in{
+	unsigned short offset;
+	struct timestamp ntimestamp;
+	unsigned int nflags;
+} __attribute__ ((packed));
+
+struct meta_out_dsp{
+	u32 offset_to_frame;
+	u32 frame_size;
+	u32 encoded_pcm_samples;
+	u32 msw_ts;
+	u32 lsw_ts;
+	u32 nflags;
+} __attribute__ ((packed));
+
+struct meta_out{
+	unsigned char num_of_frames;
+	struct meta_out_dsp meta_out_dsp[];
+} __attribute__ ((packed));
+
+struct q6audio_in{
+	spinlock_t			dsp_lock;
+	atomic_t			in_bytes;
+	atomic_t			in_samples;
+
+	struct mutex			lock;
+	struct mutex			read_lock;
+	struct mutex			write_lock;
+	wait_queue_head_t		read_wait;
+	wait_queue_head_t		write_wait;
+
+	struct audio_client             *ac;
+	struct msm_audio_stream_config  str_cfg;
+	void				*enc_cfg;
+	struct msm_audio_buf_cfg        buf_cfg;
+	struct msm_audio_config		pcm_cfg;
+	void				*codec_cfg;
+
+	/* number of buffers available to read/write */
+	atomic_t			in_count;
+	atomic_t			out_count;
+
+	/* first idx: num of frames per buf, second idx: offset to frame */
+	uint32_t			out_frame_info[FRAME_NUM][2];
+	int				eos_rsp;
+	int				opened;
+	int				enabled;
+	int				stopped;
+	int				feedback; /* Flag indicates whether used
+							in Non Tunnel mode */
+	int				rflush;
+	int				wflush;
+	int				buf_alloc;
+	uint16_t			min_frame_size;
+	uint16_t			max_frames_per_buf;
+	long (*enc_ioctl)(struct file *, unsigned int, unsigned long);
+};
+
+void  audio_in_get_dsp_frames(struct q6audio_in *audio,
+		uint32_t token,	uint32_t *payload);
+int audio_in_enable(struct q6audio_in  *audio);
+int audio_in_disable(struct q6audio_in  *audio);
+int audio_in_buf_alloc(struct q6audio_in *audio);
+long audio_in_ioctl(struct file *file,
+		unsigned int cmd, unsigned long arg);
+ssize_t audio_in_read(struct file *file, char __user *buf,
+		size_t count, loff_t *pos);
+ssize_t audio_in_write(struct file *file, const char __user *buf,
+		size_t count, loff_t *pos);
+int audio_in_release(struct inode *inode, struct file *file);
+
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_wma.c b/arch/arm/mach-msm/qdsp6v2/audio_wma.c
new file mode 100644
index 0000000..ec6466b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_wma.c
@@ -0,0 +1,1585 @@
+/* wma audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_wma.h>
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <asm/ioctls.h>
+#include <asm/atomic.h>
+#include <sound/q6asm.h>
+#include <sound/apr_audio.h>
+
+#define ADRV_STATUS_AIO_INTF 0x00000001	/* AIO interface */
+#define ADRV_STATUS_FSYNC 0x00000008
+#define ADRV_STATUS_PAUSE 0x00000010
+
+#define TUNNEL_MODE     0x0000
+#define NON_TUNNEL_MODE 0x0001
+#define AUDWMA_EOS_SET  0x00000001
+
+/* Default number of pre-allocated event packets */
+#define AUDWMA_EVENT_NUM 10
+
+#define __CONTAINS(r, v, l) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = ((__v >= __r->vaddr) &&			\
+		(__e <= __r->vaddr + __r->len));		\
+	res;							\
+})
+
+#define CONTAINS(r1, r2) ({					\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->vaddr, __r2->len);			\
+})
+
+#define IN_RANGE(r, v) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->vaddr) &&			\
+		(__vv < (__r->vaddr + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2) ({					\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->vaddr) __v = __r2->vaddr;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
+	res;							\
+})
+
+struct timestamp {
+	unsigned long lowpart;
+	unsigned long highpart;
+} __attribute__ ((packed));
+
+struct meta_in {
+	unsigned char reserved[18];
+	unsigned short offset;
+	struct timestamp ntimestamp;
+	unsigned int nflags;
+} __attribute__ ((packed));
+
+struct meta_out_dsp{
+	u32 offset_to_frame;
+	u32 frame_size;
+	u32 encoded_pcm_samples;
+	u32 msw_ts;
+	u32 lsw_ts;
+	u32 nflags;
+} __attribute__ ((packed));
+
+struct dec_meta_out{
+	unsigned int reserved[7];
+	unsigned int num_of_frames;
+	struct meta_out_dsp meta_out_dsp[];
+} __attribute__ ((packed));
+
+/* General meta field to store meta info
+locally */
+union  meta_data {
+	struct dec_meta_out meta_out;
+	struct meta_in meta_in;
+} __attribute__ ((packed));
+
+struct audwma_event {
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audwma_pmem_region {
+	struct list_head list;
+	struct file *file;
+	int fd;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	unsigned ref_cnt;
+};
+
+struct audwma_buffer_node {
+	struct list_head list;
+	struct msm_audio_aio_buf buf;
+	unsigned long paddr;
+	unsigned long token;
+	void		*kvaddr;
+	union meta_data meta_info;
+};
+
+struct q6audio;
+
+struct audwma_drv_operations {
+	void (*out_flush) (struct q6audio *);
+	void (*in_flush) (struct q6audio *);
+	int (*fsync)(struct q6audio *);
+};
+
+#define PCM_BUF_COUNT		(2)
+/* Buffer with meta */
+#define PCM_BUFSZ_MIN		((4*1024) + sizeof(struct dec_meta_out))
+
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM		(2)
+#define FRAME_SIZE		((4*1024) + sizeof(struct meta_in))
+
+struct q6audio {
+	atomic_t in_bytes;
+	atomic_t in_samples;
+
+	struct msm_audio_stream_config str_cfg;
+	struct msm_audio_buf_cfg        buf_cfg;
+	struct msm_audio_config pcm_cfg;
+	struct msm_audio_wma_config_v2 wma_config;
+
+	struct audio_client *ac;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	struct mutex write_lock;
+	struct mutex get_event_lock;
+	wait_queue_head_t cmd_wait;
+	wait_queue_head_t write_wait;
+	wait_queue_head_t event_wait;
+	spinlock_t dsp_lock;
+	spinlock_t event_queue_lock;
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+	struct list_head out_queue;	/* queue to retain output buffers */
+	struct list_head in_queue;	/* queue to retain input buffers */
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	struct list_head pmem_region_queue;	/* protected by lock */
+	struct audwma_drv_operations drv_ops;
+	union msm_audio_event_payload eos_write_payload;
+
+	uint32_t drv_status;
+	int event_abort;
+	int eos_rsp;
+	int eos_flag;
+	int opened;
+	int enabled;
+	int stopped;
+	int feedback;
+	int rflush;		/* Read  flush */
+	int wflush;		/* Write flush */
+};
+
+static int insert_eos_buf(struct q6audio *audio,
+	struct audwma_buffer_node *buf_node) {
+	struct dec_meta_out *eos_buf = buf_node->kvaddr;
+	eos_buf->num_of_frames = 0xFFFFFFFF;
+	eos_buf->meta_out_dsp[0].offset_to_frame = 0x0;
+	eos_buf->meta_out_dsp[0].nflags = AUDWMA_EOS_SET;
+	return sizeof(struct dec_meta_out) +
+		sizeof(eos_buf->meta_out_dsp[0]);
+}
+
+/* Routine which updates read buffers of driver/dsp,
+   for flush operation as DSP output might not have proper
+   value set */
+static int insert_meta_data(struct q6audio *audio,
+	struct audwma_buffer_node *buf_node) {
+	struct dec_meta_out *meta_data = buf_node->kvaddr;
+	meta_data->num_of_frames = 0x0;
+	meta_data->meta_out_dsp[0].offset_to_frame = 0x0;
+	meta_data->meta_out_dsp[0].nflags = 0x0;
+	return sizeof(struct dec_meta_out) +
+		sizeof(meta_data->meta_out_dsp[0]);
+}
+
+static void extract_meta_info(struct q6audio *audio,
+	struct audwma_buffer_node *buf_node, int dir)
+{
+	if (dir) { /* Read */
+		if (audio->buf_cfg.meta_info_enable)
+			memcpy(&buf_node->meta_info.meta_in,
+			(char *)buf_node->kvaddr, sizeof(struct meta_in));
+		else
+			memset(&buf_node->meta_info.meta_in,
+			0, sizeof(struct meta_in));
+		pr_debug("i/p: msw_ts 0x%lx lsw_ts 0x%lx nflags 0x%8x\n",
+			buf_node->meta_info.meta_in.ntimestamp.highpart,
+			buf_node->meta_info.meta_in.ntimestamp.lowpart,
+			buf_node->meta_info.meta_in.nflags);
+	} else { /* Write */
+		memcpy((char *)buf_node->kvaddr,
+			&buf_node->meta_info.meta_out,
+			sizeof(struct dec_meta_out));
+		pr_debug("o/p: msw_ts 0x%8x lsw_ts 0x%8x nflags 0x%8x\n",
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].msw_ts,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].lsw_ts,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+			meta_out_dsp[0].nflags);
+	}
+}
+
+static int audwma_pmem_lookup_vaddr(struct q6audio *audio, void *addr,
+	unsigned long len, struct audwma_pmem_region **region)
+{
+	struct audwma_pmem_region *region_elt;
+
+	int match_count = 0;
+
+	*region = NULL;
+
+	/* returns physical address or zero */
+	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+		if (addr >= region_elt->vaddr &&
+		    addr < region_elt->vaddr + region_elt->len &&
+		    addr + len <= region_elt->vaddr + region_elt->len) {
+			/* offset since we could pass vaddr inside a registerd
+			 * pmem buffer
+			 */
+
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		pr_err("multiple hits for vaddr %p, len %ld\n", addr, len);
+		list_for_each_entry(region_elt, &audio->pmem_region_queue,
+					list) {
+			if (addr >= region_elt->vaddr &&
+			    addr < region_elt->vaddr + region_elt->len &&
+			    addr + len <= region_elt->vaddr + region_elt->len)
+				pr_err("\t%p, %ld --> %p\n", region_elt->vaddr,
+				       region_elt->len,
+				       (void *)region_elt->paddr);
+		}
+	}
+
+	return *region ? 0 : -1;
+}
+
+static unsigned long audwma_pmem_fixup(struct q6audio *audio, void *addr,
+	unsigned long len, int ref_up, void **kvaddr)
+{
+	struct audwma_pmem_region *region;
+	unsigned long paddr;
+	int ret;
+
+	ret = audwma_pmem_lookup_vaddr(audio, addr, len, &region);
+	if (ret) {
+		pr_err("lookup (%p, %ld) failed\n", addr, len);
+		return 0;
+	}
+	if (ref_up)
+		region->ref_cnt++;
+	else
+		region->ref_cnt--;
+	pr_debug("found region %p ref_cnt %d\n", region, region->ref_cnt);
+	paddr = region->paddr + (addr - region->vaddr);
+	/* provide kernel virtual address for accessing meta information */
+	if (kvaddr)
+		*kvaddr = (void *) (region->kvaddr + (addr - region->vaddr));
+	return paddr;
+}
+
+static void audwma_post_event(struct q6audio *audio, int type,
+			      union msm_audio_event_payload payload)
+{
+	struct audwma_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+					  struct audwma_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audwma_event), GFP_ATOMIC);
+		if (!e_node) {
+			pr_err("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static int audwma_enable(struct q6audio *audio)
+{
+	/* 2nd arg: 0 -> run immediately
+	   3rd arg: 0 -> msw_ts, 4th arg: 0 ->lsw_ts */
+	return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
+}
+
+static int audwma_disable(struct q6audio *audio)
+{
+	int rc = 0;
+	if (audio->opened) {
+		audio->enabled = 0;
+		audio->opened = 0;
+		pr_debug("%s: inbytes[%d] insamples[%d]\n", __func__,
+			 atomic_read(&audio->in_bytes),
+			 atomic_read(&audio->in_samples));
+		/* Close the session */
+		rc = q6asm_cmd(audio->ac, CMD_CLOSE);
+		if (rc < 0)
+			pr_err("Failed to close the session rc=%d\n", rc);
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->cmd_wait);
+	}
+	pr_debug("enabled[%d]\n", audio->enabled);
+	return rc;
+}
+
+static int audwma_pause(struct q6audio *audio)
+{
+	int rc = 0;
+
+	pr_info("%s, enabled = %d\n", __func__,
+			audio->enabled);
+	if (audio->enabled) {
+		rc = q6asm_cmd(audio->ac, CMD_PAUSE);
+		if (rc < 0)
+			pr_err("%s: pause cmd failed rc=%d\n", __func__, rc);
+
+	} else
+		pr_err("%s: Driver not enabled\n", __func__);
+	return rc;
+}
+
+static int audwma_flush(struct q6audio *audio)
+{
+	int rc;
+
+	if (audio->enabled) {
+		/* Implicitly issue a pause to the decoder before flushing if
+		   it is not in pause state */
+		if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
+			rc = audwma_pause(audio);
+			if (rc < 0)
+				pr_err("%s: pause cmd failed rc=%d\n", __func__,
+					rc);
+			else
+				audio->drv_status |= ADRV_STATUS_PAUSE;
+		}
+		rc = q6asm_cmd(audio->ac, CMD_FLUSH);
+		if (rc < 0)
+			pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
+		/* Not in stop state, reenable the stream */
+		if (audio->stopped == 0) {
+			rc = audwma_enable(audio);
+			if (rc)
+				pr_err("%s:audio re-enable failed\n", __func__);
+			else {
+				audio->enabled = 1;
+				if (audio->drv_status & ADRV_STATUS_PAUSE)
+					audio->drv_status &= ~ADRV_STATUS_PAUSE;
+			}
+		}
+	}
+	pr_debug("in_bytes %d\n", atomic_read(&audio->in_bytes));
+	pr_debug("in_samples %d\n", atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+	return 0;
+}
+
+static void audwma_async_read(struct q6audio *audio,
+		struct audwma_buffer_node *buf_node)
+{
+	struct audio_client *ac;
+	struct audio_aio_read_param param;
+	int rc;
+
+	pr_debug("%s: Send read buff %p phy %lx len %d\n", __func__, buf_node,
+			buf_node->paddr, buf_node->buf.buf_len);
+	ac = audio->ac;
+	/* Provide address so driver can append nr frames information */
+	param.paddr = buf_node->paddr +
+			sizeof(struct dec_meta_out);
+	param.len = buf_node->buf.buf_len -
+			sizeof(struct dec_meta_out);
+	param.uid = param.paddr;
+	/* Write command will populate paddr as token */
+	buf_node->token = param.paddr;
+	rc = q6asm_async_read(ac, &param);
+	if (rc < 0)
+		pr_err("%s:failed\n", __func__);
+}
+
+static void audwma_async_write(struct q6audio *audio,
+		struct audwma_buffer_node *buf_node)
+{
+	int rc;
+	struct audio_client *ac;
+	struct audio_aio_write_param param;
+
+	pr_debug("%s: Send write buff %p phy %lx len %d\n", __func__, buf_node,
+		 buf_node->paddr, buf_node->buf.data_len);
+
+	ac = audio->ac;
+	/* Offset with  appropriate meta */
+	param.paddr = buf_node->paddr + sizeof(struct meta_in);
+	param.len = buf_node->buf.data_len - sizeof(struct meta_in);
+	param.msw_ts = buf_node->meta_info.meta_in.ntimestamp.highpart;
+	param.lsw_ts = buf_node->meta_info.meta_in.ntimestamp.lowpart;
+	/* If no meta_info enaled, indicate no time stamp valid */
+	if (audio->buf_cfg.meta_info_enable)
+		param.flags = 0;
+	else
+		param.flags = 0xFF00;
+	param.uid = param.paddr;
+	/* Read command will populate paddr as token */
+	buf_node->token = param.paddr;
+	rc = q6asm_async_write(ac, &param);
+	if (rc < 0)
+		pr_err("%s:failed\n", __func__);
+}
+
+/* Write buffer to DSP / Handle Ack from DSP */
+static void audwma_async_write_ack(struct q6audio *audio, uint32_t token,
+		uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload event_payload;
+	struct audwma_buffer_node *used_buf;
+
+	/* No active flush in progress */
+	if (audio->wflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	BUG_ON(list_empty(&audio->out_queue));
+	used_buf = list_first_entry(&audio->out_queue,
+				    struct audwma_buffer_node, list);
+	if (token == used_buf->token) {
+		list_del(&used_buf->list);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		pr_debug("consumed buffer\n");
+		event_payload.aio_buf = used_buf->buf;
+		audwma_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				  event_payload);
+		kfree(used_buf);
+		if (list_empty(&audio->out_queue) &&
+			   (audio->drv_status & ADRV_STATUS_FSYNC)) {
+			pr_debug("%s: list is empty, reached EOS in\
+				Tunnel\n", __func__);
+			wake_up(&audio->write_wait);
+		}
+	} else {
+		pr_err("expected=%lx ret=%x\n", used_buf->token, token);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	}
+}
+
+/* Read buffer from DSP / Handle Ack from DSP */
+static void audwma_async_read_ack(struct q6audio *audio, uint32_t token,
+		uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload event_payload;
+	struct audwma_buffer_node *filled_buf;
+
+	/* No active flush in progress */
+	if (audio->rflush)
+		return;
+
+	/* Statistics of read */
+	atomic_add(payload[2], &audio->in_bytes);
+	atomic_add(payload[7], &audio->in_samples);
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	BUG_ON(list_empty(&audio->in_queue));
+	filled_buf = list_first_entry(&audio->in_queue,
+				      struct audwma_buffer_node, list);
+	if (token == (filled_buf->token)) {
+		list_del(&filled_buf->list);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		event_payload.aio_buf = filled_buf->buf;
+		/* Read done Buffer due to flush/normal condition
+		   after EOS event, so append EOS buffer */
+		if (audio->eos_rsp == 0x1) {
+			event_payload.aio_buf.data_len =
+					insert_eos_buf(audio, filled_buf);
+			/* Reset flag back to indicate eos intimated */
+			audio->eos_rsp = 0;
+		} else {
+			filled_buf->meta_info.meta_out.num_of_frames =
+				payload[7];
+			pr_debug("nr of frames 0x%8x\n",
+				filled_buf->meta_info.meta_out.num_of_frames);
+			event_payload.aio_buf.data_len = payload[2] + \
+			payload[3] + \
+			sizeof(struct dec_meta_out);
+			extract_meta_info(audio, filled_buf, 0);
+			audio->eos_rsp = 0;
+		}
+		audwma_post_event(audio, AUDIO_EVENT_READ_DONE, event_payload);
+		kfree(filled_buf);
+	} else {
+		pr_err("expected=%lx ret=%x\n", filled_buf->token, token);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	}
+}
+
+static void q6_audwma_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv)
+{
+	struct q6audio *audio = (struct q6audio *)priv;
+
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE:
+		pr_debug("%s:ASM_DATA_EVENT_WRITE_DONE token = 0x%x\n",
+			 __func__, token);
+		audwma_async_write_ack(audio, token, payload);
+		break;
+	case ASM_DATA_EVENT_READ_DONE:
+		pr_debug("%s:ASM_DATA_EVENT_READ_DONE token = 0x%x\n",
+			 __func__, token);
+		audwma_async_read_ack(audio, token, payload);
+		break;
+	case ASM_DATA_CMDRSP_EOS:
+		/* EOS Handle */
+		pr_debug("%s:ASM_DATA_CMDRSP_EOS\n", __func__);
+		if (audio->feedback) { /* Non-Tunnel mode */
+			audio->eos_rsp = 1;
+			/* propagate input EOS i/p buffer,
+			   after receiving DSP acknowledgement */
+			if (audio->eos_flag &&
+				(audio->eos_write_payload.aio_buf.buf_addr)) {
+				audwma_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+						audio->eos_write_payload);
+				memset(&audio->eos_write_payload , 0,
+					sizeof(union msm_audio_event_payload));
+				audio->eos_flag = 0;
+			}
+		} else { /* Tunnel mode */
+			audio->eos_rsp = 1;
+			wake_up(&audio->write_wait);
+			wake_up(&audio->cmd_wait);
+		}
+		break;
+	default:
+		pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
+		break;
+	}
+}
+
+/* ------------------- device --------------------- */
+static void audwma_async_out_flush(struct q6audio *audio)
+{
+	struct audwma_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+	unsigned long flags;
+
+	pr_debug("%s\n", __func__);
+	/* EOS followed by flush, EOS response not guranteed, free EOS i/p
+	   buffer */
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (audio->eos_flag && (audio->eos_write_payload.aio_buf.buf_addr)) {
+		pr_debug("%s: EOS followed by flush received,acknowledge eos"\
+			" i/p buffer immediately\n", __func__);
+		audwma_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+					audio->eos_write_payload);
+		memset(&audio->eos_write_payload , 0,
+			sizeof(union msm_audio_event_payload));
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	list_for_each_safe(ptr, next, &audio->out_queue) {
+		buf_node = list_entry(ptr, struct audwma_buffer_node, list);
+		list_del(&buf_node->list);
+		payload.aio_buf = buf_node->buf;
+		audwma_post_event(audio, AUDIO_EVENT_WRITE_DONE, payload);
+		kfree(buf_node);
+		pr_debug("%s: Propagate WRITE_DONE during flush\n", __func__);
+	}
+}
+
+static void audwma_async_in_flush(struct q6audio *audio)
+{
+	struct audwma_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+
+	pr_debug("%s\n", __func__);
+	list_for_each_safe(ptr, next, &audio->in_queue) {
+		buf_node = list_entry(ptr, struct audwma_buffer_node, list);
+		list_del(&buf_node->list);
+		/* Forcefull send o/p eos buffer after flush, if no eos response
+		 * received by dsp even after sending eos command */
+		if ((audio->eos_rsp != 1) && audio->eos_flag) {
+			pr_debug("%s: send eos on o/p buffer during flush\n",\
+				__func__);
+			payload.aio_buf = buf_node->buf;
+			payload.aio_buf.data_len =
+					insert_eos_buf(audio, buf_node);
+			audio->eos_flag = 0;
+		} else {
+			payload.aio_buf = buf_node->buf;
+			payload.aio_buf.data_len =
+					insert_meta_data(audio, buf_node);
+		}
+		audwma_post_event(audio, AUDIO_EVENT_READ_DONE, payload);
+		kfree(buf_node);
+		pr_debug("%s: Propagate READ_DONE during flush\n", __func__);
+	}
+}
+
+static void audwma_ioport_reset(struct q6audio *audio)
+{
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
+		/* If fsync is in progress, make sure
+		 * return value of fsync indicates
+		 * abort due to flush
+		 */
+		if (audio->drv_status & ADRV_STATUS_FSYNC) {
+			pr_debug("fsync in progress\n");
+			audio->drv_ops.out_flush(audio);
+		} else
+			audio->drv_ops.out_flush(audio);
+		audio->drv_ops.in_flush(audio);
+	}
+}
+
+static int audwma_events_pending(struct q6audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audwma_reset_event_queue(struct q6audio *audio)
+{
+	unsigned long flags;
+	struct audwma_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+					   struct audwma_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+					   struct audwma_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audwma_process_event_req(struct q6audio *audio, void __user * arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audwma_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int)usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(audio->event_wait,
+						      audwma_events_pending
+						      (audio),
+						      msecs_to_jiffies
+						      (timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(audio->event_wait,
+					      audwma_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+					   struct audwma_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else {
+		pr_err("Unexpected path\n");
+		spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+		return -EPERM;
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
+		pr_debug("posted AUDIO_EVENT_WRITE_DONE to user\n");
+		mutex_lock(&audio->write_lock);
+		audwma_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0, 0);
+		mutex_unlock(&audio->write_lock);
+	} else if (drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
+		pr_debug("posted AUDIO_EVENT_READ_DONE to user\n");
+		mutex_lock(&audio->read_lock);
+		audwma_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0, 0);
+		mutex_unlock(&audio->read_lock);
+	}
+
+	/* Some read buffer might be held up in DSP,release all
+	   Once EOS indicated*/
+	if (audio->eos_rsp && !list_empty(&audio->in_queue)) {
+		pr_debug("Send flush command to release read buffers"\
+		" held up in DSP\n");
+		audwma_flush(audio);
+	}
+
+	if (copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audwma_pmem_check(struct q6audio *audio,
+			     void *vaddr, unsigned long len)
+{
+	struct audwma_pmem_region *region_elt;
+	struct audwma_pmem_region t = {.vaddr = vaddr, .len = len };
+
+	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+		    OVERLAPS(region_elt, &t)) {
+			pr_err("region (vaddr %p len %ld)"
+			       " clashes with registered region"
+			       " (vaddr %p paddr %p len %ld)\n",
+			       vaddr, len,
+			       region_elt->vaddr,
+			       (void *)region_elt->paddr, region_elt->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int audwma_pmem_add(struct q6audio *audio,
+			   struct msm_audio_pmem_info *info)
+{
+	unsigned long paddr, kvaddr, len;
+	struct file *file;
+	struct audwma_pmem_region *region;
+	int rc = -EINVAL;
+
+	pr_debug("%s:\n", __func__);
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+
+	if (!region) {
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+		kfree(region);
+		goto end;
+	}
+
+	rc = audwma_pmem_check(audio, info->vaddr, len);
+	if (rc < 0) {
+		put_pmem_file(file);
+		kfree(region);
+		goto end;
+	}
+
+	region->vaddr = info->vaddr;
+	region->fd = info->fd;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->file = file;
+	region->ref_cnt = 0;
+	pr_debug("add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+		region->paddr, region->vaddr, region->len, region->kvaddr);
+	list_add_tail(&region->list, &audio->pmem_region_queue);
+
+	rc = q6asm_memory_map(audio->ac, (uint32_t) paddr, IN, (uint32_t) len,
+			1);
+	if (rc < 0)
+		pr_err("%s: memory map failed\n", __func__);
+end:
+	return rc;
+}
+
+static int audwma_pmem_remove(struct q6audio *audio,
+			      struct msm_audio_pmem_info *info)
+{
+	struct audwma_pmem_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	pr_debug("info fd %d vaddr %p\n", info->fd, info->vaddr);
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audwma_pmem_region, list);
+
+		if ((region->fd == info->fd) &&
+			(region->vaddr == info->vaddr)) {
+			if (region->ref_cnt) {
+				pr_debug("region %p in use ref_cnt %d\n",
+					 region, region->ref_cnt);
+				break;
+			}
+			pr_debug("remove region fd %d vaddr %p\n",
+					info->fd, info->vaddr);
+			rc = q6asm_memory_unmap(audio->ac,
+						(uint32_t) region->paddr, IN);
+			if (rc < 0)
+				pr_err("%s: memory unmap failed\n", __func__);
+
+			list_del(&region->list);
+			put_pmem_file(region->file);
+			kfree(region);
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+/* audio -> lock must be held at this point */
+static int audwma_aio_buf_add(struct q6audio *audio, unsigned dir,
+			      void __user *arg)
+{
+	unsigned long flags;
+	struct audwma_buffer_node *buf_node;
+
+	buf_node = kzalloc(sizeof(*buf_node), GFP_KERNEL);
+
+	if (!buf_node)
+		return -ENOMEM;
+
+	if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
+		kfree(buf_node);
+		return -EFAULT;
+	}
+
+	pr_debug("node %p dir %x buf_addr %p buf_len %d data_len \
+			%d\n", buf_node, dir, buf_node->buf.buf_addr,
+			buf_node->buf.buf_len, buf_node->buf.data_len);
+
+	buf_node->paddr = audwma_pmem_fixup(audio, buf_node->buf.buf_addr,
+					    buf_node->buf.buf_len, 1,
+					    &buf_node->kvaddr);
+	if (dir) {
+		/* write */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (!audio->feedback && !buf_node->buf.data_len)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		extract_meta_info(audio, buf_node, 1);
+		/* Not a EOS buffer */
+		if (!(buf_node->meta_info.meta_in.nflags & AUDWMA_EOS_SET)) {
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			audwma_async_write(audio, buf_node);
+			/* EOS buffer handled in driver */
+			list_add_tail(&buf_node->list, &audio->out_queue);
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		}
+		if (buf_node->meta_info.meta_in.nflags & AUDWMA_EOS_SET) {
+			if (!audio->wflush) {
+				pr_debug("%s:Send EOS cmd at i/p\n", __func__);
+				/* Driver will forcefully post writedone event
+				   once eos ack recived from DSP*/
+				audio->eos_write_payload.aio_buf =\
+						buf_node->buf;
+				audio->eos_flag = 1;
+				audio->eos_rsp = 0;
+				q6asm_cmd(audio->ac, CMD_EOS);
+				kfree(buf_node);
+			} else { /* Flush in progress, send back i/p EOS buffer
+				    as is */
+				union msm_audio_event_payload event_payload;
+				event_payload.aio_buf = buf_node->buf;
+				audwma_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+						event_payload);
+				kfree(buf_node);
+			}
+		}
+	} else {
+		/* read */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (buf_node->buf.buf_len < PCM_BUFSZ_MIN)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		/* No EOS reached */
+		if (!audio->eos_rsp) {
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			audwma_async_read(audio, buf_node);
+			/* EOS buffer handled in driver */
+			list_add_tail(&buf_node->list, &audio->in_queue);
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		}
+		/* EOS reached at input side fake all upcoming read buffer to
+		   indicate the same */
+		else {
+			union msm_audio_event_payload event_payload;
+			event_payload.aio_buf = buf_node->buf;
+			event_payload.aio_buf.data_len =
+				insert_eos_buf(audio, buf_node);
+			pr_debug("%s: propagate READ_DONE as EOS done\n",\
+					__func__);
+			audwma_post_event(audio, AUDIO_EVENT_READ_DONE,
+					event_payload);
+			kfree(buf_node);
+		}
+	}
+	return 0;
+}
+
+/* TBD: Only useful in tunnel-mode */
+int audwma_async_fsync(struct q6audio *audio)
+{
+	int rc = 0;
+
+	/* Blocking client sends more data */
+	mutex_lock(&audio->lock);
+	audio->drv_status |= ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	pr_info("%s:\n", __func__);
+
+	mutex_lock(&audio->write_lock);
+	audio->eos_rsp = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+					(list_empty(&audio->out_queue)) ||
+					audio->wflush || audio->stopped);
+
+	if (rc < 0) {
+		pr_err("%s: wait event for list_empty failed, rc = %d\n",
+			__func__, rc);
+		goto done;
+	}
+
+	rc = q6asm_cmd(audio->ac, CMD_EOS);
+
+	if (rc < 0)
+		pr_err("%s: q6asm_cmd failed, rc = %d", __func__, rc);
+
+	rc = wait_event_interruptible(audio->write_wait,
+				  (audio->eos_rsp || audio->wflush ||
+				  audio->stopped));
+
+	if (rc < 0) {
+		pr_err("%s: wait event for eos_rsp failed, rc = %d\n", __func__,
+			rc);
+		goto done;
+	}
+
+	if (audio->eos_rsp == 1) {
+		rc = audwma_enable(audio);
+		if (rc)
+			pr_err("%s: audio enable failed\n", __func__);
+		else {
+			audio->drv_status &= ~ADRV_STATUS_PAUSE;
+			audio->enabled = 1;
+		}
+	}
+
+	if (audio->stopped || audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+	mutex_lock(&audio->lock);
+	audio->drv_status &= ~ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	return rc;
+}
+
+int audwma_fsync(struct file *file, int datasync)
+{
+	struct q6audio *audio = file->private_data;
+
+	if (!audio->enabled || audio->feedback)
+		return -EINVAL;
+
+	return audio->drv_ops.fsync(audio);
+}
+
+static void audwma_reset_pmem_region(struct q6audio *audio)
+{
+	struct audwma_pmem_region *region;
+	struct list_head *ptr, *next;
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audwma_pmem_region, list);
+		list_del(&region->list);
+		put_pmem_file(region->file);
+		kfree(region);
+	}
+
+	return;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audwma_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audwma_debug_read(struct file *file, char __user * buf,
+				 size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0;
+	struct q6audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "feedback %d\n", audio->feedback);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "inqueue empty %d\n", list_empty(&audio->in_queue));
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "outqueue empty %d\n", list_empty(&audio->out_queue));
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audwma_debug_fops = {
+	.read = audwma_debug_read,
+	.open = audwma_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct q6audio *audio = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return rc;
+	}
+
+	if (cmd == AUDIO_GET_EVENT) {
+		pr_debug("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audwma_process_event_req(audio,
+						      (void __user *)arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ASYNC_WRITE) {
+		mutex_lock(&audio->write_lock);
+		if (audio->drv_status & ADRV_STATUS_FSYNC)
+			rc = -EBUSY;
+		else {
+			if (audio->enabled)
+				rc = audwma_aio_buf_add(audio, 1,
+						(void __user *)arg);
+			else
+				rc = -EPERM;
+		}
+		mutex_unlock(&audio->write_lock);
+		return rc;
+	}
+
+	if (cmd == AUDIO_ASYNC_READ) {
+		mutex_lock(&audio->read_lock);
+		if ((audio->feedback) && (audio->enabled))
+			rc = audwma_aio_buf_add(audio, 0,
+					(void __user *)arg);
+		else
+			rc = -EPERM;
+		mutex_unlock(&audio->read_lock);
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		struct asm_wma_cfg wma_cfg;
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			/* Configure PCM output block */
+			rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+					audio->pcm_cfg.sample_rate,
+					audio->pcm_cfg.channel_count);
+			if (rc < 0) {
+				pr_err("pcm output block config failed\n");
+				break;
+			}
+		}
+		wma_cfg.format_tag = audio->wma_config.format_tag;
+		wma_cfg.ch_cfg = audio->wma_config.numchannels;
+		wma_cfg.sample_rate =  audio->wma_config.samplingrate;
+		wma_cfg.avg_bytes_per_sec = audio->wma_config.avgbytespersecond;
+		wma_cfg.block_align = audio->wma_config.block_align;
+		wma_cfg.valid_bits_per_sample =
+				audio->wma_config.validbitspersample;
+		wma_cfg.ch_mask =  audio->wma_config.channelmask;
+		wma_cfg.encode_opt = audio->wma_config.encodeopt;
+		/* Configure Media format block */
+		rc = q6asm_media_format_block_wma(audio->ac, &wma_cfg);
+		if (rc < 0) {
+			pr_err("cmd media format block failed\n");
+			break;
+		}
+		rc = audwma_enable(audio);
+		audio->eos_rsp = 0;
+		audio->eos_flag = 0;
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("Audio Start procedure failed rc=%d\n", rc);
+			break;
+		}
+		pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
+		if (audio->stopped == 1)
+			audio->stopped = 0;
+		break;
+	}
+	case AUDIO_STOP: {
+		pr_debug("AUDIO_STOP\n");
+		audio->stopped = 1;
+		audwma_flush(audio);
+		audio->enabled = 0;
+		audio->drv_status &= ~ADRV_STATUS_PAUSE;
+		if (rc < 0) {
+			pr_err("Audio Stop procedure failed rc=%d\n", rc);
+			break;
+		}
+		break;
+	}
+	case AUDIO_PAUSE: {
+		pr_debug("AUDIO_PAUSE %ld\n", arg);
+		if (arg == 1) {
+			rc = audwma_pause(audio);
+			if (rc < 0)
+				pr_err("%s: pause FAILED rc=%d\n", __func__,
+						rc);
+				audio->drv_status |= ADRV_STATUS_PAUSE;
+		} else if (arg == 0) {
+			if (audio->drv_status & ADRV_STATUS_PAUSE) {
+				rc = audwma_enable(audio);
+				if (rc)
+					pr_err("%s: audio enable failed\n",
+						__func__);
+				else {
+					audio->drv_status &= ~ADRV_STATUS_PAUSE;
+					audio->enabled = 1;
+				}
+			}
+		}
+		break;
+	}
+	case AUDIO_FLUSH: {
+		pr_debug("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		/* Flush DSP */
+		rc = audwma_flush(audio);
+		/* Flush input / Output buffer in software*/
+		audwma_ioport_reset(audio);
+		if (rc < 0) {
+			pr_err("AUDIO_FLUSH interrupted\n");
+			rc = -EINTR;
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		audio->eos_flag = 0;
+		audio->eos_rsp = 0;
+		break;
+	}
+	case AUDIO_REGISTER_PMEM: {
+		struct msm_audio_pmem_info info;
+		pr_debug("AUDIO_REGISTER_PMEM\n");
+		if (copy_from_user(&info, (void *)arg, sizeof(info)))
+			rc = -EFAULT;
+		else
+			rc = audwma_pmem_add(audio, &info);
+		break;
+	}
+	case AUDIO_DEREGISTER_PMEM: {
+		struct msm_audio_pmem_info info;
+		pr_debug("AUDIO_DEREGISTER_PMEM\n");
+		if (copy_from_user(&info, (void *)arg, sizeof(info)))
+			rc = -EFAULT;
+		else
+			rc = audwma_pmem_remove(audio, &info);
+		break;
+	}
+	case AUDIO_GET_WMA_CONFIG_V2: {
+		if (copy_to_user((void *)arg, &audio->wma_config,
+				 sizeof(struct msm_audio_wma_config_v2))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case AUDIO_SET_WMA_CONFIG_V2: {
+		if (copy_from_user(&audio->wma_config, (void *)arg,
+				 sizeof(struct msm_audio_wma_config_v2))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = audio->str_cfg.buffer_size;
+		cfg.buffer_count = audio->str_cfg.buffer_count;
+		pr_debug("GET STREAM CFG %d %d\n", cfg.buffer_size,
+			 cfg.buffer_count);
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		pr_debug("SET STREAM CONFIG\n");
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->str_cfg.buffer_size = FRAME_SIZE;
+		audio->str_cfg.buffer_count = FRAME_NUM;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config cfg;
+		if (copy_to_user((void *)arg, &audio->pcm_cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+		}
+		if (audio->feedback != NON_TUNNEL_MODE) {
+			pr_err("Not sufficient permission to"
+				       "change the playback mode\n");
+			rc = -EACCES;
+			break;
+		}
+		if ((config.buffer_count > PCM_BUF_COUNT) ||
+		    (config.buffer_count == 1))
+			config.buffer_count = PCM_BUF_COUNT;
+
+		if (config.buffer_size < PCM_BUFSZ_MIN)
+			config.buffer_size = PCM_BUFSZ_MIN;
+
+		audio->pcm_cfg.buffer_count = config.buffer_count;
+		audio->pcm_cfg.buffer_size = config.buffer_size;
+		audio->pcm_cfg.channel_count = config.channel_count;
+		audio->pcm_cfg.sample_rate = config.sample_rate;
+		rc = 0;
+		break;
+		}
+	case AUDIO_SET_BUF_CFG: {
+		struct msm_audio_buf_cfg  cfg;
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if ((audio->feedback == NON_TUNNEL_MODE) &&
+			!cfg.meta_info_enable) {
+			rc = -EFAULT;
+			break;
+		}
+
+		audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
+		pr_debug("%s:session id %d: Set-buf-cfg: meta[%d]", __func__,
+				audio->ac->session, cfg.meta_info_enable);
+		break;
+	}
+	case AUDIO_GET_BUF_CFG: {
+		pr_debug("%s:session id %d: Get-buf-cfg: meta[%d]\
+			framesperbuf[%d]\n", __func__,
+			audio->ac->session, audio->buf_cfg.meta_info_enable,
+			audio->buf_cfg.frames_per_buf);
+
+		if (copy_to_user((void *)arg, &audio->buf_cfg,
+					sizeof(struct msm_audio_buf_cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+			if (copy_to_user((void *)arg, &audio->ac->session,
+					 sizeof(unsigned short))) {
+				rc = -EFAULT;
+			}
+			break;
+		}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct q6audio *audio = file->private_data;
+	mutex_lock(&audio->lock);
+	audwma_disable(audio);
+	audio->drv_ops.out_flush(audio);
+	audio->drv_ops.in_flush(audio);
+	audwma_reset_pmem_region(audio);
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audwma_reset_event_queue(audio);
+	q6asm_audio_client_free(audio->ac);
+	mutex_unlock(&audio->lock);
+	mutex_destroy(&audio->lock);
+	mutex_destroy(&audio->read_lock);
+	mutex_destroy(&audio->write_lock);
+	mutex_destroy(&audio->get_event_lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	pr_info("%s: wma_decoder success\n", __func__);
+	return 0;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct q6audio *audio = NULL;
+	int rc = 0;
+	int i;
+	struct audwma_event *e_node = NULL;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_wma_" + 5];
+#endif
+	audio = kzalloc(sizeof(struct q6audio), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("Could not allocate memory for wma decode driver\n");
+		return -ENOMEM;
+	}
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->str_cfg.buffer_size = FRAME_SIZE;
+	audio->str_cfg.buffer_count = FRAME_NUM;
+	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+	audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+	audio->pcm_cfg.sample_rate = 48000;
+	audio->pcm_cfg.channel_count = 2;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audwma_cb,
+					     (void *)audio);
+
+	if (!audio->ac) {
+		pr_err("Could not allocate memory for audio client\n");
+		kfree(audio);
+		return -ENOMEM;
+	}
+	/* Only AIO interface */
+	if (file->f_flags & O_NONBLOCK) {
+		pr_debug("set to aio interface\n");
+		audio->drv_status |= ADRV_STATUS_AIO_INTF;
+		audio->drv_ops.out_flush = audwma_async_out_flush;
+		audio->drv_ops.in_flush = audwma_async_in_flush;
+		audio->drv_ops.fsync = audwma_async_fsync;
+		q6asm_set_io_mode(audio->ac, ASYNC_IO_MODE);
+	} else {
+		pr_err("SIO interface not supported\n");
+		rc = -EACCES;
+		goto fail;
+	}
+
+	/* open in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+					   FORMAT_WMA_V9);
+		if (rc < 0) {
+			pr_err("NT mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = NON_TUNNEL_MODE;
+		/* open WMA decoder, expected frames is always 1*/
+		audio->buf_cfg.frames_per_buf = 0x01;
+		audio->buf_cfg.meta_info_enable = 0x01;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_write(audio->ac, FORMAT_WMA_V9);
+		if (rc < 0) {
+			pr_err("T mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = TUNNEL_MODE;
+		audio->buf_cfg.meta_info_enable = 0x00;
+	} else {
+		pr_err("Not supported mode\n");
+		rc = -EACCES;
+		goto fail;
+	}
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	spin_lock_init(&audio->event_queue_lock);
+	init_waitqueue_head(&audio->cmd_wait);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->event_wait);
+	INIT_LIST_HEAD(&audio->out_queue);
+	INIT_LIST_HEAD(&audio->in_queue);
+	INIT_LIST_HEAD(&audio->pmem_region_queue);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+
+	audio->drv_ops.out_flush(audio);
+	audio->opened = 1;
+	file->private_data = audio;
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_wma_%04x", audio->ac->session);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+					    NULL, (void *)audio,
+					    &audwma_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		pr_debug("debugfs_create_file failed\n");
+#endif
+	for (i = 0; i < AUDWMA_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audwma_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			pr_err("event pkt alloc failed\n");
+			break;
+		}
+	}
+	pr_info("%s:wma decoder open success, session_id = %d\n", __func__,
+				audio->ac->session);
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_wma_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_release,
+	.unlocked_ioctl = audio_ioctl,
+	.fsync = audwma_fsync,
+};
+
+struct miscdevice audwma_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_wma",
+	.fops = &audio_wma_fops,
+};
+
+static int __init audio_wma_init(void)
+{
+	return misc_register(&audwma_misc);
+}
+
+device_initcall(audio_wma_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c b/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
new file mode 100644
index 0000000..e26bec2
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/audio_wmapro.c
@@ -0,0 +1,1644 @@
+/* wmapro audio output device
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_wmapro.h>
+#include <linux/debugfs.h>
+#include <linux/list.h>
+#include <linux/android_pmem.h>
+#include <linux/slab.h>
+#include <asm/ioctls.h>
+#include <asm/atomic.h>
+#include <sound/q6asm.h>
+#include <sound/apr_audio.h>
+
+#define ADRV_STATUS_AIO_INTF 0x00000001	/* AIO interface */
+#define ADRV_STATUS_FSYNC 0x00000008
+#define ADRV_STATUS_PAUSE 0x00000010
+
+#define TUNNEL_MODE     0x0000
+#define NON_TUNNEL_MODE 0x0001
+#define AUDWMAPRO_EOS_SET  0x00000001
+
+/* Default number of pre-allocated event packets */
+#define AUDWMAPRO_EVENT_NUM 10
+
+#define __CONTAINS(r, v, l) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __v = v;					\
+	typeof(v) __e = __v + l;				\
+	int res = ((__v >= __r->vaddr) &&			\
+		(__e <= __r->vaddr + __r->len));		\
+	res;							\
+})
+
+#define CONTAINS(r1, r2) ({					\
+	typeof(r2) __r2 = r2;					\
+	__CONTAINS(r1, __r2->vaddr, __r2->len);			\
+})
+
+#define IN_RANGE(r, v) ({					\
+	typeof(r) __r = r;					\
+	typeof(v) __vv = v;					\
+	int res = ((__vv >= __r->vaddr) &&			\
+		(__vv < (__r->vaddr + __r->len)));		\
+	res;							\
+})
+
+#define OVERLAPS(r1, r2) ({					\
+	typeof(r1) __r1 = r1;					\
+	typeof(r2) __r2 = r2;					\
+	typeof(__r2->vaddr) __v = __r2->vaddr;			\
+	typeof(__v) __e = __v + __r2->len - 1;			\
+	int res = (IN_RANGE(__r1, __v) || IN_RANGE(__r1, __e));	\
+	res;							\
+})
+
+struct timestamp {
+	unsigned long lowpart;
+	unsigned long highpart;
+} __attribute__ ((packed));
+
+struct meta_in {
+	unsigned char reserved[18];
+	unsigned short offset;
+	struct timestamp ntimestamp;
+	unsigned int nflags;
+} __attribute__ ((packed));
+
+struct meta_out_dsp{
+	u32 offset_to_frame;
+	u32 frame_size;
+	u32 encoded_pcm_samples;
+	u32 msw_ts;
+	u32 lsw_ts;
+	u32 nflags;
+} __attribute__ ((packed));
+
+struct dec_meta_out{
+	unsigned int reserved[7];
+	unsigned int num_of_frames;
+	struct meta_out_dsp meta_out_dsp[];
+} __attribute__ ((packed));
+
+/* General meta field to store meta info
+locally */
+union  meta_data {
+	struct dec_meta_out meta_out;
+	struct meta_in meta_in;
+} __attribute__ ((packed));
+
+struct audwmapro_event {
+	struct list_head list;
+	int event_type;
+	union msm_audio_event_payload payload;
+};
+
+struct audwmapro_pmem_region {
+	struct list_head list;
+	struct file *file;
+	int fd;
+	void *vaddr;
+	unsigned long paddr;
+	unsigned long kvaddr;
+	unsigned long len;
+	unsigned ref_cnt;
+};
+
+struct audwmapro_buffer_node {
+	struct list_head list;
+	struct msm_audio_aio_buf buf;
+	unsigned long paddr;
+	unsigned long token;
+	void		*kvaddr;
+	union meta_data meta_info;
+};
+
+struct q6audio;
+
+struct audwmapro_drv_operations {
+	void (*out_flush) (struct q6audio *);
+	void (*in_flush) (struct q6audio *);
+	int (*fsync)(struct q6audio *);
+};
+
+#define PCM_BUF_COUNT		(2)
+/* Buffer with meta */
+#define PCM_BUFSZ_MIN		((4*1024) + sizeof(struct dec_meta_out))
+
+/* FRAME_NUM must be a power of two */
+#define FRAME_NUM		(2)
+#define FRAME_SIZE		((4*1024) + sizeof(struct meta_in))
+
+struct q6audio {
+	atomic_t in_bytes;
+	atomic_t in_samples;
+
+	struct msm_audio_stream_config str_cfg;
+	struct msm_audio_buf_cfg        buf_cfg;
+	struct msm_audio_config pcm_cfg;
+	struct msm_audio_wmapro_config wmapro_config;
+
+	struct audio_client *ac;
+
+	struct mutex lock;
+	struct mutex read_lock;
+	struct mutex write_lock;
+	struct mutex get_event_lock;
+	wait_queue_head_t cmd_wait;
+	wait_queue_head_t write_wait;
+	wait_queue_head_t event_wait;
+	spinlock_t dsp_lock;
+	spinlock_t event_queue_lock;
+
+#ifdef CONFIG_DEBUG_FS
+	struct dentry *dentry;
+#endif
+	struct list_head out_queue;	/* queue to retain output buffers */
+	struct list_head in_queue;	/* queue to retain input buffers */
+	struct list_head free_event_queue;
+	struct list_head event_queue;
+	struct list_head pmem_region_queue;	/* protected by lock */
+	struct audwmapro_drv_operations drv_ops;
+	union msm_audio_event_payload eos_write_payload;
+
+	uint32_t drv_status;
+	int event_abort;
+	int eos_rsp;
+	int eos_flag;
+	int opened;
+	int enabled;
+	int stopped;
+	int feedback;
+	int rflush;		/* Read  flush */
+	int wflush;		/* Write flush */
+};
+
+static int insert_eos_buf(struct q6audio *audio,
+	struct audwmapro_buffer_node *buf_node) {
+	struct dec_meta_out *eos_buf = buf_node->kvaddr;
+	eos_buf->num_of_frames = 0xFFFFFFFF;
+	eos_buf->meta_out_dsp[0].offset_to_frame = 0x0;
+	eos_buf->meta_out_dsp[0].nflags = AUDWMAPRO_EOS_SET;
+	return sizeof(struct dec_meta_out) +
+		sizeof(eos_buf->meta_out_dsp[0]);
+}
+
+/* Routine which updates read buffers of driver/dsp,
+   for flush operation as DSP output might not have proper
+   value set */
+static int insert_meta_data(struct q6audio *audio,
+	struct audwmapro_buffer_node *buf_node) {
+	struct dec_meta_out *meta_data = buf_node->kvaddr;
+	meta_data->num_of_frames = 0x0;
+	meta_data->meta_out_dsp[0].offset_to_frame = 0x0;
+	meta_data->meta_out_dsp[0].nflags = 0x0;
+	return sizeof(struct dec_meta_out) +
+		sizeof(meta_data->meta_out_dsp[0]);
+}
+
+static void extract_meta_info(struct q6audio *audio,
+	struct audwmapro_buffer_node *buf_node, int dir)
+{
+	if (dir) { /* Read */
+		if (audio->buf_cfg.meta_info_enable)
+			memcpy(&buf_node->meta_info.meta_in,
+			(char *)buf_node->kvaddr, sizeof(struct meta_in));
+		else
+			memset(&buf_node->meta_info.meta_in,
+			0, sizeof(struct meta_in));
+		pr_debug("i/p: msw_ts 0x%lx lsw_ts 0x%lx nflags 0x%8x\n",
+			buf_node->meta_info.meta_in.ntimestamp.highpart,
+			buf_node->meta_info.meta_in.ntimestamp.lowpart,
+			buf_node->meta_info.meta_in.nflags);
+	} else { /* Write */
+		memcpy((char *)buf_node->kvaddr,
+			&buf_node->meta_info.meta_out,
+			sizeof(struct dec_meta_out));
+		pr_debug("o/p: msw_ts 0x%8x lsw_ts 0x%8x nflags 0x%8x\n",
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+				meta_out_dsp[0].msw_ts,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+				meta_out_dsp[0].lsw_ts,
+		((struct dec_meta_out *)buf_node->kvaddr)->\
+				meta_out_dsp[0].nflags);
+	}
+}
+
+static int audwmapro_pmem_lookup_vaddr(struct q6audio *audio, void *addr,
+	unsigned long len, struct audwmapro_pmem_region **region)
+{
+	struct audwmapro_pmem_region *region_elt;
+
+	int match_count = 0;
+
+	*region = NULL;
+
+	/* returns physical address or zero */
+	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+		if (addr >= region_elt->vaddr &&
+		    addr < region_elt->vaddr + region_elt->len &&
+		    addr + len <= region_elt->vaddr + region_elt->len) {
+			/* offset since we could pass vaddr inside a registerd
+			 * pmem buffer
+			 */
+
+			match_count++;
+			if (!*region)
+				*region = region_elt;
+		}
+	}
+
+	if (match_count > 1) {
+		pr_err("multiple hits for vaddr %p, len %ld\n", addr, len);
+		list_for_each_entry(region_elt, &audio->pmem_region_queue,
+					list) {
+			if (addr >= region_elt->vaddr &&
+			    addr < region_elt->vaddr + region_elt->len &&
+			    addr + len <= region_elt->vaddr + region_elt->len)
+				pr_err("\t%p, %ld --> %p\n", region_elt->vaddr,
+				       region_elt->len,
+				       (void *)region_elt->paddr);
+		}
+	}
+
+	return *region ? 0 : -1;
+}
+
+static unsigned long audwmapro_pmem_fixup(struct q6audio *audio, void *addr,
+	unsigned long len, int ref_up, void **kvaddr)
+{
+	struct audwmapro_pmem_region *region;
+	unsigned long paddr;
+	int ret;
+
+	ret = audwmapro_pmem_lookup_vaddr(audio, addr, len, &region);
+	if (ret) {
+		pr_err("lookup (%p, %ld) failed\n", addr, len);
+		return 0;
+	}
+	if (ref_up)
+		region->ref_cnt++;
+	else
+		region->ref_cnt--;
+	pr_debug("found region %p ref_cnt %d\n", region, region->ref_cnt);
+	paddr = region->paddr + (addr - region->vaddr);
+	/* provide kernel virtual address for accessing meta information */
+	if (kvaddr)
+		*kvaddr = (void *) (region->kvaddr + (addr - region->vaddr));
+	return paddr;
+}
+
+static void audwmapro_post_event(struct q6audio *audio, int type,
+			      union msm_audio_event_payload payload)
+{
+	struct audwmapro_event *e_node = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+
+	if (!list_empty(&audio->free_event_queue)) {
+		e_node = list_first_entry(&audio->free_event_queue,
+					  struct audwmapro_event, list);
+		list_del(&e_node->list);
+	} else {
+		e_node = kmalloc(sizeof(struct audwmapro_event), GFP_ATOMIC);
+		if (!e_node) {
+			pr_err("No mem to post event %d\n", type);
+			spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+			return;
+		}
+	}
+
+	e_node->event_type = type;
+	e_node->payload = payload;
+
+	list_add_tail(&e_node->list, &audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	wake_up(&audio->event_wait);
+}
+
+static int audwmapro_enable(struct q6audio *audio)
+{
+	/* 2nd arg: 0 -> run immediately
+	   3rd arg: 0 -> msw_ts, 4th arg: 0 ->lsw_ts */
+	return q6asm_run(audio->ac, 0x00, 0x00, 0x00);
+}
+
+static int audwmapro_disable(struct q6audio *audio)
+{
+	int rc = 0;
+	if (audio->opened) {
+		audio->enabled = 0;
+		audio->opened = 0;
+		pr_debug("%s: inbytes[%d] insamples[%d]\n", __func__,
+			 atomic_read(&audio->in_bytes),
+			 atomic_read(&audio->in_samples));
+		/* Close the session */
+		rc = q6asm_cmd(audio->ac, CMD_CLOSE);
+		if (rc < 0)
+			pr_err("Failed to close the session rc=%d\n", rc);
+		audio->stopped = 1;
+		wake_up(&audio->write_wait);
+		wake_up(&audio->cmd_wait);
+	}
+	pr_debug("enabled[%d]\n", audio->enabled);
+	return rc;
+}
+
+static int audwmapro_pause(struct q6audio *audio)
+{
+	int rc = 0;
+
+	pr_info("%s, enabled = %d\n", __func__,
+			audio->enabled);
+	if (audio->enabled) {
+		rc = q6asm_cmd(audio->ac, CMD_PAUSE);
+		if (rc < 0)
+			pr_err("%s: pause cmd failed rc=%d\n", __func__, rc);
+
+	} else
+		pr_err("%s: Driver not enabled\n", __func__);
+	return rc;
+}
+
+static int audwmapro_flush(struct q6audio *audio)
+{
+	int rc;
+
+	if (audio->enabled) {
+		/* Implicitly issue a pause to the decoder before flushing if
+		   it is not in pause state */
+		if (!(audio->drv_status & ADRV_STATUS_PAUSE)) {
+			rc = audwmapro_pause(audio);
+			if (rc < 0)
+				pr_err("%s: pause cmd failed rc=%d\n", __func__,
+					rc);
+			else
+				audio->drv_status |= ADRV_STATUS_PAUSE;
+		}
+		rc = q6asm_cmd(audio->ac, CMD_FLUSH);
+		if (rc < 0)
+			pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
+		/* Not in stop state, reenable the stream */
+		if (audio->stopped == 0) {
+			rc = audwmapro_enable(audio);
+			if (rc)
+				pr_err("%s:audio re-enable failed\n", __func__);
+			else {
+				audio->enabled = 1;
+				if (audio->drv_status & ADRV_STATUS_PAUSE)
+					audio->drv_status &= ~ADRV_STATUS_PAUSE;
+			}
+		}
+	}
+	pr_debug("in_bytes %d\n", atomic_read(&audio->in_bytes));
+	pr_debug("in_samples %d\n", atomic_read(&audio->in_samples));
+	atomic_set(&audio->in_bytes, 0);
+	atomic_set(&audio->in_samples, 0);
+	return 0;
+}
+
+static void audwmapro_async_read(struct q6audio *audio,
+		struct audwmapro_buffer_node *buf_node)
+{
+	struct audio_client *ac;
+	struct audio_aio_read_param param;
+	int rc;
+
+	pr_debug("%s: Send read buff %p phy %lx len %d\n", __func__, buf_node,
+			buf_node->paddr, buf_node->buf.buf_len);
+	ac = audio->ac;
+	/* Provide address so driver can append nr frames information */
+	param.paddr = buf_node->paddr +
+			sizeof(struct dec_meta_out);
+	param.len = buf_node->buf.buf_len -
+			sizeof(struct dec_meta_out);
+	param.uid = param.paddr;
+	/* Write command will populate paddr as token */
+	buf_node->token = param.paddr;
+	rc = q6asm_async_read(ac, &param);
+	if (rc < 0)
+		pr_err("%s:failed\n", __func__);
+}
+
+static void audwmapro_async_write(struct q6audio *audio,
+		struct audwmapro_buffer_node *buf_node)
+{
+	int rc;
+	struct audio_client *ac;
+	struct audio_aio_write_param param;
+
+	pr_debug("%s: Send write buff %p phy %lx len %d\n", __func__, buf_node,
+		 buf_node->paddr, buf_node->buf.data_len);
+
+	ac = audio->ac;
+	/* Offset with  appropriate meta */
+	param.paddr = buf_node->paddr + sizeof(struct meta_in);
+	param.len = buf_node->buf.data_len - sizeof(struct meta_in);
+	param.msw_ts = buf_node->meta_info.meta_in.ntimestamp.highpart;
+	param.lsw_ts = buf_node->meta_info.meta_in.ntimestamp.lowpart;
+	/* If no meta_info enaled, indicate no time stamp valid */
+	if (audio->buf_cfg.meta_info_enable)
+		param.flags = 0;
+	else
+		param.flags = 0xFF00;
+	param.uid = param.paddr;
+	/* Read command will populate paddr as token */
+	buf_node->token = param.paddr;
+	rc = q6asm_async_write(ac, &param);
+	if (rc < 0)
+		pr_err("%s:failed\n", __func__);
+}
+
+/* Write buffer to DSP / Handle Ack from DSP */
+static void audwmapro_async_write_ack(struct q6audio *audio, uint32_t token,
+		uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload event_payload;
+	struct audwmapro_buffer_node *used_buf;
+
+	/* No active flush in progress */
+	if (audio->wflush)
+		return;
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	BUG_ON(list_empty(&audio->out_queue));
+	used_buf = list_first_entry(&audio->out_queue,
+				    struct audwmapro_buffer_node, list);
+	if (token == used_buf->token) {
+		list_del(&used_buf->list);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		pr_debug("consumed buffer\n");
+		event_payload.aio_buf = used_buf->buf;
+		audwmapro_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+				  event_payload);
+		kfree(used_buf);
+		if (list_empty(&audio->out_queue) &&
+			   (audio->drv_status & ADRV_STATUS_FSYNC)) {
+			pr_debug("%s: list is empty, reached EOS in\
+				Tunnel\n", __func__);
+			wake_up(&audio->write_wait);
+		}
+	} else {
+		pr_err("expected=%lx ret=%x\n", used_buf->token, token);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	}
+}
+
+/* Read buffer from DSP / Handle Ack from DSP */
+static void audwmapro_async_read_ack(struct q6audio *audio, uint32_t token,
+		uint32_t *payload)
+{
+	unsigned long flags;
+	union msm_audio_event_payload event_payload;
+	struct audwmapro_buffer_node *filled_buf;
+
+	/* No active flush in progress */
+	if (audio->rflush)
+		return;
+
+	/* Statistics of read */
+	atomic_add(payload[2], &audio->in_bytes);
+	atomic_add(payload[7], &audio->in_samples);
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	BUG_ON(list_empty(&audio->in_queue));
+	filled_buf = list_first_entry(&audio->in_queue,
+				      struct audwmapro_buffer_node, list);
+	if (token == (filled_buf->token)) {
+		list_del(&filled_buf->list);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		event_payload.aio_buf = filled_buf->buf;
+		/* Read done Buffer due to flush/normal condition
+		   after EOS event, so append EOS buffer */
+		if (audio->eos_rsp == 0x1) {
+			event_payload.aio_buf.data_len =
+					insert_eos_buf(audio, filled_buf);
+			/* Reset flag back to indicate eos intimated */
+			audio->eos_rsp = 0;
+		} else {
+			filled_buf->meta_info.meta_out.num_of_frames =
+				payload[7];
+			pr_debug("nr of frames 0x%8x\n",
+				filled_buf->meta_info.meta_out.num_of_frames);
+			event_payload.aio_buf.data_len = payload[2] + \
+			payload[3] + \
+			sizeof(struct dec_meta_out);
+			extract_meta_info(audio, filled_buf, 0);
+			audio->eos_rsp = 0;
+		}
+		audwmapro_post_event(audio, AUDIO_EVENT_READ_DONE,
+				event_payload);
+		kfree(filled_buf);
+	} else {
+		pr_err("expected=%lx ret=%x\n", filled_buf->token, token);
+		spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	}
+}
+
+static void q6_audwmapro_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv)
+{
+	struct q6audio *audio = (struct q6audio *)priv;
+
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE:
+		pr_debug("%s:ASM_DATA_EVENT_WRITE_DONE token = 0x%x\n",
+			 __func__, token);
+		audwmapro_async_write_ack(audio, token, payload);
+		break;
+	case ASM_DATA_EVENT_READ_DONE:
+		pr_debug("%s:ASM_DATA_EVENT_READ_DONE token = 0x%x\n",
+			 __func__, token);
+		audwmapro_async_read_ack(audio, token, payload);
+		break;
+	case ASM_DATA_CMDRSP_EOS:
+		/* EOS Handle */
+		pr_debug("%s:ASM_DATA_CMDRSP_EOS\n", __func__);
+		if (audio->feedback) { /* Non-Tunnel mode */
+			audio->eos_rsp = 1;
+			/* propagate input EOS i/p buffer,
+			   after receiving DSP acknowledgement */
+			if (audio->eos_flag &&
+				(audio->eos_write_payload.aio_buf.buf_addr)) {
+				audwmapro_post_event(audio,
+					AUDIO_EVENT_WRITE_DONE,
+					audio->eos_write_payload);
+				memset(&audio->eos_write_payload , 0,
+					sizeof(union msm_audio_event_payload));
+				audio->eos_flag = 0;
+			}
+		} else { /* Tunnel mode */
+			audio->eos_rsp = 1;
+			wake_up(&audio->write_wait);
+			wake_up(&audio->cmd_wait);
+		}
+		break;
+	default:
+		pr_debug("%s:Unhandled event = 0x%8x\n", __func__, opcode);
+		break;
+	}
+}
+
+/* ------------------- device --------------------- */
+static void audwmapro_async_out_flush(struct q6audio *audio)
+{
+	struct audwmapro_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+	unsigned long flags;
+
+	pr_debug("%s\n", __func__);
+	/* EOS followed by flush, EOS response not guranteed, free EOS i/p
+	   buffer */
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	if (audio->eos_flag && (audio->eos_write_payload.aio_buf.buf_addr)) {
+		pr_debug("%s: EOS followed by flush received,acknowledge eos"\
+			" i/p buffer immediately\n", __func__);
+		audwmapro_post_event(audio, AUDIO_EVENT_WRITE_DONE,
+					audio->eos_write_payload);
+		memset(&audio->eos_write_payload , 0,
+			sizeof(union msm_audio_event_payload));
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+	list_for_each_safe(ptr, next, &audio->out_queue) {
+		buf_node = list_entry(ptr, struct audwmapro_buffer_node, list);
+		list_del(&buf_node->list);
+		payload.aio_buf = buf_node->buf;
+		audwmapro_post_event(audio, AUDIO_EVENT_WRITE_DONE, payload);
+		kfree(buf_node);
+		pr_debug("%s: Propagate WRITE_DONE during flush\n", __func__);
+	}
+}
+
+static void audwmapro_async_in_flush(struct q6audio *audio)
+{
+	struct audwmapro_buffer_node *buf_node;
+	struct list_head *ptr, *next;
+	union msm_audio_event_payload payload;
+
+	pr_debug("%s\n", __func__);
+	list_for_each_safe(ptr, next, &audio->in_queue) {
+		buf_node = list_entry(ptr, struct audwmapro_buffer_node, list);
+		list_del(&buf_node->list);
+		/* Forcefull send o/p eos buffer after flush, if no eos response
+		 * received by dsp even after sending eos command */
+		if ((audio->eos_rsp != 1) && audio->eos_flag) {
+			pr_debug("%s: send eos on o/p buffer during flush\n",\
+				__func__);
+			payload.aio_buf = buf_node->buf;
+			payload.aio_buf.data_len =
+					insert_eos_buf(audio, buf_node);
+			audio->eos_flag = 0;
+		} else {
+			payload.aio_buf = buf_node->buf;
+			payload.aio_buf.data_len =
+					insert_meta_data(audio, buf_node);
+		}
+		audwmapro_post_event(audio, AUDIO_EVENT_READ_DONE, payload);
+		kfree(buf_node);
+		pr_debug("%s: Propagate READ_DONE during flush\n", __func__);
+	}
+}
+
+static void audwmapro_ioport_reset(struct q6audio *audio)
+{
+	if (audio->drv_status & ADRV_STATUS_AIO_INTF) {
+		/* If fsync is in progress, make sure
+		 * return value of fsync indicates
+		 * abort due to flush
+		 */
+		if (audio->drv_status & ADRV_STATUS_FSYNC) {
+			pr_debug("fsync in progress\n");
+			audio->drv_ops.out_flush(audio);
+		} else
+			audio->drv_ops.out_flush(audio);
+		audio->drv_ops.in_flush(audio);
+	}
+}
+
+static int audwmapro_events_pending(struct q6audio *audio)
+{
+	unsigned long flags;
+	int empty;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	empty = !list_empty(&audio->event_queue);
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+	return empty || audio->event_abort;
+}
+
+static void audwmapro_reset_event_queue(struct q6audio *audio)
+{
+	unsigned long flags;
+	struct audwmapro_event *drv_evt;
+	struct list_head *ptr, *next;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	list_for_each_safe(ptr, next, &audio->event_queue) {
+		drv_evt = list_first_entry(&audio->event_queue,
+					   struct audwmapro_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	list_for_each_safe(ptr, next, &audio->free_event_queue) {
+		drv_evt = list_first_entry(&audio->free_event_queue,
+					   struct audwmapro_event, list);
+		list_del(&drv_evt->list);
+		kfree(drv_evt);
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	return;
+}
+
+static long audwmapro_process_event_req(struct q6audio *audio,
+		void __user *arg)
+{
+	long rc;
+	struct msm_audio_event usr_evt;
+	struct audwmapro_event *drv_evt = NULL;
+	int timeout;
+	unsigned long flags;
+
+	if (copy_from_user(&usr_evt, arg, sizeof(struct msm_audio_event)))
+		return -EFAULT;
+
+	timeout = (int)usr_evt.timeout_ms;
+
+	if (timeout > 0) {
+		rc = wait_event_interruptible_timeout(audio->event_wait,
+						      audwmapro_events_pending
+						      (audio),
+						      msecs_to_jiffies
+						      (timeout));
+		if (rc == 0)
+			return -ETIMEDOUT;
+	} else {
+		rc = wait_event_interruptible(audio->event_wait,
+					      audwmapro_events_pending(audio));
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (audio->event_abort) {
+		audio->event_abort = 0;
+		return -ENODEV;
+	}
+
+	rc = 0;
+
+	spin_lock_irqsave(&audio->event_queue_lock, flags);
+	if (!list_empty(&audio->event_queue)) {
+		drv_evt = list_first_entry(&audio->event_queue,
+					   struct audwmapro_event, list);
+		list_del(&drv_evt->list);
+	}
+	if (drv_evt) {
+		usr_evt.event_type = drv_evt->event_type;
+		usr_evt.event_payload = drv_evt->payload;
+		list_add_tail(&drv_evt->list, &audio->free_event_queue);
+	} else {
+		pr_err("Unexpected path\n");
+		spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+		return -EPERM;
+	}
+	spin_unlock_irqrestore(&audio->event_queue_lock, flags);
+
+	if (drv_evt->event_type == AUDIO_EVENT_WRITE_DONE) {
+		pr_debug("posted AUDIO_EVENT_WRITE_DONE to user\n");
+		mutex_lock(&audio->write_lock);
+		audwmapro_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0, 0);
+		mutex_unlock(&audio->write_lock);
+	} else if (drv_evt->event_type == AUDIO_EVENT_READ_DONE) {
+		pr_debug("posted AUDIO_EVENT_READ_DONE to user\n");
+		mutex_lock(&audio->read_lock);
+		audwmapro_pmem_fixup(audio, drv_evt->payload.aio_buf.buf_addr,
+				  drv_evt->payload.aio_buf.buf_len, 0, 0);
+		mutex_unlock(&audio->read_lock);
+	}
+
+	/* Some read buffer might be held up in DSP,release all
+	   Once EOS indicated*/
+	if (audio->eos_rsp && !list_empty(&audio->in_queue)) {
+		pr_debug("Send flush command to release read buffers"\
+		" held up in DSP\n");
+		audwmapro_flush(audio);
+	}
+
+	if (copy_to_user(arg, &usr_evt, sizeof(usr_evt)))
+		rc = -EFAULT;
+
+	return rc;
+}
+
+static int audwmapro_pmem_check(struct q6audio *audio,
+			     void *vaddr, unsigned long len)
+{
+	struct audwmapro_pmem_region *region_elt;
+	struct audwmapro_pmem_region t = {.vaddr = vaddr, .len = len };
+
+	list_for_each_entry(region_elt, &audio->pmem_region_queue, list) {
+		if (CONTAINS(region_elt, &t) || CONTAINS(&t, region_elt) ||
+		    OVERLAPS(region_elt, &t)) {
+			pr_err("region (vaddr %p len %ld)"
+			       " clashes with registered region"
+			       " (vaddr %p paddr %p len %ld)\n",
+			       vaddr, len,
+			       region_elt->vaddr,
+			       (void *)region_elt->paddr, region_elt->len);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int audwmapro_pmem_add(struct q6audio *audio,
+			   struct msm_audio_pmem_info *info)
+{
+	unsigned long paddr, kvaddr, len;
+	struct file *file;
+	struct audwmapro_pmem_region *region;
+	int rc = -EINVAL;
+
+	pr_debug("%s\n", __func__);
+	region = kmalloc(sizeof(*region), GFP_KERNEL);
+
+	if (!region) {
+		rc = -ENOMEM;
+		goto end;
+	}
+
+	if (get_pmem_file(info->fd, &paddr, &kvaddr, &len, &file)) {
+		kfree(region);
+		goto end;
+	}
+
+	rc = audwmapro_pmem_check(audio, info->vaddr, len);
+	if (rc < 0) {
+		put_pmem_file(file);
+		kfree(region);
+		goto end;
+	}
+
+	region->vaddr = info->vaddr;
+	region->fd = info->fd;
+	region->paddr = paddr;
+	region->kvaddr = kvaddr;
+	region->len = len;
+	region->file = file;
+	region->ref_cnt = 0;
+	pr_debug("add region paddr %lx vaddr %p, len %lu kvaddr %lx\n",
+		region->paddr, region->vaddr, region->len, region->kvaddr);
+	list_add_tail(&region->list, &audio->pmem_region_queue);
+
+	rc = q6asm_memory_map(audio->ac, (uint32_t) paddr, IN, (uint32_t) len,
+			1);
+	if (rc < 0)
+		pr_err("%s: memory map failed\n", __func__);
+end:
+	return rc;
+}
+
+static int audwmapro_pmem_remove(struct q6audio *audio,
+			      struct msm_audio_pmem_info *info)
+{
+	struct audwmapro_pmem_region *region;
+	struct list_head *ptr, *next;
+	int rc = -EINVAL;
+
+	pr_debug("info fd %d vaddr %p\n", info->fd, info->vaddr);
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audwmapro_pmem_region, list);
+
+		if ((region->fd == info->fd) &&
+				(region->vaddr == info->vaddr)) {
+			if (region->ref_cnt) {
+				pr_debug("region %p in use ref_cnt %d\n",
+					 region, region->ref_cnt);
+				break;
+			}
+			pr_debug("remove region fd %d vaddr %p\n",
+					info->fd, info->vaddr);
+			rc = q6asm_memory_unmap(audio->ac,
+						(uint32_t) region->paddr, IN);
+			if (rc < 0)
+				pr_err("%s: memory unmap failed\n", __func__);
+
+			list_del(&region->list);
+			put_pmem_file(region->file);
+			kfree(region);
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+/* audio -> lock must be held at this point */
+static int audwmapro_aio_buf_add(struct q6audio *audio, unsigned dir,
+			      void __user *arg)
+{
+	unsigned long flags;
+	struct audwmapro_buffer_node *buf_node;
+
+	buf_node = kzalloc(sizeof(*buf_node), GFP_KERNEL);
+
+	if (!buf_node)
+		return -ENOMEM;
+
+	if (copy_from_user(&buf_node->buf, arg, sizeof(buf_node->buf))) {
+		kfree(buf_node);
+		return -EFAULT;
+	}
+
+	pr_debug("node %p dir %x buf_addr %p buf_len %d data_len \
+			%d\n", buf_node, dir, buf_node->buf.buf_addr,
+			buf_node->buf.buf_len, buf_node->buf.data_len);
+
+	buf_node->paddr = audwmapro_pmem_fixup(audio, buf_node->buf.buf_addr,
+					    buf_node->buf.buf_len, 1,
+					    &buf_node->kvaddr);
+	if (dir) {
+		/* write */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (!audio->feedback && !buf_node->buf.data_len)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		extract_meta_info(audio, buf_node, 1);
+		/* Not a EOS buffer */
+		if (!(buf_node->meta_info.meta_in.nflags & AUDWMAPRO_EOS_SET)) {
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			audwmapro_async_write(audio, buf_node);
+			/* EOS buffer handled in driver */
+			list_add_tail(&buf_node->list, &audio->out_queue);
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		}
+		if (buf_node->meta_info.meta_in.nflags & AUDWMAPRO_EOS_SET) {
+			if (!audio->wflush) {
+				pr_debug("%s:Send EOS cmd at i/p\n", __func__);
+				/* Driver will forcefully post writedone event
+				   once eos ack recived from DSP*/
+				audio->eos_write_payload.aio_buf =\
+						buf_node->buf;
+				audio->eos_flag = 1;
+				audio->eos_rsp = 0;
+				q6asm_cmd(audio->ac, CMD_EOS);
+				kfree(buf_node);
+			} else { /* Flush in progress, send back i/p EOS buffer
+				    as is */
+				union msm_audio_event_payload event_payload;
+				event_payload.aio_buf = buf_node->buf;
+				audwmapro_post_event(audio,
+					AUDIO_EVENT_WRITE_DONE,
+					event_payload);
+				kfree(buf_node);
+			}
+		}
+	} else {
+		/* read */
+		if (!buf_node->paddr ||
+		    (buf_node->paddr & 0x1) ||
+		    (buf_node->buf.buf_len < PCM_BUFSZ_MIN)) {
+			kfree(buf_node);
+			return -EINVAL;
+		}
+		/* No EOS reached */
+		if (!audio->eos_rsp) {
+			spin_lock_irqsave(&audio->dsp_lock, flags);
+			audwmapro_async_read(audio, buf_node);
+			/* EOS buffer handled in driver */
+			list_add_tail(&buf_node->list, &audio->in_queue);
+			spin_unlock_irqrestore(&audio->dsp_lock, flags);
+		}
+		/* EOS reached at input side fake all upcoming read buffer to
+		   indicate the same */
+		else {
+			union msm_audio_event_payload event_payload;
+			event_payload.aio_buf = buf_node->buf;
+			event_payload.aio_buf.data_len =
+				insert_eos_buf(audio, buf_node);
+			pr_debug("%s: propagate READ_DONE as EOS done\n",\
+					__func__);
+			audwmapro_post_event(audio, AUDIO_EVENT_READ_DONE,
+					event_payload);
+			kfree(buf_node);
+		}
+	}
+	return 0;
+}
+
+/* TBD: Only useful in tunnel-mode */
+int audwmapro_async_fsync(struct q6audio *audio)
+{
+	int rc = 0;
+
+	/* Blocking client sends more data */
+	mutex_lock(&audio->lock);
+	audio->drv_status |= ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	pr_info("%s:\n", __func__);
+
+	mutex_lock(&audio->write_lock);
+	audio->eos_rsp = 0;
+
+	rc = wait_event_interruptible(audio->write_wait,
+					(list_empty(&audio->out_queue)) ||
+					audio->wflush || audio->stopped);
+
+	if (rc < 0) {
+		pr_err("%s: wait event for list_empty failed, rc = %d\n",
+			__func__, rc);
+		goto done;
+	}
+
+	rc = q6asm_cmd(audio->ac, CMD_EOS);
+
+	if (rc < 0)
+		pr_err("%s: q6asm_cmd failed, rc = %d", __func__, rc);
+
+	rc = wait_event_interruptible(audio->write_wait,
+				  (audio->eos_rsp || audio->wflush ||
+				  audio->stopped));
+
+	if (rc < 0) {
+		pr_err("%s: wait event for eos_rsp failed, rc = %d\n", __func__,
+			rc);
+		goto done;
+	}
+
+	if (audio->eos_rsp == 1) {
+		rc = audwmapro_enable(audio);
+		if (rc)
+			pr_err("%s: audio enable failed\n", __func__);
+		else {
+			audio->drv_status &= ~ADRV_STATUS_PAUSE;
+			audio->enabled = 1;
+		}
+	}
+
+	if (audio->stopped || audio->wflush)
+		rc = -EBUSY;
+
+done:
+	mutex_unlock(&audio->write_lock);
+	mutex_lock(&audio->lock);
+	audio->drv_status &= ~ADRV_STATUS_FSYNC;
+	mutex_unlock(&audio->lock);
+
+	return rc;
+}
+
+int audwmapro_fsync(struct file *file, int datasync)
+{
+	struct q6audio *audio = file->private_data;
+
+	if (!audio->enabled || audio->feedback)
+		return -EINVAL;
+
+	return audio->drv_ops.fsync(audio);
+}
+
+static void audwmapro_reset_pmem_region(struct q6audio *audio)
+{
+	struct audwmapro_pmem_region *region;
+	struct list_head *ptr, *next;
+
+	list_for_each_safe(ptr, next, &audio->pmem_region_queue) {
+		region = list_entry(ptr, struct audwmapro_pmem_region, list);
+		list_del(&region->list);
+		put_pmem_file(region->file);
+		kfree(region);
+	}
+
+	return;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static ssize_t audwmapro_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t audwmapro_debug_read(struct file *file, char __user * buf,
+				 size_t count, loff_t *ppos)
+{
+	const int debug_bufmax = 4096;
+	static char buffer[4096];
+	int n = 0;
+	struct q6audio *audio = file->private_data;
+
+	mutex_lock(&audio->lock);
+	n = scnprintf(buffer, debug_bufmax, "opened %d\n", audio->opened);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "enabled %d\n", audio->enabled);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "stopped %d\n", audio->stopped);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "feedback %d\n", audio->feedback);
+	mutex_unlock(&audio->lock);
+	/* Following variables are only useful for debugging when
+	 * when playback halts unexpectedly. Thus, no mutual exclusion
+	 * enforced
+	 */
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "wflush %d\n", audio->wflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "rflush %d\n", audio->rflush);
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "inqueue empty %d\n", list_empty(&audio->in_queue));
+	n += scnprintf(buffer + n, debug_bufmax - n,
+		       "outqueue empty %d\n", list_empty(&audio->out_queue));
+	buffer[n] = 0;
+	return simple_read_from_buffer(buf, count, ppos, buffer, n);
+}
+
+static const struct file_operations audwmapro_debug_fops = {
+	.read = audwmapro_debug_read,
+	.open = audwmapro_debug_open,
+};
+#endif
+
+static long audio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct q6audio *audio = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		stats.byte_count = atomic_read(&audio->in_bytes);
+		stats.sample_count = atomic_read(&audio->in_samples);
+		if (copy_to_user((void *)arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return rc;
+	}
+
+	if (cmd == AUDIO_GET_EVENT) {
+		pr_debug("AUDIO_GET_EVENT\n");
+		if (mutex_trylock(&audio->get_event_lock)) {
+			rc = audwmapro_process_event_req(audio,
+						      (void __user *)arg);
+			mutex_unlock(&audio->get_event_lock);
+		} else
+			rc = -EBUSY;
+		return rc;
+	}
+
+	if (cmd == AUDIO_ASYNC_WRITE) {
+		mutex_lock(&audio->write_lock);
+		if (audio->drv_status & ADRV_STATUS_FSYNC)
+			rc = -EBUSY;
+		else {
+			if (audio->enabled)
+				rc = audwmapro_aio_buf_add(audio, 1,
+						(void __user *)arg);
+			else
+				rc = -EPERM;
+		}
+		mutex_unlock(&audio->write_lock);
+		return rc;
+	}
+
+	if (cmd == AUDIO_ASYNC_READ) {
+		mutex_lock(&audio->read_lock);
+		if ((audio->feedback) && (audio->enabled))
+			rc = audwmapro_aio_buf_add(audio, 0,
+					(void __user *)arg);
+		else
+			rc = -EPERM;
+		mutex_unlock(&audio->read_lock);
+		return rc;
+	}
+
+	if (cmd == AUDIO_ABORT_GET_EVENT) {
+		audio->event_abort = 1;
+		wake_up(&audio->event_wait);
+		return 0;
+	}
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START: {
+		struct asm_wmapro_cfg wmapro_cfg;
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			/* Configure PCM output block */
+			rc = q6asm_enc_cfg_blk_pcm(audio->ac,
+					audio->pcm_cfg.sample_rate,
+					audio->pcm_cfg.channel_count);
+			if (rc < 0) {
+				pr_err("pcm output block config failed\n");
+				break;
+			}
+		}
+		if ((audio->wmapro_config.formattag == 0x162) ||
+		(audio->wmapro_config.formattag == 0x166)) {
+			wmapro_cfg.format_tag = audio->wmapro_config.formattag;
+		} else {
+			pr_err("%s:AUDIO_START failed: formattag = %d\n",
+				__func__, audio->wmapro_config.formattag);
+			rc = -EINVAL;
+			break;
+		}
+		if ((audio->wmapro_config.numchannels == 1) ||
+		(audio->wmapro_config.numchannels == 2)) {
+			wmapro_cfg.ch_cfg = audio->wmapro_config.numchannels;
+		} else {
+			pr_err("%s:AUDIO_START failed: channels = %d\n",
+				__func__, audio->wmapro_config.numchannels);
+			rc = -EINVAL;
+			break;
+		}
+		if ((audio->wmapro_config.samplingrate <= 48000) ||
+		(audio->wmapro_config.samplingrate > 0)) {
+			wmapro_cfg.sample_rate =
+				audio->wmapro_config.samplingrate;
+		} else {
+			pr_err("%s:AUDIO_START failed: sample_rate = %d\n",
+				__func__, audio->wmapro_config.samplingrate);
+			rc = -EINVAL;
+			break;
+		}
+		wmapro_cfg.avg_bytes_per_sec =
+				audio->wmapro_config.avgbytespersecond;
+		if ((audio->wmapro_config.asfpacketlength <= 13376) ||
+		(audio->wmapro_config.asfpacketlength > 0)) {
+			wmapro_cfg.block_align =
+				audio->wmapro_config.asfpacketlength;
+		} else {
+			pr_err("%s:AUDIO_START failed: block_align = %d\n",
+				__func__, audio->wmapro_config.asfpacketlength);
+			rc = -EINVAL;
+			break;
+		}
+		if (audio->wmapro_config.validbitspersample == 16) {
+			wmapro_cfg.valid_bits_per_sample =
+				audio->wmapro_config.validbitspersample;
+		} else {
+			pr_err("%s:AUDIO_START failed: bitspersample = %d\n",
+				__func__,
+				audio->wmapro_config.validbitspersample);
+			rc = -EINVAL;
+			break;
+		}
+		if ((audio->wmapro_config.channelmask  == 4) ||
+		(audio->wmapro_config.channelmask == 3)) {
+			wmapro_cfg.ch_mask =  audio->wmapro_config.channelmask;
+		} else {
+			pr_err("%s:AUDIO_START failed: channel_mask = %d\n",
+				__func__, audio->wmapro_config.channelmask);
+			rc = -EINVAL;
+			break;
+		}
+		wmapro_cfg.encode_opt = audio->wmapro_config.encodeopt;
+		wmapro_cfg.adv_encode_opt =
+				audio->wmapro_config.advancedencodeopt;
+		wmapro_cfg.adv_encode_opt2 =
+				audio->wmapro_config.advancedencodeopt2;
+		/* Configure Media format block */
+		rc = q6asm_media_format_block_wmapro(audio->ac, &wmapro_cfg);
+		if (rc < 0) {
+			pr_err("cmd media format block failed\n");
+			break;
+		}
+		rc = audwmapro_enable(audio);
+		audio->eos_rsp = 0;
+		audio->eos_flag = 0;
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("Audio Start procedure failed rc=%d\n", rc);
+			break;
+		}
+		pr_debug("AUDIO_START success enable[%d]\n", audio->enabled);
+		if (audio->stopped == 1)
+			audio->stopped = 0;
+		break;
+	}
+	case AUDIO_STOP: {
+		pr_debug("AUDIO_STOP\n");
+		audio->stopped = 1;
+		audwmapro_flush(audio);
+		audio->enabled = 0;
+		audio->drv_status &= ~ADRV_STATUS_PAUSE;
+		if (rc < 0) {
+			pr_err("Audio Stop procedure failed rc=%d\n", rc);
+			break;
+		}
+		break;
+	}
+	case AUDIO_PAUSE: {
+		pr_debug("AUDIO_PAUSE %ld\n", arg);
+		if (arg == 1) {
+			rc = audwmapro_pause(audio);
+			if (rc < 0)
+				pr_err("%s: pause FAILED rc=%d\n", __func__,
+						rc);
+				audio->drv_status |= ADRV_STATUS_PAUSE;
+		} else if (arg == 0) {
+			if (audio->drv_status & ADRV_STATUS_PAUSE) {
+				rc = audwmapro_enable(audio);
+				if (rc)
+					pr_err("%s: audio enable failed\n",
+						__func__);
+				else {
+					audio->drv_status &= ~ADRV_STATUS_PAUSE;
+					audio->enabled = 1;
+				}
+			}
+		}
+		break;
+	}
+	case AUDIO_FLUSH: {
+		pr_debug("AUDIO_FLUSH\n");
+		audio->rflush = 1;
+		audio->wflush = 1;
+		/* Flush DSP */
+		rc = audwmapro_flush(audio);
+		/* Flush input / Output buffer in software*/
+		audwmapro_ioport_reset(audio);
+		if (rc < 0) {
+			pr_err("AUDIO_FLUSH interrupted\n");
+			rc = -EINTR;
+		} else {
+			audio->rflush = 0;
+			audio->wflush = 0;
+		}
+		audio->eos_flag = 0;
+		audio->eos_rsp = 0;
+		break;
+	}
+	case AUDIO_REGISTER_PMEM: {
+		struct msm_audio_pmem_info info;
+		pr_debug("AUDIO_REGISTER_PMEM\n");
+		if (copy_from_user(&info, (void *)arg, sizeof(info)))
+			rc = -EFAULT;
+		else
+			rc = audwmapro_pmem_add(audio, &info);
+		break;
+	}
+	case AUDIO_DEREGISTER_PMEM: {
+		struct msm_audio_pmem_info info;
+		pr_debug("AUDIO_DEREGISTER_PMEM\n");
+		if (copy_from_user(&info, (void *)arg, sizeof(info)))
+			rc = -EFAULT;
+		else
+			rc = audwmapro_pmem_remove(audio, &info);
+		break;
+	}
+	case AUDIO_GET_WMAPRO_CONFIG: {
+		if (copy_to_user((void *)arg, &audio->wmapro_config,
+				 sizeof(struct msm_audio_wmapro_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+		}
+	case AUDIO_SET_WMAPRO_CONFIG: {
+		if (copy_from_user(&audio->wmapro_config, (void *)arg,
+				 sizeof(struct msm_audio_wmapro_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+		}
+	case AUDIO_GET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		memset(&cfg, 0, sizeof(cfg));
+		cfg.buffer_size = audio->str_cfg.buffer_size;
+		cfg.buffer_count = audio->str_cfg.buffer_count;
+		pr_debug("GET STREAM CFG %d %d\n", cfg.buffer_size,
+			 cfg.buffer_count);
+		if (copy_to_user((void *)arg, &cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_STREAM_CONFIG: {
+		struct msm_audio_stream_config cfg;
+		pr_debug("SET STREAM CONFIG\n");
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		audio->str_cfg.buffer_size = FRAME_SIZE;
+		audio->str_cfg.buffer_count = FRAME_NUM;
+		rc = 0;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config cfg;
+		if (copy_to_user((void *)arg, &audio->pcm_cfg, sizeof(cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		if (copy_from_user(&config, (void *)arg, sizeof(config))) {
+				rc = -EFAULT;
+				break;
+		}
+		if (audio->feedback != NON_TUNNEL_MODE) {
+			pr_err("Not sufficient permission to"
+				       "change the playback mode\n");
+			rc = -EACCES;
+			break;
+		}
+		if ((config.buffer_count > PCM_BUF_COUNT) ||
+		    (config.buffer_count == 1))
+			config.buffer_count = PCM_BUF_COUNT;
+
+		if (config.buffer_size < PCM_BUFSZ_MIN)
+			config.buffer_size = PCM_BUFSZ_MIN;
+
+		audio->pcm_cfg.buffer_count = config.buffer_count;
+		audio->pcm_cfg.buffer_size = config.buffer_size;
+		audio->pcm_cfg.channel_count = config.channel_count;
+		audio->pcm_cfg.sample_rate = config.sample_rate;
+		rc = 0;
+		break;
+		}
+	case AUDIO_SET_BUF_CFG: {
+		struct msm_audio_buf_cfg  cfg;
+		if (copy_from_user(&cfg, (void *)arg, sizeof(cfg))) {
+			rc = -EFAULT;
+			break;
+		}
+		if ((audio->feedback == NON_TUNNEL_MODE) &&
+			!cfg.meta_info_enable) {
+			rc = -EFAULT;
+			break;
+		}
+
+		audio->buf_cfg.meta_info_enable = cfg.meta_info_enable;
+		pr_debug("%s:session id %d: Set-buf-cfg: meta[%d]", __func__,
+				audio->ac->session, cfg.meta_info_enable);
+		break;
+	}
+	case AUDIO_GET_BUF_CFG: {
+		pr_debug("%s:session id %d: Get-buf-cfg: meta[%d]\
+			framesperbuf[%d]\n", __func__,
+			audio->ac->session, audio->buf_cfg.meta_info_enable,
+			audio->buf_cfg.frames_per_buf);
+
+		if (copy_to_user((void *)arg, &audio->buf_cfg,
+					sizeof(struct msm_audio_buf_cfg)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+			if (copy_to_user((void *)arg, &audio->ac->session,
+					 sizeof(unsigned short))) {
+				rc = -EFAULT;
+			}
+			break;
+		}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static int audio_release(struct inode *inode, struct file *file)
+{
+	struct q6audio *audio = file->private_data;
+	mutex_lock(&audio->lock);
+	audwmapro_disable(audio);
+	audio->drv_ops.out_flush(audio);
+	audio->drv_ops.in_flush(audio);
+	audwmapro_reset_pmem_region(audio);
+	audio->event_abort = 1;
+	wake_up(&audio->event_wait);
+	audwmapro_reset_event_queue(audio);
+	q6asm_audio_client_free(audio->ac);
+	mutex_unlock(&audio->lock);
+	mutex_destroy(&audio->lock);
+	mutex_destroy(&audio->read_lock);
+	mutex_destroy(&audio->write_lock);
+	mutex_destroy(&audio->get_event_lock);
+#ifdef CONFIG_DEBUG_FS
+	if (audio->dentry)
+		debugfs_remove(audio->dentry);
+#endif
+	kfree(audio);
+	pr_info("%s: wmapro decoder success\n", __func__);
+	return 0;
+}
+
+static int audio_open(struct inode *inode, struct file *file)
+{
+	struct q6audio *audio = NULL;
+	int rc = 0;
+	int i;
+	struct audwmapro_event *e_node = NULL;
+
+#ifdef CONFIG_DEBUG_FS
+	/* 4 bytes represents decoder number, 1 byte for terminate string */
+	char name[sizeof "msm_wmapro_" + 5];
+#endif
+	audio = kzalloc(sizeof(struct q6audio), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("Could not allocate memory for wma decode driver\n");
+		return -ENOMEM;
+	}
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	 * but at least we need to have initial config
+	 */
+	audio->str_cfg.buffer_size = FRAME_SIZE;
+	audio->str_cfg.buffer_count = FRAME_NUM;
+	audio->pcm_cfg.buffer_size = PCM_BUFSZ_MIN;
+	audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+	audio->pcm_cfg.sample_rate = 48000;
+	audio->pcm_cfg.channel_count = 2;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb) q6_audwmapro_cb,
+					     (void *)audio);
+
+	if (!audio->ac) {
+		pr_err("Could not allocate memory for audio client\n");
+		kfree(audio);
+		return -ENOMEM;
+	}
+	/* Only AIO interface */
+	if (file->f_flags & O_NONBLOCK) {
+		pr_debug("set to aio interface\n");
+		audio->drv_status |= ADRV_STATUS_AIO_INTF;
+		audio->drv_ops.out_flush = audwmapro_async_out_flush;
+		audio->drv_ops.in_flush = audwmapro_async_in_flush;
+		audio->drv_ops.fsync = audwmapro_async_fsync;
+		q6asm_set_io_mode(audio->ac, ASYNC_IO_MODE);
+	} else {
+		pr_err("SIO interface not supported\n");
+		rc = -EACCES;
+		goto fail;
+	}
+
+	/* open in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) && (file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_read_write(audio->ac, FORMAT_LINEAR_PCM,
+					   FORMAT_WMA_V10PRO);
+		if (rc < 0) {
+			pr_err("NT mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = NON_TUNNEL_MODE;
+		/* open WMA decoder, expected frames is always 1*/
+		audio->buf_cfg.frames_per_buf = 0x01;
+		audio->buf_cfg.meta_info_enable = 0x01;
+	} else if ((file->f_mode & FMODE_WRITE) &&
+			!(file->f_mode & FMODE_READ)) {
+		rc = q6asm_open_write(audio->ac, FORMAT_WMA_V10PRO);
+		if (rc < 0) {
+			pr_err("T mode Open failed rc=%d\n", rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		audio->feedback = TUNNEL_MODE;
+		audio->buf_cfg.meta_info_enable = 0x00;
+	} else {
+		pr_err("Not supported mode\n");
+		rc = -EACCES;
+		goto fail;
+	}
+	/* Initialize all locks of audio instance */
+	mutex_init(&audio->lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->write_lock);
+	mutex_init(&audio->get_event_lock);
+	spin_lock_init(&audio->dsp_lock);
+	spin_lock_init(&audio->event_queue_lock);
+	init_waitqueue_head(&audio->cmd_wait);
+	init_waitqueue_head(&audio->write_wait);
+	init_waitqueue_head(&audio->event_wait);
+	INIT_LIST_HEAD(&audio->out_queue);
+	INIT_LIST_HEAD(&audio->in_queue);
+	INIT_LIST_HEAD(&audio->pmem_region_queue);
+	INIT_LIST_HEAD(&audio->free_event_queue);
+	INIT_LIST_HEAD(&audio->event_queue);
+
+	audio->drv_ops.out_flush(audio);
+	audio->opened = 1;
+	file->private_data = audio;
+
+#ifdef CONFIG_DEBUG_FS
+	snprintf(name, sizeof name, "msm_wmapro_%04x", audio->ac->session);
+	audio->dentry = debugfs_create_file(name, S_IFREG | S_IRUGO,
+					    NULL, (void *)audio,
+					    &audwmapro_debug_fops);
+
+	if (IS_ERR(audio->dentry))
+		pr_debug("debugfs_create_file failed\n");
+#endif
+	for (i = 0; i < AUDWMAPRO_EVENT_NUM; i++) {
+		e_node = kmalloc(sizeof(struct audwmapro_event), GFP_KERNEL);
+		if (e_node)
+			list_add_tail(&e_node->list, &audio->free_event_queue);
+		else {
+			pr_err("event pkt alloc failed\n");
+			break;
+		}
+	}
+	pr_info("%s:wmapro decoder open success, session_id = %d\n", __func__,
+				audio->ac->session);
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_wmapro_fops = {
+	.owner = THIS_MODULE,
+	.open = audio_open,
+	.release = audio_release,
+	.unlocked_ioctl = audio_ioctl,
+	.fsync = audwmapro_fsync,
+};
+
+struct miscdevice audwmapro_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_wmapro",
+	.fops = &audio_wmapro_fops,
+};
+
+static int __init audio_wmapro_init(void)
+{
+	return misc_register(&audwmapro_misc);
+}
+
+device_initcall(audio_wmapro_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c b/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c
new file mode 100644
index 0000000..8bf7794
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/board-msm8x60-audio.c
@@ -0,0 +1,2507 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/mfd/pmic8058.h>
+#include <linux/pmic8058-othc.h>
+#include <linux/mfd/pmic8901.h>
+#include <linux/mfd/msm-adie-codec.h>
+#include <linux/regulator/pmic8058-regulator.h>
+#include <linux/regulator/pmic8901-regulator.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regulator/machine.h>
+
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <mach/mpp.h>
+#include <sound/apr_audio.h>
+#include <asm/mach-types.h>
+#include <asm/uaccess.h>
+
+#include "snddev_icodec.h"
+#include "snddev_ecodec.h"
+#include "timpani_profile_8x60.h"
+#include "snddev_hdmi.h"
+#include "snddev_mi2s.h"
+#include "snddev_virtual.h"
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_hsed_config;
+static void snddev_hsed_config_modify_setting(int type);
+static void snddev_hsed_config_restore_setting(void);
+#endif
+
+/* GPIO_CLASS_D0_EN */
+#define SNDDEV_GPIO_CLASS_D0_EN 227
+
+/* GPIO_CLASS_D1_EN */
+#define SNDDEV_GPIO_CLASS_D1_EN 229
+
+#define SNDDEV_GPIO_MIC2_ANCR_SEL 294
+#define SNDDEV_GPIO_MIC1_ANCL_SEL 295
+
+static struct resource msm_cdcclk_ctl_resources[] = {
+	{
+		.name   = "msm_snddev_tx_mclk",
+		.start  = 108,
+		.end    = 108,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "msm_snddev_rx_mclk",
+		.start  = 109,
+		.end    = 109,
+		.flags  = IORESOURCE_IO,
+	},
+};
+
+static struct platform_device msm_cdcclk_ctl_device = {
+	.name   = "msm_cdcclk_ctl",
+	.num_resources  = ARRAY_SIZE(msm_cdcclk_ctl_resources),
+	.resource       = msm_cdcclk_ctl_resources,
+};
+
+static struct resource msm_aux_pcm_resources[] = {
+
+	{
+		.name   = "aux_pcm_dout",
+		.start  = 111,
+		.end    = 111,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "aux_pcm_din",
+		.start  = 112,
+		.end    = 112,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "aux_pcm_syncout",
+		.start  = 113,
+		.end    = 113,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "aux_pcm_clkin_a",
+		.start  = 114,
+		.end    = 114,
+		.flags  = IORESOURCE_IO,
+	},
+};
+
+static struct platform_device msm_aux_pcm_device = {
+	.name   = "msm_aux_pcm",
+	.num_resources  = ARRAY_SIZE(msm_aux_pcm_resources),
+	.resource       = msm_aux_pcm_resources,
+};
+
+static struct resource msm_mi2s_gpio_resources[] = {
+
+	{
+		.name   = "mi2s_ws",
+		.start  = 101,
+		.end    = 101,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "mi2s_sclk",
+		.start  = 102,
+		.end    = 102,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "mi2s_mclk",
+		.start  = 103,
+		.end    = 103,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "fm_mi2s_sd",
+		.start  = 107,
+		.end    = 107,
+		.flags  = IORESOURCE_IO,
+	},
+};
+
+static struct platform_device msm_mi2s_device = {
+	.name		= "msm_mi2s",
+	.num_resources	= ARRAY_SIZE(msm_mi2s_gpio_resources),
+	.resource	= msm_mi2s_gpio_resources,
+};
+
+/* Must be same size as msm_icodec_gpio_resources */
+static int msm_icodec_gpio_defaults[] = {
+	0,
+	0,
+};
+
+static struct resource msm_icodec_gpio_resources[] = {
+	{
+		.name   = "msm_icodec_speaker_left",
+		.start  = SNDDEV_GPIO_CLASS_D0_EN,
+		.end    = SNDDEV_GPIO_CLASS_D0_EN,
+		.flags  = IORESOURCE_IO,
+	},
+	{
+		.name   = "msm_icodec_speaker_right",
+		.start  = SNDDEV_GPIO_CLASS_D1_EN,
+		.end    = SNDDEV_GPIO_CLASS_D1_EN,
+		.flags  = IORESOURCE_IO,
+	},
+};
+
+static struct platform_device msm_icodec_gpio_device = {
+	.name   = "msm_icodec_gpio",
+	.num_resources  = ARRAY_SIZE(msm_icodec_gpio_resources),
+	.resource       = msm_icodec_gpio_resources,
+	.dev = { .platform_data = &msm_icodec_gpio_defaults },
+};
+
+static struct regulator *s3;
+static struct regulator *mvs;
+
+static int msm_snddev_enable_dmic_power(void)
+{
+	int ret;
+
+	s3 = regulator_get(NULL, "8058_s3");
+	if (IS_ERR(s3)) {
+		ret = -EBUSY;
+		goto fail_get_s3;
+	}
+
+	ret = regulator_set_voltage(s3, 1800000, 1800000);
+	if (ret) {
+		pr_err("%s: error setting voltage\n", __func__);
+		goto fail_s3;
+	}
+
+	ret = regulator_enable(s3);
+	if (ret) {
+		pr_err("%s: error enabling regulator\n", __func__);
+		goto fail_s3;
+	}
+
+	mvs = regulator_get(NULL, "8901_mvs0");
+	if (IS_ERR(mvs))
+		goto fail_mvs0_get;
+
+	ret = regulator_enable(mvs);
+	if (ret) {
+		pr_err("%s: error setting regulator\n", __func__);
+		goto fail_mvs0_enable;
+	}
+	return ret;
+
+fail_mvs0_enable:
+	regulator_put(mvs);
+	mvs = NULL;
+fail_mvs0_get:
+	regulator_disable(s3);
+fail_s3:
+	regulator_put(s3);
+	s3 = NULL;
+fail_get_s3:
+	return ret;
+}
+
+static void msm_snddev_disable_dmic_power(void)
+{
+	int ret;
+
+	if (mvs) {
+		ret = regulator_disable(mvs);
+		if (ret < 0)
+			pr_err("%s: error disabling vreg mvs\n", __func__);
+		regulator_put(mvs);
+		mvs = NULL;
+	}
+
+	if (s3) {
+		ret = regulator_disable(s3);
+		if (ret < 0)
+			pr_err("%s: error disabling regulator s3\n", __func__);
+		regulator_put(s3);
+		s3 = NULL;
+	}
+}
+
+#define PM8901_MPP_3 (2) /* PM8901 MPP starts from 0 */
+
+static int config_class_d0_gpio(int enable)
+{
+	int rc;
+
+	if (enable) {
+		rc = pm8901_mpp_config_digital_out(PM8901_MPP_3,
+			PM8901_MPP_DIG_LEVEL_MSMIO, 1);
+
+		if (rc) {
+			pr_err("%s: CLASS_D0_EN failed\n", __func__);
+			return rc;
+		}
+
+		rc = gpio_request(SNDDEV_GPIO_CLASS_D0_EN, "CLASSD0_EN");
+
+		if (rc) {
+			pr_err("%s: spkr pamp gpio pm8901 mpp3 request"
+			"failed\n", __func__);
+			pm8901_mpp_config_digital_out(PM8901_MPP_3,
+			PM8901_MPP_DIG_LEVEL_MSMIO, 0);
+			return rc;
+		}
+
+		gpio_direction_output(SNDDEV_GPIO_CLASS_D0_EN, 1);
+		gpio_set_value(SNDDEV_GPIO_CLASS_D0_EN, 1);
+
+	} else {
+		pm8901_mpp_config_digital_out(PM8901_MPP_3,
+		PM8901_MPP_DIG_LEVEL_MSMIO, 0);
+		gpio_set_value(SNDDEV_GPIO_CLASS_D0_EN, 0);
+		gpio_free(SNDDEV_GPIO_CLASS_D0_EN);
+	}
+	return 0;
+}
+
+static atomic_t pamp_ref_cnt;
+
+static int msm_snddev_poweramp_on(void)
+{
+	int rc;
+
+	if (atomic_inc_return(&pamp_ref_cnt) > 1)
+		return 0;
+
+	pr_debug("%s: enable stereo spkr amp\n", __func__);
+	rc = config_class_d0_gpio(1);
+	if (rc) {
+		pr_err("%s: d0 gpio configuration failed\n", __func__);
+		goto config_gpio_fail;
+	}
+config_gpio_fail:
+	return rc;
+}
+
+static void msm_snddev_poweramp_off(void)
+{
+	if (atomic_dec_return(&pamp_ref_cnt) == 0) {
+		pr_debug("%s: disable stereo spkr amp\n", __func__);
+		config_class_d0_gpio(0);
+		msleep(30);
+	}
+}
+
+/* Regulator 8058_l10 supplies regulator 8058_ncp. */
+static struct regulator *snddev_reg_ncp;
+static struct regulator *snddev_reg_l10;
+
+static atomic_t preg_ref_cnt;
+
+static int msm_snddev_voltage_on(void)
+{
+	int rc;
+	pr_debug("%s\n", __func__);
+
+	if (atomic_inc_return(&preg_ref_cnt) > 1)
+		return 0;
+
+	snddev_reg_l10 = regulator_get(NULL, "8058_l10");
+	if (IS_ERR(snddev_reg_l10)) {
+		pr_err("%s: regulator_get(%s) failed (%ld)\n", __func__,
+			"l10", PTR_ERR(snddev_reg_l10));
+		return -EBUSY;
+	}
+
+	rc = regulator_set_voltage(snddev_reg_l10, 2600000, 2600000);
+	if (rc < 0)
+		pr_err("%s: regulator_set_voltage(l10) failed (%d)\n",
+			__func__, rc);
+
+	rc = regulator_enable(snddev_reg_l10);
+	if (rc < 0)
+		pr_err("%s: regulator_enable(l10) failed (%d)\n", __func__, rc);
+
+	snddev_reg_ncp = regulator_get(NULL, "8058_ncp");
+	if (IS_ERR(snddev_reg_ncp)) {
+		pr_err("%s: regulator_get(%s) failed (%ld)\n", __func__,
+			"ncp", PTR_ERR(snddev_reg_ncp));
+		return -EBUSY;
+	}
+
+	rc = regulator_set_voltage(snddev_reg_ncp, 1800000, 1800000);
+	if (rc < 0) {
+		pr_err("%s: regulator_set_voltage(ncp) failed (%d)\n",
+			__func__, rc);
+		goto regulator_fail;
+	}
+
+	rc = regulator_enable(snddev_reg_ncp);
+	if (rc < 0) {
+		pr_err("%s: regulator_enable(ncp) failed (%d)\n", __func__, rc);
+		goto regulator_fail;
+	}
+
+	return rc;
+
+regulator_fail:
+	regulator_put(snddev_reg_ncp);
+	snddev_reg_ncp = NULL;
+	return rc;
+}
+
+static void msm_snddev_voltage_off(void)
+{
+	int rc;
+	pr_debug("%s\n", __func__);
+
+	if (!snddev_reg_ncp)
+		goto done;
+
+	if (atomic_dec_return(&preg_ref_cnt) == 0) {
+		rc = regulator_disable(snddev_reg_ncp);
+		if (rc < 0)
+			pr_err("%s: regulator_disable(ncp) failed (%d)\n",
+				__func__, rc);
+		regulator_put(snddev_reg_ncp);
+
+		snddev_reg_ncp = NULL;
+	}
+
+done:
+	if (!snddev_reg_l10)
+		return;
+
+	rc = regulator_disable(snddev_reg_l10);
+	if (rc < 0)
+		pr_err("%s: regulator_disable(l10) failed (%d)\n",
+			__func__, rc);
+
+	regulator_put(snddev_reg_l10);
+
+	snddev_reg_l10 = NULL;
+}
+
+static int msm_snddev_enable_amic_power(void)
+{
+	int ret = 0;
+#ifdef CONFIG_PMIC8058_OTHC
+
+	if (machine_is_msm8x60_fluid()) {
+
+		ret = pm8058_micbias_enable(OTHC_MICBIAS_0,
+				OTHC_SIGNAL_ALWAYS_ON);
+		if (ret)
+			pr_err("%s: Enabling amic power failed\n", __func__);
+
+		ret = gpio_request(SNDDEV_GPIO_MIC2_ANCR_SEL, "MIC2_ANCR_SEL");
+		if (ret) {
+			pr_err("%s: spkr pamp gpio %d request failed\n",
+				__func__, SNDDEV_GPIO_MIC2_ANCR_SEL);
+			return ret;
+		}
+		gpio_direction_output(SNDDEV_GPIO_MIC2_ANCR_SEL, 0);
+
+		ret = gpio_request(SNDDEV_GPIO_MIC1_ANCL_SEL, "MIC1_ANCL_SEL");
+		if (ret) {
+			pr_err("%s: mic1 ancl gpio %d request failed\n",
+				__func__, SNDDEV_GPIO_MIC1_ANCL_SEL);
+			gpio_free(SNDDEV_GPIO_MIC2_ANCR_SEL);
+			return ret;
+		}
+		gpio_direction_output(SNDDEV_GPIO_MIC1_ANCL_SEL, 0);
+
+	} else {
+		ret = pm8058_micbias_enable(OTHC_MICBIAS_2,
+				OTHC_SIGNAL_ALWAYS_ON);
+		if (ret)
+			pr_err("%s: Enabling amic power failed\n", __func__);
+	}
+#endif
+	return ret;
+}
+
+static void msm_snddev_disable_amic_power(void)
+{
+#ifdef CONFIG_PMIC8058_OTHC
+	int ret;
+	if (machine_is_msm8x60_fluid()) {
+		ret = pm8058_micbias_enable(OTHC_MICBIAS_0,
+				OTHC_SIGNAL_OFF);
+		gpio_free(SNDDEV_GPIO_MIC1_ANCL_SEL);
+		gpio_free(SNDDEV_GPIO_MIC2_ANCR_SEL);
+	} else
+		ret = pm8058_micbias_enable(OTHC_MICBIAS_2, OTHC_SIGNAL_OFF);
+
+	if (ret)
+		pr_err("%s: Disabling amic power failed\n", __func__);
+#endif
+}
+
+static int msm_snddev_enable_anc_power(void)
+{
+	int ret = 0;
+#ifdef CONFIG_PMIC8058_OTHC
+	ret = pm8058_micbias_enable(OTHC_MICBIAS_2,
+		OTHC_SIGNAL_ALWAYS_ON);
+	if (ret)
+		pr_err("%s: Enabling anc micbias 2 failed\n", __func__);
+
+	if (machine_is_msm8x60_fluid()) {
+
+		ret = pm8058_micbias_enable(OTHC_MICBIAS_0,
+				OTHC_SIGNAL_ALWAYS_ON);
+		if (ret)
+			pr_err("%s: Enabling anc micbias 0 failed\n", __func__);
+
+		ret = gpio_request(SNDDEV_GPIO_MIC2_ANCR_SEL, "MIC2_ANCR_SEL");
+		if (ret) {
+			pr_err("%s: mic2 ancr gpio %d request failed\n",
+				__func__, SNDDEV_GPIO_MIC2_ANCR_SEL);
+			return ret;
+		}
+		gpio_direction_output(SNDDEV_GPIO_MIC2_ANCR_SEL, 1);
+
+		ret = gpio_request(SNDDEV_GPIO_MIC1_ANCL_SEL, "MIC1_ANCL_SEL");
+		if (ret) {
+			pr_err("%s: mic1 ancl gpio %d request failed\n",
+				__func__, SNDDEV_GPIO_MIC1_ANCL_SEL);
+			gpio_free(SNDDEV_GPIO_MIC2_ANCR_SEL);
+			return ret;
+		}
+		gpio_direction_output(SNDDEV_GPIO_MIC1_ANCL_SEL, 1);
+
+	}
+#endif
+	return ret;
+}
+
+static void msm_snddev_disable_anc_power(void)
+{
+#ifdef CONFIG_PMIC8058_OTHC
+	int ret;
+
+	ret = pm8058_micbias_enable(OTHC_MICBIAS_2, OTHC_SIGNAL_OFF);
+
+	if (machine_is_msm8x60_fluid()) {
+		ret |= pm8058_micbias_enable(OTHC_MICBIAS_0,
+				OTHC_SIGNAL_OFF);
+		gpio_free(SNDDEV_GPIO_MIC2_ANCR_SEL);
+		gpio_free(SNDDEV_GPIO_MIC1_ANCL_SEL);
+	}
+
+	if (ret)
+		pr_err("%s: Disabling anc power failed\n", __func__);
+#endif
+}
+
+static int msm_snddev_enable_dmic_sec_power(void)
+{
+	int ret;
+
+	ret = msm_snddev_enable_dmic_power();
+	if (ret) {
+		pr_err("%s: Error: Enabling dmic power failed\n", __func__);
+		return ret;
+	}
+#ifdef CONFIG_PMIC8058_OTHC
+	ret = pm8058_micbias_enable(OTHC_MICBIAS_2, OTHC_SIGNAL_ALWAYS_ON);
+	if (ret) {
+		pr_err("%s: Error: Enabling micbias failed\n", __func__);
+		msm_snddev_disable_dmic_power();
+		return ret;
+	}
+#endif
+	return 0;
+}
+
+static void msm_snddev_disable_dmic_sec_power(void)
+{
+	msm_snddev_disable_dmic_power();
+
+#ifdef CONFIG_PMIC8058_OTHC
+	pm8058_micbias_enable(OTHC_MICBIAS_2, OTHC_SIGNAL_OFF);
+#endif
+}
+
+static struct adie_codec_action_unit iearpiece_48KHz_osr256_actions[] =
+	EAR_PRI_MONO_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry iearpiece_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = iearpiece_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(iearpiece_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile iearpiece_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = iearpiece_settings,
+	.setting_sz = ARRAY_SIZE(iearpiece_settings),
+};
+
+static struct snddev_icodec_data snddev_iearpiece_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "handset_rx",
+	.copp_id = 0,
+	.profile = &iearpiece_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+};
+
+static struct platform_device msm_iearpiece_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_iearpiece_data },
+};
+
+static struct adie_codec_action_unit imic_48KHz_osr256_actions[] =
+	AMIC_PRI_MONO_OSR_256;
+
+static struct adie_codec_hwsetting_entry imic_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = imic_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(imic_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile imic_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = imic_settings,
+	.setting_sz = ARRAY_SIZE(imic_settings),
+};
+
+static struct snddev_icodec_data snddev_imic_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_tx",
+	.copp_id = 1,
+	.profile = &imic_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_amic_power,
+	.pamp_off = msm_snddev_disable_amic_power,
+};
+
+static struct platform_device msm_imic_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_imic_data },
+};
+
+static struct snddev_icodec_data snddev_fluid_ispkr_mic_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_mono_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &imic_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_amic_power,
+	.pamp_off = msm_snddev_disable_amic_power,
+};
+
+static struct platform_device msm_fluid_ispkr_mic_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_fluid_ispkr_mic_data },
+};
+
+
+static struct adie_codec_action_unit headset_ab_cpls_48KHz_osr256_actions[] =
+	HEADSET_AB_CPLS_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry headset_ab_cpls_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = headset_ab_cpls_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(headset_ab_cpls_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile headset_ab_cpls_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = headset_ab_cpls_settings,
+	.setting_sz = ARRAY_SIZE(headset_ab_cpls_settings),
+};
+
+static struct snddev_icodec_data snddev_ihs_stereo_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "headset_stereo_rx",
+	.copp_id = 0,
+	.profile = &headset_ab_cpls_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+};
+
+static struct platform_device msm_headset_stereo_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_ihs_stereo_rx_data },
+};
+
+static struct adie_codec_action_unit headset_anc_48KHz_osr256_actions[] =
+	ANC_HEADSET_CPLS_AMIC1_AUXL_RX1_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry headset_anc_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = headset_anc_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(headset_anc_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile headset_anc_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = headset_anc_settings,
+	.setting_sz = ARRAY_SIZE(headset_anc_settings),
+};
+
+static struct snddev_icodec_data snddev_anc_headset_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE | SNDDEV_CAP_ANC),
+	.name = "anc_headset_stereo_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &headset_anc_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_anc_power,
+	.pamp_off = msm_snddev_disable_anc_power,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+};
+
+static struct platform_device msm_anc_headset_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_anc_headset_data },
+};
+
+static struct adie_codec_action_unit ispkr_stereo_48KHz_osr256_actions[] =
+	SPEAKER_PRI_STEREO_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry ispkr_stereo_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ispkr_stereo_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(ispkr_stereo_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ispkr_stereo_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ispkr_stereo_settings,
+	.setting_sz = ARRAY_SIZE(ispkr_stereo_settings),
+};
+
+static struct snddev_icodec_data snddev_ispkr_stereo_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "speaker_stereo_rx",
+	.copp_id = 0,
+	.profile = &ispkr_stereo_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+};
+
+static struct platform_device msm_ispkr_stereo_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_ispkr_stereo_data },
+};
+
+static struct adie_codec_action_unit idmic_mono_48KHz_osr256_actions[] =
+	DMIC1_PRI_MONO_OSR_256;
+
+static struct adie_codec_hwsetting_entry idmic_mono_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = idmic_mono_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(idmic_mono_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile idmic_mono_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = idmic_mono_settings,
+	.setting_sz = ARRAY_SIZE(idmic_mono_settings),
+};
+
+static struct snddev_icodec_data snddev_ispkr_mic_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_mono_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &idmic_mono_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+};
+
+static struct platform_device msm_ispkr_mic_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_ispkr_mic_data },
+};
+
+static struct adie_codec_action_unit iearpiece_ffa_48KHz_osr256_actions[] =
+	EAR_PRI_MONO_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry iearpiece_ffa_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = iearpiece_ffa_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(iearpiece_ffa_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile iearpiece_ffa_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = iearpiece_ffa_settings,
+	.setting_sz = ARRAY_SIZE(iearpiece_ffa_settings),
+};
+
+static struct snddev_icodec_data snddev_iearpiece_ffa_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "handset_rx",
+	.copp_id = 0,
+	.profile = &iearpiece_ffa_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+};
+
+static struct platform_device msm_iearpiece_ffa_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_iearpiece_ffa_data },
+};
+
+static struct snddev_icodec_data snddev_imic_ffa_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &idmic_mono_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+};
+
+static struct platform_device msm_imic_ffa_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_imic_ffa_data },
+};
+
+static struct adie_codec_action_unit dual_mic_endfire_8KHz_osr256_actions[] =
+	DMIC1_PRI_STEREO_OSR_256;
+
+static struct adie_codec_hwsetting_entry dual_mic_endfire_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = dual_mic_endfire_8KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE(dual_mic_endfire_8KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile dual_mic_endfire_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = dual_mic_endfire_settings,
+	.setting_sz = ARRAY_SIZE(dual_mic_endfire_settings),
+};
+
+static struct snddev_icodec_data snddev_dual_mic_endfire_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_dual_mic_endfire_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &dual_mic_endfire_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+};
+
+static struct platform_device msm_hs_dual_mic_endfire_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_dual_mic_endfire_data },
+};
+
+static struct snddev_icodec_data snddev_dual_mic_spkr_endfire_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_dual_mic_endfire_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &dual_mic_endfire_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+};
+
+static struct platform_device msm_spkr_dual_mic_endfire_device = {
+	.name = "snddev_icodec",
+	.id = 15,
+	.dev = { .platform_data = &snddev_dual_mic_spkr_endfire_data },
+};
+
+static struct adie_codec_action_unit dual_mic_broadside_8osr256_actions[] =
+	HS_DMIC2_STEREO_OSR_256;
+
+static struct adie_codec_hwsetting_entry dual_mic_broadside_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = dual_mic_broadside_8osr256_actions,
+		.action_sz = ARRAY_SIZE(dual_mic_broadside_8osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile dual_mic_broadside_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = dual_mic_broadside_settings,
+	.setting_sz = ARRAY_SIZE(dual_mic_broadside_settings),
+};
+
+static struct snddev_icodec_data snddev_hs_dual_mic_broadside_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_dual_mic_broadside_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &dual_mic_broadside_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_sec_power,
+	.pamp_off = msm_snddev_disable_dmic_sec_power,
+};
+
+static struct platform_device msm_hs_dual_mic_broadside_device = {
+	.name = "snddev_icodec",
+	.id = 21,
+	.dev = { .platform_data = &snddev_hs_dual_mic_broadside_data },
+};
+
+static struct snddev_icodec_data snddev_spkr_dual_mic_broadside_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "speaker_dual_mic_broadside_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &dual_mic_broadside_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_sec_power,
+	.pamp_off = msm_snddev_disable_dmic_sec_power,
+};
+
+static struct platform_device msm_spkr_dual_mic_broadside_device = {
+	.name = "snddev_icodec",
+	.id = 18,
+	.dev = { .platform_data = &snddev_spkr_dual_mic_broadside_data },
+};
+
+static struct snddev_hdmi_data snddev_hdmi_stereo_rx_data = {
+	.capability = SNDDEV_CAP_RX ,
+	.name = "hdmi_stereo_rx",
+	.copp_id = HDMI_RX,
+	.channel_mode = 0,
+	.default_sample_rate = 48000,
+};
+
+static struct platform_device msm_snddev_hdmi_stereo_rx_device = {
+	.name = "snddev_hdmi",
+	.dev = { .platform_data = &snddev_hdmi_stereo_rx_data },
+};
+
+static struct snddev_mi2s_data snddev_mi2s_fm_tx_data = {
+	.capability = SNDDEV_CAP_TX ,
+	.name = "fmradio_stereo_tx",
+	.copp_id = MI2S_TX,
+	.channel_mode = 2, /* stereo */
+	.sd_lines = MI2S_SD3, /* sd3 */
+	.sample_rate = 48000,
+};
+
+static struct platform_device msm_mi2s_fm_tx_device = {
+	.name = "snddev_mi2s",
+	.dev = { .platform_data = &snddev_mi2s_fm_tx_data },
+};
+
+static struct snddev_mi2s_data snddev_mi2s_fm_rx_data = {
+	.capability = SNDDEV_CAP_RX ,
+	.name = "fmradio_stereo_rx",
+	.copp_id = MI2S_RX,
+	.channel_mode = 2, /* stereo */
+	.sd_lines = MI2S_SD3, /* sd3 */
+	.sample_rate = 48000,
+};
+
+static struct platform_device msm_mi2s_fm_rx_device = {
+	.name = "snddev_mi2s",
+	.id = 1,
+	.dev = { .platform_data = &snddev_mi2s_fm_rx_data },
+};
+
+static struct adie_codec_action_unit iheadset_mic_tx_osr256_actions[] =
+	HEADSET_AMIC2_TX_MONO_PRI_OSR_256;
+
+static struct adie_codec_hwsetting_entry iheadset_mic_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = iheadset_mic_tx_osr256_actions,
+		.action_sz = ARRAY_SIZE(iheadset_mic_tx_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile iheadset_mic_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = iheadset_mic_tx_settings,
+	.setting_sz = ARRAY_SIZE(iheadset_mic_tx_settings),
+};
+
+static struct snddev_icodec_data snddev_headset_mic_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "headset_mono_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &iheadset_mic_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+};
+
+static struct platform_device msm_headset_mic_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_headset_mic_data },
+};
+
+static struct adie_codec_action_unit
+	ihs_stereo_speaker_stereo_rx_48KHz_osr256_actions[] =
+	SPEAKER_HPH_AB_CPL_PRI_STEREO_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry
+	ihs_stereo_speaker_stereo_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ihs_stereo_speaker_stereo_rx_48KHz_osr256_actions,
+		.action_sz =
+		ARRAY_SIZE(ihs_stereo_speaker_stereo_rx_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ihs_stereo_speaker_stereo_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ihs_stereo_speaker_stereo_rx_settings,
+	.setting_sz = ARRAY_SIZE(ihs_stereo_speaker_stereo_rx_settings),
+};
+
+static struct snddev_icodec_data snddev_ihs_stereo_speaker_stereo_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "headset_stereo_speaker_stereo_rx",
+	.copp_id = 0,
+	.profile = &ihs_stereo_speaker_stereo_rx_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+};
+
+static struct platform_device msm_ihs_stereo_speaker_stereo_rx_device = {
+	.name = "snddev_icodec",
+	.id = 22,
+	.dev = { .platform_data = &snddev_ihs_stereo_speaker_stereo_rx_data },
+};
+
+/* define the value for BT_SCO */
+
+static struct snddev_ecodec_data snddev_bt_sco_earpiece_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "bt_sco_rx",
+	.copp_id = PCM_RX,
+	.channel_mode = 1,
+};
+
+static struct snddev_ecodec_data snddev_bt_sco_mic_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "bt_sco_tx",
+	.copp_id = PCM_TX,
+	.channel_mode = 1,
+};
+
+struct platform_device msm_bt_sco_earpiece_device = {
+	.name = "msm_snddev_ecodec",
+	.dev = { .platform_data = &snddev_bt_sco_earpiece_data },
+};
+
+struct platform_device msm_bt_sco_mic_device = {
+	.name = "msm_snddev_ecodec",
+	.dev = { .platform_data = &snddev_bt_sco_mic_data },
+};
+
+static struct adie_codec_action_unit itty_mono_tx_actions[] =
+	TTY_HEADSET_MONO_TX_OSR_256;
+
+static struct adie_codec_hwsetting_entry itty_mono_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = itty_mono_tx_actions,
+		.action_sz = ARRAY_SIZE(itty_mono_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile itty_mono_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = itty_mono_tx_settings,
+	.setting_sz = ARRAY_SIZE(itty_mono_tx_settings),
+};
+
+static struct snddev_icodec_data snddev_itty_mono_tx_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE | SNDDEV_CAP_TTY),
+	.name = "tty_headset_mono_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &itty_mono_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+};
+
+static struct platform_device msm_itty_mono_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_itty_mono_tx_data },
+};
+
+static struct adie_codec_action_unit itty_mono_rx_actions[] =
+	TTY_HEADSET_MONO_RX_8000_OSR_256;
+
+static struct adie_codec_hwsetting_entry itty_mono_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = itty_mono_rx_actions,
+		.action_sz = ARRAY_SIZE(itty_mono_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile itty_mono_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = itty_mono_rx_settings,
+	.setting_sz = ARRAY_SIZE(itty_mono_rx_settings),
+};
+
+static struct snddev_icodec_data snddev_itty_mono_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE | SNDDEV_CAP_TTY),
+	.name = "tty_headset_mono_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &itty_mono_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+};
+
+static struct platform_device msm_itty_mono_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_itty_mono_rx_data },
+};
+
+static struct adie_codec_action_unit linein_pri_actions[] =
+	LINEIN_PRI_STEREO_OSR_256;
+
+static struct adie_codec_hwsetting_entry linein_pri_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = linein_pri_actions,
+		.action_sz = ARRAY_SIZE(linein_pri_actions),
+	},
+};
+
+static struct adie_codec_dev_profile linein_pri_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = linein_pri_settings,
+	.setting_sz = ARRAY_SIZE(linein_pri_settings),
+};
+
+static struct snddev_icodec_data snddev_linein_pri_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "linein_pri_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &linein_pri_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+};
+
+static struct platform_device msm_linein_pri_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_linein_pri_data },
+};
+
+static struct adie_codec_action_unit auxpga_lp_lo_actions[] =
+	LB_AUXPGA_LO_STEREO;
+
+static struct adie_codec_hwsetting_entry auxpga_lp_lo_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = auxpga_lp_lo_actions,
+		.action_sz = ARRAY_SIZE(auxpga_lp_lo_actions),
+	},
+};
+
+static struct adie_codec_dev_profile auxpga_lp_lo_profile = {
+	.path_type = ADIE_CODEC_LB,
+	.settings = auxpga_lp_lo_settings,
+	.setting_sz = ARRAY_SIZE(auxpga_lp_lo_settings),
+};
+
+static struct snddev_icodec_data snddev_auxpga_lp_lo_data = {
+	.capability = SNDDEV_CAP_LB,
+	.name = "speaker_stereo_lb",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &auxpga_lp_lo_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_ANALOG,
+};
+
+static struct platform_device msm_auxpga_lp_lo_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_auxpga_lp_lo_data },
+};
+
+static struct adie_codec_action_unit auxpga_lp_hs_actions[] =
+	LB_AUXPGA_HPH_AB_CPLS_STEREO;
+
+static struct adie_codec_hwsetting_entry auxpga_lp_hs_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = auxpga_lp_hs_actions,
+		.action_sz = ARRAY_SIZE(auxpga_lp_hs_actions),
+	},
+};
+
+static struct adie_codec_dev_profile auxpga_lp_hs_profile = {
+	.path_type = ADIE_CODEC_LB,
+	.settings = auxpga_lp_hs_settings,
+	.setting_sz = ARRAY_SIZE(auxpga_lp_hs_settings),
+};
+
+static struct snddev_icodec_data snddev_auxpga_lp_hs_data = {
+	.capability = SNDDEV_CAP_LB,
+	.name = "hs_stereo_lb",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &auxpga_lp_hs_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_ANALOG,
+};
+
+static struct platform_device msm_auxpga_lp_hs_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &snddev_auxpga_lp_hs_data },
+};
+
+#ifdef CONFIG_MSM8X60_FTM_AUDIO_DEVICES
+static struct adie_codec_action_unit ftm_headset_mono_rx_actions[] =
+	HPH_PRI_AB_CPLS_MONO;
+
+static struct adie_codec_hwsetting_entry ftm_headset_mono_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_headset_mono_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_headset_mono_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_headset_mono_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_headset_mono_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_headset_mono_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_headset_mono_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_headset_mono_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_headset_mono_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_headset_mono_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_headset_mono_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_headset_mono_diff_rx_actions[] =
+	HEADSET_MONO_DIFF_RX;
+
+static struct adie_codec_hwsetting_entry ftm_headset_mono_diff_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_headset_mono_diff_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_headset_mono_diff_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_headset_mono_diff_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_headset_mono_diff_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_headset_mono_diff_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_headset_mono_diff_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_headset_mono_diff_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_headset_mono_diff_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_headset_mono_diff_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_headset_mono_diff_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_spkr_mono_rx_actions[] =
+	SPEAKER_PRI_STEREO_48000_OSR_256;
+
+static struct adie_codec_hwsetting_entry ftm_spkr_mono_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_spkr_mono_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_spkr_mono_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_spkr_mono_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_spkr_mono_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_spkr_mono_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_spkr_mono_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_spkr_mono_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_spkr_mono_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_spkr_mono_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_spkr_mono_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_spkr_l_rx_actions[] =
+	FTM_SPKR_L_RX;
+
+static struct adie_codec_hwsetting_entry ftm_spkr_l_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_spkr_l_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_spkr_l_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_spkr_l_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_spkr_l_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_spkr_l_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_spkr_l_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_spkr_l_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_spkr_l_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_spkr_l_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_spkr_l_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_spkr_r_rx_actions[] =
+	SPKR_R_RX;
+
+static struct adie_codec_hwsetting_entry ftm_spkr_r_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_spkr_r_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_spkr_r_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_spkr_r_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_spkr_r_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_spkr_r_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_spkr_r_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_spkr_r_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_spkr_r_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_spkr_r_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_spkr_r_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_spkr_mono_diff_rx_actions[] =
+	SPKR_MONO_DIFF_RX;
+
+static struct adie_codec_hwsetting_entry ftm_spkr_mono_diff_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_spkr_mono_diff_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_spkr_mono_diff_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_spkr_mono_diff_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_spkr_mono_diff_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_spkr_mono_diff_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_spkr_mono_diff_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_spkr_mono_diff_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_spkr_mono_diff_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_spkr_mono_diff_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_spkr_mono_diff_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_headset_mono_l_rx_actions[] =
+	HPH_PRI_AB_CPLS_MONO_LEFT;
+
+static struct adie_codec_hwsetting_entry ftm_headset_mono_l_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_headset_mono_l_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_headset_mono_l_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_headset_mono_l_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_headset_mono_l_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_headset_mono_l_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_headset_mono_l_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_headset_mono_l_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_headset_mono_l_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_headset_mono_l_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_headset_mono_l_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_headset_mono_r_rx_actions[] =
+	HPH_PRI_AB_CPLS_MONO_RIGHT;
+
+static struct adie_codec_hwsetting_entry ftm_headset_mono_r_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_headset_mono_r_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_headset_mono_r_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_headset_mono_r_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_headset_mono_r_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_headset_mono_r_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_headset_mono_r_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_headset_mono_r_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_headset_mono_r_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_headset_mono_r_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_headset_mono_r_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_linein_l_tx_actions[] =
+	LINEIN_MONO_L_TX;
+
+static struct adie_codec_hwsetting_entry ftm_linein_l_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_linein_l_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_linein_l_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_linein_l_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_linein_l_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_linein_l_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_linein_l_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_linein_l_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_linein_l_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_linein_l_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_linein_l_tx_data },
+};
+
+static struct adie_codec_action_unit ftm_linein_r_tx_actions[] =
+	LINEIN_MONO_R_TX;
+
+static struct adie_codec_hwsetting_entry ftm_linein_r_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_linein_r_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_linein_r_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_linein_r_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_linein_r_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_linein_r_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_linein_r_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_linein_r_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_linein_r_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_linein_r_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_linein_r_tx_data },
+};
+
+static struct adie_codec_action_unit ftm_aux_out_rx_actions[] =
+	AUX_OUT_RX;
+
+static struct adie_codec_hwsetting_entry ftm_aux_out_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_aux_out_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_aux_out_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_aux_out_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_aux_out_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_aux_out_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_aux_out_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_aux_out_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_aux_out_rx_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_aux_out_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_aux_out_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_dmic1_left_tx_actions[] =
+	DMIC1_LEFT_TX;
+
+static struct adie_codec_hwsetting_entry ftm_dmic1_left_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_dmic1_left_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_dmic1_left_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_dmic1_left_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_dmic1_left_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_dmic1_left_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_dmic1_left_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_dmic1_left_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_dmic1_left_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_dmic1_left_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_dmic1_left_tx_data},
+};
+
+static struct adie_codec_action_unit ftm_dmic1_right_tx_actions[] =
+	DMIC1_RIGHT_TX;
+
+static struct adie_codec_hwsetting_entry ftm_dmic1_right_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_dmic1_right_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_dmic1_right_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_dmic1_right_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_dmic1_right_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_dmic1_right_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_dmic1_right_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_dmic1_right_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_dmic1_right_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_dmic1_right_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_dmic1_right_tx_data},
+};
+
+static struct adie_codec_action_unit ftm_dmic1_l_and_r_tx_actions[] =
+	DMIC1_LEFT_AND_RIGHT_TX;
+
+static struct adie_codec_hwsetting_entry ftm_dmic1_l_and_r_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_dmic1_l_and_r_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_dmic1_l_and_r_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_dmic1_l_and_r_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_dmic1_l_and_r_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_dmic1_l_and_r_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_dmic1_l_and_r_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_dmic1_l_and_r_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_dmic1_l_and_r_tx_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_dmic1_l_and_r_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_dmic1_l_and_r_tx_data},
+};
+
+static struct adie_codec_action_unit ftm_dmic2_left_tx_actions[] =
+	DMIC2_LEFT_TX;
+
+static struct adie_codec_hwsetting_entry ftm_dmic2_left_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_dmic2_left_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_dmic2_left_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_dmic2_left_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_dmic2_left_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_dmic2_left_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_dmic2_left_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_dmic2_left_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_dmic2_left_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_dmic2_left_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_dmic2_left_tx_data },
+};
+
+static struct adie_codec_action_unit ftm_dmic2_right_tx_actions[] =
+	DMIC2_RIGHT_TX;
+
+static struct adie_codec_hwsetting_entry ftm_dmic2_right_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_dmic2_right_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_dmic2_right_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_dmic2_right_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_dmic2_right_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_dmic2_right_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_dmic2_right_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_dmic2_right_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_dmic2_right_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_dmic2_right_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_dmic2_right_tx_data },
+};
+
+static struct adie_codec_action_unit ftm_dmic2_l_and_r_tx_actions[] =
+	DMIC2_LEFT_AND_RIGHT_TX;
+
+static struct adie_codec_hwsetting_entry ftm_dmic2_l_and_r_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_dmic2_l_and_r_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_dmic2_l_and_r_tx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_dmic2_l_and_r_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_dmic2_l_and_r_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_dmic2_l_and_r_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_dmic2_l_and_r_tx_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_dmic2_l_and_r_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_dmic2_l_and_r_tx_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_dmic_power,
+	.pamp_off = msm_snddev_disable_dmic_power,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_dmic2_l_and_r_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_dmic2_l_and_r_tx_data},
+};
+
+static struct adie_codec_action_unit ftm_handset_mic1_aux_in_actions[] =
+	HANDSET_MIC1_AUX_IN;
+
+static struct adie_codec_hwsetting_entry ftm_handset_mic1_aux_in_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_handset_mic1_aux_in_actions,
+		.action_sz = ARRAY_SIZE(ftm_handset_mic1_aux_in_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_handset_mic1_aux_in_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_handset_mic1_aux_in_settings,
+	.setting_sz = ARRAY_SIZE(ftm_handset_mic1_aux_in_settings),
+};
+
+static struct snddev_icodec_data ftm_handset_mic1_aux_in_data = {
+	.capability = SNDDEV_CAP_TX,
+	.name = "ftm_handset_mic1_aux_in",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_handset_mic1_aux_in_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	/* Assumption is that inputs are not tied to analog mic, so
+	 * no need to enable mic bias.
+	 */
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_handset_mic1_aux_in_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_handset_mic1_aux_in_data},
+};
+
+static struct snddev_mi2s_data snddev_mi2s_sd0_rx_data = {
+	.capability = SNDDEV_CAP_RX ,
+	.name = "mi2s_sd0_rx",
+	.copp_id = MI2S_RX,
+	.channel_mode = 2, /* stereo */
+	.sd_lines = MI2S_SD0, /* sd0 */
+	.sample_rate = 48000,
+};
+
+static struct platform_device ftm_mi2s_sd0_rx_device = {
+	.name = "snddev_mi2s",
+	.dev = { .platform_data = &snddev_mi2s_sd0_rx_data },
+};
+
+static struct snddev_mi2s_data snddev_mi2s_sd1_rx_data = {
+	.capability = SNDDEV_CAP_RX ,
+	.name = "mi2s_sd1_rx",
+	.copp_id = MI2S_RX,
+	.channel_mode = 2, /* stereo */
+	.sd_lines = MI2S_SD1, /* sd1 */
+	.sample_rate = 48000,
+};
+
+static struct platform_device ftm_mi2s_sd1_rx_device = {
+	.name = "snddev_mi2s",
+	.dev = { .platform_data = &snddev_mi2s_sd1_rx_data },
+};
+
+static struct snddev_mi2s_data snddev_mi2s_sd2_rx_data = {
+	.capability = SNDDEV_CAP_RX ,
+	.name = "mi2s_sd2_rx",
+	.copp_id = MI2S_RX,
+	.channel_mode = 2, /* stereo */
+	.sd_lines = MI2S_SD2, /* sd2 */
+	.sample_rate = 48000,
+};
+
+static struct platform_device ftm_mi2s_sd2_rx_device = {
+	.name = "snddev_mi2s",
+	.dev = { .platform_data = &snddev_mi2s_sd2_rx_data },
+};
+
+/* earpiece */
+static struct adie_codec_action_unit ftm_handset_adie_lp_rx_actions[] =
+	EAR_PRI_MONO_LB;
+
+static struct adie_codec_hwsetting_entry ftm_handset_adie_lp_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_handset_adie_lp_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_handset_adie_lp_rx_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ftm_handset_adie_lp_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_handset_adie_lp_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_handset_adie_lp_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_handset_adie_lp_rx_data = {
+	.capability = (SNDDEV_CAP_RX | SNDDEV_CAP_VOICE),
+	.name = "ftm_handset_adie_lp_rx",
+	.copp_id = 0,
+	.profile = &ftm_handset_adie_lp_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_handset_adie_lp_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_handset_adie_lp_rx_data },
+};
+
+static struct adie_codec_action_unit ftm_headset_l_adie_lp_rx_actions[] =
+	FTM_HPH_PRI_AB_CPLS_MONO_LB_LEFT;
+
+static struct adie_codec_hwsetting_entry ftm_headset_l_adie_lp_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_headset_l_adie_lp_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_headset_l_adie_lp_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_headset_l_adie_lp_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_headset_l_adie_lp_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_headset_l_adie_lp_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_headset_l_adie_lp_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_headset_l_adie_lp_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_headset_l_adie_lp_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_headset_l_adie_lp_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_headset_l_adie_lp_rx_data },
+};
+
+static struct adie_codec_action_unit ftm_headset_r_adie_lp_rx_actions[] =
+	FTM_HPH_PRI_AB_CPLS_MONO_LB_RIGHT;
+
+static struct adie_codec_hwsetting_entry ftm_headset_r_adie_lp_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_headset_r_adie_lp_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_headset_r_adie_lp_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_headset_r_adie_lp_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_headset_r_adie_lp_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_headset_r_adie_lp_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_headset_r_adie_lp_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_headset_r_adie_lp_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_headset_r_adie_lp_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.voltage_on = msm_snddev_voltage_on,
+	.voltage_off = msm_snddev_voltage_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_headset_r_adie_lp_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_headset_r_adie_lp_rx_data },
+};
+
+static struct adie_codec_action_unit ftm_spkr_l_rx_lp_actions[] =
+	FTM_SPKR_L_RX;
+
+static struct adie_codec_hwsetting_entry ftm_spkr_l_rx_lp_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_spkr_l_rx_lp_actions,
+		.action_sz = ARRAY_SIZE(ftm_spkr_l_rx_lp_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_spkr_l_rx_lp_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_spkr_l_rx_lp_settings,
+	.setting_sz = ARRAY_SIZE(ftm_spkr_l_rx_lp_settings),
+};
+
+static struct snddev_icodec_data ftm_spkr_l_rx_lp_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_spk_l_adie_lp_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_spkr_l_rx_lp_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_spk_l_adie_lp_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_spkr_l_rx_lp_data},
+};
+
+static struct adie_codec_action_unit ftm_spkr_r_adie_lp_rx_actions[] =
+	FTM_SPKR_RX_LB;
+
+static struct adie_codec_hwsetting_entry ftm_spkr_r_adie_lp_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_spkr_r_adie_lp_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_spkr_r_adie_lp_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_spkr_r_adie_lp_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_spkr_r_adie_lp_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_spkr_r_adie_lp_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_spkr_r_adie_lp_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_spk_r_adie_lp_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_spkr_r_adie_lp_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_spk_r_adie_lp_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_spkr_r_adie_lp_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_spkr_adie_lp_rx_actions[] =
+	FTM_SPKR_RX_LB;
+
+static struct adie_codec_hwsetting_entry ftm_spkr_adie_lp_rx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_spkr_adie_lp_rx_actions,
+		.action_sz = ARRAY_SIZE(ftm_spkr_adie_lp_rx_actions),
+	},
+};
+
+static struct adie_codec_dev_profile ftm_spkr_adie_lp_rx_profile = {
+	.path_type = ADIE_CODEC_RX,
+	.settings = ftm_spkr_adie_lp_rx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_spkr_adie_lp_rx_settings),
+};
+
+static struct snddev_icodec_data ftm_spkr_adie_lp_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "ftm_spk_adie_lp_rx",
+	.copp_id = PRIMARY_I2S_RX,
+	.profile = &ftm_spkr_adie_lp_rx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_poweramp_on,
+	.pamp_off = msm_snddev_poweramp_off,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_spk_adie_lp_rx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_spkr_adie_lp_rx_data},
+};
+
+static struct adie_codec_action_unit ftm_handset_dual_tx_lp_actions[] =
+	FTM_AMIC_DUAL_HANDSET_TX_LB;
+
+static struct adie_codec_hwsetting_entry ftm_handset_dual_tx_lp_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_handset_dual_tx_lp_actions,
+		.action_sz = ARRAY_SIZE(ftm_handset_dual_tx_lp_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ftm_handset_dual_tx_lp_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_handset_dual_tx_lp_settings,
+	.setting_sz = ARRAY_SIZE(ftm_handset_dual_tx_lp_settings),
+};
+
+static struct snddev_icodec_data ftm_handset_dual_tx_lp_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "handset_mic1_handset_mic2",
+	.copp_id = 1,
+	.profile = &ftm_handset_dual_tx_lp_profile,
+	.channel_mode = 2,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_amic_power,
+	.pamp_off = msm_snddev_disable_amic_power,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_handset_dual_tx_lp_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_handset_dual_tx_lp_data },
+};
+
+static struct adie_codec_action_unit ftm_handset_mic_adie_lp_tx_actions[] =
+	FTM_HANDSET_LB_TX;
+
+static struct adie_codec_hwsetting_entry
+	ftm_handset_mic_adie_lp_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_handset_mic_adie_lp_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_handset_mic_adie_lp_tx_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ftm_handset_mic_adie_lp_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_handset_mic_adie_lp_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_handset_mic_adie_lp_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_handset_mic_adie_lp_tx_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "ftm_handset_mic_adie_lp_tx",
+	.copp_id = 1,
+	.profile = &ftm_handset_mic_adie_lp_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.pamp_on = msm_snddev_enable_amic_power,
+	.pamp_off = msm_snddev_disable_amic_power,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_handset_mic_adie_lp_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_handset_mic_adie_lp_tx_data },
+};
+
+static struct adie_codec_action_unit ftm_headset_mic_adie_lp_tx_actions[] =
+	FTM_HEADSET_LB_TX;
+
+static struct adie_codec_hwsetting_entry
+			ftm_headset_mic_adie_lp_tx_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions = ftm_headset_mic_adie_lp_tx_actions,
+		.action_sz = ARRAY_SIZE(ftm_headset_mic_adie_lp_tx_actions),
+	}
+};
+
+static struct adie_codec_dev_profile ftm_headset_mic_adie_lp_tx_profile = {
+	.path_type = ADIE_CODEC_TX,
+	.settings = ftm_headset_mic_adie_lp_tx_settings,
+	.setting_sz = ARRAY_SIZE(ftm_headset_mic_adie_lp_tx_settings),
+};
+
+static struct snddev_icodec_data ftm_headset_mic_adie_lp_tx_data = {
+	.capability = (SNDDEV_CAP_TX | SNDDEV_CAP_VOICE),
+	.name = "ftm_headset_mic_adie_lp_tx",
+	.copp_id = PRIMARY_I2S_TX,
+	.profile = &ftm_headset_mic_adie_lp_tx_profile,
+	.channel_mode = 1,
+	.default_sample_rate = 48000,
+	.dev_vol_type = SNDDEV_DEV_VOL_DIGITAL,
+};
+
+static struct platform_device ftm_headset_mic_adie_lp_tx_device = {
+	.name = "snddev_icodec",
+	.dev = { .platform_data = &ftm_headset_mic_adie_lp_tx_data },
+};
+#endif /* CONFIG_MSM8X60_FTM_AUDIO_DEVICES */
+
+static struct snddev_virtual_data snddev_uplink_rx_data = {
+	.capability = SNDDEV_CAP_RX,
+	.name = "uplink_rx",
+	.copp_id = VOICE_PLAYBACK_TX,
+};
+
+static struct platform_device msm_uplink_rx_device = {
+	.name = "snddev_virtual",
+	.dev = { .platform_data = &snddev_uplink_rx_data },
+};
+
+static struct snddev_hdmi_data snddev_hdmi_non_linear_pcm_rx_data = {
+	.capability = SNDDEV_CAP_RX ,
+	.name = "hdmi_pass_through",
+	.default_sample_rate = 48000,
+	.on_apps = 1,
+};
+
+static struct platform_device msm_snddev_hdmi_non_linear_pcm_rx_device = {
+	.name = "snddev_hdmi",
+	.dev = { .platform_data = &snddev_hdmi_non_linear_pcm_rx_data },
+};
+
+
+#ifdef CONFIG_DEBUG_FS
+static struct adie_codec_action_unit
+	ihs_stereo_rx_class_d_legacy_48KHz_osr256_actions[] =
+	HPH_PRI_D_LEG_STEREO;
+
+static struct adie_codec_hwsetting_entry
+	ihs_stereo_rx_class_d_legacy_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions =
+		ihs_stereo_rx_class_d_legacy_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE
+		(ihs_stereo_rx_class_d_legacy_48KHz_osr256_actions),
+	}
+};
+
+static struct adie_codec_action_unit
+	ihs_stereo_rx_class_ab_legacy_48KHz_osr256_actions[] =
+	HPH_PRI_AB_LEG_STEREO;
+
+static struct adie_codec_hwsetting_entry
+	ihs_stereo_rx_class_ab_legacy_settings[] = {
+	{
+		.freq_plan = 48000,
+		.osr = 256,
+		.actions =
+		ihs_stereo_rx_class_ab_legacy_48KHz_osr256_actions,
+		.action_sz = ARRAY_SIZE
+		(ihs_stereo_rx_class_ab_legacy_48KHz_osr256_actions),
+	}
+};
+
+static void snddev_hsed_config_modify_setting(int type)
+{
+	struct platform_device *device;
+	struct snddev_icodec_data *icodec_data;
+
+	device = &msm_headset_stereo_device;
+	icodec_data = (struct snddev_icodec_data *)device->dev.platform_data;
+
+	if (icodec_data) {
+		if (type == 1) {
+			icodec_data->voltage_on = NULL;
+			icodec_data->voltage_off = NULL;
+			icodec_data->profile->settings =
+				ihs_stereo_rx_class_d_legacy_settings;
+			icodec_data->profile->setting_sz =
+			ARRAY_SIZE(ihs_stereo_rx_class_d_legacy_settings);
+		} else if (type == 2) {
+			icodec_data->voltage_on = NULL;
+			icodec_data->voltage_off = NULL;
+			icodec_data->profile->settings =
+				ihs_stereo_rx_class_ab_legacy_settings;
+			icodec_data->profile->setting_sz =
+			ARRAY_SIZE(ihs_stereo_rx_class_ab_legacy_settings);
+		}
+	}
+}
+
+static void snddev_hsed_config_restore_setting(void)
+{
+	struct platform_device *device;
+	struct snddev_icodec_data *icodec_data;
+
+	device = &msm_headset_stereo_device;
+	icodec_data = (struct snddev_icodec_data *)device->dev.platform_data;
+
+	if (icodec_data) {
+		icodec_data->voltage_on = msm_snddev_voltage_on;
+		icodec_data->voltage_off = msm_snddev_voltage_off;
+		icodec_data->profile->settings = headset_ab_cpls_settings;
+		icodec_data->profile->setting_sz =
+			ARRAY_SIZE(headset_ab_cpls_settings);
+	}
+}
+
+static ssize_t snddev_hsed_config_debug_write(struct file *filp,
+	const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+	char *lb_str = filp->private_data;
+	char cmd;
+
+	if (get_user(cmd, ubuf))
+		return -EFAULT;
+
+	if (!strcmp(lb_str, "msm_hsed_config")) {
+		switch (cmd) {
+		case '0':
+			snddev_hsed_config_restore_setting();
+			break;
+
+		case '1':
+			snddev_hsed_config_modify_setting(1);
+			break;
+
+		case '2':
+			snddev_hsed_config_modify_setting(2);
+			break;
+
+		default:
+			break;
+		}
+	}
+	return cnt;
+}
+
+static int snddev_hsed_config_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static const struct file_operations snddev_hsed_config_debug_fops = {
+	.open = snddev_hsed_config_debug_open,
+	.write = snddev_hsed_config_debug_write
+};
+#endif
+
+static struct platform_device *snd_devices_ffa[] __initdata = {
+	&msm_iearpiece_ffa_device,
+	&msm_imic_ffa_device,
+	&msm_ispkr_stereo_device,
+	&msm_snddev_hdmi_stereo_rx_device,
+	&msm_headset_mic_device,
+	&msm_ispkr_mic_device,
+	&msm_bt_sco_earpiece_device,
+	&msm_bt_sco_mic_device,
+	&msm_headset_stereo_device,
+	&msm_itty_mono_tx_device,
+	&msm_itty_mono_rx_device,
+	&msm_mi2s_fm_tx_device,
+	&msm_mi2s_fm_rx_device,
+	&msm_hs_dual_mic_endfire_device,
+	&msm_spkr_dual_mic_endfire_device,
+	&msm_hs_dual_mic_broadside_device,
+	&msm_spkr_dual_mic_broadside_device,
+	&msm_ihs_stereo_speaker_stereo_rx_device,
+	&msm_anc_headset_device,
+	&msm_auxpga_lp_hs_device,
+	&msm_auxpga_lp_lo_device,
+	&msm_linein_pri_device,
+	&msm_icodec_gpio_device,
+	&msm_snddev_hdmi_non_linear_pcm_rx_device,
+};
+
+static struct platform_device *snd_devices_surf[] __initdata = {
+	&msm_iearpiece_device,
+	&msm_imic_device,
+	&msm_ispkr_stereo_device,
+	&msm_snddev_hdmi_stereo_rx_device,
+	&msm_headset_mic_device,
+	&msm_ispkr_mic_device,
+	&msm_bt_sco_earpiece_device,
+	&msm_bt_sco_mic_device,
+	&msm_headset_stereo_device,
+	&msm_itty_mono_tx_device,
+	&msm_itty_mono_rx_device,
+	&msm_mi2s_fm_tx_device,
+	&msm_mi2s_fm_rx_device,
+	&msm_ihs_stereo_speaker_stereo_rx_device,
+	&msm_auxpga_lp_hs_device,
+	&msm_auxpga_lp_lo_device,
+	&msm_linein_pri_device,
+	&msm_icodec_gpio_device,
+	&msm_snddev_hdmi_non_linear_pcm_rx_device,
+};
+
+static struct platform_device *snd_devices_fluid[] __initdata = {
+	&msm_iearpiece_device,
+	&msm_imic_device,
+	&msm_ispkr_stereo_device,
+	&msm_snddev_hdmi_stereo_rx_device,
+	&msm_headset_stereo_device,
+	&msm_headset_mic_device,
+	&msm_fluid_ispkr_mic_device,
+	&msm_bt_sco_earpiece_device,
+	&msm_bt_sco_mic_device,
+	&msm_mi2s_fm_tx_device,
+	&msm_mi2s_fm_rx_device,
+	&msm_anc_headset_device,
+	&msm_auxpga_lp_hs_device,
+	&msm_auxpga_lp_lo_device,
+	&msm_icodec_gpio_device,
+	&msm_snddev_hdmi_non_linear_pcm_rx_device,
+};
+
+static struct platform_device *snd_devices_common[] __initdata = {
+	&msm_aux_pcm_device,
+	&msm_cdcclk_ctl_device,
+	&msm_mi2s_device,
+	&msm_uplink_rx_device,
+};
+
+#ifdef CONFIG_MSM8X60_FTM_AUDIO_DEVICES
+static struct platform_device *snd_devices_ftm[] __initdata = {
+	&ftm_headset_mono_rx_device,
+	&ftm_headset_mono_l_rx_device,
+	&ftm_headset_mono_r_rx_device,
+	&ftm_headset_mono_diff_rx_device,
+	&ftm_spkr_mono_rx_device,
+	&ftm_spkr_l_rx_device,
+	&ftm_spkr_r_rx_device,
+	&ftm_spkr_mono_diff_rx_device,
+	&ftm_linein_l_tx_device,
+	&ftm_linein_r_tx_device,
+	&ftm_aux_out_rx_device,
+	&ftm_dmic1_left_tx_device,
+	&ftm_dmic1_right_tx_device,
+	&ftm_dmic1_l_and_r_tx_device,
+	&ftm_dmic2_left_tx_device,
+	&ftm_dmic2_right_tx_device,
+	&ftm_dmic2_l_and_r_tx_device,
+	&ftm_handset_mic1_aux_in_device,
+	&ftm_mi2s_sd0_rx_device,
+	&ftm_mi2s_sd1_rx_device,
+	&ftm_mi2s_sd2_rx_device,
+	&ftm_handset_mic_adie_lp_tx_device,
+	&ftm_headset_mic_adie_lp_tx_device,
+	&ftm_handset_adie_lp_rx_device,
+	&ftm_headset_l_adie_lp_rx_device,
+	&ftm_headset_r_adie_lp_rx_device,
+	&ftm_spk_l_adie_lp_rx_device,
+	&ftm_spk_r_adie_lp_rx_device,
+	&ftm_spk_adie_lp_rx_device,
+	&ftm_handset_dual_tx_lp_device,
+};
+#else
+static struct platform_device *snd_devices_ftm[] __initdata = {};
+#endif
+
+
+void __init msm_snddev_init(void)
+{
+	int i;
+	int dev_id;
+
+	atomic_set(&pamp_ref_cnt, 0);
+	atomic_set(&preg_ref_cnt, 0);
+
+	for (i = 0, dev_id = 0; i < ARRAY_SIZE(snd_devices_common); i++)
+		snd_devices_common[i]->id = dev_id++;
+
+	platform_add_devices(snd_devices_common,
+		ARRAY_SIZE(snd_devices_common));
+
+	/* Auto detect device base on machine info */
+	if (machine_is_msm8x60_surf() || machine_is_msm8x60_fusion()) {
+		for (i = 0; i < ARRAY_SIZE(snd_devices_surf); i++)
+			snd_devices_surf[i]->id = dev_id++;
+
+		platform_add_devices(snd_devices_surf,
+		ARRAY_SIZE(snd_devices_surf));
+	} else if (machine_is_msm8x60_ffa() ||
+			machine_is_msm8x60_fusn_ffa()) {
+		for (i = 0; i < ARRAY_SIZE(snd_devices_ffa); i++)
+			snd_devices_ffa[i]->id = dev_id++;
+
+		platform_add_devices(snd_devices_ffa,
+		ARRAY_SIZE(snd_devices_ffa));
+	} else if (machine_is_msm8x60_fluid()) {
+		for (i = 0; i < ARRAY_SIZE(snd_devices_fluid); i++)
+			snd_devices_fluid[i]->id = dev_id++;
+
+		platform_add_devices(snd_devices_fluid,
+		ARRAY_SIZE(snd_devices_fluid));
+	} else if (machine_is_msm8x60_surf()) {
+		for (i = 0; i < ARRAY_SIZE(snd_devices_ftm); i++)
+			snd_devices_ftm[i]->id = dev_id++;
+
+		platform_add_devices(snd_devices_ftm,
+				ARRAY_SIZE(snd_devices_ftm));
+	}
+
+#ifdef CONFIG_DEBUG_FS
+	debugfs_hsed_config = debugfs_create_file("msm_hsed_config",
+				S_IFREG | S_IRUGO, NULL,
+		(void *) "msm_hsed_config", &snddev_hsed_config_debug_fops);
+#endif
+}
diff --git a/arch/arm/mach-msm/qdsp6v2/dsp_debug.c b/arch/arm/mach-msm/qdsp6v2/dsp_debug.c
new file mode 100644
index 0000000..4382c23
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/dsp_debug.c
@@ -0,0 +1,224 @@
+/* arch/arm/mach-msm/qdsp6/dsp_dump.c
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <asm/atomic.h>
+
+#include "../proc_comm.h"
+#include <mach/debug_mm.h>
+#include <mach/msm_subsystem_map.h>
+#include <mach/qdsp6v2/dsp_debug.h>
+
+static wait_queue_head_t dsp_wait;
+static int dsp_has_crashed;
+static int dsp_wait_count;
+
+static atomic_t dsp_crash_count = ATOMIC_INIT(0);
+dsp_state_cb cb_ptr;
+
+void q6audio_dsp_not_responding(void)
+{
+	if (cb_ptr)
+		cb_ptr(DSP_STATE_CRASHED);
+	if (atomic_add_return(1, &dsp_crash_count) != 1) {
+		pr_err("q6audio_dsp_not_responding() \
+			- parking additional crasher...\n");
+		for (;;)
+			msleep(1000);
+	}
+	if (dsp_wait_count) {
+		dsp_has_crashed = 1;
+		wake_up(&dsp_wait);
+
+		while (dsp_has_crashed != 2)
+			wait_event(dsp_wait, dsp_has_crashed == 2);
+	} else {
+		pr_err("q6audio_dsp_not_responding() - no waiter?\n");
+	}
+	if (cb_ptr)
+		cb_ptr(DSP_STATE_CRASH_DUMP_DONE);
+
+	BUG();
+}
+
+static int dsp_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+#define DSP_NMI_ADDR 0x28800010
+
+static ssize_t dsp_write(struct file *file, const char __user *buf,
+			 size_t count, loff_t *pos)
+{
+	char cmd[32];
+	void __iomem *ptr;
+	unsigned int flags = MSM_SUBSYSTEM_MAP_KADDR | MSM_SUBSYSTEM_MAP_CACHED;
+	struct msm_mapped_buffer *mem_buffer;
+
+	if (count >= sizeof(cmd))
+		return -EINVAL;
+	if (copy_from_user(cmd, buf, count))
+		return -EFAULT;
+	cmd[count] = 0;
+
+	if ((count > 1) && (cmd[count-1] == '\n'))
+		cmd[count-1] = 0;
+
+	if (!strcmp(cmd, "wait-for-crash")) {
+		while (!dsp_has_crashed) {
+			int res;
+			dsp_wait_count++;
+			res = wait_event_interruptible(dsp_wait,
+							dsp_has_crashed);
+			if (res < 0) {
+				dsp_wait_count--;
+				return res;
+			}
+		}
+		/* assert DSP NMI */
+		mem_buffer = msm_subsystem_map_buffer(DSP_NMI_ADDR, 0x16, flags,
+							NULL, 0);
+		if (IS_ERR((void *)mem_buffer)) {
+			pr_err("%s:map_buffer failed, error = %ld\n", __func__,
+				   PTR_ERR((void *)mem_buffer));
+			return -ENOMEM;
+		}
+		ptr = mem_buffer->vaddr;
+		if (!ptr) {
+			pr_err("Unable to map DSP NMI\n");
+			return -EFAULT;
+		}
+		writel(0x1, (void *)ptr);
+		if (msm_subsystem_unmap_buffer(mem_buffer) < 0)
+			pr_err("%s:unmap buffer failed\n", __func__);
+	} else if (!strcmp(cmd, "boom")) {
+		q6audio_dsp_not_responding();
+	} else if (!strcmp(cmd, "continue-crash")) {
+		dsp_has_crashed = 2;
+		wake_up(&dsp_wait);
+	} else {
+		pr_err("[%s:%s] unknown dsp_debug command: %s\n", __MM_FILE__,
+				__func__, cmd);
+	}
+
+	return count;
+}
+
+#define DSP_RAM_BASE 0x46700000
+#define DSP_RAM_SIZE 0x2000000
+
+static unsigned copy_ok_count;
+
+static ssize_t dsp_read(struct file *file, char __user *buf,
+			size_t count, loff_t *pos)
+{
+	size_t actual = 0;
+	size_t mapsize = PAGE_SIZE;
+	unsigned addr;
+	void __iomem *ptr;
+	unsigned int flags = MSM_SUBSYSTEM_MAP_KADDR | MSM_SUBSYSTEM_MAP_CACHED;
+	struct msm_mapped_buffer *mem_buffer;
+
+	if (*pos >= DSP_RAM_SIZE)
+		return 0;
+
+	if (*pos & (PAGE_SIZE - 1))
+		return -EINVAL;
+
+	addr = (*pos + DSP_RAM_BASE);
+
+	/* don't blow up if we're unaligned */
+	if (addr & (PAGE_SIZE - 1))
+		mapsize *= 2;
+
+	while (count >= PAGE_SIZE) {
+		mem_buffer = msm_subsystem_map_buffer(addr, mapsize, flags,
+							NULL, 0);
+		if (IS_ERR((void *)mem_buffer)) {
+			pr_err("%s:map_buffer failed, error = %ld\n",
+				__func__, PTR_ERR((void *)mem_buffer));
+			return -ENOMEM;
+		}
+		ptr = mem_buffer->vaddr;
+		if (!ptr) {
+			pr_err("[%s:%s] map error @ %x\n", __MM_FILE__,
+					__func__, addr);
+			return -EFAULT;
+		}
+		if (copy_to_user(buf, ptr, PAGE_SIZE)) {
+			if (msm_subsystem_unmap_buffer(mem_buffer) < 0)
+				pr_err("%s: unmap buffer failed\n", __func__);
+			pr_err("[%s:%s] copy error @ %p\n", __MM_FILE__,
+					__func__, buf);
+			return -EFAULT;
+		}
+		copy_ok_count += PAGE_SIZE;
+		if (msm_subsystem_unmap_buffer(mem_buffer) < 0)
+			pr_err("%s: unmap buffer failed\n", __func__);
+		addr += PAGE_SIZE;
+		buf += PAGE_SIZE;
+		actual += PAGE_SIZE;
+		count -= PAGE_SIZE;
+	}
+
+	*pos += actual;
+	return actual;
+}
+
+static int dsp_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+int dsp_debug_register(dsp_state_cb ptr)
+{
+	if (ptr == NULL)
+		return -EINVAL;
+	cb_ptr = ptr;
+
+	return 0;
+}
+
+static const struct file_operations dsp_fops = {
+	.owner		= THIS_MODULE,
+	.open		= dsp_open,
+	.read		= dsp_read,
+	.write		= dsp_write,
+	.release	= dsp_release,
+};
+
+static struct miscdevice dsp_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "dsp_debug",
+	.fops	= &dsp_fops,
+};
+
+
+static int __init dsp_init(void)
+{
+	init_waitqueue_head(&dsp_wait);
+	return misc_register(&dsp_misc);
+}
+
+device_initcall(dsp_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/evrc_in.c b/arch/arm/mach-msm/qdsp6v2/evrc_in.c
new file mode 100644
index 0000000..0f56620
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/evrc_in.c
@@ -0,0 +1,332 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_qcp.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <sound/q6asm.h>
+#include <sound/apr_audio.h>
+#include "audio_utils.h"
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE		(4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE		(1 + ((23+sizeof(struct meta_out_dsp)) * 10))
+
+void q6asm_evrc_in_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv)
+{
+	struct q6audio_in * audio = (struct q6audio_in *)priv;
+	unsigned long flags;
+
+	pr_debug("%s:session id %d: opcode - %d\n", __func__,
+			audio->ac->session, opcode);
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	switch (opcode) {
+	case ASM_DATA_EVENT_READ_DONE:
+		audio_in_get_dsp_frames(audio, token, payload);
+		break;
+	case ASM_DATA_EVENT_WRITE_DONE:
+		atomic_inc(&audio->in_count);
+		wake_up(&audio->write_wait);
+		break;
+	case ASM_DATA_CMDRSP_EOS:
+		audio->eos_rsp = 1;
+		wake_up(&audio->read_wait);
+		break;
+	case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
+		break;
+	case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
+		break;
+	case ASM_SESSION_EVENT_TX_OVERFLOW:
+		pr_err("%s:session id %d: ASM_SESSION_EVENT_TX_OVERFLOW\n",
+				__func__, audio->ac->session);
+		break;
+	default:
+		pr_err("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
+				audio->ac->session, opcode);
+		break;
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+
+/* ------------------- device --------------------- */
+static long evrc_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_in  *audio = file->private_data;
+	int rc = 0;
+	int cnt = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		struct msm_audio_evrc_enc_config *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+				audio->ac->session, audio->buf_alloc);
+		if (audio->enabled == 1) {
+			pr_info("%s:AUDIO_START already over\n", __func__);
+			rc = 0;
+			break;
+		}
+		rc = audio_in_buf_alloc(audio);
+		if (rc < 0) {
+			pr_err("%s:session id %d: buffer allocation failed\n",
+				__func__, audio->ac->session);
+			break;
+		}
+
+		/* rate_modulation_cmd set to zero
+			 currently not configurable from user space */
+		rc = q6asm_enc_cfg_blk_evrc(audio->ac,
+			audio->buf_cfg.frames_per_buf,
+			enc_cfg->min_bit_rate,
+			enc_cfg->max_bit_rate, 0);
+
+		if (rc < 0) {
+			pr_err("%s:session id %d: cmd evrc media format block\
+				failed\n", __func__, audio->ac->session);
+			break;
+		}
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			rc = q6asm_media_format_block_pcm(audio->ac,
+				audio->pcm_cfg.sample_rate,
+				audio->pcm_cfg.channel_count);
+
+			if (rc < 0) {
+				pr_err("%s:session id %d: media format block\
+				failed\n", __func__, audio->ac->session);
+				break;
+			}
+		}
+		pr_debug("%s:session id %d: AUDIO_START enable[%d]\n",
+				__func__, audio->ac->session, audio->enabled);
+		rc = audio_in_enable(audio);
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("%s:session id %d: Audio Start procedure failed\
+				rc=%d\n", __func__, audio->ac->session, rc);
+			break;
+		}
+		while (cnt++ < audio->str_cfg.buffer_count)
+			q6asm_read(audio->ac); /* Push buffer to DSP */
+		rc = 0;
+		pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+				__func__, audio->ac->session, audio->enabled);
+		break;
+	}
+	case AUDIO_STOP: {
+		pr_debug("%s:session id %d: AUDIO_STOP\n", __func__,
+				audio->ac->session);
+		rc = audio_in_disable(audio);
+		if (rc  < 0) {
+			pr_err("%s:session id %d: Audio Stop procedure failed\
+				rc=%d\n", __func__, audio->ac->session, rc);
+			break;
+		}
+		break;
+	}
+	case AUDIO_GET_EVRC_ENC_CONFIG: {
+		if (copy_to_user((void *)arg, audio->enc_cfg,
+			sizeof(struct msm_audio_evrc_enc_config)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_EVRC_ENC_CONFIG: {
+		struct msm_audio_evrc_enc_config cfg;
+		struct msm_audio_evrc_enc_config *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+
+		if (copy_from_user(&cfg, (void *) arg,
+				sizeof(struct msm_audio_evrc_enc_config))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		if (cfg.min_bit_rate > 4 ||
+			 cfg.min_bit_rate < 1 ||
+			 (cfg.min_bit_rate == 2)) {
+			pr_err("%s:session id %d: invalid min bitrate\n",
+					__func__, audio->ac->session);
+			rc = -EINVAL;
+			break;
+		}
+		if (cfg.max_bit_rate > 4 ||
+			 cfg.max_bit_rate < 1 ||
+			 (cfg.max_bit_rate == 2)) {
+			pr_err("%s:session id %d: invalid max bitrate\n",
+				__func__, audio->ac->session);
+			rc = -EINVAL;
+			break;
+		}
+		enc_cfg->min_bit_rate = cfg.min_bit_rate;
+		enc_cfg->max_bit_rate = cfg.max_bit_rate;
+		pr_debug("%s:session id %d: min_bit_rate= 0x%x\
+			max_bit_rate=0x%x\n", __func__,
+			audio->ac->session, enc_cfg->min_bit_rate,
+			enc_cfg->max_bit_rate);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int evrc_in_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_in *audio = NULL;
+	struct msm_audio_evrc_enc_config *enc_cfg;
+	int rc = 0;
+
+	audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("%s:session id %d: Could not allocate memory for evrc\
+				driver\n", __func__, audio->ac->session);
+		return -ENOMEM;
+	}
+	/* Allocate memory for encoder config param */
+	audio->enc_cfg = kzalloc(sizeof(struct msm_audio_evrc_enc_config),
+				GFP_KERNEL);
+	if (audio->enc_cfg == NULL) {
+		pr_err("%s:session id %d: Could not allocate memory for aac\
+				config param\n", __func__, audio->ac->session);
+		kfree(audio);
+		return -ENOMEM;
+	}
+	enc_cfg = audio->enc_cfg;
+	mutex_init(&audio->lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->write_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->read_wait);
+	init_waitqueue_head(&audio->write_wait);
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	* but at least we need to have initial config
+	*/
+	audio->str_cfg.buffer_size = FRAME_SIZE;
+	audio->str_cfg.buffer_count = FRAME_NUM;
+	audio->min_frame_size = 23;
+	audio->max_frames_per_buf = 10;
+	audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+	audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+	enc_cfg->min_bit_rate = 4;
+	enc_cfg->max_bit_rate = 4;
+	audio->pcm_cfg.channel_count = 1;
+	audio->pcm_cfg.sample_rate = 8000;
+	audio->buf_cfg.meta_info_enable = 0x01;
+	audio->buf_cfg.frames_per_buf = 0x01;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_evrc_in_cb,
+				(void *)audio);
+
+	if (!audio->ac) {
+		pr_err("%s:session id %d: Could not allocate memory for audio\
+				client\n", __func__, audio->ac->session);
+		kfree(audio->enc_cfg);
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	/* open evrc encoder in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) &&
+		(file->f_mode & FMODE_READ)) {
+		audio->feedback = NON_TUNNEL_MODE;
+		rc = q6asm_open_read_write(audio->ac, FORMAT_EVRC,
+					FORMAT_LINEAR_PCM);
+		if (rc < 0) {
+			pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
+					__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		pr_info("%s:session id %d: NT mode encoder success\n",
+				__func__, audio->ac->session);
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+				(file->f_mode & FMODE_READ)) {
+		audio->feedback = TUNNEL_MODE;
+		rc = q6asm_open_read(audio->ac, FORMAT_EVRC);
+		if (rc < 0) {
+			pr_err("%s:session id %d: T mode Open failed rc=%d\n",
+					__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		/* register for tx overflow (valid for tunnel mode only) */
+		rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+		if (rc < 0) {
+			pr_err("%s:session id %d: TX Overflow registration\
+				failed rc=%d\n", __func__,
+				audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		pr_info("%s:session id %d: T mode encoder success\n", __func__,
+				audio->ac->session);
+	} else {
+		pr_err("%s:session id %d: Unexpected mode\n", __func__,
+				audio->ac->session);
+		rc = -EACCES;
+		goto fail;
+	}
+
+	audio->opened = 1;
+	atomic_set(&audio->in_count, PCM_BUF_COUNT);
+	atomic_set(&audio->out_count, 0x00);
+	audio->enc_ioctl = evrc_in_ioctl;
+	file->private_data = audio;
+
+	pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio->enc_cfg);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= evrc_in_open,
+	.release	= audio_in_release,
+	.read		= audio_in_read,
+	.write		= audio_in_write,
+	.unlocked_ioctl	= audio_in_ioctl,
+};
+
+struct miscdevice audio_evrc_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_evrc_in",
+	.fops	= &audio_in_fops,
+};
+
+static int __init evrc_in_init(void)
+{
+	return misc_register(&audio_evrc_in_misc);
+}
+
+device_initcall(evrc_in_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/fm.c b/arch/arm/mach-msm/qdsp6v2/fm.c
new file mode 100644
index 0000000..9cf2723
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/fm.c
@@ -0,0 +1,262 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * Based on the mp3 native driver in arch/arm/mach-msm/qdsp5v2/audio_mp3.c
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ *
+ * All source code in this file is licensed under the following license except
+ * where indicated.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+#include <linux/kthread.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/android_pmem.h>
+#include <linux/msm_audio.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <mach/msm_adsp.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <sound/q6afe.h>
+
+#define SESSION_ID_FM  (MAX_SESSIONS + 1)
+#define FM_ENABLE	0x1
+#define FM_DISABLE	0x0
+#define FM_COPP		0x7
+
+struct audio {
+	struct mutex lock;
+
+	int opened;
+	int enabled;
+	int running;
+
+	uint16_t fm_source;
+	uint16_t fm_src_copp_id;
+	uint16_t fm_dest;
+	uint16_t fm_dst_copp_id;
+	uint16_t dec_id;
+	uint32_t device_events;
+	uint16_t volume;
+};
+
+
+static struct audio fm_audio;
+static int fm_audio_enable(struct audio *audio)
+{
+	if (audio->enabled)
+		return 0;
+
+	pr_info("%s: fm dest= %08x fm_source = %08x\n", __func__,
+		audio->fm_dst_copp_id, audio->fm_src_copp_id);
+
+	/* do afe loopback here */
+
+	if (audio->fm_dest && audio->fm_source) {
+		if (afe_loopback(FM_ENABLE, audio->fm_dst_copp_id,
+					audio->fm_src_copp_id) < 0) {
+			pr_err("%s: afe_loopback failed\n", __func__);
+		}
+
+		audio->running = 1;
+	}
+
+	audio->enabled = 1;
+	return 0;
+}
+
+static void fm_audio_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct audio *audio = (struct audio *) private_data;
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		pr_info("%s :AUDDEV_EVT_DEV_RDY\n", __func__);
+		if (evt_payload->routing_id == FM_COPP) {
+			audio->fm_source = 1;
+			audio->fm_src_copp_id = FM_COPP;
+		} else {
+			audio->fm_dest = 1;
+			audio->fm_dst_copp_id = evt_payload->routing_id;
+		}
+
+		if (audio->enabled &&
+			audio->fm_dest &&
+			audio->fm_source) {
+
+			afe_loopback_gain(audio->fm_src_copp_id,
+						audio->volume);
+			afe_loopback(FM_ENABLE, audio->fm_dst_copp_id,
+						audio->fm_src_copp_id);
+			audio->running = 1;
+		}
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		pr_info("%s: AUDDEV_EVT_DEV_RLS\n", __func__);
+		if (evt_payload->routing_id == audio->fm_src_copp_id)
+			audio->fm_source = 0;
+		else
+			audio->fm_dest = 0;
+		if (audio->running
+			&& (!audio->fm_dest || !audio->fm_source)) {
+			afe_loopback(FM_DISABLE, audio->fm_dst_copp_id,
+						audio->fm_src_copp_id);
+			audio->running = 0;
+		} else {
+			pr_err("%s: device switch happened\n", __func__);
+		}
+		break;
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		pr_debug("%s: AUDDEV_EVT_STREAM_VOL_CHG\n", __func__);
+		if (audio->fm_source) {
+			audio->volume = evt_payload->session_vol;
+			afe_loopback_gain(audio->fm_src_copp_id,
+					audio->volume);
+		}
+		break;
+
+	default:
+		pr_err("%s: ERROR:wrong event %08x\n", __func__, evt_id);
+		break;
+	}
+}
+
+static int fm_audio_disable(struct audio *audio)
+{
+
+	/* break the AFE loopback here */
+	afe_loopback(FM_DISABLE, audio->fm_dst_copp_id, audio->fm_src_copp_id);
+	return 0;
+}
+
+static long fm_audio_ioctl(struct file *file, unsigned int cmd,
+		unsigned long arg)
+{
+	struct audio *audio = file->private_data;
+	int rc = -EINVAL;
+
+
+	mutex_lock(&audio->lock);
+	switch (cmd) {
+	case AUDIO_START:
+		pr_info("%s: AUDIO_START\n", __func__);
+		rc = fm_audio_enable(audio);
+		break;
+	case AUDIO_STOP:
+		pr_info("%s: AUDIO_STOP\n", __func__);
+		rc = fm_audio_disable(audio);
+		audio->running = 0;
+		audio->enabled = 0;
+		break;
+	case AUDIO_GET_SESSION_ID:
+		if (copy_to_user((void *) arg, &audio->dec_id,
+					sizeof(unsigned short)))
+			rc = -EFAULT;
+		else
+			rc = 0;
+		break;
+	default:
+		rc = -EINVAL;
+		pr_err("%s: Un supported IOCTL\n", __func__);
+	}
+	mutex_unlock(&audio->lock);
+	return rc;
+}
+
+static int fm_audio_release(struct inode *inode, struct file *file)
+{
+	struct audio *audio = file->private_data;
+
+	pr_debug("audio instance 0x%08x freeing\n", (int)audio);
+	mutex_lock(&audio->lock);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, audio->dec_id);
+	fm_audio_disable(audio);
+	audio->running = 0;
+	audio->enabled = 0;
+	audio->opened = 0;
+	mutex_unlock(&audio->lock);
+	return 0;
+}
+
+static int fm_audio_open(struct inode *inode, struct file *file)
+{
+	struct audio *audio = &fm_audio;
+	int rc = 0;
+
+
+	if (audio->opened)
+		return -EPERM;
+
+	/* Allocate the decoder */
+	audio->dec_id = SESSION_ID_FM;
+
+	audio->running = 0;
+	audio->fm_source = 0;
+	audio->fm_dest = 0;
+
+	audio->device_events = AUDDEV_EVT_DEV_RDY
+				|AUDDEV_EVT_DEV_RLS|
+				AUDDEV_EVT_STREAM_VOL_CHG;
+
+	rc = auddev_register_evt_listner(audio->device_events,
+					AUDDEV_CLNT_DEC,
+					audio->dec_id,
+					fm_audio_listner,
+					(void *)audio);
+
+	if (rc) {
+		pr_err("%s: failed to register listnet\n", __func__);
+		goto event_err;
+	}
+
+	audio->opened = 1;
+	file->private_data = audio;
+
+event_err:
+	return rc;
+}
+
+static const struct file_operations audio_fm_fops = {
+	.owner		= THIS_MODULE,
+	.open		= fm_audio_open,
+	.release	= fm_audio_release,
+	.unlocked_ioctl	= fm_audio_ioctl,
+};
+
+struct miscdevice audio_fm_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_fm",
+	.fops	= &audio_fm_fops,
+};
+
+static int __init fm_audio_init(void)
+{
+	struct audio *audio = &fm_audio;
+
+	mutex_init(&audio->lock);
+	return misc_register(&audio_fm_misc);
+}
+
+device_initcall(fm_audio_init);
+
+MODULE_DESCRIPTION("MSM FM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
new file mode 100644
index 0000000..11fff28
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/lpa_if_hdmi.c
@@ -0,0 +1,381 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#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/slab.h>
+#include <linux/interrupt.h>
+#include <linux/uaccess.h>
+#include <linux/dma-mapping.h>
+#include <linux/msm_audio.h>
+#include <mach/msm_hdmi_audio.h>
+#include <mach/audio_dma_msm8k.h>
+#include <sound/dai.h>
+#include "q6core.h"
+
+#define NUM_FRA_IN_BLOCK		192
+#define NUM_SAMP_PER_CH_PER_AC3_FRAME	1536
+#define AC3_REP_PER			1536	/* num of 60958 Frames */
+#define FRAME_60958_SZ			8	/* bytes */
+#define PREABLE_61937_SZ_16_BIT		4	/* in 16 bit words */
+
+
+#define MAX_AC3_FRA_SZ_16_BIT		1920  /* in 16 bit words */
+#define DMA_PERIOD_SZ			(AC3_REP_PER * FRAME_60958_SZ)
+#define DMA_BUF_SZ			(DMA_PERIOD_SZ * 2)
+#define USER_BUF_SZ			DMA_PERIOD_SZ
+#define DMA_ALLOC_BUF_SZ		(SZ_4K * 6)
+
+#define HDMI_AUDIO_FIFO_WATER_MARK	4
+
+struct audio_buffer {
+	dma_addr_t phys;
+	void *data;
+	uint32_t size;
+	uint32_t used;	/* 1 = CPU is waiting for DMA to consume this buf */
+	uint32_t actual_size;	/* actual number of bytes read by DMA */
+};
+
+struct lpa_if {
+	struct mutex lock;
+	struct msm_audio_config cfg;
+	struct audio_buffer audio_buf[2];
+	int cpu_buf;		/* next buffer the CPU will touch */
+	int dma_buf;		/* next buffer the DMA will touch */
+	u8 *buffer;
+	dma_addr_t buffer_phys;
+	u32 dma_ch;
+	wait_queue_head_t wait;
+	u32 config;
+};
+
+static struct lpa_if  *lpa_if_ptr;
+
+static unsigned int dma_buf_index;
+
+static irqreturn_t lpa_if_irq(int intrsrc, void *data)
+{
+	struct lpa_if *lpa_if = data;
+	int dma_ch = 0;
+	unsigned int pending;
+
+	if (lpa_if)
+		dma_ch = lpa_if->dma_ch;
+	else {
+		pr_err("invalid lpa_if\n");
+		return IRQ_NONE;
+	}
+
+	pending = (intrsrc
+		   & (UNDER_CH(dma_ch) | PER_CH(dma_ch) | ERR_CH(dma_ch)));
+
+	pr_debug("pending = 0x%08x\n", pending);
+
+	if (pending & UNDER_CH(dma_ch))
+		pr_err("under run\n");
+	if (pending & ERR_CH(dma_ch))
+		pr_err("DMA %x Master Error\n", dma_ch);
+
+	if (pending & PER_CH(dma_ch)) {
+
+		lpa_if->audio_buf[lpa_if->dma_buf].used = 0;
+
+		pr_debug("dma_buf %d  used %d\n", lpa_if->dma_buf,
+			lpa_if->audio_buf[lpa_if->dma_buf].used);
+
+		lpa_if->dma_buf ^= 1;
+
+		wake_up(&lpa_if->wait);
+	}
+	return IRQ_HANDLED;
+}
+
+
+int lpa_if_start(struct lpa_if *lpa_if)
+{
+	pr_debug("buf1 0x%x, buf2 0x%x dma_ch %d\n",
+		(unsigned int)lpa_if->audio_buf[0].data,
+		(unsigned int)lpa_if->audio_buf[1].data, lpa_if->dma_ch);
+
+	dai_start_hdmi(lpa_if->dma_ch);
+
+	mb();
+
+	hdmi_audio_enable(1, HDMI_AUDIO_FIFO_WATER_MARK);
+	mb();
+	return 0;
+}
+
+int lpa_if_config(struct lpa_if *lpa_if)
+{
+	struct dai_dma_params dma_params;
+
+	dma_params.src_start = lpa_if->buffer_phys;
+	dma_params.buffer = lpa_if->buffer;
+	dma_params.buffer_size = DMA_BUF_SZ;
+	dma_params.period_size = DMA_PERIOD_SZ;
+	dma_params.channels = 2;
+
+	lpa_if->dma_ch = 0;
+
+	dai_set_params(lpa_if->dma_ch, &dma_params);
+
+	register_dma_irq_handler(lpa_if->dma_ch, lpa_if_irq, (void *)lpa_if);
+
+	mb();
+	pr_debug("lpa_if 0x%08x  buf_vir 0x%08x   buf_phys 0x%08x  "
+		"config %u\n", (u32)lpa_if, (u32) (lpa_if->buffer),
+		lpa_if->buffer_phys, lpa_if->config);
+
+	pr_debug("user_buf_cnt %u user_buf_size %u\n",
+			lpa_if->cfg.buffer_count, lpa_if->cfg.buffer_size);
+
+	lpa_if->config = 1;
+
+	lpa_if_start(lpa_if);
+
+	return 0;
+}
+
+
+static long lpa_if_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct lpa_if *lpa_if = file->private_data;
+	int rc = 0;
+
+	pr_debug("cmd %u\n", cmd);
+
+	mutex_lock(&lpa_if->lock);
+
+	switch (cmd) {
+	case AUDIO_START:
+		pr_debug("AUDIO_START\n");
+
+		if (dma_buf_index == 2) {
+			if (!lpa_if->config) {
+				rc = lpa_if_config(lpa_if);
+				if (rc)
+					pr_err("lpa_if_config failed\n");
+			}
+		} else {
+			pr_err("did not receved two buffer for "
+				"AUDIO_STAR\n");
+			rc =  -EPERM;
+		}
+		break;
+
+	case AUDIO_STOP:
+		pr_debug("AUDIO_STOP\n");
+		break;
+
+	case AUDIO_FLUSH:
+		pr_debug("AUDIO_FLUSH\n");
+		break;
+
+
+	case AUDIO_GET_CONFIG:
+		pr_debug("AUDIO_GET_CONFIG\n");
+		if (copy_to_user((void *)arg, &lpa_if->cfg,
+				 sizeof(struct msm_audio_config))) {
+			rc = -EFAULT;
+		}
+		break;
+
+	default:
+		pr_err("UnKnown Ioctl\n");
+		rc = -EINVAL;
+	}
+
+	mutex_unlock(&lpa_if->lock);
+
+	return rc;
+}
+
+
+static int lpa_if_open(struct inode *inode, struct file *file)
+{
+	struct lpa_if *lpa_if;
+
+	pr_debug("\n");
+
+	file->private_data = lpa_if_ptr;
+	lpa_if = lpa_if_ptr;
+
+	lpa_if->cfg.buffer_count = 2;
+	lpa_if->cfg.buffer_size = USER_BUF_SZ;
+
+	lpa_if->audio_buf[0].phys = lpa_if->buffer_phys;
+	lpa_if->audio_buf[0].data = lpa_if->buffer;
+	lpa_if->audio_buf[0].size = DMA_PERIOD_SZ;
+	lpa_if->audio_buf[0].used = 0;
+
+	lpa_if->audio_buf[1].phys = lpa_if->buffer_phys + DMA_PERIOD_SZ;
+	lpa_if->audio_buf[1].data = lpa_if->buffer + DMA_PERIOD_SZ;
+	lpa_if->audio_buf[1].size = DMA_PERIOD_SZ;
+	lpa_if->audio_buf[1].used = 0;
+
+	dma_buf_index = 0;
+
+	core_req_bus_bandwith(AUDIO_IF_BUS_ID, 100000, 0);
+
+	return 0;
+}
+
+static ssize_t lpa_if_write(struct file *file, const char __user *buf,
+		size_t count, loff_t *pos)
+{
+	struct lpa_if *lpa_if = file->private_data;
+	struct audio_buffer *ab;
+	const char __user *start = buf;
+	int xfer, rc;
+
+	pr_debug("count %u cpu_buf %d dma_buf %d\n",
+		(unsigned int)count, lpa_if->cpu_buf, lpa_if->dma_buf);
+
+	mutex_lock(&lpa_if->lock);
+
+	if (dma_buf_index < 2) {
+
+		ab = lpa_if->audio_buf + dma_buf_index;
+
+		if (copy_from_user(ab->data, buf, count)) {
+			pr_err("copy from user failed\n");
+			rc = 0;
+			goto end;
+
+		}
+		pr_debug("prefill: count %u  audio_buf[%u].size %u\n",
+			 count, dma_buf_index, ab->size);
+
+		ab->used = 1;
+		dma_buf_index++;
+		rc =  count;
+		goto end;
+	}
+
+	if (lpa_if->config != 1) {
+		pr_err("AUDIO_START did not happen\n");
+		rc = 0;
+		goto end;
+	}
+
+	while (count > 0) {
+
+		ab = lpa_if->audio_buf + lpa_if->cpu_buf;
+
+		rc = wait_event_timeout(lpa_if->wait, (ab->used == 0), 10 * HZ);
+		if (!rc) {
+			pr_err("wait_event_timeout failed\n");
+			rc =  buf - start;
+			goto end;
+		}
+
+		xfer = count;
+
+		if (xfer > USER_BUF_SZ)
+			xfer = USER_BUF_SZ;
+
+		if (copy_from_user(ab->data, buf, xfer)) {
+			pr_err("copy from user failed\n");
+			rc = buf - start;
+			goto end;
+		}
+
+		mb();
+		buf += xfer;
+		count -= xfer;
+		ab->used = 1;
+
+		pr_debug("xfer %d, size %d, used %d cpu_buf %d\n",
+			xfer, ab->size, ab->used, lpa_if->cpu_buf);
+
+		lpa_if->cpu_buf ^= 1;
+	}
+	rc = buf - start;
+end:
+	mutex_unlock(&lpa_if->lock);
+	return rc;
+}
+
+static int lpa_if_release(struct inode *inode, struct file *file)
+{
+	struct lpa_if *lpa_if = file->private_data;
+	hdmi_audio_enable(0, HDMI_AUDIO_FIFO_WATER_MARK);
+
+	smp_mb();
+
+	if (lpa_if->config) {
+		unregister_dma_irq_handler(lpa_if->dma_ch);
+		dai_stop_hdmi(lpa_if->dma_ch);
+		lpa_if->config = 0;
+	}
+	return 0;
+}
+
+static const struct file_operations lpa_if_fops = {
+	.owner = THIS_MODULE,
+	.open = lpa_if_open,
+	.write = lpa_if_write,
+	.release = lpa_if_release,
+	.unlocked_ioctl = lpa_if_ioctl,
+};
+
+struct miscdevice lpa_if_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = "msm_lpa_if_out",
+	.fops = &lpa_if_fops,
+};
+
+static int __init lpa_if_init(void)
+{
+	int rc;
+
+	lpa_if_ptr = kzalloc(sizeof(struct lpa_if), GFP_KERNEL);
+	if (!lpa_if_ptr) {
+		pr_info("No mem for lpa-if\n");
+		return -ENOMEM;
+	}
+
+	mutex_init(&lpa_if_ptr->lock);
+	init_waitqueue_head(&lpa_if_ptr->wait);
+
+	lpa_if_ptr->buffer = dma_alloc_coherent(NULL, DMA_ALLOC_BUF_SZ,
+				    &(lpa_if_ptr->buffer_phys), GFP_KERNEL);
+	if (!lpa_if_ptr->buffer) {
+		pr_err("dma_alloc_coherent failed\n");
+		kfree(lpa_if_ptr);
+		return -ENOMEM;
+	}
+
+	pr_info("lpa_if_ptr 0x%08x   buf_vir 0x%08x   buf_phy 0x%08x "
+		" buf_zise %u\n", (u32)lpa_if_ptr,
+		(u32)(lpa_if_ptr->buffer), lpa_if_ptr->buffer_phys,
+		DMA_ALLOC_BUF_SZ);
+
+	rc =  misc_register(&lpa_if_misc);
+	if (rc < 0) {
+		pr_err("misc_register failed\n");
+
+		dma_free_coherent(NULL, DMA_ALLOC_BUF_SZ, lpa_if_ptr->buffer,
+				lpa_if_ptr->buffer_phys);
+		kfree(lpa_if_ptr);
+	}
+	return rc;
+}
+
+device_initcall(lpa_if_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/msm_qdsp6_audio.h b/arch/arm/mach-msm/qdsp6v2/msm_qdsp6_audio.h
new file mode 100644
index 0000000..3890816
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/msm_qdsp6_audio.h
@@ -0,0 +1,52 @@
+/* arch/arm/mach-msm/include/mach/msm_qdsp6_audio.h
+ *
+ * Copyright (C) 2009 Google, Inc.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _MACH_MSM_QDSP6_Q6AUDIO_
+#define _MACH_MSM_QDSP6_Q6AUDIO_
+
+#define AUDIO_FLAG_READ		0
+#define AUDIO_FLAG_WRITE	1
+#define AUDIO_FLAG_INCALL_MIXED	2
+
+struct audio_buffer {
+	dma_addr_t phys;
+	void *data;
+	uint32_t size;
+	uint32_t used;	/* 1 = CPU is waiting for DSP to consume this buf */
+	uint32_t actual_size; /* actual number of bytes read by DSP */
+};
+
+struct audio_client {
+	struct audio_buffer buf[2];
+	int cpu_buf;	/* next buffer the CPU will touch */
+	int dsp_buf;	/* next buffer the DSP will touch */
+	int running;
+	int session;
+
+	int state;
+
+	wait_queue_head_t wait;
+	wait_queue_head_t cmd_wait;
+
+	struct dal_client *client;
+
+	int cb_status;
+	uint32_t flags;
+	void *apr;
+	int ref_count;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/pcm_in.c b/arch/arm/mach-msm/qdsp6v2/pcm_in.c
new file mode 100644
index 0000000..be1927d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/pcm_in.c
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (C) 2009 HTC Corporation
+ * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/msm_audio.h>
+#include <asm/atomic.h>
+#include <mach/debug_mm.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <sound/q6asm.h>
+#include <sound/apr_audio.h>
+
+#define MAX_BUF 4
+#define BUFSZ (480 * 8)
+#define BUFFER_SIZE_MULTIPLE 4
+#define MIN_BUFFER_SIZE 160
+
+#define VOC_REC_NONE 0xFF
+
+struct pcm {
+	struct mutex lock;
+	struct mutex read_lock;
+	wait_queue_head_t wait;
+	spinlock_t dsp_lock;
+	struct audio_client *ac;
+	uint32_t sample_rate;
+	uint32_t channel_count;
+	uint32_t buffer_size;
+	uint32_t buffer_count;
+	uint32_t rec_mode;
+	uint32_t in_frame_info[MAX_BUF][2];
+	atomic_t in_count;
+	atomic_t in_enabled;
+	atomic_t in_opened;
+	atomic_t in_stopped;
+};
+
+static void pcm_in_get_dsp_buffers(struct pcm*,
+				uint32_t token, uint32_t *payload);
+
+void pcm_in_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv)
+{
+	struct pcm *pcm = (struct pcm *) priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pcm->dsp_lock, flags);
+	switch (opcode) {
+	case ASM_DATA_EVENT_READ_DONE:
+		pcm_in_get_dsp_buffers(pcm, token, payload);
+		break;
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&pcm->dsp_lock, flags);
+}
+
+static void pcm_in_get_dsp_buffers(struct pcm *pcm,
+				uint32_t token, uint32_t *payload)
+{
+	pcm->in_frame_info[token][0] = payload[7];
+	pcm->in_frame_info[token][1] = payload[3];
+	if (atomic_read(&pcm->in_count) <= pcm->buffer_count)
+		atomic_inc(&pcm->in_count);
+	wake_up(&pcm->wait);
+}
+
+static int pcm_in_enable(struct pcm *pcm)
+{
+	if (atomic_read(&pcm->in_enabled))
+		return 0;
+	return q6asm_run(pcm->ac, 0, 0, 0);
+}
+
+static int pcm_in_disable(struct pcm *pcm)
+{
+	int rc = 0;
+
+	if (atomic_read(&pcm->in_opened)) {
+		atomic_set(&pcm->in_enabled, 0);
+		atomic_set(&pcm->in_opened, 0);
+		rc = q6asm_cmd(pcm->ac, CMD_CLOSE);
+
+		atomic_set(&pcm->in_stopped, 1);
+		memset(pcm->in_frame_info, 0,
+				sizeof(char) * pcm->buffer_count * 2);
+		wake_up(&pcm->wait);
+	}
+	return rc;
+}
+
+static int config(struct pcm *pcm)
+{
+	int rc = 0;
+
+	pr_debug("%s: pcm prefill, buffer_size = %d\n", __func__,
+		pcm->buffer_size);
+	rc = q6asm_audio_client_buf_alloc(OUT, pcm->ac,
+				pcm->buffer_size, pcm->buffer_count);
+	if (rc < 0) {
+		pr_err("Audio Start: Buffer Allocation failed \
+						rc = %d\n", rc);
+		goto fail;
+	}
+
+	rc = q6asm_enc_cfg_blk_pcm(pcm->ac, pcm->sample_rate,
+						pcm->channel_count);
+	if (rc < 0) {
+		pr_err("%s: cmd media format block failed", __func__);
+		goto fail;
+	}
+fail:
+	return rc;
+}
+
+static long pcm_in_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct pcm *pcm = file->private_data;
+	int rc = 0;
+
+	mutex_lock(&pcm->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME:
+		break;
+	case AUDIO_GET_STATS: {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_START: {
+		int cnt = 0;
+		if (atomic_read(&pcm->in_enabled)) {
+			pr_info("%s:AUDIO_START already over\n", __func__);
+			rc = 0;
+			break;
+		}
+		rc = config(pcm);
+		if (rc) {
+			pr_err("%s: IN Configuration failed\n", __func__);
+			rc = -EFAULT;
+			break;
+		}
+
+		rc = pcm_in_enable(pcm);
+		if (rc) {
+			pr_err("%s: In Enable failed\n", __func__);
+			rc = -EFAULT;
+			break;
+		}
+
+		atomic_set(&pcm->in_enabled, 1);
+
+		while (cnt++ < pcm->buffer_count)
+			q6asm_read(pcm->ac);
+		pr_info("%s: AUDIO_START session id[%d]\n", __func__,
+							pcm->ac->session);
+
+		if (pcm->rec_mode != VOC_REC_NONE)
+			msm_enable_incall_recording(pcm->ac->session,
+			pcm->rec_mode, pcm->sample_rate, pcm->channel_count);
+
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+		if (copy_to_user((void *) arg, &pcm->ac->session,
+					sizeof(unsigned short)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		pr_debug("%s: SET_CONFIG: buffer_size:%d channel_count:%d"
+			"sample_rate:%d, buffer_count:%d\n", __func__,
+			config.buffer_size, config.channel_count,
+			config.sample_rate, config.buffer_count);
+
+		if (!config.channel_count || config.channel_count > 2) {
+			rc = -EINVAL;
+			break;
+		}
+
+		if (config.sample_rate < 8000 || config.sample_rate > 48000) {
+			rc = -EINVAL;
+			break;
+		}
+
+		if ((config.buffer_size % (config.channel_count *
+			BUFFER_SIZE_MULTIPLE)) ||
+			(config.buffer_size < MIN_BUFFER_SIZE)) {
+			pr_err("%s: Buffer Size should be multiple of "
+				"[4 * no. of channels] and greater than 160\n",
+				__func__);
+			rc = -EINVAL;
+			break;
+		}
+
+		pcm->sample_rate = config.sample_rate;
+		pcm->channel_count = config.channel_count;
+		pcm->buffer_size = config.buffer_size;
+		pcm->buffer_count = config.buffer_count;
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		config.buffer_size = pcm->buffer_size;
+		config.buffer_count = pcm->buffer_count;
+		config.sample_rate = pcm->sample_rate;
+		config.channel_count = pcm->channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_ENABLE_AUDPRE: {
+
+		uint16_t enable_mask;
+
+		if (copy_from_user(&enable_mask, (void *) arg,
+						sizeof(enable_mask))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (enable_mask & FLUENCE_ENABLE)
+			rc = auddev_cfg_tx_copp_topology(pcm->ac->session,
+					VPM_TX_DM_FLUENCE_COPP_TOPOLOGY);
+		else
+			rc = auddev_cfg_tx_copp_topology(pcm->ac->session,
+					DEFAULT_COPP_TOPOLOGY);
+		break;
+	}
+
+	case AUDIO_SET_INCALL: {
+		if (copy_from_user(&pcm->rec_mode,
+				   (void *) arg,
+				   sizeof(pcm->rec_mode))) {
+			rc = -EFAULT;
+			pr_err("%s: Error copying in-call mode\n", __func__);
+			break;
+		}
+
+		if (pcm->rec_mode != VOC_REC_UPLINK &&
+		    pcm->rec_mode != VOC_REC_DOWNLINK &&
+		    pcm->rec_mode != VOC_REC_BOTH) {
+			rc = -EINVAL;
+			pcm->rec_mode = VOC_REC_NONE;
+
+			pr_err("%s: Invalid %d in-call rec_mode\n",
+			       __func__, pcm->rec_mode);
+			break;
+		}
+
+		pr_debug("%s: In-call rec_mode %d\n", __func__, pcm->rec_mode);
+		break;
+	}
+
+	default:
+		rc = -EINVAL;
+		break;
+	}
+	mutex_unlock(&pcm->lock);
+	return rc;
+}
+
+static int pcm_in_open(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm;
+	int rc = 0;
+
+	pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL);
+	if (!pcm)
+		return -ENOMEM;
+
+	pcm->channel_count = 1;
+	pcm->sample_rate = 8000;
+	pcm->buffer_size = BUFSZ;
+	pcm->buffer_count = MAX_BUF;
+
+	pcm->ac = q6asm_audio_client_alloc((app_cb)pcm_in_cb, (void *)pcm);
+	if (!pcm->ac) {
+		pr_err("%s: Could not allocate memory\n", __func__);
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	mutex_init(&pcm->lock);
+	mutex_init(&pcm->read_lock);
+	spin_lock_init(&pcm->dsp_lock);
+	init_waitqueue_head(&pcm->wait);
+
+	rc = q6asm_open_read(pcm->ac, FORMAT_LINEAR_PCM);
+	if (rc < 0) {
+		pr_err("%s: Cmd Open Failed\n", __func__);
+		goto fail;
+	}
+
+	atomic_set(&pcm->in_stopped, 0);
+	atomic_set(&pcm->in_enabled, 0);
+	atomic_set(&pcm->in_count, 0);
+	atomic_set(&pcm->in_opened, 1);
+
+	pcm->rec_mode = VOC_REC_NONE;
+
+	file->private_data = pcm;
+	pr_info("%s: pcm in open session id[%d]\n", __func__, pcm->ac->session);
+	return 0;
+fail:
+	if (pcm->ac)
+		q6asm_audio_client_free(pcm->ac);
+	kfree(pcm);
+	return rc;
+}
+
+static ssize_t pcm_in_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *pos)
+{
+	struct pcm *pcm = file->private_data;
+	const char __user *start = buf;
+	void *data;
+	uint32_t offset = 0;
+	uint32_t size = 0;
+	uint32_t idx;
+	int rc = 0;
+	int len = 0;
+
+	if (!atomic_read(&pcm->in_enabled))
+		return -EFAULT;
+	mutex_lock(&pcm->read_lock);
+	while (count > 0) {
+		rc = wait_event_timeout(pcm->wait,
+				(atomic_read(&pcm->in_count) ||
+				atomic_read(&pcm->in_stopped)), 5 * HZ);
+		if (!rc) {
+			pr_err("%s: wait_event_timeout failed\n", __func__);
+			goto fail;
+		}
+
+		if (atomic_read(&pcm->in_stopped) &&
+					!atomic_read(&pcm->in_count)) {
+			mutex_unlock(&pcm->read_lock);
+			return 0;
+		}
+
+		data = q6asm_is_cpu_buf_avail(OUT, pcm->ac, &size, &idx);
+		if (count >= size)
+			len = size;
+		else {
+			len = count;
+			pr_err("%s: short read data[%p]bytesavail[%d]"
+				"bytesrequest[%d]"
+				"bytesrejected%d]\n",\
+				__func__, data, size,
+				count, (size - count));
+		}
+		if ((len) && data) {
+			offset = pcm->in_frame_info[idx][1];
+			if (copy_to_user(buf, data+offset, len)) {
+				pr_err("%s copy_to_user failed len[%d]\n",
+							__func__, len);
+				rc = -EFAULT;
+				goto fail;
+			}
+			count -= len;
+			buf += len;
+		}
+		atomic_dec(&pcm->in_count);
+		memset(&pcm->in_frame_info[idx], 0,
+						sizeof(uint32_t) * 2);
+
+		rc = q6asm_read(pcm->ac);
+		if (rc < 0) {
+			pr_err("%s q6asm_read fail\n", __func__);
+				goto fail;
+		}
+		rmb();
+		break;
+	}
+	rc = buf-start;
+fail:
+	mutex_unlock(&pcm->read_lock);
+	return rc;
+}
+
+static int pcm_in_release(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct pcm *pcm = file->private_data;
+
+	pr_info("[%s:%s] release session id[%d]\n", __MM_FILE__,
+		__func__, pcm->ac->session);
+	mutex_lock(&pcm->lock);
+
+	if ((pcm->rec_mode != VOC_REC_NONE) && atomic_read(&pcm->in_enabled)) {
+		msm_disable_incall_recording(pcm->ac->session, pcm->rec_mode);
+
+		pcm->rec_mode = VOC_REC_NONE;
+	}
+
+	/* remove this session from topology list */
+	auddev_cfg_tx_copp_topology(pcm->ac->session,
+				DEFAULT_COPP_TOPOLOGY);
+	mutex_unlock(&pcm->lock);
+
+	rc = pcm_in_disable(pcm);
+	 msm_clear_session_id(pcm->ac->session);
+	q6asm_audio_client_free(pcm->ac);
+	kfree(pcm);
+	return rc;
+}
+
+static const struct file_operations pcm_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= pcm_in_open,
+	.read		= pcm_in_read,
+	.release	= pcm_in_release,
+	.unlocked_ioctl	= pcm_in_ioctl,
+};
+
+struct miscdevice pcm_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_in",
+	.fops	= &pcm_in_fops,
+};
+
+static int __init pcm_in_init(void)
+{
+	return misc_register(&pcm_in_misc);
+}
+
+device_initcall(pcm_in_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/pcm_out.c b/arch/arm/mach-msm/qdsp6v2/pcm_out.c
new file mode 100644
index 0000000..b8521f6
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/pcm_out.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) 2009 Google, Inc.
+ * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ * Author: Brian Swetland <swetland@google.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/msm_audio.h>
+#include <linux/slab.h>
+#include <linux/wakelock.h>
+#include <asm/atomic.h>
+#include <sound/q6asm.h>
+#include <sound/apr_audio.h>
+#include <mach/debug_mm.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+
+#define MAX_BUF 2
+#define BUFSZ (4800)
+
+struct pcm {
+	struct mutex lock;
+	struct mutex write_lock;
+	spinlock_t   dsp_lock;
+	wait_queue_head_t write_wait;
+	struct audio_client *ac;
+	uint32_t sample_rate;
+	uint32_t channel_count;
+	uint32_t buffer_size;
+	uint32_t buffer_count;
+	uint32_t rec_mode;
+	uint32_t stream_event;
+	uint32_t volume;
+	atomic_t out_count;
+	atomic_t out_enabled;
+	atomic_t out_opened;
+	atomic_t out_stopped;
+	atomic_t out_prefill;
+	struct wake_lock wakelock;
+	struct wake_lock idlelock;
+};
+
+void pcm_out_cb(uint32_t opcode, uint32_t token,
+			uint32_t *payload, void *priv)
+{
+	struct pcm *pcm = (struct pcm *) priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&pcm->dsp_lock, flags);
+	switch (opcode) {
+	case ASM_DATA_EVENT_WRITE_DONE:
+		atomic_inc(&pcm->out_count);
+		wake_up(&pcm->write_wait);
+		break;
+	default:
+		break;
+	}
+	spin_unlock_irqrestore(&pcm->dsp_lock, flags);
+}
+
+static void audio_prevent_sleep(struct pcm *audio)
+{
+	pr_debug("%s:\n", __func__);
+	wake_lock(&audio->wakelock);
+	wake_lock(&audio->idlelock);
+}
+
+static void audio_allow_sleep(struct pcm *audio)
+{
+	pr_debug("%s:\n", __func__);
+	wake_unlock(&audio->wakelock);
+	wake_unlock(&audio->idlelock);
+}
+
+static int pcm_out_enable(struct pcm *pcm)
+{
+	if (atomic_read(&pcm->out_enabled))
+		return 0;
+	return q6asm_run(pcm->ac, 0, 0, 0);
+}
+
+static int pcm_out_disable(struct pcm *pcm)
+{
+	int rc = 0;
+
+	if (atomic_read(&pcm->out_opened)) {
+		atomic_set(&pcm->out_enabled, 0);
+		atomic_set(&pcm->out_opened, 0);
+		rc = q6asm_cmd(pcm->ac, CMD_CLOSE);
+
+		atomic_set(&pcm->out_stopped, 1);
+		wake_up(&pcm->write_wait);
+	}
+	return rc;
+}
+
+static int config(struct pcm *pcm)
+{
+	int rc = 0;
+	if (!atomic_read(&pcm->out_prefill)) {
+		pr_debug("%s: pcm prefill\n", __func__);
+		rc = q6asm_audio_client_buf_alloc(IN, pcm->ac,
+				pcm->buffer_size, pcm->buffer_count);
+		if (rc < 0) {
+			pr_err("Audio Start: Buffer Allocation failed \
+							rc = %d\n", rc);
+			goto fail;
+		}
+
+		rc = q6asm_media_format_block_pcm(pcm->ac, pcm->sample_rate,
+							pcm->channel_count);
+		if (rc < 0)
+			pr_err("%s: CMD Format block failed\n", __func__);
+
+		atomic_set(&pcm->out_prefill, 1);
+		atomic_set(&pcm->out_count, pcm->buffer_count);
+	}
+fail:
+	return rc;
+}
+
+static void pcm_event_listner(u32 evt_id, union auddev_evt_data *evt_payload,
+							void *private_data)
+{
+	struct pcm *pcm = (struct pcm *) private_data;
+	int rc  = 0;
+
+	switch (evt_id) {
+	case AUDDEV_EVT_STREAM_VOL_CHG:
+		pcm->volume = evt_payload->session_vol;
+		pr_debug("%s: AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d, "
+				"enabled = %d\n", __func__, pcm->volume,
+					atomic_read(&pcm->out_enabled));
+		if (atomic_read(&pcm->out_enabled)) {
+			if (pcm->ac) {
+				rc = q6asm_set_volume(pcm->ac, pcm->volume);
+				if (rc < 0)
+					pr_err("%s: Send Volume command"
+					"failed rc=%d\n", __func__, rc);
+			}
+		}
+		break;
+	default:
+		pr_err("%s:ERROR:wrong event\n", __func__);
+		break;
+	}
+}
+
+static long pcm_out_ioctl(struct file *file, unsigned int cmd,
+				unsigned long arg)
+{
+	struct pcm *pcm = file->private_data;
+	int rc = 0;
+
+	if (cmd == AUDIO_GET_STATS) {
+		struct msm_audio_stats stats;
+		memset(&stats, 0, sizeof(stats));
+		if (copy_to_user((void *) arg, &stats, sizeof(stats)))
+			return -EFAULT;
+		return 0;
+	}
+
+	mutex_lock(&pcm->lock);
+	switch (cmd) {
+	case AUDIO_SET_VOLUME: {
+		int vol;
+		if (copy_from_user(&vol, (void *) arg, sizeof(vol))) {
+			rc = -EFAULT;
+			break;
+		}
+		break;
+	}
+	case AUDIO_START: {
+		pr_info("%s: AUDIO_START\n", __func__);
+		rc = config(pcm);
+		if (rc) {
+			pr_err("%s: Out Configuration failed\n", __func__);
+			rc = -EFAULT;
+			break;
+		}
+
+		rc = pcm_out_enable(pcm);
+		if (rc) {
+			pr_err("Out enable failed\n");
+			rc = -EFAULT;
+			break;
+		}
+		audio_prevent_sleep(pcm);
+		atomic_set(&pcm->out_enabled, 1);
+
+		rc = q6asm_set_volume(pcm->ac, pcm->volume);
+		if (rc < 0)
+			pr_err("%s: Send Volume command failed rc=%d\n",
+							__func__, rc);
+		rc = q6asm_set_lrgain(pcm->ac, 0x2000, 0x2000);
+		if (rc < 0)
+			pr_err("%s: Send channel gain failed rc=%d\n",
+							__func__, rc);
+		/* disable mute by default */
+		rc = q6asm_set_mute(pcm->ac, 0);
+		if (rc < 0)
+			pr_err("%s: Send mute command failed rc=%d\n",
+							__func__, rc);
+		break;
+	}
+	case AUDIO_GET_SESSION_ID: {
+		if (copy_to_user((void *) arg, &pcm->ac->session,
+					sizeof(unsigned short)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_STOP:
+		break;
+	case AUDIO_FLUSH:
+		break;
+	case AUDIO_SET_CONFIG: {
+		struct msm_audio_config config;
+		pr_debug("%s: AUDIO_SET_CONFIG\n", __func__);
+		if (copy_from_user(&config, (void *) arg, sizeof(config))) {
+			rc = -EFAULT;
+			break;
+		}
+		if (config.channel_count < 1 || config.channel_count > 2) {
+			rc = -EINVAL;
+			break;
+		}
+		if (config.sample_rate < 8000 || config.sample_rate > 48000) {
+			rc = -EINVAL;
+			break;
+		}
+		if (config.buffer_size < 128) {
+			rc = -EINVAL;
+			break;
+		}
+		pcm->sample_rate = config.sample_rate;
+		pcm->channel_count = config.channel_count;
+		pcm->buffer_size = config.buffer_size;
+		pcm->buffer_count = config.buffer_count;
+		pr_debug("%s:buffer_size:%d buffer_count:%d sample_rate:%d \
+			channel_count:%d\n",  __func__, pcm->buffer_size,
+			pcm->buffer_count, pcm->sample_rate,
+			pcm->channel_count);
+		break;
+	}
+	case AUDIO_GET_CONFIG: {
+		struct msm_audio_config config;
+		pr_debug("%s: AUDIO_GET_CONFIG\n", __func__);
+		config.buffer_size = pcm->buffer_size;
+		config.buffer_count = pcm->buffer_count;
+		config.sample_rate = pcm->sample_rate;
+		config.channel_count = pcm->channel_count;
+		config.unused[0] = 0;
+		config.unused[1] = 0;
+		config.unused[2] = 0;
+		if (copy_to_user((void *) arg, &config, sizeof(config)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_EQ: {
+		struct msm_audio_eq_stream_config eq_config;
+		if (copy_from_user(&eq_config, (void *) arg,
+						sizeof(eq_config))) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = q6asm_equalizer(pcm->ac, (void *) &eq_config);
+		if (rc < 0)
+			pr_err("%s: EQUALIZER FAILED\n", __func__);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	mutex_unlock(&pcm->lock);
+	return rc;
+}
+
+static int pcm_out_open(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm;
+	int rc = 0;
+	char name[24];
+
+	pr_info("[%s:%s] open\n", __MM_FILE__, __func__);
+	pcm = kzalloc(sizeof(struct pcm), GFP_KERNEL);
+	if (!pcm) {
+		pr_err("%s: Failed to allocated memory\n", __func__);
+		return -ENOMEM;
+	}
+
+	pcm->channel_count = 2;
+	pcm->sample_rate = 44100;
+	pcm->buffer_size = BUFSZ;
+	pcm->buffer_count = MAX_BUF;
+	pcm->stream_event = AUDDEV_EVT_STREAM_VOL_CHG;
+	pcm->volume = 0x2000;
+
+	pcm->ac = q6asm_audio_client_alloc((app_cb)pcm_out_cb, (void *)pcm);
+	if (!pcm->ac) {
+		pr_err("%s: Could not allocate memory\n", __func__);
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	rc = q6asm_open_write(pcm->ac, FORMAT_LINEAR_PCM);
+	if (rc < 0) {
+		pr_err("%s: pcm out open failed for session %d\n", __func__,
+			pcm->ac->session);
+		rc = -EINVAL;
+		goto fail;
+	}
+
+	mutex_init(&pcm->lock);
+	mutex_init(&pcm->write_lock);
+	init_waitqueue_head(&pcm->write_wait);
+	spin_lock_init(&pcm->dsp_lock);
+	atomic_set(&pcm->out_enabled, 0);
+	atomic_set(&pcm->out_stopped, 0);
+	atomic_set(&pcm->out_count, pcm->buffer_count);
+	atomic_set(&pcm->out_prefill, 0);
+	atomic_set(&pcm->out_opened, 1);
+	snprintf(name, sizeof name, "audio_pcm_%x", pcm->ac->session);
+	wake_lock_init(&pcm->wakelock, WAKE_LOCK_SUSPEND, name);
+	snprintf(name, sizeof name, "audio_pcm_idle_%x", pcm->ac->session);
+	wake_lock_init(&pcm->idlelock, WAKE_LOCK_IDLE, name);
+
+	rc = auddev_register_evt_listner(pcm->stream_event,
+					AUDDEV_CLNT_DEC,
+					pcm->ac->session,
+					pcm_event_listner,
+					(void *)pcm);
+	if (rc < 0) {
+		pr_err("%s: failed to register listner\n", __func__);
+		goto fail;
+	}
+
+	file->private_data = pcm;
+	pr_info("[%s:%s] open session id[%d]\n", __MM_FILE__,
+				__func__, pcm->ac->session);
+	return 0;
+fail:
+	if (pcm->ac)
+		q6asm_audio_client_free(pcm->ac);
+	kfree(pcm);
+	return rc;
+}
+
+static ssize_t pcm_out_write(struct file *file, const char __user *buf,
+					size_t count, loff_t *pos)
+{
+	struct pcm *pcm = file->private_data;
+	const char __user *start = buf;
+	int xfer;
+	char *bufptr;
+	uint32_t idx;
+	void *data;
+	int rc = 0;
+	uint32_t size;
+
+	if (!pcm->ac)
+		return -ENODEV;
+
+	if (!atomic_read(&pcm->out_enabled)) {
+		rc = config(pcm);
+		if (rc < 0)
+			return rc;
+	}
+
+	mutex_lock(&pcm->write_lock);
+	while (count > 0) {
+		rc = wait_event_timeout(pcm->write_wait,
+				(atomic_read(&pcm->out_count) ||
+				atomic_read(&pcm->out_stopped)), 5 * HZ);
+		if (!rc) {
+			pr_err("%s: wait_event_timeout failed for session %d\n",
+				__func__, pcm->ac->session);
+			goto fail;
+		}
+
+		if (atomic_read(&pcm->out_stopped) &&
+					!atomic_read(&pcm->out_count)) {
+			pr_info("%s: pcm stopped out_count 0\n", __func__);
+			mutex_unlock(&pcm->write_lock);
+			return 0;
+		}
+
+		data = q6asm_is_cpu_buf_avail(IN, pcm->ac, &size, &idx);
+		bufptr = data;
+		if (bufptr) {
+			xfer = count;
+			if (xfer > BUFSZ)
+				xfer = BUFSZ;
+
+			if (copy_from_user(bufptr, buf, xfer)) {
+				rc = -EFAULT;
+				goto fail;
+			}
+			buf += xfer;
+			count -= xfer;
+			rc = q6asm_write(pcm->ac, xfer, 0, 0, NO_TIMESTAMP);
+			wmb();
+			if (rc < 0) {
+				rc = -EFAULT;
+				goto fail;
+			}
+		}
+		atomic_dec(&pcm->out_count);
+	}
+
+	rc = buf - start;
+fail:
+	mutex_unlock(&pcm->write_lock);
+	return rc;
+}
+
+static int pcm_out_release(struct inode *inode, struct file *file)
+{
+	struct pcm *pcm = file->private_data;
+
+	pr_info("[%s:%s] release session id[%d]\n", __MM_FILE__,
+				__func__, pcm->ac->session);
+	if (pcm->ac)
+		pcm_out_disable(pcm);
+	msm_clear_session_id(pcm->ac->session);
+	auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, pcm->ac->session);
+	q6asm_audio_client_free(pcm->ac);
+	audio_allow_sleep(pcm);
+	wake_lock_destroy(&pcm->wakelock);
+	wake_lock_destroy(&pcm->idlelock);
+	mutex_destroy(&pcm->lock);
+	mutex_destroy(&pcm->write_lock);
+	kfree(pcm);
+	return 0;
+}
+
+static const struct file_operations pcm_out_fops = {
+	.owner		= THIS_MODULE,
+	.open		= pcm_out_open,
+	.write		= pcm_out_write,
+	.release	= pcm_out_release,
+	.unlocked_ioctl	= pcm_out_ioctl,
+};
+
+struct miscdevice pcm_out_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_pcm_out",
+	.fops	= &pcm_out_fops,
+};
+
+static int __init pcm_out_init(void)
+{
+	return misc_register(&pcm_out_misc);
+}
+
+device_initcall(pcm_out_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/q6core.c b/arch/arm/mach-msm/qdsp6v2/q6core.c
new file mode 100644
index 0000000..edb1e7d
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/q6core.c
@@ -0,0 +1,409 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <mach/msm_smd.h>
+#include <mach/qdsp6v2/apr.h>
+#include "q6core.h"
+
+#define TIMEOUT_MS 1000
+
+static struct apr_svc *apr_handle_q;
+static struct apr_svc *apr_handle_m;
+static struct apr_svc *core_handle_q;
+
+static int32_t query_adsp_ver;
+static wait_queue_head_t adsp_version_wait;
+static uint32_t adsp_version;
+
+static wait_queue_head_t bus_bw_req_wait;
+static u32 bus_bw_resp_received;
+
+static struct dentry *dentry;
+static char l_buf[4096];
+
+static int32_t aprv2_core_fn_q(struct apr_client_data *data, void *priv)
+{
+	struct adsp_get_version *payload;
+	uint32_t *payload1;
+	struct adsp_service_info *svc_info;
+	int i;
+
+	pr_info("core msg: payload len = %u, apr resp opcode = 0x%X\n",
+		data->payload_size, data->opcode);
+
+	switch (data->opcode) {
+
+	case APR_BASIC_RSP_RESULT:{
+
+		if (data->payload_size == 0) {
+			pr_err("%s: APR_BASIC_RSP_RESULT No Payload ",
+					__func__);
+			return 0;
+		}
+
+		payload1 = data->payload;
+
+		switch (payload1[0]) {
+
+		case ADSP_CMD_SET_POWER_COLLAPSE_STATE:
+			pr_info("Cmd = ADSP_CMD_SET_POWER_COLLAPSE_STATE"
+				" status[0x%x]\n", payload1[1]);
+			break;
+		case ADSP_CMD_REMOTE_BUS_BW_REQUEST:
+			pr_info("%s: cmd = ADSP_CMD_REMOTE_BUS_BW_REQUEST"
+				"  status = 0x%x\n", __func__, payload1[1]);
+
+			bus_bw_resp_received = 1;
+			wake_up(&bus_bw_req_wait);
+			break;
+		default:
+			pr_err("Invalid cmd rsp[0x%x][0x%x]\n",
+					payload1[0], payload1[1]);
+			break;
+		}
+		break;
+	}
+	case ADSP_GET_VERSION_RSP:{
+		if (data->payload_size) {
+			payload = data->payload;
+			if (query_adsp_ver == 1) {
+				query_adsp_ver = 0;
+				adsp_version  = payload->build_id;
+				wake_up(&adsp_version_wait);
+			}
+			svc_info = (struct adsp_service_info *)
+			((char *)payload + sizeof(struct adsp_get_version));
+			pr_info("----------------------------------------\n");
+			pr_info("Build id          = %x\n", payload->build_id);
+			pr_info("Number of services= %x\n", payload->svc_cnt);
+			pr_info("----------------------------------------\n");
+			for (i = 0; i < payload->svc_cnt; i++) {
+				pr_info("svc-id[%d]\tver[%x.%x]\n",
+					svc_info[i].svc_id,
+					(svc_info[i].svc_ver & 0xFFFF0000)
+					>> 16,
+					(svc_info[i].svc_ver & 0xFFFF));
+			}
+			pr_info("-----------------------------------------\n");
+		} else
+			pr_info("zero payload for ADSP_GET_VERSION_RSP\n");
+		break;
+	}
+	case RESET_EVENTS:{
+		pr_debug("Reset event received in Core service");
+		apr_reset(core_handle_q);
+		core_handle_q = NULL;
+		break;
+	}
+
+	default:
+		pr_err("Message id from adsp core svc: %d\n", data->opcode);
+		break;
+	}
+
+	return 0;
+}
+
+static int32_t aprv2_debug_fn_q(struct apr_client_data *data, void *priv)
+{
+	pr_debug("Q6_Payload Length = %d\n", data->payload_size);
+	if (memcmp(data->payload, l_buf + 20, data->payload_size))
+		pr_info("FAIL: %d\n", data->payload_size);
+	else
+		pr_info("SUCCESS: %d\n", data->payload_size);
+	return 0;
+}
+
+static int32_t aprv2_debug_fn_m(struct apr_client_data *data, void *priv)
+{
+	pr_info("M_Payload Length = %d\n", data->payload_size);
+	return 0;
+}
+
+static ssize_t apr_debug_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	pr_debug("apr debugfs opened\n");
+	return 0;
+}
+
+void core_open(void)
+{
+	if (core_handle_q == NULL) {
+		core_handle_q = apr_register("ADSP", "CORE",
+					aprv2_core_fn_q, 0xFFFFFFFF, NULL);
+	}
+	pr_info("Open_q %p\n", core_handle_q);
+	if (core_handle_q == NULL) {
+		pr_err("%s: Unable to register CORE\n", __func__);
+	}
+}
+
+int core_req_bus_bandwith(u16 bus_id, u32 ab_bps, u32 ib_bps)
+{
+	struct adsp_cmd_remote_bus_bw_request bus_bw_req;
+	int ret;
+
+	pr_debug("%s: bus_id %u ab_bps %u ib_bps %u\n",
+			__func__, bus_id, ab_bps, ib_bps);
+
+	core_open();
+	if (core_handle_q == NULL) {
+		pr_info("%s: apr registration for CORE failed\n", __func__);
+		return -ENODEV;
+	}
+
+	bus_bw_req.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	bus_bw_req.hdr.pkt_size = sizeof(struct adsp_cmd_remote_bus_bw_request);
+
+	bus_bw_req.hdr.src_port = 0;
+	bus_bw_req.hdr.dest_port = 0;
+	bus_bw_req.hdr.token = 0;
+	bus_bw_req.hdr.opcode = ADSP_CMD_REMOTE_BUS_BW_REQUEST;
+
+	bus_bw_req.bus_identifier = bus_id;
+	bus_bw_req.reserved = 0;
+	bus_bw_req.ab_bps = ab_bps;
+	bus_bw_req.ib_bps = ib_bps;
+
+	bus_bw_resp_received = 0;
+	ret = apr_send_pkt(core_handle_q, (uint32_t *) &bus_bw_req);
+	if (ret < 0) {
+		pr_err("%s: CORE bus bw request failed\n", __func__);
+		goto fail_cmd;
+	}
+
+	ret = wait_event_timeout(bus_bw_req_wait, (bus_bw_resp_received == 1),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		ret = -ETIME;
+		goto fail_cmd;
+	}
+
+	return 0;
+
+fail_cmd:
+	return ret;
+}
+
+uint32_t core_get_adsp_version(void)
+{
+	struct apr_hdr *hdr;
+	int32_t rc = 0, ret = 0;
+	core_open();
+	if (core_handle_q) {
+		hdr = (struct apr_hdr *)l_buf;
+		hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		hdr->pkt_size = APR_PKT_SIZE(APR_HDR_SIZE, 0);
+		hdr->src_port = 0;
+		hdr->dest_port = 0;
+		hdr->token = 0;
+		hdr->opcode = ADSP_GET_VERSION;
+
+		apr_send_pkt(core_handle_q, (uint32_t *)l_buf);
+		query_adsp_ver = 1;
+		pr_info("Write_q\n");
+		ret = wait_event_timeout(adsp_version_wait,
+					(query_adsp_ver == 0),
+					msecs_to_jiffies(TIMEOUT_MS));
+		rc = adsp_version;
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			rc = -ENODEV;
+		}
+	} else
+		pr_info("apr registration failed\n");
+	return rc;
+}
+EXPORT_SYMBOL(core_get_adsp_version);
+
+static ssize_t apr_debug_write(struct file *file, const char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	int len;
+	static int t_len;
+
+	if (count < 0)
+		return 0;
+	len = count > 63 ? 63 : count;
+	if (copy_from_user(l_buf + 20 , buf, len)) {
+		pr_info("Unable to copy data from user space\n");
+		return -EFAULT;
+	}
+	l_buf[len + 20] = 0;
+	if (l_buf[len + 20 - 1] == '\n') {
+		l_buf[len + 20 - 1] = 0;
+		len--;
+	}
+	if (!strncmp(l_buf + 20, "open_q", 64)) {
+		apr_handle_q = apr_register("ADSP", "TEST", aprv2_debug_fn_q,
+							0xFFFFFFFF, NULL);
+		pr_info("Open_q %p\n", apr_handle_q);
+	} else if (!strncmp(l_buf + 20, "open_m", 64)) {
+		apr_handle_m = apr_register("MODEM", "TEST", aprv2_debug_fn_m,
+							0xFFFFFFFF, NULL);
+		pr_info("Open_m %p\n", apr_handle_m);
+	} else if (!strncmp(l_buf + 20, "write_q", 64)) {
+		struct apr_hdr *hdr;
+
+		t_len++;
+		t_len = t_len % 450;
+		if (!t_len % 99)
+			msleep(2000);
+		hdr = (struct apr_hdr *)l_buf;
+		hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+					APR_HDR_LEN(20), APR_PKT_VER);
+		hdr->pkt_size = APR_PKT_SIZE(20, t_len);
+		hdr->src_port = 0;
+		hdr->dest_port = 0;
+		hdr->token = 0;
+		hdr->opcode = 0x12345678;
+		memset(l_buf + 20, 9, 4060);
+
+		apr_send_pkt(apr_handle_q, (uint32_t *)l_buf);
+		pr_debug("Write_q\n");
+	} else if (!strncmp(l_buf + 20, "write_m", 64)) {
+		struct apr_hdr *hdr;
+
+		hdr = (struct apr_hdr *)l_buf;
+		hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+					APR_HDR_LEN(20), APR_PKT_VER);
+		hdr->pkt_size = APR_PKT_SIZE(20, 8);
+		hdr->src_port = 0;
+		hdr->dest_port = 0;
+		hdr->token = 0;
+		hdr->opcode = 0x12345678;
+		memset(l_buf + 30, 9, 4060);
+
+		apr_send_pkt(apr_handle_m, (uint32_t *)l_buf);
+		pr_info("Write_m\n");
+	} else if (!strncmp(l_buf + 20, "write_q4", 64)) {
+		struct apr_hdr *hdr;
+
+		hdr = (struct apr_hdr *)l_buf;
+		hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+					APR_HDR_LEN(20), APR_PKT_VER);
+		hdr->pkt_size = APR_PKT_SIZE(20, 4076);
+		hdr->src_port = 0;
+		hdr->dest_port = 0;
+		hdr->token = 0;
+		hdr->opcode = 0x12345678;
+		memset(l_buf + 30, 9, 4060);
+
+		apr_send_pkt(apr_handle_q, (uint32_t *)l_buf);
+		pr_info("Write_q\n");
+	} else if (!strncmp(l_buf + 20, "write_m4", 64)) {
+		struct apr_hdr *hdr;
+
+		hdr = (struct apr_hdr *)l_buf;
+		hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+					APR_HDR_LEN(20), APR_PKT_VER);
+		hdr->pkt_size = APR_PKT_SIZE(20, 4076);
+		hdr->src_port = 0;
+		hdr->dest_port = 0;
+		hdr->token = 0;
+		hdr->opcode = 0x12345678;
+		memset(l_buf + 30, 9, 4060);
+
+		apr_send_pkt(apr_handle_m, (uint32_t *)l_buf);
+		pr_info("Write_m\n");
+	} else if (!strncmp(l_buf + 20, "close", 64)) {
+		if (apr_handle_q)
+			apr_deregister(apr_handle_q);
+	} else if (!strncmp(l_buf + 20, "loaded", 64)) {
+		change_q6_state(APR_Q6_LOADED);
+	} else if (!strncmp(l_buf + 20, "boom", 64)) {
+		q6audio_dsp_not_responding();
+	} else if (!strncmp(l_buf + 20, "dsp_ver", 64)) {
+			core_get_adsp_version();
+	} else if (!strncmp(l_buf + 20, "en_pwr_col", 64)) {
+		struct adsp_power_collapse pc;
+
+		core_open();
+		if (core_handle_q) {
+			pc.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+			pc.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+						sizeof(uint32_t));;
+			pc.hdr.src_port = 0;
+			pc.hdr.dest_port = 0;
+			pc.hdr.token = 0;
+			pc.hdr.opcode = ADSP_CMD_SET_POWER_COLLAPSE_STATE;
+			pc.power_collapse = 0x00000000;
+			apr_send_pkt(core_handle_q, (uint32_t *)&pc);
+			pr_info("Write_q :enable power collapse\n");
+		}
+	} else if (!strncmp(l_buf + 20, "dis_pwr_col", 64)) {
+		struct adsp_power_collapse pc;
+
+		core_open();
+		if (core_handle_q) {
+			pc.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_EVENT,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+			pc.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+							sizeof(uint32_t));
+			pc.hdr.src_port = 0;
+			pc.hdr.dest_port = 0;
+			pc.hdr.token = 0;
+			pc.hdr.opcode = ADSP_CMD_SET_POWER_COLLAPSE_STATE;
+			pc.power_collapse = 0x00000001;
+			apr_send_pkt(core_handle_q, (uint32_t *)&pc);
+			pr_info("Write_q:disable power collapse\n");
+		}
+	} else
+		pr_info("Unknown Command\n");
+
+	return count;
+}
+
+static const struct file_operations apr_debug_fops = {
+	.write = apr_debug_write,
+	.open = apr_debug_open,
+};
+
+static int __init core_init(void)
+{
+	init_waitqueue_head(&bus_bw_req_wait);
+	bus_bw_resp_received = 0;
+
+	query_adsp_ver = 0;
+	init_waitqueue_head(&adsp_version_wait);
+	adsp_version = 0;
+
+	core_handle_q = NULL;
+
+#ifdef CONFIG_DEBUG_FS
+	dentry = debugfs_create_file("apr", S_IFREG | S_IRUGO | S_IWUSR
+		| S_IWGRP, NULL, (void *) NULL, &apr_debug_fops);
+#endif /* CONFIG_DEBUG_FS */
+
+	return 0;
+}
+
+device_initcall(core_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/q6core.h b/arch/arm/mach-msm/qdsp6v2/q6core.h
new file mode 100644
index 0000000..cb25d6b
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/q6core.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __Q6CORE_H__
+#define __Q6CORE_H__
+#include <mach/qdsp6v2/apr.h>
+
+
+#define ADSP_CMD_REMOTE_BUS_BW_REQUEST		0x0001115D
+#define AUDIO_IF_BUS_ID				1
+
+struct adsp_cmd_remote_bus_bw_request {
+	struct apr_hdr hdr;
+	u16 bus_identifier;
+	u16 reserved;
+	u32 ab_bps;
+	u32 ib_bps;
+} __packed;
+
+#define ADSP_GET_VERSION     0x00011152
+#define ADSP_GET_VERSION_RSP 0x00011153
+
+struct adsp_get_version {
+	uint32_t build_id;
+	uint32_t svc_cnt;
+};
+
+struct adsp_service_info {
+	uint32_t svc_id;
+	uint32_t svc_ver;
+};
+
+#define ADSP_CMD_SET_POWER_COLLAPSE_STATE 0x0001115C
+struct adsp_power_collapse {
+	struct apr_hdr hdr;
+	uint32_t power_collapse;
+};
+
+int core_req_bus_bandwith(u16 bus_id, u32 ab_bps, u32 ib_bps);
+
+uint32_t core_get_adsp_version(void);
+
+#endif /* __Q6CORE_H__ */
diff --git a/arch/arm/mach-msm/qdsp6v2/q6voice.c b/arch/arm/mach-msm/qdsp6v2/q6voice.c
new file mode 100644
index 0000000..b5a152c
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/q6voice.c
@@ -0,0 +1,2817 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/msm_audio.h>
+#include <linux/kthread.h>
+#include <linux/completion.h>
+#include <linux/wait.h>
+#include <linux/mutex.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <mach/dal.h>
+#include <mach/qdsp6v2/q6voice.h>
+#include <mach/qdsp6v2/rtac.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+#include "q6core.h"
+
+
+#define TIMEOUT_MS 3000
+#define SNDDEV_CAP_TTY 0x20
+
+#define CMD_STATUS_SUCCESS 0
+#define CMD_STATUS_FAIL 1
+
+#define VOC_PATH_PASSIVE 0
+#define VOC_PATH_FULL 1
+#define ADSP_VERSION_CVD 0x60300000
+
+#define BUFFER_PAYLOAD_SIZE 4000
+
+#define VOC_REC_NONE 0xFF
+
+struct voice_data voice;
+
+static bool is_adsp_support_cvd(void)
+{
+	return (voice.adsp_version >= ADSP_VERSION_CVD);
+}
+static int voice_send_enable_vocproc_cmd(struct voice_data *v);
+static int voice_send_netid_timing_cmd(struct voice_data *v);
+
+static void *voice_get_apr_mvm(struct voice_data *v)
+{
+	void *apr_mvm = NULL;
+
+	if (v->voc_path == VOC_PATH_PASSIVE &&
+		!(is_adsp_support_cvd()))
+		apr_mvm = v->apr_mvm;
+	else
+		apr_mvm = v->apr_q6_mvm;
+
+	pr_debug("%s: apr_mvm 0x%x\n", __func__, (unsigned int)apr_mvm);
+
+	return apr_mvm;
+}
+
+static void voice_set_apr_mvm(struct voice_data *v, void *apr_mvm)
+{
+	pr_debug("%s: apr_mvm 0x%x\n", __func__, (unsigned int)apr_mvm);
+
+	if (v->voc_path == VOC_PATH_PASSIVE &&
+		!(is_adsp_support_cvd()))
+		v->apr_mvm = apr_mvm;
+	else
+		v->apr_q6_mvm = apr_mvm;
+}
+
+static void *voice_get_apr_cvs(struct voice_data *v)
+{
+	void *apr_cvs = NULL;
+
+	if (v->voc_path == VOC_PATH_PASSIVE &&
+		!(is_adsp_support_cvd()))
+		apr_cvs = v->apr_cvs;
+	else
+		apr_cvs = v->apr_q6_cvs;
+
+	pr_debug("%s: apr_cvs 0x%x\n", __func__, (unsigned int)apr_cvs);
+
+	return apr_cvs;
+}
+
+static void voice_set_apr_cvs(struct voice_data *v, void *apr_cvs)
+{
+	pr_debug("%s: apr_cvs 0x%x\n", __func__, (unsigned int)apr_cvs);
+
+	if (v->voc_path == VOC_PATH_PASSIVE &&
+		!(is_adsp_support_cvd()))
+		v->apr_cvs = apr_cvs;
+	else
+		v->apr_q6_cvs = apr_cvs;
+#ifdef CONFIG_MSM8X60_RTAC
+	rtac_set_voice_handle(RTAC_CVS, apr_cvs);
+#endif
+}
+
+static void *voice_get_apr_cvp(struct voice_data *v)
+{
+	void *apr_cvp = NULL;
+
+	if (v->voc_path == VOC_PATH_PASSIVE &&
+		!(is_adsp_support_cvd()))
+		apr_cvp = v->apr_cvp;
+	else
+		apr_cvp = v->apr_q6_cvp;
+
+	pr_debug("%s: apr_cvp 0x%x\n", __func__, (unsigned int)apr_cvp);
+
+	return apr_cvp;
+}
+
+static void voice_set_apr_cvp(struct voice_data *v, void *apr_cvp)
+{
+	pr_debug("%s: apr_cvp 0x%x\n", __func__, (unsigned int)apr_cvp);
+
+	if (v->voc_path == VOC_PATH_PASSIVE &&
+		!(is_adsp_support_cvd()))
+		v->apr_cvp = apr_cvp;
+	else
+		v->apr_q6_cvp = apr_cvp;
+#ifdef CONFIG_MSM8X60_RTAC
+	rtac_set_voice_handle(RTAC_CVP, apr_cvp);
+#endif
+}
+
+static u16 voice_get_mvm_handle(struct voice_data *v)
+{
+	u16 mvm_handle = 0;
+
+	if (v->voc_path == VOC_PATH_PASSIVE)
+		mvm_handle = v->mvm_handle;
+	else
+		mvm_handle = v->mvm_q6_handle;
+
+	pr_debug("%s: mvm_handle %d\n", __func__, mvm_handle);
+
+	return mvm_handle;
+}
+
+static void voice_set_mvm_handle(struct voice_data *v, u16 mvm_handle)
+{
+	pr_debug("%s: mvm_handle %d\n", __func__, mvm_handle);
+
+	if (v->voc_path == VOC_PATH_PASSIVE)
+		v->mvm_handle = mvm_handle;
+	else
+		v->mvm_q6_handle = mvm_handle;
+}
+
+static u16 voice_get_cvs_handle(struct voice_data *v)
+{
+	u16 cvs_handle = 0;
+
+	if (v->voc_path == VOC_PATH_PASSIVE)
+		cvs_handle = v->cvs_handle;
+	else
+		cvs_handle = v->cvs_q6_handle;
+
+	pr_debug("%s: cvs_handle %d\n", __func__, cvs_handle);
+
+	return cvs_handle;
+}
+
+static void voice_set_cvs_handle(struct voice_data *v, u16 cvs_handle)
+{
+	pr_debug("%s: cvs_handle %d\n", __func__, cvs_handle);
+
+	if (v->voc_path == VOC_PATH_PASSIVE)
+		v->cvs_handle = cvs_handle;
+	else
+		v->cvs_q6_handle = cvs_handle;
+}
+
+static u16 voice_get_cvp_handle(struct voice_data *v)
+{
+	u16 cvp_handle = 0;
+
+	if (v->voc_path == VOC_PATH_PASSIVE)
+		cvp_handle = v->cvp_handle;
+	else
+		cvp_handle = v->cvp_q6_handle;
+
+	pr_debug("%s: cvp_handle %d\n", __func__, cvp_handle);
+
+	return cvp_handle;
+}
+
+static void voice_set_cvp_handle(struct voice_data *v, u16 cvp_handle)
+{
+	pr_debug("%s: cvp_handle %d\n", __func__, cvp_handle);
+
+	if (v->voc_path == VOC_PATH_PASSIVE)
+		v->cvp_handle = cvp_handle;
+	else
+		v->cvp_q6_handle = cvp_handle;
+}
+
+static void voice_auddev_cb_function(u32 evt_id,
+			union auddev_evt_data *evt_payload,
+			void *private_data);
+
+static int32_t modem_mvm_callback(struct apr_client_data *data, void *priv);
+static int32_t modem_cvs_callback(struct apr_client_data *data, void *priv);
+static int32_t modem_cvp_callback(struct apr_client_data *data, void *priv);
+
+static int voice_apr_register(struct voice_data *v)
+{
+	int rc = 0;
+	void *apr_mvm;
+	void *apr_cvs;
+	void *apr_cvp;
+
+	if (v->adsp_version == 0) {
+		v->adsp_version = core_get_adsp_version();
+		pr_info("adsp_ver fetched:%x\n", v->adsp_version);
+	}
+	apr_mvm = voice_get_apr_mvm(v);
+	apr_cvs = voice_get_apr_cvs(v);
+	apr_cvp = voice_get_apr_cvp(v);
+
+
+	pr_debug("into voice_apr_register_callback\n");
+	/* register callback to APR */
+	if (apr_mvm == NULL) {
+		pr_debug("start to register MVM callback\n");
+
+		if (v->voc_path == VOC_PATH_PASSIVE &&
+			!(is_adsp_support_cvd())) {
+			apr_mvm = apr_register("MODEM", "MVM",
+					       modem_mvm_callback, 0xFFFFFFFF,
+					       v);
+		} else {
+			apr_mvm = apr_register("ADSP", "MVM",
+					       modem_mvm_callback, 0xFFFFFFFF,
+					       v);
+		}
+
+		if (apr_mvm == NULL) {
+			pr_err("Unable to register MVM %d\n",
+						is_adsp_support_cvd());
+			rc = -ENODEV;
+			goto done;
+		}
+
+		voice_set_apr_mvm(v, apr_mvm);
+	}
+
+	if (apr_cvs == NULL) {
+		pr_debug("start to register CVS callback\n");
+
+		if (v->voc_path == VOC_PATH_PASSIVE &&
+			!(is_adsp_support_cvd())) {
+			apr_cvs = apr_register("MODEM", "CVS",
+					       modem_cvs_callback, 0xFFFFFFFF,
+					       v);
+		} else {
+			apr_cvs = apr_register("ADSP", "CVS",
+					       modem_cvs_callback, 0xFFFFFFFF,
+					       v);
+		}
+
+		if (apr_cvs == NULL) {
+			pr_err("Unable to register CVS %d\n",
+							is_adsp_support_cvd());
+			rc = -ENODEV;
+			goto err;
+		}
+
+		voice_set_apr_cvs(v, apr_cvs);
+	}
+
+	if (apr_cvp == NULL) {
+		pr_debug("start to register CVP callback\n");
+
+		if (v->voc_path == VOC_PATH_PASSIVE &&
+			!(is_adsp_support_cvd())) {
+			apr_cvp = apr_register("MODEM", "CVP",
+					       modem_cvp_callback, 0xFFFFFFFF,
+					       v);
+		} else {
+			apr_cvp = apr_register("ADSP", "CVP",
+					       modem_cvp_callback, 0xFFFFFFFF,
+					       v);
+	}
+
+		if (apr_cvp == NULL) {
+			pr_err("Unable to register CVP %d\n",
+							is_adsp_support_cvd());
+			rc = -ENODEV;
+			goto err1;
+		}
+
+		voice_set_apr_cvp(v, apr_cvp);
+	}
+	return 0;
+
+err1:
+	apr_deregister(apr_cvs);
+	apr_cvs = NULL;
+	voice_set_apr_cvs(v, apr_cvs);
+err:
+	apr_deregister(apr_mvm);
+	apr_mvm = NULL;
+	voice_set_apr_mvm(v, apr_mvm);
+
+done:
+	return rc;
+}
+
+static int voice_create_mvm_cvs_session(struct voice_data *v)
+{
+	int ret = 0;
+	struct mvm_create_ctl_session_cmd mvm_session_cmd;
+	struct cvs_create_passive_ctl_session_cmd cvs_session_cmd;
+	struct cvs_create_full_ctl_session_cmd cvs_full_ctl_cmd;
+	struct mvm_attach_stream_cmd attach_stream_cmd;
+	void *apr_mvm = voice_get_apr_mvm(v);
+	void *apr_cvs = voice_get_apr_cvs(v);
+	void *apr_cvp = voice_get_apr_cvp(v);
+	u16 mvm_handle = voice_get_mvm_handle(v);
+	u16 cvs_handle = voice_get_cvs_handle(v);
+	u16 cvp_handle = voice_get_cvp_handle(v);
+
+	pr_info("%s:\n", __func__);
+
+	/* start to ping if modem service is up */
+	pr_debug("in voice_create_mvm_cvs_session, mvm_hdl=%d, cvs_hdl=%d\n",
+					mvm_handle, cvs_handle);
+	/* send cmd to create mvm session and wait for response */
+
+	if (!mvm_handle) {
+		if (v->voc_path == VOC_PATH_PASSIVE) {
+			mvm_session_cmd.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+			mvm_session_cmd.hdr.pkt_size =
+				APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(mvm_session_cmd) - APR_HDR_SIZE);
+			pr_debug("Send mvm create session pkt size = %d\n",
+				mvm_session_cmd.hdr.pkt_size);
+			mvm_session_cmd.hdr.src_port = 0;
+			mvm_session_cmd.hdr.dest_port = 0;
+			mvm_session_cmd.hdr.token = 0;
+			pr_debug("%s: Creating MVM passive ctrl\n", __func__);
+			mvm_session_cmd.hdr.opcode =
+				VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION;
+			strncpy(mvm_session_cmd.mvm_session.name,
+				"default modem voice", SESSION_NAME_LEN);
+
+			v->mvm_state = CMD_STATUS_FAIL;
+
+			ret = apr_send_pkt(apr_mvm,
+					   (uint32_t *) &mvm_session_cmd);
+			if (ret < 0) {
+				pr_err("Error sending MVM_CONTROL_SESSION\n");
+				goto fail;
+			}
+			ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+			if (!ret) {
+				pr_err("%s: wait_event timeout\n", __func__);
+				goto fail;
+			}
+		} else {
+			mvm_session_cmd.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+			mvm_session_cmd.hdr.pkt_size =
+				APR_PKT_SIZE(APR_HDR_SIZE,
+				       sizeof(mvm_session_cmd) - APR_HDR_SIZE);
+			pr_debug("Send mvm create session pkt size = %d\n",
+				mvm_session_cmd.hdr.pkt_size);
+			mvm_session_cmd.hdr.src_port = 0;
+			mvm_session_cmd.hdr.dest_port = 0;
+			mvm_session_cmd.hdr.token = 0;
+			pr_debug("%s: Creating MVM full ctrl\n", __func__);
+			mvm_session_cmd.hdr.opcode =
+				VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION;
+			strncpy(mvm_session_cmd.mvm_session.name,
+				"default voip", SESSION_NAME_LEN);
+
+			v->mvm_state = CMD_STATUS_FAIL;
+
+			ret = apr_send_pkt(apr_mvm,
+					   (uint32_t *) &mvm_session_cmd);
+			if (ret < 0) {
+				pr_err("Error sending MVM_FULL_CTL_SESSION\n");
+				goto fail;
+			}
+			ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+			if (!ret) {
+				pr_err("%s: wait_event timeout\n", __func__);
+				goto fail;
+			}
+		}
+
+		/* Get the created MVM handle. */
+		mvm_handle = voice_get_mvm_handle(v);
+	}
+
+	/* send cmd to create cvs session */
+	if (!cvs_handle) {
+		if (v->voc_path == VOC_PATH_PASSIVE) {
+			pr_info("%s:creating CVS passive session\n", __func__);
+
+		cvs_session_cmd.hdr.hdr_field = APR_HDR_FIELD(
+						APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		cvs_session_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(cvs_session_cmd) - APR_HDR_SIZE);
+		pr_info("send stream create session pkt size = %d\n",
+					cvs_session_cmd.hdr.pkt_size);
+		cvs_session_cmd.hdr.src_port = 0;
+		cvs_session_cmd.hdr.dest_port = 0;
+		cvs_session_cmd.hdr.token = 0;
+		cvs_session_cmd.hdr.opcode =
+				VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION;
+		strncpy(cvs_session_cmd.cvs_session.name,
+			"default modem voice", SESSION_NAME_LEN);
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		pr_info("%s: CVS create\n", __func__);
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_session_cmd);
+		if (ret < 0) {
+			pr_err("Fail in sending STREAM_CONTROL_SESSION\n");
+			goto fail;
+		}
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			goto fail;
+		}
+
+			/* Get the created CVS handle. */
+			cvs_handle = voice_get_cvs_handle(v);
+		} else {
+			pr_info("%s:creating CVS full session\n", __func__);
+
+			cvs_full_ctl_cmd.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+
+			cvs_full_ctl_cmd.hdr.pkt_size =
+				APR_PKT_SIZE(APR_HDR_SIZE,
+				       sizeof(cvs_full_ctl_cmd) - APR_HDR_SIZE);
+
+			cvs_full_ctl_cmd.hdr.src_port = 0;
+			cvs_full_ctl_cmd.hdr.dest_port = 0;
+			cvs_full_ctl_cmd.hdr.token = 0;
+			cvs_full_ctl_cmd.hdr.opcode =
+			VSS_ISTREAM_CMD_CREATE_FULL_CONTROL_SESSION;
+			cvs_full_ctl_cmd.cvs_session.direction = 2;
+
+			cvs_full_ctl_cmd.cvs_session.enc_media_type =
+							v->mvs_info.media_type;
+			cvs_full_ctl_cmd.cvs_session.dec_media_type =
+							v->mvs_info.media_type;
+			cvs_full_ctl_cmd.cvs_session.network_id =
+						       v->mvs_info.network_type;
+			strncpy(cvs_full_ctl_cmd.cvs_session.name,
+				"default voip", SESSION_NAME_LEN);
+
+			v->cvs_state = CMD_STATUS_FAIL;
+
+			ret = apr_send_pkt(apr_cvs,
+					   (uint32_t *) &cvs_full_ctl_cmd);
+
+			if (ret < 0) {
+				pr_err("%s: Err %d sending CREATE_FULL_CTRL\n",
+					   __func__, ret);
+				goto fail;
+			}
+			ret = wait_event_timeout(v->cvs_wait,
+					(v->cvs_state == CMD_STATUS_SUCCESS),
+					msecs_to_jiffies(TIMEOUT_MS));
+			if (!ret) {
+				pr_err("%s: wait_event timeout\n", __func__);
+				goto fail;
+			}
+
+			/* Get the created CVS handle. */
+			cvs_handle = voice_get_cvs_handle(v);
+
+			/* Attach MVM to CVS. */
+			pr_info("%s: Attach MVM to stream\n", __func__);
+
+			attach_stream_cmd.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+
+			attach_stream_cmd.hdr.pkt_size =
+				APR_PKT_SIZE(APR_HDR_SIZE,
+				      sizeof(attach_stream_cmd) - APR_HDR_SIZE);
+			attach_stream_cmd.hdr.src_port = 0;
+			attach_stream_cmd.hdr.dest_port = mvm_handle;
+			attach_stream_cmd.hdr.token = 0;
+			attach_stream_cmd.hdr.opcode =
+						VSS_IMVM_CMD_ATTACH_STREAM;
+			attach_stream_cmd.attach_stream.handle = cvs_handle;
+
+			v->mvm_state = CMD_STATUS_FAIL;
+			ret = apr_send_pkt(apr_mvm,
+					   (uint32_t *) &attach_stream_cmd);
+			if (ret < 0) {
+				pr_err("%s: Error %d sending ATTACH_STREAM\n",
+				       __func__, ret);
+				goto fail;
+			}
+			ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+			if (!ret) {
+				pr_err("%s: wait_event timeout\n", __func__);
+				goto fail;
+			}
+		}
+	}
+
+	return 0;
+
+fail:
+	apr_deregister(apr_mvm);
+	apr_mvm = NULL;
+	voice_set_apr_mvm(v, apr_mvm);
+
+	apr_deregister(apr_cvs);
+	apr_cvs = NULL;
+	voice_set_apr_cvs(v, apr_cvs);
+
+	apr_deregister(apr_cvp);
+	apr_cvp = NULL;
+	voice_set_apr_cvp(v, apr_cvp);
+
+	cvp_handle = 0;
+	voice_set_cvp_handle(v, cvp_handle);
+
+	cvs_handle = 0;
+	voice_set_cvs_handle(v, cvs_handle);
+
+	return -EINVAL;
+}
+
+static int voice_destroy_mvm_cvs_session(struct voice_data *v)
+{
+	int ret = 0;
+	struct mvm_detach_stream_cmd detach_stream;
+	struct apr_hdr mvm_destroy;
+	struct apr_hdr cvs_destroy;
+	void *apr_mvm = voice_get_apr_mvm(v);
+	void *apr_cvs = voice_get_apr_cvs(v);
+	u16 mvm_handle = voice_get_mvm_handle(v);
+	u16 cvs_handle = voice_get_cvs_handle(v);
+
+	/* MVM, CVS sessions are destroyed only for Full control sessions. */
+	if (v->voc_path == VOC_PATH_FULL) {
+		pr_info("%s: MVM detach stream\n", __func__);
+
+		/* Detach voice stream. */
+		detach_stream.hdr.hdr_field =
+			APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				      APR_HDR_LEN(APR_HDR_SIZE),
+				      APR_PKT_VER);
+		detach_stream.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					  sizeof(detach_stream) - APR_HDR_SIZE);
+		detach_stream.hdr.src_port = 0;
+		detach_stream.hdr.dest_port = mvm_handle;
+		detach_stream.hdr.token = 0;
+		detach_stream.hdr.opcode = VSS_IMVM_CMD_DETACH_STREAM;
+		detach_stream.detach_stream.handle = cvs_handle;
+
+		v->mvm_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_mvm, (uint32_t *) &detach_stream);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending DETACH_STREAM\n",
+			       __func__, ret);
+
+			goto fail;
+		}
+
+		ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait event timeout\n", __func__);
+			goto fail;
+		}
+
+		/* Destroy CVS. */
+		pr_info("%s: CVS destroy session\n", __func__);
+
+		cvs_destroy.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						      APR_HDR_LEN(APR_HDR_SIZE),
+						      APR_PKT_VER);
+		cvs_destroy.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					    sizeof(cvs_destroy) - APR_HDR_SIZE);
+		cvs_destroy.src_port = 0;
+		cvs_destroy.dest_port = cvs_handle;
+		cvs_destroy.token = 0;
+		cvs_destroy.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_destroy);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending CVS DESTROY\n",
+			       __func__, ret);
+
+			goto fail;
+		}
+
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait event timeout\n", __func__);
+
+			goto fail;
+		}
+		cvs_handle = 0;
+		voice_set_cvs_handle(v, cvs_handle);
+
+		/* Destroy MVM. */
+		pr_info("%s: MVM destroy session\n", __func__);
+
+		mvm_destroy.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						      APR_HDR_LEN(APR_HDR_SIZE),
+						      APR_PKT_VER);
+		mvm_destroy.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					    sizeof(mvm_destroy) - APR_HDR_SIZE);
+		mvm_destroy.src_port = 0;
+		mvm_destroy.dest_port = mvm_handle;
+		mvm_destroy.token = 0;
+		mvm_destroy.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
+
+		v->mvm_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_destroy);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending MVM DESTROY\n",
+			       __func__, ret);
+
+			goto fail;
+		}
+
+		ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait event timeout\n", __func__);
+
+			goto fail;
+		}
+		mvm_handle = 0;
+		voice_set_mvm_handle(v, mvm_handle);
+	}
+
+fail:
+	return 0;
+}
+
+static int voice_send_tty_mode_to_modem(struct voice_data *v)
+{
+	struct msm_snddev_info *dev_tx_info;
+	struct msm_snddev_info *dev_rx_info;
+	int tty_mode = 0;
+	int ret = 0;
+	struct mvm_set_tty_mode_cmd mvm_tty_mode_cmd;
+	void *apr_mvm = voice_get_apr_mvm(v);
+	u16 mvm_handle = voice_get_mvm_handle(v);
+
+	dev_rx_info = audio_dev_ctrl_find_dev(v->dev_rx.dev_id);
+	if (IS_ERR(dev_rx_info)) {
+		pr_err("bad dev_id %d\n", v->dev_rx.dev_id);
+		goto done;
+	}
+
+	dev_tx_info = audio_dev_ctrl_find_dev(v->dev_tx.dev_id);
+	if (IS_ERR(dev_tx_info)) {
+		pr_err("bad dev_id %d\n", v->dev_tx.dev_id);
+		goto done;
+	}
+
+	if ((dev_rx_info->capability & SNDDEV_CAP_TTY) &&
+		(dev_tx_info->capability & SNDDEV_CAP_TTY))
+		tty_mode = 3; /* FULL */
+	else if (!(dev_tx_info->capability & SNDDEV_CAP_TTY) &&
+		(dev_rx_info->capability & SNDDEV_CAP_TTY))
+		tty_mode = 2; /* VCO */
+	else if ((dev_tx_info->capability & SNDDEV_CAP_TTY) &&
+		!(dev_rx_info->capability & SNDDEV_CAP_TTY))
+		tty_mode = 1; /* HCO */
+
+	if (tty_mode) {
+		/* send tty mode cmd to mvm */
+		mvm_tty_mode_cmd.hdr.hdr_field = APR_HDR_FIELD(
+			APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE),
+								APR_PKT_VER);
+		mvm_tty_mode_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			sizeof(mvm_tty_mode_cmd) - APR_HDR_SIZE);
+		pr_debug("pkt size = %d\n", mvm_tty_mode_cmd.hdr.pkt_size);
+		mvm_tty_mode_cmd.hdr.src_port = 0;
+		mvm_tty_mode_cmd.hdr.dest_port = mvm_handle;
+		mvm_tty_mode_cmd.hdr.token = 0;
+		mvm_tty_mode_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_TTY_MODE;
+		mvm_tty_mode_cmd.tty_mode.mode = tty_mode;
+		pr_info("tty mode =%d\n", mvm_tty_mode_cmd.tty_mode.mode);
+
+		v->mvm_state = CMD_STATUS_FAIL;
+		pr_info("%s: MVM set tty\n", __func__);
+		ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_tty_mode_cmd);
+		if (ret < 0) {
+			pr_err("Fail: sending VSS_ISTREAM_CMD_SET_TTY_MODE\n");
+			goto done;
+		}
+		ret = wait_event_timeout(v->mvm_wait,
+					 (v->mvm_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			goto done;
+		}
+	}
+	return 0;
+done:
+	return -EINVAL;
+}
+
+static int voice_send_cvs_cal_to_modem(struct voice_data *v)
+{
+	struct apr_hdr cvs_cal_cmd_hdr;
+	uint32_t *cmd_buf;
+	struct acdb_cal_data cal_data;
+	struct acdb_cal_block *cal_blk;
+	int32_t cal_size_per_network;
+	uint32_t *cal_data_per_network;
+	int index = 0;
+	int ret = 0;
+	void *apr_cvs = voice_get_apr_cvs(v);
+	u16 cvs_handle = voice_get_cvs_handle(v);
+
+	/* fill the header */
+	cvs_cal_cmd_hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvs_cal_cmd_hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		sizeof(cvs_cal_cmd_hdr) - APR_HDR_SIZE);
+	cvs_cal_cmd_hdr.src_port = 0;
+	cvs_cal_cmd_hdr.dest_port = cvs_handle;
+	cvs_cal_cmd_hdr.token = 0;
+	cvs_cal_cmd_hdr.opcode =
+		VSS_ISTREAM_CMD_CACHE_CALIBRATION_DATA;
+
+	pr_debug("voice_send_cvs_cal_to_modem\n");
+	/* get the cvs cal data */
+	get_vocstrm_cal(&cal_data);
+	if (cal_data.num_cal_blocks == 0) {
+		pr_err("%s: No calibration data to send!\n", __func__);
+		goto done;
+	}
+
+	/* send cvs cal to modem */
+	cmd_buf = kzalloc((sizeof(struct apr_hdr) + BUFFER_PAYLOAD_SIZE),
+								GFP_KERNEL);
+	if (!cmd_buf) {
+		pr_err("No memory is allocated.\n");
+		return -ENOMEM;
+	}
+	pr_debug("----- num_cal_blocks=%d\n", (s32)cal_data.num_cal_blocks);
+	cal_blk = cal_data.cal_blocks;
+	pr_debug("cal_blk =%x\n", (uint32_t)cal_data.cal_blocks);
+
+	for (; index < cal_data.num_cal_blocks; index++) {
+		cal_size_per_network = cal_blk[index].cal_size;
+		pr_debug(" cal size =%d\n", cal_size_per_network);
+		if (cal_size_per_network >= BUFFER_PAYLOAD_SIZE)
+			pr_err("Cal size is too big\n");
+		cal_data_per_network = (u32 *)cal_blk[index].cal_kvaddr;
+		pr_debug(" cal data=%x\n", (uint32_t)cal_data_per_network);
+		cvs_cal_cmd_hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			cal_size_per_network);
+		pr_debug("header size =%d,  pkt_size =%d\n",
+			APR_HDR_SIZE, cvs_cal_cmd_hdr.pkt_size);
+		memcpy(cmd_buf, &cvs_cal_cmd_hdr,  APR_HDR_SIZE);
+		memcpy(cmd_buf + (APR_HDR_SIZE / sizeof(uint32_t)),
+			cal_data_per_network, cal_size_per_network);
+		pr_debug("send cvs cal: index =%d\n", index);
+		v->cvs_state = CMD_STATUS_FAIL;
+		ret = apr_send_pkt(apr_cvs, cmd_buf);
+		if (ret < 0) {
+			pr_err("Fail: sending cvs cal, idx=%d\n", index);
+			continue;
+		}
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			return -EINVAL;
+		}
+	}
+	kfree(cmd_buf);
+done:
+	return 0;
+}
+
+static int voice_send_cvp_cal_to_modem(struct voice_data *v)
+{
+	struct apr_hdr cvp_cal_cmd_hdr;
+	uint32_t *cmd_buf;
+	struct acdb_cal_data cal_data;
+	struct acdb_cal_block *cal_blk;
+	int32_t cal_size_per_network;
+	uint32_t *cal_data_per_network;
+	int index = 0;
+	int ret = 0;
+	void *apr_cvp = voice_get_apr_cvp(v);
+	u16 cvp_handle = voice_get_cvp_handle(v);
+
+
+	/* fill the header */
+	cvp_cal_cmd_hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvp_cal_cmd_hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		sizeof(cvp_cal_cmd_hdr) - APR_HDR_SIZE);
+	cvp_cal_cmd_hdr.src_port = 0;
+	cvp_cal_cmd_hdr.dest_port = cvp_handle;
+	cvp_cal_cmd_hdr.token = 0;
+	cvp_cal_cmd_hdr.opcode =
+		VSS_IVOCPROC_CMD_CACHE_CALIBRATION_DATA;
+
+	/* get cal data */
+	get_vocproc_cal(&cal_data);
+	if (cal_data.num_cal_blocks == 0) {
+		pr_err("%s: No calibration data to send!\n", __func__);
+		goto done;
+	}
+
+	/* send cal to modem */
+	cmd_buf = kzalloc((sizeof(struct apr_hdr) + BUFFER_PAYLOAD_SIZE),
+								GFP_KERNEL);
+	if (!cmd_buf) {
+		pr_err("No memory is allocated.\n");
+		return -ENOMEM;
+	}
+	pr_debug("----- num_cal_blocks=%d\n", (s32)cal_data.num_cal_blocks);
+	cal_blk = cal_data.cal_blocks;
+	pr_debug(" cal_blk =%x\n", (uint32_t)cal_data.cal_blocks);
+
+	for (; index < cal_data.num_cal_blocks; index++) {
+		cal_size_per_network = cal_blk[index].cal_size;
+		if (cal_size_per_network >= BUFFER_PAYLOAD_SIZE)
+			pr_err("Cal size is too big\n");
+		pr_debug(" cal size =%d\n", cal_size_per_network);
+		cal_data_per_network = (u32 *)cal_blk[index].cal_kvaddr;
+		pr_debug(" cal data=%x\n", (uint32_t)cal_data_per_network);
+
+		cvp_cal_cmd_hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			cal_size_per_network);
+		memcpy(cmd_buf, &cvp_cal_cmd_hdr,  APR_HDR_SIZE);
+		memcpy(cmd_buf + (APR_HDR_SIZE / sizeof(*cmd_buf)),
+			cal_data_per_network, cal_size_per_network);
+		pr_debug("Send cvp cal\n");
+		v->cvp_state = CMD_STATUS_FAIL;
+		pr_info("%s: CVP calib\n", __func__);
+		ret = apr_send_pkt(apr_cvp, cmd_buf);
+		if (ret < 0) {
+			pr_err("Fail: sending cvp cal, idx=%d\n", index);
+			continue;
+		}
+		ret = wait_event_timeout(v->cvp_wait,
+					 (v->cvp_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			return -EINVAL;
+		}
+	}
+	kfree(cmd_buf);
+done:
+	return 0;
+}
+
+static int voice_send_cvp_vol_tbl_to_modem(struct voice_data *v)
+{
+	struct apr_hdr cvp_vol_cal_cmd_hdr;
+	uint32_t *cmd_buf;
+	struct acdb_cal_data cal_data;
+	struct acdb_cal_block *cal_blk;
+	int32_t cal_size_per_network;
+	uint32_t *cal_data_per_network;
+	int index = 0;
+	int ret = 0;
+	void *apr_cvp = voice_get_apr_cvp(v);
+	u16 cvp_handle = voice_get_cvp_handle(v);
+
+
+	/* fill the header */
+	cvp_vol_cal_cmd_hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvp_vol_cal_cmd_hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		sizeof(cvp_vol_cal_cmd_hdr) - APR_HDR_SIZE);
+	cvp_vol_cal_cmd_hdr.src_port = 0;
+	cvp_vol_cal_cmd_hdr.dest_port = cvp_handle;
+	cvp_vol_cal_cmd_hdr.token = 0;
+	cvp_vol_cal_cmd_hdr.opcode =
+		VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE;
+
+	/* get cal data */
+	get_vocvol_cal(&cal_data);
+	if (cal_data.num_cal_blocks == 0) {
+		pr_err("%s: No calibration data to send!\n", __func__);
+		goto done;
+	}
+
+	/* send cal to modem */
+	cmd_buf = kzalloc((sizeof(struct apr_hdr) + BUFFER_PAYLOAD_SIZE),
+								GFP_KERNEL);
+	if (!cmd_buf) {
+		pr_err("No memory is allocated.\n");
+		return -ENOMEM;
+	}
+	pr_debug("----- num_cal_blocks=%d\n", (s32)cal_data.num_cal_blocks);
+	cal_blk = cal_data.cal_blocks;
+	pr_debug("Cal_blk =%x\n", (uint32_t)cal_data.cal_blocks);
+
+	for (; index < cal_data.num_cal_blocks; index++) {
+		cal_size_per_network = cal_blk[index].cal_size;
+		cal_data_per_network = (u32 *)cal_blk[index].cal_kvaddr;
+		pr_debug("Cal size =%d, index=%d\n", cal_size_per_network,
+			index);
+		pr_debug("Cal data=%x\n", (uint32_t)cal_data_per_network);
+		cvp_vol_cal_cmd_hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			cal_size_per_network);
+		memcpy(cmd_buf, &cvp_vol_cal_cmd_hdr,  APR_HDR_SIZE);
+		memcpy(cmd_buf + (APR_HDR_SIZE / sizeof(uint32_t)),
+			cal_data_per_network, cal_size_per_network);
+		pr_debug("Send vol table\n");
+
+		v->cvp_state = CMD_STATUS_FAIL;
+		ret = apr_send_pkt(apr_cvp, cmd_buf);
+		if (ret < 0) {
+			pr_err("Fail: sending cvp vol cal, idx=%d\n", index);
+			continue;
+		}
+		ret = wait_event_timeout(v->cvp_wait,
+					 (v->cvp_state == CMD_STATUS_SUCCESS),
+			msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+			return -EINVAL;
+		}
+	}
+	kfree(cmd_buf);
+done:
+	return 0;
+}
+
+static int voice_set_dtx(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_cvs = voice_get_apr_cvs(v);
+	u16 cvs_handle = voice_get_cvs_handle(v);
+
+	/* Set DTX */
+	struct cvs_set_enc_dtx_mode_cmd cvs_set_dtx = {
+		.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER),
+		.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+					sizeof(cvs_set_dtx) - APR_HDR_SIZE),
+		.hdr.src_port = 0,
+		.hdr.dest_port = cvs_handle,
+		.hdr.token = 0,
+		.hdr.opcode = VSS_ISTREAM_CMD_SET_ENC_DTX_MODE,
+		.dtx_mode.enable = v->mvs_info.dtx_mode,
+	};
+
+	pr_debug("%s: Setting DTX %d\n", __func__, v->mvs_info.dtx_mode);
+
+	v->cvs_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_dtx);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_DTX\n", __func__, ret);
+
+		goto done;
+	}
+
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+
+		ret = -EINVAL;
+	}
+
+done:
+	return ret;
+}
+
+static int voice_config_cvs_vocoder(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_cvs = voice_get_apr_cvs(v);
+	u16 cvs_handle = voice_get_cvs_handle(v);
+
+	/* Set media type. */
+	struct cvs_set_media_type_cmd cvs_set_media_cmd;
+
+	pr_info("%s: Setting media type\n", __func__);
+
+	cvs_set_media_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+						APR_HDR_LEN(APR_HDR_SIZE),
+						APR_PKT_VER);
+	cvs_set_media_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				      sizeof(cvs_set_media_cmd) - APR_HDR_SIZE);
+	cvs_set_media_cmd.hdr.src_port = 0;
+	cvs_set_media_cmd.hdr.dest_port = cvs_handle;
+	cvs_set_media_cmd.hdr.token = 0;
+	cvs_set_media_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_MEDIA_TYPE;
+	cvs_set_media_cmd.media_type.tx_media_id = v->mvs_info.media_type;
+	cvs_set_media_cmd.media_type.rx_media_id = v->mvs_info.media_type;
+
+	v->cvs_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_media_cmd);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_MEDIA_TYPE\n",
+		       __func__, ret);
+
+		goto done;
+	}
+
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+
+		ret = -EINVAL;
+		goto done;
+	}
+
+	/* Set encoder properties. */
+	switch (v->mvs_info.media_type) {
+	case VSS_MEDIA_ID_EVRC_MODEM: {
+		struct cvs_set_cdma_enc_minmax_rate_cmd cvs_set_cdma_rate;
+
+		pr_info("%s: Setting EVRC min-max rate\n", __func__);
+
+		cvs_set_cdma_rate.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+		cvs_set_cdma_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				      sizeof(cvs_set_cdma_rate) - APR_HDR_SIZE);
+		cvs_set_cdma_rate.hdr.src_port = 0;
+		cvs_set_cdma_rate.hdr.dest_port = cvs_handle;
+		cvs_set_cdma_rate.hdr.token = 0;
+		cvs_set_cdma_rate.hdr.opcode =
+				VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE;
+		cvs_set_cdma_rate.cdma_rate.min_rate = v->mvs_info.rate;
+		cvs_set_cdma_rate.cdma_rate.max_rate = v->mvs_info.rate;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_cdma_rate);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending SET_EVRC_MINMAX_RATE\n",
+			       __func__, ret);
+
+			goto done;
+		}
+
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+
+			ret = -EINVAL;
+			goto done;
+		}
+
+		break;
+	}
+
+	case VSS_MEDIA_ID_AMR_NB_MODEM: {
+		struct cvs_set_amr_enc_rate_cmd cvs_set_amr_rate;
+
+		pr_info("%s: Setting AMR rate\n", __func__);
+
+		cvs_set_amr_rate.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+		cvs_set_amr_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				       sizeof(cvs_set_amr_rate) - APR_HDR_SIZE);
+		cvs_set_amr_rate.hdr.src_port = 0;
+		cvs_set_amr_rate.hdr.dest_port = cvs_handle;
+		cvs_set_amr_rate.hdr.token = 0;
+		cvs_set_amr_rate.hdr.opcode =
+					VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE;
+		cvs_set_amr_rate.amr_rate.mode = v->mvs_info.rate;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amr_rate);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending SET_AMR_RATE\n",
+			       __func__, ret);
+
+			goto done;
+		}
+
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+
+			ret = -EINVAL;
+			goto done;
+		}
+
+		ret = voice_set_dtx(v);
+
+		break;
+	}
+
+	case VSS_MEDIA_ID_AMR_WB_MODEM: {
+		struct cvs_set_amrwb_enc_rate_cmd cvs_set_amrwb_rate;
+
+		pr_info("%s: Setting AMR WB rate\n", __func__);
+
+		cvs_set_amrwb_rate.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+		cvs_set_amrwb_rate.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				     sizeof(cvs_set_amrwb_rate) - APR_HDR_SIZE);
+		cvs_set_amrwb_rate.hdr.src_port = 0;
+		cvs_set_amrwb_rate.hdr.dest_port = cvs_handle;
+		cvs_set_amrwb_rate.hdr.token = 0;
+		cvs_set_amrwb_rate.hdr.opcode =
+					VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE;
+		cvs_set_amrwb_rate.amrwb_rate.mode = v->mvs_info.rate;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_set_amrwb_rate);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending SET_AMRWB_RATE\n",
+			       __func__, ret);
+
+			goto done;
+		}
+
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+
+			ret = -EINVAL;
+			goto done;
+		}
+
+		ret = voice_set_dtx(v);
+
+		break;
+	}
+
+	case VSS_MEDIA_ID_G729:
+	case VSS_MEDIA_ID_G711_ALAW:
+	case VSS_MEDIA_ID_G711_MULAW: {
+		ret = voice_set_dtx(v);
+
+		break;
+	}
+
+	default: {
+		/* Do nothing. */
+	}
+	}
+
+done:
+	return ret;
+}
+
+static int voice_send_start_voice_cmd(struct voice_data *v)
+{
+	struct apr_hdr mvm_start_voice_cmd;
+	int ret = 0;
+	void *apr_mvm = voice_get_apr_mvm(v);
+	u16 mvm_handle = voice_get_mvm_handle(v);
+
+	mvm_start_voice_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mvm_start_voice_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(mvm_start_voice_cmd) - APR_HDR_SIZE);
+	pr_info("send mvm_start_voice_cmd pkt size = %d\n",
+				mvm_start_voice_cmd.pkt_size);
+	mvm_start_voice_cmd.src_port = 0;
+	mvm_start_voice_cmd.dest_port = mvm_handle;
+	mvm_start_voice_cmd.token = 0;
+	mvm_start_voice_cmd.opcode = VSS_IMVM_CMD_START_VOICE;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_start_voice_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_IMVM_CMD_START_VOICE\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->mvm_wait,
+				 (v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_disable_vocproc(struct voice_data *v)
+{
+	struct apr_hdr cvp_disable_cmd;
+	int ret = 0;
+	void *apr_cvp = voice_get_apr_cvp(v);
+	u16 cvp_handle = voice_get_cvp_handle(v);
+
+	/* disable vocproc and wait for respose */
+	cvp_disable_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvp_disable_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			sizeof(cvp_disable_cmd) - APR_HDR_SIZE);
+	pr_debug("cvp_disable_cmd pkt size = %d, cvp_handle=%d\n",
+		cvp_disable_cmd.pkt_size, cvp_handle);
+	cvp_disable_cmd.src_port = 0;
+	cvp_disable_cmd.dest_port = cvp_handle;
+	cvp_disable_cmd.token = 0;
+	cvp_disable_cmd.opcode = VSS_IVOCPROC_CMD_DISABLE;
+
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_disable_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_IVOCPROC_CMD_DISABLE\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->cvp_wait,
+			(v->cvp_state == CMD_STATUS_SUCCESS),
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+#ifdef CONFIG_MSM8X60_RTAC
+	rtac_remove_voice(v);
+#endif
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_set_device(struct voice_data *v)
+{
+	struct cvp_set_device_cmd  cvp_setdev_cmd;
+	struct msm_snddev_info *dev_tx_info;
+	int ret = 0;
+	void *apr_cvp = voice_get_apr_cvp(v);
+	u16 cvp_handle = voice_get_cvp_handle(v);
+
+
+	/* set device and wait for response */
+	cvp_setdev_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvp_setdev_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvp_setdev_cmd) - APR_HDR_SIZE);
+	pr_debug(" send create cvp setdev, pkt size = %d\n",
+			cvp_setdev_cmd.hdr.pkt_size);
+	cvp_setdev_cmd.hdr.src_port = 0;
+	cvp_setdev_cmd.hdr.dest_port = cvp_handle;
+	cvp_setdev_cmd.hdr.token = 0;
+	cvp_setdev_cmd.hdr.opcode = VSS_IVOCPROC_CMD_SET_DEVICE;
+
+	dev_tx_info = audio_dev_ctrl_find_dev(v->dev_tx.dev_id);
+	if (IS_ERR(dev_tx_info)) {
+		pr_err("bad dev_id %d\n", v->dev_tx.dev_id);
+		goto fail;
+	}
+
+	cvp_setdev_cmd.cvp_set_device.tx_topology_id =
+				get_voice_tx_topology();
+	if (cvp_setdev_cmd.cvp_set_device.tx_topology_id == 0) {
+		if (dev_tx_info->channel_mode > 1)
+			cvp_setdev_cmd.cvp_set_device.tx_topology_id =
+				VSS_IVOCPROC_TOPOLOGY_ID_TX_DM_FLUENCE;
+		else
+			cvp_setdev_cmd.cvp_set_device.tx_topology_id =
+				VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS;
+	}
+
+	/* Use default topology if invalid value in ACDB */
+	cvp_setdev_cmd.cvp_set_device.rx_topology_id =
+				get_voice_rx_topology();
+	if (cvp_setdev_cmd.cvp_set_device.rx_topology_id == 0)
+		cvp_setdev_cmd.cvp_set_device.rx_topology_id =
+			VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
+	cvp_setdev_cmd.cvp_set_device.tx_port_id = v->dev_tx.dev_port_id;
+	cvp_setdev_cmd.cvp_set_device.rx_port_id = v->dev_rx.dev_port_id;
+	pr_info("topology=%d , tx_port_id=%d, rx_port_id=%d\n",
+			cvp_setdev_cmd.cvp_set_device.tx_topology_id,
+			cvp_setdev_cmd.cvp_set_device.tx_port_id,
+			cvp_setdev_cmd.cvp_set_device.rx_port_id);
+
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_setdev_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VOCPROC_FULL_CONTROL_SESSION\n");
+	goto fail;
+	}
+	pr_debug("wait for cvp create session event\n");
+	ret = wait_event_timeout(v->cvp_wait,
+			(v->cvp_state == CMD_STATUS_SUCCESS),
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	/* send cvs cal */
+	voice_send_cvs_cal_to_modem(v);
+
+	/* send cvp cal */
+	voice_send_cvp_cal_to_modem(v);
+
+	/* send cvp vol table cal */
+	voice_send_cvp_vol_tbl_to_modem(v);
+
+	/* enable vocproc and wait for respose */
+	voice_send_enable_vocproc_cmd(v);
+
+	/* send tty mode if tty device is used */
+	voice_send_tty_mode_to_modem(v);
+
+	if (v->voc_path == VOC_PATH_FULL)
+		voice_send_netid_timing_cmd(v);
+
+#ifdef CONFIG_MSM8X60_RTAC
+	rtac_add_voice(v);
+#endif
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_stop_voice_cmd(struct voice_data *v)
+{
+	struct apr_hdr mvm_stop_voice_cmd;
+	int ret = 0;
+	void *apr_mvm = voice_get_apr_mvm(v);
+	u16 mvm_handle = voice_get_mvm_handle(v);
+
+	mvm_stop_voice_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mvm_stop_voice_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(mvm_stop_voice_cmd) - APR_HDR_SIZE);
+	pr_info("send mvm_stop_voice_cmd pkt size = %d\n",
+				mvm_stop_voice_cmd.pkt_size);
+	mvm_stop_voice_cmd.src_port = 0;
+	mvm_stop_voice_cmd.dest_port = mvm_handle;
+	mvm_stop_voice_cmd.token = 0;
+	mvm_stop_voice_cmd.opcode = VSS_IMVM_CMD_STOP_VOICE;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_stop_voice_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_IMVM_CMD_STOP_VOICE\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->mvm_wait,
+				 (v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_setup_modem_voice(struct voice_data *v)
+{
+	struct cvp_create_full_ctl_session_cmd cvp_session_cmd;
+	int ret = 0;
+	struct msm_snddev_info *dev_tx_info;
+	void *apr_cvp = voice_get_apr_cvp(v);
+
+	/* create cvp session and wait for response */
+	cvp_session_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvp_session_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvp_session_cmd) - APR_HDR_SIZE);
+	pr_info(" send create cvp session, pkt size = %d\n",
+				cvp_session_cmd.hdr.pkt_size);
+	cvp_session_cmd.hdr.src_port = 0;
+	cvp_session_cmd.hdr.dest_port = 0;
+	cvp_session_cmd.hdr.token = 0;
+	cvp_session_cmd.hdr.opcode =
+		VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION;
+
+	dev_tx_info = audio_dev_ctrl_find_dev(v->dev_tx.dev_id);
+	if (IS_ERR(dev_tx_info)) {
+		pr_err("bad dev_id %d\n", v->dev_tx.dev_id);
+		goto fail;
+	}
+
+	/* Use default topology if invalid value in ACDB */
+	cvp_session_cmd.cvp_session.tx_topology_id =
+				get_voice_tx_topology();
+	if (cvp_session_cmd.cvp_session.tx_topology_id == 0) {
+		if (dev_tx_info->channel_mode > 1)
+			cvp_session_cmd.cvp_session.tx_topology_id =
+				VSS_IVOCPROC_TOPOLOGY_ID_TX_DM_FLUENCE;
+		else
+			cvp_session_cmd.cvp_session.tx_topology_id =
+				VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS;
+	}
+
+	cvp_session_cmd.cvp_session.rx_topology_id =
+				get_voice_rx_topology();
+	if (cvp_session_cmd.cvp_session.rx_topology_id == 0)
+		cvp_session_cmd.cvp_session.rx_topology_id =
+			VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT;
+
+	cvp_session_cmd.cvp_session.direction = 2; /*tx and rx*/
+	cvp_session_cmd.cvp_session.network_id = VSS_NETWORK_ID_DEFAULT;
+	cvp_session_cmd.cvp_session.tx_port_id = v->dev_tx.dev_port_id;
+	cvp_session_cmd.cvp_session.rx_port_id = v->dev_rx.dev_port_id;
+	pr_info("topology=%d net_id=%d, dir=%d tx_port_id=%d, rx_port_id=%d\n",
+			cvp_session_cmd.cvp_session.tx_topology_id,
+			cvp_session_cmd.cvp_session.network_id,
+			cvp_session_cmd.cvp_session.direction,
+			cvp_session_cmd.cvp_session.tx_port_id,
+			cvp_session_cmd.cvp_session.rx_port_id);
+
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_session_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VOCPROC_FULL_CONTROL_SESSION\n");
+		goto fail;
+	}
+	pr_debug("wait for cvp create session event\n");
+	ret = wait_event_timeout(v->cvp_wait,
+				 (v->cvp_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	/* send cvs cal */
+	voice_send_cvs_cal_to_modem(v);
+
+	/* send cvp cal */
+	voice_send_cvp_cal_to_modem(v);
+
+	/* send cvp vol table cal */
+	voice_send_cvp_vol_tbl_to_modem(v);
+
+	return 0;
+
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_enable_vocproc_cmd(struct voice_data *v)
+{
+	int ret = 0;
+	struct apr_hdr cvp_enable_cmd;
+
+	u16 cvp_handle = voice_get_cvp_handle(v);
+	void *apr_cvp = voice_get_apr_cvp(v);
+
+	/* enable vocproc and wait for respose */
+	cvp_enable_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvp_enable_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvp_enable_cmd) - APR_HDR_SIZE);
+	pr_debug("cvp_enable_cmd pkt size = %d, cvp_handle=%d\n",
+			cvp_enable_cmd.pkt_size, cvp_handle);
+	cvp_enable_cmd.src_port = 0;
+	cvp_enable_cmd.dest_port = cvp_handle;
+	cvp_enable_cmd.token = 0;
+	cvp_enable_cmd.opcode = VSS_IVOCPROC_CMD_ENABLE;
+
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_enable_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_IVOCPROC_CMD_ENABLE\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->cvp_wait,
+			(v->cvp_state == CMD_STATUS_SUCCESS),
+			msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_netid_timing_cmd(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_mvm = voice_get_apr_mvm(v);
+	struct mvm_set_network_cmd mvm_set_network;
+	struct mvm_set_voice_timing_cmd mvm_set_voice_timing;
+	u16 mvm_handle = voice_get_mvm_handle(v);
+
+	ret = voice_config_cvs_vocoder(v);
+	if (ret < 0) {
+		pr_err("%s: Error %d configuring CVS voc",
+					__func__, ret);
+		goto fail;
+	}
+	/* Set network ID. */
+	pr_debug("%s: Setting network ID\n", __func__);
+
+	mvm_set_network.hdr.hdr_field =
+			APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mvm_set_network.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			sizeof(mvm_set_network) - APR_HDR_SIZE);
+	mvm_set_network.hdr.src_port = 0;
+	mvm_set_network.hdr.dest_port = mvm_handle;
+	mvm_set_network.hdr.token = 0;
+	mvm_set_network.hdr.opcode = VSS_ICOMMON_CMD_SET_NETWORK;
+	mvm_set_network.network.network_id = v->mvs_info.network_type;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_network);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_NETWORK\n", __func__, ret);
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->mvm_wait,
+			(v->mvm_state == CMD_STATUS_SUCCESS),
+			 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	/* Set voice timing. */
+	 pr_debug("%s: Setting voice timing\n", __func__);
+
+	mvm_set_voice_timing.hdr.hdr_field =
+			APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+			APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mvm_set_voice_timing.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			sizeof(mvm_set_voice_timing) - APR_HDR_SIZE);
+	mvm_set_voice_timing.hdr.src_port = 0;
+	mvm_set_voice_timing.hdr.dest_port = mvm_handle;
+	mvm_set_voice_timing.hdr.token = 0;
+	mvm_set_voice_timing.hdr.opcode =
+			VSS_ICOMMON_CMD_SET_VOICE_TIMING;
+	mvm_set_voice_timing.timing.mode = 0;
+	mvm_set_voice_timing.timing.enc_offset = 8000;
+	mvm_set_voice_timing.timing.dec_req_offset = 3300;
+	mvm_set_voice_timing.timing.dec_offset = 8300;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_set_voice_timing);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending SET_TIMING\n", __func__, ret);
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->mvm_wait,
+			(v->mvm_state == CMD_STATUS_SUCCESS),
+				msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_attach_vocproc(struct voice_data *v)
+{
+	int ret = 0;
+	struct mvm_attach_vocproc_cmd mvm_a_vocproc_cmd;
+	void *apr_mvm = voice_get_apr_mvm(v);
+	u16 mvm_handle = voice_get_mvm_handle(v);
+	u16 cvp_handle = voice_get_cvp_handle(v);
+
+	/* send enable vocproc */
+	voice_send_enable_vocproc_cmd(v);
+
+	/* attach vocproc and wait for response */
+	mvm_a_vocproc_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mvm_a_vocproc_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(mvm_a_vocproc_cmd) - APR_HDR_SIZE);
+	pr_info("send mvm_a_vocproc_cmd pkt size = %d\n",
+				mvm_a_vocproc_cmd.hdr.pkt_size);
+	mvm_a_vocproc_cmd.hdr.src_port = 0;
+	mvm_a_vocproc_cmd.hdr.dest_port = mvm_handle;
+	mvm_a_vocproc_cmd.hdr.token = 0;
+	mvm_a_vocproc_cmd.hdr.opcode = VSS_IMVM_CMD_ATTACH_VOCPROC;
+	mvm_a_vocproc_cmd.mvm_attach_cvp_handle.handle = cvp_handle;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_a_vocproc_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_IMVM_CMD_ATTACH_VOCPROC\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->mvm_wait,
+				 (v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	/* send tty mode if tty device is used */
+	voice_send_tty_mode_to_modem(v);
+
+	if (v->voc_path == VOC_PATH_FULL)
+		voice_send_netid_timing_cmd(v);
+
+#ifdef CONFIG_MSM8X60_RTAC
+	rtac_add_voice(v);
+#endif
+	return 0;
+fail:
+	return -EINVAL;
+}
+
+static int voice_destroy_modem_voice(struct voice_data *v)
+{
+	struct mvm_detach_vocproc_cmd mvm_d_vocproc_cmd;
+	struct apr_hdr cvp_destroy_session_cmd;
+	int ret = 0;
+	void *apr_mvm = voice_get_apr_mvm(v);
+	void *apr_cvp = voice_get_apr_cvp(v);
+	u16 mvm_handle = voice_get_mvm_handle(v);
+	u16 cvp_handle = voice_get_cvp_handle(v);
+
+	/* detach VOCPROC and wait for response from mvm */
+	mvm_d_vocproc_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	mvm_d_vocproc_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(mvm_d_vocproc_cmd) - APR_HDR_SIZE);
+	pr_info("mvm_d_vocproc_cmd  pkt size = %d\n",
+				mvm_d_vocproc_cmd.hdr.pkt_size);
+	mvm_d_vocproc_cmd.hdr.src_port = 0;
+	mvm_d_vocproc_cmd.hdr.dest_port = mvm_handle;
+	mvm_d_vocproc_cmd.hdr.token = 0;
+	mvm_d_vocproc_cmd.hdr.opcode = VSS_IMVM_CMD_DETACH_VOCPROC;
+	mvm_d_vocproc_cmd.mvm_detach_cvp_handle.handle = cvp_handle;
+
+	v->mvm_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_mvm, (uint32_t *) &mvm_d_vocproc_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending VSS_IMVM_CMD_DETACH_VOCPROC\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->mvm_wait,
+				 (v->mvm_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+	/* destrop cvp session */
+	cvp_destroy_session_cmd.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvp_destroy_session_cmd.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvp_destroy_session_cmd) - APR_HDR_SIZE);
+	pr_info("cvp_destroy_session_cmd pkt size = %d\n",
+				cvp_destroy_session_cmd.pkt_size);
+	cvp_destroy_session_cmd.src_port = 0;
+	cvp_destroy_session_cmd.dest_port = cvp_handle;
+	cvp_destroy_session_cmd.token = 0;
+	cvp_destroy_session_cmd.opcode = APRV2_IBASIC_CMD_DESTROY_SESSION;
+
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_destroy_session_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending APRV2_IBASIC_CMD_DESTROY_SESSION\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->cvp_wait,
+				 (v->cvp_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		goto fail;
+	}
+
+#ifdef CONFIG_MSM8X60_RTAC
+	rtac_remove_voice(v);
+#endif
+	cvp_handle = 0;
+	voice_set_cvp_handle(v, cvp_handle);
+
+	return 0;
+
+fail:
+	return -EINVAL;
+}
+
+static int voice_send_mute_cmd_to_modem(struct voice_data *v)
+{
+	struct cvs_set_mute_cmd cvs_mute_cmd;
+	int ret = 0;
+	void *apr_cvs = voice_get_apr_cvs(v);
+	u16 cvs_handle = voice_get_cvs_handle(v);
+
+	/* send mute/unmute to cvs */
+	cvs_mute_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvs_mute_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvs_mute_cmd) - APR_HDR_SIZE);
+	cvs_mute_cmd.hdr.src_port = 0;
+	cvs_mute_cmd.hdr.dest_port = cvs_handle;
+	cvs_mute_cmd.hdr.token = 0;
+	cvs_mute_cmd.hdr.opcode = VSS_ISTREAM_CMD_SET_MUTE;
+	cvs_mute_cmd.cvs_set_mute.direction = 0; /*tx*/
+	cvs_mute_cmd.cvs_set_mute.mute_flag = v->dev_tx.mute;
+
+	pr_info(" mute value =%d\n", cvs_mute_cmd.cvs_set_mute.mute_flag);
+	v->cvs_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_mute_cmd);
+	if (ret < 0) {
+		pr_err("Fail: send STREAM SET MUTE\n");
+		goto fail;
+	}
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret)
+		pr_err("%s: wait_event timeout\n", __func__);
+
+fail:
+	return 0;
+}
+
+static int voice_send_vol_index_to_modem(struct voice_data *v)
+{
+	struct cvp_set_rx_volume_index_cmd cvp_vol_cmd;
+	int ret = 0;
+	void *apr_cvp = voice_get_apr_cvp(v);
+	u16 cvp_handle = voice_get_cvp_handle(v);
+
+	/* send volume index to cvp */
+	cvp_vol_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvp_vol_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		sizeof(cvp_vol_cmd) - APR_HDR_SIZE);
+	cvp_vol_cmd.hdr.src_port = 0;
+	cvp_vol_cmd.hdr.dest_port = cvp_handle;
+	cvp_vol_cmd.hdr.token = 0;
+	cvp_vol_cmd.hdr.opcode =
+		VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX;
+	cvp_vol_cmd.cvp_set_vol_idx.vol_index = v->dev_rx.volume;
+	v->cvp_state = CMD_STATUS_FAIL;
+	ret = apr_send_pkt(apr_cvp, (uint32_t *) &cvp_vol_cmd);
+	if (ret < 0) {
+		pr_err("Fail in sending RX VOL INDEX\n");
+		return -EINVAL;
+	}
+	ret = wait_event_timeout(v->cvp_wait,
+				 (v->cvp_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static int voice_cvs_start_record(struct voice_data *v, uint32_t rec_mode)
+{
+	int ret = 0;
+	void *apr_cvs = voice_get_apr_cvs(v);
+	u16 cvs_handle = voice_get_cvs_handle(v);
+	struct cvs_start_record_cmd cvs_start_record;
+
+	pr_debug("%s: Start record %d\n", __func__, rec_mode);
+
+	cvs_start_record.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				  APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvs_start_record.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				  sizeof(cvs_start_record) - APR_HDR_SIZE);
+	cvs_start_record.hdr.src_port = 0;
+	cvs_start_record.hdr.dest_port = cvs_handle;
+	cvs_start_record.hdr.token = 0;
+	cvs_start_record.hdr.opcode = VSS_ISTREAM_CMD_START_RECORD;
+
+	if (rec_mode == VOC_REC_UPLINK) {
+		cvs_start_record.rec_mode.rx_tap_point = VSS_TAP_POINT_NONE;
+		cvs_start_record.rec_mode.tx_tap_point =
+						VSS_TAP_POINT_STREAM_END;
+	} else if (rec_mode == VOC_REC_DOWNLINK) {
+		cvs_start_record.rec_mode.rx_tap_point =
+						VSS_TAP_POINT_STREAM_END;
+		cvs_start_record.rec_mode.tx_tap_point = VSS_TAP_POINT_NONE;
+	} else if (rec_mode == VOC_REC_BOTH) {
+		cvs_start_record.rec_mode.rx_tap_point =
+						VSS_TAP_POINT_STREAM_END;
+		cvs_start_record.rec_mode.tx_tap_point =
+						VSS_TAP_POINT_STREAM_END;
+	} else {
+		pr_err("%s: Invalid in-call rec_mode %d\n", __func__, rec_mode);
+
+		ret = -EINVAL;
+		goto fail;
+	}
+
+	v->cvs_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_start_record);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending START_RECORD\n", __func__, ret);
+
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	return ret;
+}
+
+static int voice_cvs_stop_record(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_cvs = voice_get_apr_cvs(v);
+	u16 cvs_handle = voice_get_cvs_handle(v);
+	struct apr_hdr cvs_stop_record;
+
+	pr_debug("%s: Stop record\n", __func__);
+
+	cvs_stop_record.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				  APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvs_stop_record.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				  sizeof(cvs_stop_record) - APR_HDR_SIZE);
+	cvs_stop_record.src_port = 0;
+	cvs_stop_record.dest_port = cvs_handle;
+	cvs_stop_record.token = 0;
+	cvs_stop_record.opcode = VSS_ISTREAM_CMD_STOP_RECORD;
+
+	v->cvs_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_stop_record);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending STOP_RECORD\n", __func__, ret);
+
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+
+		goto fail;
+	}
+
+	return 0;
+
+fail:
+	return ret;
+}
+
+int voice_start_record(uint32_t rec_mode, uint32_t set)
+{
+	int ret = 0;
+	u16 cvs_handle;
+
+	pr_debug("%s: rec_mode %d, set %d\n", __func__, rec_mode, set);
+
+	mutex_lock(&voice.lock);
+
+	cvs_handle = voice_get_cvs_handle(&voice);
+
+	if (cvs_handle != 0) {
+		if (set)
+			ret = voice_cvs_start_record(&voice, rec_mode);
+		else
+			ret = voice_cvs_stop_record(&voice);
+	} else {
+		/* Cache the value for later. */
+		voice.rec_info.pending = set;
+		voice.rec_info.rec_mode = rec_mode;
+	}
+
+	mutex_unlock(&voice.lock);
+
+	return ret;
+}
+
+static int voice_cvs_start_playback(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_cvs = voice_get_apr_cvs(v);
+	u16 cvs_handle = voice_get_cvs_handle(v);
+	struct apr_hdr cvs_start_playback;
+
+	pr_debug("%s: Start playback\n", __func__);
+
+	cvs_start_playback.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+	cvs_start_playback.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvs_start_playback) - APR_HDR_SIZE);
+	cvs_start_playback.src_port = 0;
+	cvs_start_playback.dest_port = cvs_handle;
+	cvs_start_playback.token = 0;
+	cvs_start_playback.opcode = VSS_ISTREAM_CMD_START_PLAYBACK;
+
+	v->cvs_state = CMD_STATUS_FAIL;
+
+	ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_start_playback);
+	if (ret < 0) {
+		pr_err("%s: Error %d sending START_PLAYBACK\n",
+		       __func__, ret);
+
+		goto fail;
+	}
+
+	ret = wait_event_timeout(v->cvs_wait,
+				 (v->cvs_state == CMD_STATUS_SUCCESS),
+				 msecs_to_jiffies(TIMEOUT_MS));
+	if (!ret) {
+		pr_err("%s: wait_event timeout\n", __func__);
+
+		goto fail;
+	}
+
+	v->music_info.playing = 1;
+
+	return 0;
+
+fail:
+	return ret;
+}
+
+static int voice_cvs_stop_playback(struct voice_data *v)
+{
+	int ret = 0;
+	void *apr_cvs = voice_get_apr_cvs(v);
+	u16 cvs_handle = voice_get_cvs_handle(v);
+	struct apr_hdr cvs_stop_playback;
+
+	pr_debug("%s: Stop playback\n", __func__);
+
+	if (v->music_info.playing) {
+		cvs_stop_playback.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+				APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+		cvs_stop_playback.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+				sizeof(cvs_stop_playback) - APR_HDR_SIZE);
+		cvs_stop_playback.src_port = 0;
+		cvs_stop_playback.dest_port = cvs_handle;
+		cvs_stop_playback.token = 0;
+
+		cvs_stop_playback.opcode = VSS_ISTREAM_CMD_STOP_PLAYBACK;
+
+		v->cvs_state = CMD_STATUS_FAIL;
+
+		ret = apr_send_pkt(apr_cvs, (uint32_t *) &cvs_stop_playback);
+		if (ret < 0) {
+			pr_err("%s: Error %d sending STOP_PLAYBACK\n",
+			       __func__, ret);
+
+			goto fail;
+		}
+
+		ret = wait_event_timeout(v->cvs_wait,
+					 (v->cvs_state == CMD_STATUS_SUCCESS),
+					 msecs_to_jiffies(TIMEOUT_MS));
+		if (!ret) {
+			pr_err("%s: wait_event timeout\n", __func__);
+
+			goto fail;
+		}
+
+		v->music_info.playing = 0;
+	} else {
+		pr_err("%s: Stop playback already sent\n", __func__);
+	}
+
+	return 0;
+
+fail:
+	return ret;
+}
+
+int voice_start_playback(uint32_t set)
+{
+	int ret = 0;
+	u16 cvs_handle;
+
+	pr_debug("%s: Start playback %d\n", __func__, set);
+
+	mutex_lock(&voice.lock);
+
+	cvs_handle = voice_get_cvs_handle(&voice);
+
+	if (cvs_handle != 0) {
+		if (set)
+			ret = voice_cvs_start_playback(&voice);
+		else
+			ret = voice_cvs_stop_playback(&voice);
+	} else {
+		/* Cache the value for later. */
+		pr_debug("%s: Caching ICP value", __func__);
+
+		voice.music_info.pending = set;
+	}
+
+	mutex_unlock(&voice.lock);
+
+	return ret;
+}
+
+static void voice_auddev_cb_function(u32 evt_id,
+			union auddev_evt_data *evt_payload,
+			void *private_data)
+{
+	struct voice_data *v = &voice;
+	struct sidetone_cal sidetone_cal_data;
+	int rc = 0;
+	pr_info("auddev_cb_function, evt_id=%d,\n", evt_id);
+	if ((evt_id != AUDDEV_EVT_START_VOICE) ||
+			(evt_id != AUDDEV_EVT_END_VOICE)) {
+		if (evt_payload == NULL) {
+			pr_err(" evt_payload is NULL pointer\n");
+			return;
+		}
+	}
+
+	switch (evt_id) {
+	case AUDDEV_EVT_START_VOICE:
+		mutex_lock(&v->lock);
+
+		if ((v->voc_state == VOC_INIT) ||
+				(v->voc_state == VOC_RELEASE)) {
+			v->v_call_status = VOICE_CALL_START;
+			if ((v->dev_rx.enabled == VOICE_DEV_ENABLED)
+				&& (v->dev_tx.enabled == VOICE_DEV_ENABLED)) {
+				rc = voice_apr_register(v);
+				if (rc < 0) {
+					pr_err("%s: voice apr registration"
+						"failed\n", __func__);
+					mutex_unlock(&v->lock);
+					return;
+				}
+				voice_create_mvm_cvs_session(v);
+				voice_setup_modem_voice(v);
+				voice_attach_vocproc(v);
+				voice_send_start_voice_cmd(v);
+				get_sidetone_cal(&sidetone_cal_data);
+				msm_snddev_enable_sidetone(
+					v->dev_rx.dev_id,
+					sidetone_cal_data.enable,
+					sidetone_cal_data.gain);
+				v->voc_state = VOC_RUN;
+
+				/* Start in-call recording if command was
+				 * pending. */
+				if (v->rec_info.pending) {
+					voice_cvs_start_record(v,
+						v->rec_info.rec_mode);
+
+					v->rec_info.pending = 0;
+				}
+
+				/* Start in-call music delivery if command was
+				 * pending. */
+				if (v->music_info.pending) {
+					voice_cvs_start_playback(v);
+
+					v->music_info.pending = 0;
+				}
+			}
+		}
+
+		mutex_unlock(&v->lock);
+		break;
+	case AUDDEV_EVT_DEV_CHG_VOICE:
+		if (v->dev_rx.enabled == VOICE_DEV_ENABLED)
+			msm_snddev_enable_sidetone(v->dev_rx.dev_id, 0, 0);
+		v->dev_rx.enabled = VOICE_DEV_DISABLED;
+		v->dev_tx.enabled = VOICE_DEV_DISABLED;
+
+		mutex_lock(&v->lock);
+
+		if (v->voc_state == VOC_RUN) {
+			/* send cmd to modem to do voice device change */
+			voice_disable_vocproc(v);
+			v->voc_state = VOC_CHANGE;
+		}
+
+		mutex_unlock(&v->lock);
+		break;
+	case AUDDEV_EVT_DEV_RDY:
+		mutex_lock(&v->lock);
+
+		if (v->voc_state == VOC_CHANGE) {
+			/* get port Ids */
+			if (evt_payload->voc_devinfo.dev_type == DIR_RX) {
+				v->dev_rx.dev_port_id =
+					evt_payload->voc_devinfo.dev_port_id;
+				v->dev_rx.sample =
+					evt_payload->voc_devinfo.dev_sample;
+				v->dev_rx.dev_id =
+				evt_payload->voc_devinfo.dev_id;
+				v->dev_rx.enabled = VOICE_DEV_ENABLED;
+			} else {
+				v->dev_tx.dev_port_id =
+					evt_payload->voc_devinfo.dev_port_id;
+				v->dev_tx.sample =
+					evt_payload->voc_devinfo.dev_sample;
+				v->dev_tx.enabled = VOICE_DEV_ENABLED;
+				v->dev_tx.dev_id =
+				evt_payload->voc_devinfo.dev_id;
+			}
+			if ((v->dev_rx.enabled == VOICE_DEV_ENABLED) &&
+				(v->dev_tx.enabled == VOICE_DEV_ENABLED)) {
+				voice_set_device(v);
+				get_sidetone_cal(&sidetone_cal_data);
+				msm_snddev_enable_sidetone(
+					v->dev_rx.dev_id,
+					sidetone_cal_data.enable,
+					sidetone_cal_data.gain);
+				v->voc_state = VOC_RUN;
+			}
+		} else if ((v->voc_state == VOC_INIT) ||
+			(v->voc_state == VOC_RELEASE)) {
+			/* get AFE ports */
+			if (evt_payload->voc_devinfo.dev_type == DIR_RX) {
+				/* get rx port id */
+				v->dev_rx.dev_port_id =
+					evt_payload->voc_devinfo.dev_port_id;
+				v->dev_rx.sample =
+					evt_payload->voc_devinfo.dev_sample;
+				v->dev_rx.dev_id =
+				evt_payload->voc_devinfo.dev_id;
+				v->dev_rx.enabled = VOICE_DEV_ENABLED;
+			} else {
+				/* get tx port id */
+				v->dev_tx.dev_port_id =
+					evt_payload->voc_devinfo.dev_port_id;
+				v->dev_tx.sample =
+					evt_payload->voc_devinfo.dev_sample;
+				v->dev_tx.dev_id =
+				evt_payload->voc_devinfo.dev_id;
+				v->dev_tx.enabled = VOICE_DEV_ENABLED;
+			}
+			if ((v->dev_rx.enabled == VOICE_DEV_ENABLED) &&
+				(v->dev_tx.enabled == VOICE_DEV_ENABLED) &&
+				(v->v_call_status == VOICE_CALL_START)) {
+				rc = voice_apr_register(v);
+				if (rc < 0) {
+					pr_err("%s: voice apr registration"
+						"failed\n", __func__);
+					mutex_unlock(&v->lock);
+					return;
+				}
+				voice_create_mvm_cvs_session(v);
+				voice_setup_modem_voice(v);
+				voice_attach_vocproc(v);
+				voice_send_start_voice_cmd(v);
+				get_sidetone_cal(&sidetone_cal_data);
+				msm_snddev_enable_sidetone(
+					v->dev_rx.dev_id,
+					sidetone_cal_data.enable,
+					sidetone_cal_data.gain);
+				v->voc_state = VOC_RUN;
+
+				/* Start in-call recording if command was
+				 * pending. */
+				if (v->rec_info.pending) {
+					voice_cvs_start_record(v,
+						v->rec_info.rec_mode);
+
+					v->rec_info.pending = 0;
+				}
+
+				/* Start in-call music delivery if command was
+				 * pending. */
+				if (v->music_info.pending) {
+					voice_cvs_start_playback(v);
+
+					v->music_info.pending = 0;
+				}
+			}
+		}
+
+		mutex_unlock(&v->lock);
+		break;
+	case AUDDEV_EVT_DEVICE_VOL_MUTE_CHG:
+		/* cache the mute and volume index value */
+		if (evt_payload->voc_devinfo.dev_type == DIR_TX) {
+			v->dev_tx.mute =
+				evt_payload->voc_vm_info.dev_vm_val.mute;
+
+			mutex_lock(&v->lock);
+
+			if (v->voc_state == VOC_RUN)
+				voice_send_mute_cmd_to_modem(v);
+
+			mutex_unlock(&v->lock);
+		} else {
+			v->dev_rx.volume = evt_payload->
+				voc_vm_info.dev_vm_val.vol;
+
+			mutex_lock(&v->lock);
+
+			if (v->voc_state == VOC_RUN)
+				voice_send_vol_index_to_modem(v);
+
+			mutex_unlock(&v->lock);
+		}
+		break;
+	case AUDDEV_EVT_REL_PENDING:
+
+		mutex_lock(&v->lock);
+
+		if (v->voc_state == VOC_RUN) {
+			voice_disable_vocproc(v);
+			v->voc_state = VOC_CHANGE;
+		}
+
+		mutex_unlock(&v->lock);
+
+		if (evt_payload->voc_devinfo.dev_type == DIR_RX)
+			v->dev_rx.enabled = VOICE_DEV_DISABLED;
+		else
+			v->dev_tx.enabled = VOICE_DEV_DISABLED;
+
+		break;
+	case AUDDEV_EVT_END_VOICE:
+		/* recover the tx mute and rx volume to the default values */
+		v->dev_tx.mute = v->default_mute_val;
+		v->dev_rx.volume = v->default_vol_val;
+		if (v->dev_rx.enabled == VOICE_DEV_ENABLED)
+			msm_snddev_enable_sidetone(v->dev_rx.dev_id, 0, 0);
+
+		mutex_lock(&v->lock);
+
+		if (v->voc_state == VOC_RUN) {
+			/* call stop modem voice */
+			voice_send_stop_voice_cmd(v);
+			voice_destroy_modem_voice(v);
+			voice_destroy_mvm_cvs_session(v);
+			v->voc_state = VOC_RELEASE;
+		} else if (v->voc_state == VOC_CHANGE) {
+			voice_send_stop_voice_cmd(v);
+			voice_destroy_mvm_cvs_session(v);
+			v->voc_state = VOC_RELEASE;
+		}
+
+		mutex_unlock(&v->lock);
+
+		v->v_call_status = VOICE_CALL_END;
+
+		break;
+	default:
+		pr_err("UNKNOWN EVENT\n");
+	}
+	return;
+}
+EXPORT_SYMBOL(voice_auddev_cb_function);
+
+int voice_set_voc_path_full(uint32_t set)
+{
+	int rc = 0;
+
+	pr_info("%s: %d\n", __func__, set);
+
+	mutex_lock(&voice.lock);
+
+	if (voice.voc_state == VOC_INIT || voice.voc_state == VOC_RELEASE) {
+		if (set)
+			voice.voc_path = VOC_PATH_FULL;
+		else
+			voice.voc_path = VOC_PATH_PASSIVE;
+	} else {
+		pr_err("%s: Invalid voc path set to %d, in state %d\n",
+		       __func__, set, voice.voc_state);
+
+		rc = -EPERM;
+	}
+
+	mutex_unlock(&voice.lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(voice_set_voc_path_full);
+
+void voice_register_mvs_cb(ul_cb_fn ul_cb,
+			   dl_cb_fn dl_cb,
+			   void *private_data)
+{
+	voice.mvs_info.ul_cb = ul_cb;
+	voice.mvs_info.dl_cb = dl_cb;
+	voice.mvs_info.private_data = private_data;
+}
+
+void voice_config_vocoder(uint32_t media_type,
+			  uint32_t rate,
+			  uint32_t network_type,
+			  uint32_t dtx_mode)
+{
+	voice.mvs_info.media_type = media_type;
+	voice.mvs_info.rate = rate;
+	voice.mvs_info.network_type = network_type;
+	voice.mvs_info.dtx_mode = dtx_mode;
+}
+
+static int32_t modem_mvm_callback(struct apr_client_data *data, void *priv)
+{
+	uint32_t *ptr;
+	struct voice_data *v = priv;
+
+	pr_debug("%s\n", __func__);
+	pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+				data->payload_size, data->opcode);
+
+	if (data->opcode == RESET_EVENTS) {
+		pr_debug("%s:Reset event received in Voice service\n",
+					__func__);
+		apr_reset(v->apr_mvm);
+		apr_reset(v->apr_q6_mvm);
+		v->apr_q6_mvm = NULL;
+		v->apr_mvm = NULL;
+		v->mvm_handle = 0;
+		v->mvm_q6_handle = 0;
+		return 0;
+	}
+
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		if (data->payload_size) {
+			ptr = data->payload;
+
+			pr_info("%x %x\n", ptr[0], ptr[1]);
+			/* ping mvm service ACK */
+
+			if (ptr[0] ==
+			 VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION ||
+			ptr[0] ==
+			    VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION) {
+				/* Passive session is used for voice call
+				 * through modem. Full session is used for voice
+				 * call through Q6. */
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				if (!ptr[1]) {
+					pr_debug("%s: MVM handle is %d\n",
+						 __func__, data->src_port);
+
+					voice_set_mvm_handle(v, data->src_port);
+				} else
+					pr_info("got NACK for sending \
+							MVM create session \n");
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_IMVM_CMD_START_VOICE) {
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_IMVM_CMD_ATTACH_VOCPROC) {
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_IMVM_CMD_STOP_VOICE) {
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_IMVM_CMD_DETACH_VOCPROC) {
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_ISTREAM_CMD_SET_TTY_MODE) {
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == APRV2_IBASIC_CMD_DESTROY_SESSION) {
+				pr_debug("%s: DESTROY resp\n", __func__);
+
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_IMVM_CMD_ATTACH_STREAM) {
+				pr_debug("%s: ATTACH_STREAM resp 0x%x\n",
+					__func__, ptr[1]);
+
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_IMVM_CMD_DETACH_STREAM) {
+				pr_debug("%s: DETACH_STREAM resp 0x%x\n",
+					__func__, ptr[1]);
+
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_ICOMMON_CMD_SET_NETWORK) {
+				pr_debug("%s: SET_NETWORK resp 0x%x\n",
+					__func__, ptr[1]);
+
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else if (ptr[0] == VSS_ICOMMON_CMD_SET_VOICE_TIMING) {
+				pr_debug("%s: SET_VOICE_TIMING resp 0x%x\n",
+					__func__, ptr[1]);
+
+				v->mvm_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->mvm_wait);
+			} else
+				pr_debug("%s: not match cmd = 0x%x\n",
+					__func__, ptr[0]);
+		}
+	}
+
+	return 0;
+}
+
+static int32_t modem_cvs_callback(struct apr_client_data *data, void *priv)
+{
+	uint32_t *ptr;
+	struct voice_data *v = priv;
+
+	pr_debug("%s\n", __func__);
+	pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+					data->payload_size, data->opcode);
+
+	if (data->opcode == RESET_EVENTS) {
+		pr_debug("%s:Reset event received in Voice service\n",
+					__func__);
+		apr_reset(v->apr_cvs);
+		apr_reset(v->apr_q6_cvs);
+		v->apr_q6_cvs = NULL;
+		v->apr_cvs = NULL;
+		v->cvs_handle = 0;
+		v->cvs_q6_handle = 0;
+		return 0;
+	}
+
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		if (data->payload_size) {
+			ptr = data->payload;
+
+			pr_info("%x %x\n", ptr[0], ptr[1]);
+			/*response from modem CVS */
+			if (ptr[0] ==
+			VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION ||
+			    ptr[0] ==
+			    VSS_ISTREAM_CMD_CREATE_FULL_CONTROL_SESSION) {
+				if (!ptr[1]) {
+					pr_debug("%s: CVS handle is %d\n",
+						 __func__, data->src_port);
+					voice_set_cvs_handle(v, data->src_port);
+				} else
+					pr_info("got NACK for sending \
+							CVS create session \n");
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] ==
+				VSS_ISTREAM_CMD_CACHE_CALIBRATION_DATA) {
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] ==
+					VSS_ISTREAM_CMD_SET_MUTE) {
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] == VSS_ISTREAM_CMD_SET_MEDIA_TYPE) {
+				pr_debug("%s: SET_MEDIA resp 0x%x\n",
+					 __func__, ptr[1]);
+
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] ==
+				   VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE) {
+				pr_debug("%s: SET_AMR_RATE resp 0x%x\n",
+					 __func__, ptr[1]);
+
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] ==
+				   VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE) {
+				pr_debug("%s: SET_AMR_WB_RATE resp 0x%x\n",
+					 __func__, ptr[1]);
+
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] == VSS_ISTREAM_CMD_SET_ENC_DTX_MODE) {
+				pr_debug("%s: SET_DTX resp 0x%x\n",
+					 __func__, ptr[1]);
+
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] ==
+				   VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE) {
+				pr_debug("%s: SET_CDMA_RATE resp 0x%x\n",
+					 __func__, ptr[1]);
+
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] == APRV2_IBASIC_CMD_DESTROY_SESSION) {
+				pr_debug("%s: DESTROY resp\n", __func__);
+
+				v->cvs_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvs_wait);
+			} else if (ptr[0] == VSS_ISTREAM_CMD_START_RECORD) {
+				pr_debug("%s: START_RECORD resp 0x%x\n",
+					 __func__, ptr[1]);
+
+					v->cvs_state = CMD_STATUS_SUCCESS;
+					wake_up(&v->cvs_wait);
+			} else if (ptr[0] == VSS_ISTREAM_CMD_STOP_RECORD) {
+				pr_debug("%s: STOP_RECORD resp 0x%x\n",
+					 __func__, ptr[1]);
+
+					v->cvs_state = CMD_STATUS_SUCCESS;
+					wake_up(&v->cvs_wait);
+#ifdef CONFIG_MSM8X60_RTAC
+			} else if (ptr[0] == VOICE_CMD_SET_PARAM) {
+				rtac_make_voice_callback(RTAC_CVS, ptr,
+					data->payload_size);
+#endif
+			} else if (ptr[0] == VSS_ISTREAM_CMD_START_PLAYBACK) {
+				pr_debug("%s: START_PLAYBACK resp 0x%x\n",
+					 __func__, ptr[1]);
+
+					v->cvs_state = CMD_STATUS_SUCCESS;
+					wake_up(&v->cvs_wait);
+			} else if (ptr[0] == VSS_ISTREAM_CMD_STOP_PLAYBACK) {
+				pr_debug("%s: STOP_PLAYBACK resp 0x%x\n",
+					 __func__, ptr[1]);
+
+					v->cvs_state = CMD_STATUS_SUCCESS;
+					wake_up(&v->cvs_wait);
+			} else
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+		}
+	} else if (data->opcode == VSS_ISTREAM_EVT_SEND_ENC_BUFFER) {
+		uint32_t *voc_pkt = data->payload;
+		uint32_t pkt_len = data->payload_size;
+
+		if (voc_pkt != NULL && v->mvs_info.ul_cb != NULL) {
+			pr_debug("%s: Media type is 0x%x\n",
+				 __func__, voc_pkt[0]);
+
+			/* Remove media ID from payload. */
+			voc_pkt++;
+			pkt_len = pkt_len - 4;
+
+			v->mvs_info.ul_cb((uint8_t *)voc_pkt,
+					  pkt_len,
+					  v->mvs_info.private_data);
+			} else {
+				pr_err("%s: voc_pkt is 0x%x ul_cb is 0x%x\n",
+				       __func__, (unsigned int)voc_pkt,
+				       (unsigned int) v->mvs_info.ul_cb);
+			}
+	} else if (data->opcode == VSS_ISTREAM_EVT_SEND_DEC_BUFFER) {
+			pr_debug("%s: Send dec buf resp\n", __func__);
+	} else if (data->opcode == VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER) {
+		struct cvs_send_dec_buf_cmd send_dec_buf;
+		int ret = 0;
+		uint32_t pkt_len = 0;
+
+		if (v->mvs_info.dl_cb != NULL) {
+			send_dec_buf.dec_buf.media_id = v->mvs_info.media_type;
+
+			v->mvs_info.dl_cb(
+				(uint8_t *)&send_dec_buf.dec_buf.packet_data,
+				&pkt_len,
+				v->mvs_info.private_data);
+
+			send_dec_buf.hdr.hdr_field =
+				APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+					      APR_HDR_LEN(APR_HDR_SIZE),
+					      APR_PKT_VER);
+			send_dec_buf.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+			       sizeof(send_dec_buf.dec_buf.media_id) + pkt_len);
+			send_dec_buf.hdr.src_port = 0;
+			send_dec_buf.hdr.dest_port = voice_get_cvs_handle(v);
+			send_dec_buf.hdr.token = 0;
+			send_dec_buf.hdr.opcode =
+					VSS_ISTREAM_EVT_SEND_DEC_BUFFER;
+
+			ret = apr_send_pkt(voice_get_apr_cvs(v),
+					   (uint32_t *) &send_dec_buf);
+			if (ret < 0) {
+				pr_err("%s: Error %d sending DEC_BUF\n",
+				       __func__, ret);
+				goto fail;
+			}
+		} else {
+			pr_err("%s: ul_cb is NULL\n", __func__);
+		}
+#ifdef CONFIG_MSM8X60_RTAC
+	} else if (data->opcode ==  VOICE_EVT_GET_PARAM_ACK) {
+		rtac_make_voice_callback(RTAC_CVS, data->payload,
+					data->payload_size);
+#endif
+
+	} else {
+		pr_debug("%s: Unknown opcode 0x%x\n", __func__, data->opcode);
+	}
+
+fail:
+	return 0;
+}
+
+static int32_t modem_cvp_callback(struct apr_client_data *data, void *priv)
+{
+	uint32_t *ptr;
+	struct voice_data *v = priv;
+
+	pr_debug("%s\n", __func__);
+	pr_debug("%s: Payload Length = %d, opcode=%x\n", __func__,
+				data->payload_size, data->opcode);
+
+	if (data->opcode == RESET_EVENTS) {
+		pr_debug("%s:Reset event received in Voice service\n",
+					__func__);
+		apr_reset(v->apr_cvp);
+		apr_reset(v->apr_q6_cvp);
+		v->apr_q6_cvp = NULL;
+		v->apr_cvp = NULL;
+		v->cvp_handle = 0;
+		v->cvp_q6_handle = 0;
+		return 0;
+	}
+
+	if (data->opcode == APR_BASIC_RSP_RESULT) {
+		if (data->payload_size) {
+			ptr = data->payload;
+
+			pr_info("%x %x\n", ptr[0], ptr[1]);
+			/*response from modem CVP */
+			if (ptr[0] ==
+				VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION) {
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				if (!ptr[1]) {
+					voice_set_cvp_handle(v, data->src_port);
+					pr_debug("cvphdl=%d\n", data->src_port);
+				} else
+					pr_info("got NACK from CVP create \
+						session response\n");
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+			} else if (ptr[0] ==
+				VSS_IVOCPROC_CMD_CACHE_CALIBRATION_DATA) {
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+			} else if (ptr[0] == VSS_IVOCPROC_CMD_SET_DEVICE) {
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+			} else if (ptr[0] ==
+					VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX) {
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+			} else if (ptr[0] == VSS_IVOCPROC_CMD_ENABLE) {
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+			} else if (ptr[0] == VSS_IVOCPROC_CMD_DISABLE) {
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+			} else if (ptr[0] == APRV2_IBASIC_CMD_DESTROY_SESSION) {
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+			} else if (ptr[0] ==
+				VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE
+				) {
+
+				pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
+				v->cvp_state = CMD_STATUS_SUCCESS;
+				wake_up(&v->cvp_wait);
+#ifdef CONFIG_MSM8X60_RTAC
+			} else if (ptr[0] == VOICE_CMD_SET_PARAM) {
+				rtac_make_voice_callback(RTAC_CVP, ptr,
+					data->payload_size);
+#endif
+			} else
+				pr_debug("%s: not match cmd = 0x%x\n",
+							__func__, ptr[0]);
+		}
+#ifdef CONFIG_MSM8X60_RTAC
+	} else if (data->opcode ==  VOICE_EVT_GET_PARAM_ACK) {
+		rtac_make_voice_callback(RTAC_CVP, data->payload,
+			data->payload_size);
+#endif
+	}
+	return 0;
+}
+
+
+static int __init voice_init(void)
+{
+	int rc = 0;
+	struct voice_data *v = &voice;
+
+	/* set default value */
+	v->default_mute_val = 1;  /* default is mute */
+	v->default_vol_val = 0;
+	v->default_sample_val = 8000;
+
+	/* initialize dev_rx and dev_tx */
+	memset(&v->dev_tx, 0, sizeof(struct device_data));
+	memset(&v->dev_rx, 0, sizeof(struct device_data));
+	v->dev_rx.volume = v->default_vol_val;
+	v->dev_tx.mute = v->default_mute_val;
+
+	v->voc_state = VOC_INIT;
+	v->voc_path = VOC_PATH_PASSIVE;
+	v->adsp_version = 0;
+	init_waitqueue_head(&v->mvm_wait);
+	init_waitqueue_head(&v->cvs_wait);
+	init_waitqueue_head(&v->cvp_wait);
+
+	mutex_init(&v->lock);
+
+	v->mvm_handle = 0;
+	v->cvs_handle = 0;
+	v->cvp_handle = 0;
+
+	v->mvm_q6_handle = 0;
+	v->cvs_q6_handle = 0;
+	v->cvp_q6_handle = 0;
+
+	v->apr_mvm = NULL;
+	v->apr_cvs = NULL;
+	v->apr_cvp = NULL;
+
+	v->apr_q6_mvm = NULL;
+	v->apr_q6_cvs = NULL;
+	v->apr_q6_cvp = NULL;
+
+	/* Initialize MVS info. */
+	memset(&v->mvs_info, 0, sizeof(v->mvs_info));
+	v->mvs_info.network_type = VSS_NETWORK_ID_DEFAULT;
+
+	v->rec_info.pending = 0;
+	v->rec_info.rec_mode = VOC_REC_NONE;
+
+	memset(&v->music_info, 0, sizeof(v->music_info));
+
+	v->device_events = AUDDEV_EVT_DEV_CHG_VOICE |
+			AUDDEV_EVT_DEV_RDY |
+			AUDDEV_EVT_REL_PENDING |
+			AUDDEV_EVT_START_VOICE |
+			AUDDEV_EVT_END_VOICE |
+			AUDDEV_EVT_DEVICE_VOL_MUTE_CHG |
+			AUDDEV_EVT_FREQ_CHG;
+
+	pr_debug("to register call back\n");
+	/* register callback to auddev */
+	auddev_register_evt_listner(v->device_events, AUDDEV_CLNT_VOC,
+				0, voice_auddev_cb_function, v);
+
+	return rc;
+}
+
+device_initcall(voice_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/qcelp_in.c b/arch/arm/mach-msm/qdsp6v2/qcelp_in.c
new file mode 100644
index 0000000..894f1ed
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/qcelp_in.c
@@ -0,0 +1,329 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/msm_audio_qcp.h>
+#include <asm/atomic.h>
+#include <asm/ioctls.h>
+#include <sound/q6asm.h>
+#include <sound/apr_audio.h>
+#include "audio_utils.h"
+
+/* Buffer with meta*/
+#define PCM_BUF_SIZE		(4096 + sizeof(struct meta_in))
+
+/* Maximum 10 frames in buffer with meta */
+#define FRAME_SIZE		(1 + ((35+sizeof(struct meta_out_dsp)) * 10))
+
+void q6asm_qcelp_in_cb(uint32_t opcode, uint32_t token,
+		uint32_t *payload, void *priv)
+{
+	struct q6audio_in * audio = (struct q6audio_in *)priv;
+	unsigned long flags;
+
+	pr_debug("%s:session id %d: opcode - %d\n", __func__,
+			audio->ac->session, opcode);
+
+	spin_lock_irqsave(&audio->dsp_lock, flags);
+	switch (opcode) {
+	case ASM_DATA_EVENT_READ_DONE:
+		audio_in_get_dsp_frames(audio, token, payload);
+		break;
+	case ASM_DATA_EVENT_WRITE_DONE:
+		atomic_inc(&audio->in_count);
+		wake_up(&audio->write_wait);
+		break;
+	case ASM_DATA_CMDRSP_EOS:
+		audio->eos_rsp = 1;
+		wake_up(&audio->read_wait);
+		break;
+	case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
+		break;
+	case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
+		break;
+	case ASM_SESSION_EVENT_TX_OVERFLOW:
+		pr_err("%s:session id %d:ASM_SESSION_EVENT_TX_OVERFLOW\n",
+			__func__, audio->ac->session);
+		break;
+	default:
+		pr_err("%s:session id %d: Ignore opcode[0x%x]\n", __func__,
+			audio->ac->session, opcode);
+		break;
+	}
+	spin_unlock_irqrestore(&audio->dsp_lock, flags);
+}
+/* ------------------- device --------------------- */
+static long qcelp_in_ioctl(struct file *file,
+				unsigned int cmd, unsigned long arg)
+{
+	struct q6audio_in  *audio = file->private_data;
+	int rc = 0;
+	int cnt = 0;
+
+	switch (cmd) {
+	case AUDIO_START: {
+		struct msm_audio_qcelp_enc_config *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		pr_debug("%s:session id %d: default buf alloc[%d]\n", __func__,
+				audio->ac->session, audio->buf_alloc);
+		if (audio->enabled == 1) {
+			pr_info("%s:AUDIO_START already over\n", __func__);
+			rc = 0;
+			break;
+		}
+		rc = audio_in_buf_alloc(audio);
+		if (rc < 0) {
+			pr_err("%s:session id %d: buffer allocation failed\n",
+				__func__, audio->ac->session);
+			break;
+		}
+
+		/* reduced_rate_level, rate_modulation_cmd set to zero
+			 currently not configurable from user space */
+		rc = q6asm_enc_cfg_blk_qcelp(audio->ac,
+			audio->buf_cfg.frames_per_buf,
+			enc_cfg->min_bit_rate,
+			enc_cfg->max_bit_rate, 0, 0);
+
+		if (rc < 0) {
+			pr_err("%s:session id %d: cmd qcelp media format block\
+				failed\n", __func__, audio->ac->session);
+			break;
+		}
+		if (audio->feedback == NON_TUNNEL_MODE) {
+			rc = q6asm_media_format_block_pcm(audio->ac,
+				audio->pcm_cfg.sample_rate,
+				audio->pcm_cfg.channel_count);
+
+			if (rc < 0) {
+				pr_err("%s:session id %d: media format block\
+				failed\n", __func__, audio->ac->session);
+				break;
+			}
+		}
+		pr_debug("%s:session id %d: AUDIO_START enable[%d]\n", __func__,
+				audio->ac->session, audio->enabled);
+		rc = audio_in_enable(audio);
+		if (!rc) {
+			audio->enabled = 1;
+		} else {
+			audio->enabled = 0;
+			pr_err("%s:session id %d: Audio Start procedure failed\
+				rc=%d\n", __func__, audio->ac->session, rc);
+			break;
+		}
+		while (cnt++ < audio->str_cfg.buffer_count)
+			q6asm_read(audio->ac); /* Push buffer to DSP */
+		rc = 0;
+		pr_debug("%s:session id %d: AUDIO_START success enable[%d]\n",
+				__func__, audio->ac->session, audio->enabled);
+		break;
+	}
+	case AUDIO_STOP: {
+		pr_debug("%s:session id %d: AUDIO_STOP\n", __func__,
+				audio->ac->session);
+		rc = audio_in_disable(audio);
+		if (rc  < 0) {
+			pr_err("%s:session id %d: Audio Stop procedure failed\
+					rc=%d\n", __func__, audio->ac->session,
+					rc);
+			break;
+		}
+		break;
+	}
+	case AUDIO_GET_QCELP_ENC_CONFIG: {
+		if (copy_to_user((void *)arg, audio->enc_cfg,
+			sizeof(struct msm_audio_qcelp_enc_config)))
+			rc = -EFAULT;
+		break;
+	}
+	case AUDIO_SET_QCELP_ENC_CONFIG: {
+		struct msm_audio_qcelp_enc_config cfg;
+		struct msm_audio_qcelp_enc_config *enc_cfg;
+		enc_cfg = audio->enc_cfg;
+		if (copy_from_user(&cfg, (void *) arg,
+				sizeof(struct msm_audio_qcelp_enc_config))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		if (cfg.min_bit_rate > 4 ||
+			 cfg.min_bit_rate < 1) {
+			pr_err("%s:session id %d: invalid min bitrate\n",
+					__func__, audio->ac->session);
+			rc = -EINVAL;
+			break;
+		}
+		if (cfg.max_bit_rate > 4 ||
+			 cfg.max_bit_rate < 1) {
+			pr_err("%s:session id %d: invalid max bitrate\n",
+					__func__, audio->ac->session);
+			rc = -EINVAL;
+			break;
+		}
+		enc_cfg->min_bit_rate = cfg.min_bit_rate;
+		enc_cfg->max_bit_rate = cfg.max_bit_rate;
+		pr_debug("%s:session id %d: min_bit_rate= 0x%x\
+			max_bit_rate=0x%x\n", __func__,
+			audio->ac->session, enc_cfg->min_bit_rate,
+			enc_cfg->max_bit_rate);
+		break;
+	}
+	default:
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static int qcelp_in_open(struct inode *inode, struct file *file)
+{
+	struct q6audio_in *audio = NULL;
+	struct msm_audio_qcelp_enc_config *enc_cfg;
+	int rc = 0;
+
+	audio = kzalloc(sizeof(struct q6audio_in), GFP_KERNEL);
+
+	if (audio == NULL) {
+		pr_err("%s:session id %d: Could not allocate memory for qcelp\
+				driver\n", __func__, audio->ac->session);
+		return -ENOMEM;
+	}
+	/* Allocate memory for encoder config param */
+	audio->enc_cfg = kzalloc(sizeof(struct msm_audio_qcelp_enc_config),
+				GFP_KERNEL);
+	if (audio->enc_cfg == NULL) {
+		pr_err("%s:session id %d: Could not allocate memory for aac\
+				config param\n", __func__, audio->ac->session);
+		kfree(audio);
+		return -ENOMEM;
+	}
+	enc_cfg = audio->enc_cfg;
+
+	mutex_init(&audio->lock);
+	mutex_init(&audio->read_lock);
+	mutex_init(&audio->write_lock);
+	spin_lock_init(&audio->dsp_lock);
+	init_waitqueue_head(&audio->read_wait);
+	init_waitqueue_head(&audio->write_wait);
+
+	/* Settings will be re-config at AUDIO_SET_CONFIG,
+	* but at least we need to have initial config
+	*/
+	audio->str_cfg.buffer_size = FRAME_SIZE;
+	audio->str_cfg.buffer_count = FRAME_NUM;
+	audio->min_frame_size = 35;
+	audio->max_frames_per_buf = 10;
+	audio->pcm_cfg.buffer_size = PCM_BUF_SIZE;
+	audio->pcm_cfg.buffer_count = PCM_BUF_COUNT;
+	enc_cfg->min_bit_rate = 4;
+	enc_cfg->max_bit_rate = 4;
+	audio->pcm_cfg.channel_count = 1;
+	audio->pcm_cfg.sample_rate = 8000;
+	audio->buf_cfg.meta_info_enable = 0x01;
+	audio->buf_cfg.frames_per_buf = 0x01;
+
+	audio->ac = q6asm_audio_client_alloc((app_cb)q6asm_qcelp_in_cb,
+				(void *)audio);
+
+	if (!audio->ac) {
+		pr_err("%s:session id %d: Could not allocate memory for audio\
+				client\n", __func__, audio->ac->session);
+		kfree(audio->enc_cfg);
+		kfree(audio);
+		return -ENOMEM;
+	}
+
+	/* open qcelp encoder in T/NT mode */
+	if ((file->f_mode & FMODE_WRITE) &&
+		(file->f_mode & FMODE_READ)) {
+		audio->feedback = NON_TUNNEL_MODE;
+		rc = q6asm_open_read_write(audio->ac, FORMAT_V13K,
+					FORMAT_LINEAR_PCM);
+		if (rc < 0) {
+			pr_err("%s:session id %d: NT mode Open failed rc=%d\n",
+				__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		pr_info("%s:session id %d: NT mode encoder success\n", __func__,
+				audio->ac->session);
+	} else if (!(file->f_mode & FMODE_WRITE) &&
+				(file->f_mode & FMODE_READ)) {
+		audio->feedback = TUNNEL_MODE;
+		rc = q6asm_open_read(audio->ac, FORMAT_V13K);
+		if (rc < 0) {
+			pr_err("%s:session id %d: T mode Open failed rc=%d\n",
+				__func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		/* register for tx overflow (valid for tunnel mode only) */
+		rc = q6asm_reg_tx_overflow(audio->ac, 0x01);
+		if (rc < 0) {
+			pr_err("%s:session id %d: TX Overflow registration\
+			failed rc=%d\n", __func__, audio->ac->session, rc);
+			rc = -ENODEV;
+			goto fail;
+		}
+		pr_info("%s:session id %d: T mode encoder success\n", __func__,
+				audio->ac->session);
+	} else {
+		pr_err("%s:session id %d: Unexpected mode\n", __func__,
+				audio->ac->session);
+		rc = -EACCES;
+		goto fail;
+	}
+
+	audio->opened = 1;
+	atomic_set(&audio->in_count, PCM_BUF_COUNT);
+	atomic_set(&audio->out_count, 0x00);
+	audio->enc_ioctl = qcelp_in_ioctl;
+	file->private_data = audio;
+
+	pr_info("%s:session id %d: success\n", __func__, audio->ac->session);
+	return 0;
+fail:
+	q6asm_audio_client_free(audio->ac);
+	kfree(audio->enc_cfg);
+	kfree(audio);
+	return rc;
+}
+
+static const struct file_operations audio_in_fops = {
+	.owner		= THIS_MODULE,
+	.open		= qcelp_in_open,
+	.release	= audio_in_release,
+	.read		= audio_in_read,
+	.write		= audio_in_write,
+	.unlocked_ioctl	= audio_in_ioctl,
+};
+
+struct miscdevice audio_qcelp_in_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_qcelp_in",
+	.fops	= &audio_in_fops,
+};
+
+static int __init qcelp_in_init(void)
+{
+	return misc_register(&audio_qcelp_in_misc);
+}
+
+device_initcall(qcelp_in_init);
diff --git a/arch/arm/mach-msm/qdsp6v2/rtac.c b/arch/arm/mach-msm/qdsp6v2/rtac.c
new file mode 100644
index 0000000..3476224
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/rtac.c
@@ -0,0 +1,1032 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/msm_audio_acdb.h>
+#include <asm/atomic.h>
+#include <mach/qdsp6v2/apr_audio.h>
+#include <mach/qdsp6v2/q6asm.h>
+#include <mach/qdsp6v2/q6afe.h>
+#include <mach/qdsp6v2/rtac.h>
+#include <sound/q6adm.h>
+
+
+/* Max size of payload (buf size - apr header) */
+#define MAX_PAYLOAD_SIZE		4076
+#define RTAC_MAX_ACTIVE_DEVICES		4
+#define RTAC_MAX_ACTIVE_VOICE_COMBOS	2
+#define RTAC_MAX_ACTIVE_POPP		8
+#define RTAC_BUF_SIZE			4096
+
+#define TIMEOUT_MS	1000
+
+/* APR data */
+struct rtac_apr_data {
+	void			*apr_handle;
+	atomic_t		cmd_state;
+	wait_queue_head_t	cmd_wait;
+};
+
+static struct rtac_apr_data	rtac_adm_apr_data;
+static struct rtac_apr_data	rtac_asm_apr_data[SESSION_MAX+1];
+static struct rtac_apr_data	rtac_voice_apr_data[RTAC_VOICE_MODES];
+
+
+/* Dev ctrl info */
+struct rtac_dev_ctrl_data {
+	uint32_t	dev_id;
+	uint32_t	afe_port;
+};
+
+struct rtac_dev_ctrl {
+	uint32_t			num_of_dev;
+	struct rtac_dev_ctrl_data	device[RTAC_MAX_ACTIVE_DEVICES];
+};
+
+static struct rtac_dev_ctrl	rtac_dev_ctl_data;
+
+
+/* ADM info & APR */
+struct rtac_adm_data {
+	uint32_t	afe_port;
+	uint32_t	copp;
+	uint32_t	num_of_popp;
+	uint32_t	popp[RTAC_MAX_ACTIVE_POPP];
+};
+
+struct rtac_adm {
+	uint32_t		num_of_dev;
+	struct rtac_adm_data	device[RTAC_MAX_ACTIVE_DEVICES];
+};
+static struct rtac_adm		rtac_adm_data;
+static u32			rtac_adm_payload_size;
+static u32			rtac_adm_user_buf_size;
+static u8			*rtac_adm_buffer;
+
+
+/* ASM APR */
+static u32			rtac_asm_payload_size;
+static u32			rtac_asm_user_buf_size;
+static u8			*rtac_asm_buffer;
+
+
+/* Voice info & APR */
+struct rtac_voice_data {
+	uint32_t	tx_dev_id;
+	uint32_t	rx_dev_id;
+	uint32_t	tx_afe_port;
+	uint32_t	rx_afe_port;
+	uint16_t	cvs_handle;
+	uint16_t	cvp_handle;
+};
+
+struct rtac_voice {
+	uint32_t		num_of_voice_combos;
+	struct rtac_voice_data	voice[RTAC_MAX_ACTIVE_VOICE_COMBOS];
+};
+
+static struct rtac_voice	rtac_voice_data;
+static u32			rtac_voice_payload_size;
+static u32			rtac_voice_user_buf_size;
+static u8			*rtac_voice_buffer;
+
+
+
+struct mutex			rtac_dev_ctrl_mutex;
+struct mutex			rtac_adm_mutex;
+struct mutex			rtac_adm_apr_mutex;
+struct mutex			rtac_asm_apr_mutex;
+struct mutex			rtac_voice_mutex;
+struct mutex			rtac_voice_apr_mutex;
+
+static int rtac_open(struct inode *inode, struct file *f)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+static int rtac_release(struct inode *inode, struct file *f)
+{
+	pr_debug("%s\n", __func__);
+	return 0;
+}
+
+
+/* Dev ctrl info */
+void rtac_add_dev_ctrl_device(u32 dev_id, struct msm_snddev_info *dev_info)
+{
+	s32 i = 0;
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&rtac_dev_ctrl_mutex);
+	if (rtac_dev_ctl_data.num_of_dev == RTAC_MAX_ACTIVE_DEVICES) {
+		pr_err("%s, Can't add anymore RTAC devices!\n", __func__);
+		goto done;
+	}
+
+	/* Check if device already added */
+	if (rtac_dev_ctl_data.num_of_dev != 0) {
+		for (; i < rtac_dev_ctl_data.num_of_dev; i++) {
+			if (rtac_dev_ctl_data.device[i].dev_id == dev_id)
+				goto done;
+		}
+	}
+
+	/* Add device */
+	rtac_dev_ctl_data.num_of_dev++;
+	rtac_dev_ctl_data.device[i].dev_id = dev_id;
+	rtac_dev_ctl_data.device[i].afe_port = dev_info->copp_id;
+done:
+	mutex_unlock(&rtac_dev_ctrl_mutex);
+	return;
+}
+
+void shift_dev_ctrl_devices(u32 dev_idx)
+{
+	for (; dev_idx < rtac_dev_ctl_data.num_of_dev - 1; dev_idx++) {
+		rtac_dev_ctl_data.device[dev_idx].dev_id =
+			rtac_dev_ctl_data.device[dev_idx + 1].dev_id;
+		rtac_dev_ctl_data.device[dev_idx].afe_port =
+			rtac_dev_ctl_data.device[dev_idx + 1].afe_port;
+	}
+}
+
+void rtac_remove_dev_ctrl_device(u32 dev_id)
+{
+	s32 i;
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&rtac_dev_ctrl_mutex);
+	if (rtac_dev_ctl_data.num_of_dev == 0)
+		goto done;
+
+	/* look for device */
+	for (i = 0; i < rtac_dev_ctl_data.num_of_dev; i++) {
+		if (rtac_dev_ctl_data.device[i].dev_id == dev_id) {
+			shift_dev_ctrl_devices(i);
+			rtac_dev_ctl_data.device[i].dev_id = 0;
+			rtac_dev_ctl_data.device[i].afe_port = 0;
+			rtac_dev_ctl_data.num_of_dev--;
+			break;
+		}
+	}
+done:
+	mutex_unlock(&rtac_dev_ctrl_mutex);
+	return;
+}
+
+void update_rtac(u32 evt_id, u32 dev_id, struct msm_snddev_info *dev_info)
+{
+	switch (evt_id) {
+	case AUDDEV_EVT_DEV_RDY:
+		rtac_add_dev_ctrl_device(dev_id, dev_info);
+		break;
+	case AUDDEV_EVT_DEV_RLS:
+		rtac_remove_dev_ctrl_device(dev_id);
+		break;
+	default:
+		break;
+	}
+}
+
+
+/* ADM Info */
+void add_popp(u32 dev_idx, u32 port_id, u32 popp_id)
+{
+	u32 i = 0;
+
+	for (; i < rtac_adm_data.device[dev_idx].num_of_popp; i++)
+		if (rtac_adm_data.device[dev_idx].popp[i] == popp_id)
+			goto done;
+
+
+	if (rtac_adm_data.device[dev_idx].num_of_popp ==
+			RTAC_MAX_ACTIVE_POPP) {
+		pr_err("%s, Max POPP!\n", __func__);
+		goto done;
+	}
+	rtac_adm_data.device[dev_idx].popp[
+		rtac_adm_data.device[dev_idx].num_of_popp++] = popp_id;
+done:
+	return;
+}
+
+void rtac_add_adm_device(u32 port_id, u32 popp_id)
+{
+	u32 i = 0;
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&rtac_adm_mutex);
+	if (rtac_adm_data.num_of_dev == RTAC_MAX_ACTIVE_DEVICES) {
+		pr_err("%s, Can't add anymore RTAC devices!\n", __func__);
+		goto done;
+	}
+
+	/* Check if device already added */
+	if (rtac_adm_data.num_of_dev != 0) {
+		for (; i < rtac_adm_data.num_of_dev; i++) {
+			if (rtac_adm_data.device[i].afe_port == port_id)
+				add_popp(i, port_id, popp_id);
+				goto done;
+		}
+	}
+
+	if (rtac_adm_data.device[i].num_of_popp == RTAC_MAX_ACTIVE_POPP) {
+		pr_err("%s, Max POPP!\n", __func__);
+		goto done;
+	}
+
+	/* Add device */
+	rtac_adm_data.num_of_dev++;
+	rtac_adm_data.device[i].afe_port = port_id;
+	rtac_adm_data.device[i].copp = adm_get_copp_id(port_id);
+	rtac_adm_data.device[i].popp[
+		rtac_adm_data.device[i].num_of_popp++] = popp_id;
+done:
+	mutex_unlock(&rtac_adm_mutex);
+	return;
+}
+
+void shift_adm_devices(u32 dev_idx)
+{
+	for (; dev_idx < rtac_adm_data.num_of_dev - 1; dev_idx++) {
+		memcpy(&rtac_adm_data.device[dev_idx],
+			&rtac_adm_data.device[dev_idx + 1],
+			sizeof(rtac_adm_data.device[dev_idx]));
+	}
+}
+
+void rtac_remove_adm_device(u32 port_id)
+{
+	s32 i;
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&rtac_adm_mutex);
+	/* look for device */
+	for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
+		if (rtac_adm_data.device[i].afe_port == port_id) {
+			shift_adm_devices(i);
+			memset(&rtac_adm_data.device[i], 0,
+				sizeof(rtac_adm_data.device[i]));
+			rtac_adm_data.num_of_dev--;
+			break;
+		}
+	}
+	mutex_unlock(&rtac_adm_mutex);
+	return;
+}
+
+
+/* Voice Info */
+void set_rtac_voice_data(int idx, struct voice_data *v)
+{
+	rtac_voice_data.voice[idx].tx_dev_id = v->dev_tx.dev_id;
+	rtac_voice_data.voice[idx].rx_dev_id = v->dev_rx.dev_id;
+	rtac_voice_data.voice[idx].tx_afe_port = v->dev_tx.dev_port_id;
+	rtac_voice_data.voice[idx].rx_afe_port = v->dev_rx.dev_port_id;
+	rtac_voice_data.voice[idx].cvs_handle = v->cvs_handle;
+	rtac_voice_data.voice[idx].cvp_handle = v->cvp_handle;
+
+}
+
+void rtac_add_voice(struct voice_data *v)
+{
+	u32 i = 0;
+	pr_debug("%s\n", __func__);
+	mutex_lock(&rtac_voice_mutex);
+
+	if (rtac_voice_data.num_of_voice_combos ==
+			RTAC_MAX_ACTIVE_VOICE_COMBOS) {
+		pr_err("%s, Can't add anymore RTAC devices!\n", __func__);
+		goto done;
+	}
+
+	/* Check if device already added */
+	if (rtac_voice_data.num_of_voice_combos != 0) {
+		for (; i < rtac_voice_data.num_of_voice_combos; i++) {
+			if (rtac_voice_data.voice[i].cvp_handle ==
+							v->cvp_handle) {
+				set_rtac_voice_data(i, v);
+				goto done;
+			}
+		}
+	}
+
+	/* Add device */
+	rtac_voice_data.num_of_voice_combos++;
+	set_rtac_voice_data(i, v);
+done:
+	mutex_unlock(&rtac_voice_mutex);
+	return;
+}
+
+void shift_voice_devices(u32 idx)
+{
+	for (; idx < rtac_voice_data.num_of_voice_combos - 1; idx++) {
+		memcpy(&rtac_voice_data.voice[idx],
+			&rtac_voice_data.voice[idx + 1],
+			sizeof(rtac_voice_data.voice[idx]));
+	}
+}
+
+void rtac_remove_voice(struct voice_data *v)
+{
+	u32 i = 0;
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&rtac_voice_mutex);
+	/* look for device */
+	for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
+		if (rtac_voice_data.voice[i].cvp_handle == v->cvp_handle) {
+			shift_voice_devices(i);
+			rtac_voice_data.num_of_voice_combos--;
+			memset(&rtac_voice_data.voice[
+				rtac_voice_data.num_of_voice_combos], 0,
+				sizeof(rtac_voice_data.voice
+				[rtac_voice_data.num_of_voice_combos]));
+			break;
+		}
+	}
+	mutex_unlock(&rtac_voice_mutex);
+	return;
+}
+
+
+
+/* ADM APR */
+void rtac_set_adm_handle(void *handle)
+{
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&rtac_adm_apr_mutex);
+	rtac_adm_apr_data.apr_handle = handle;
+	mutex_unlock(&rtac_adm_apr_mutex);
+}
+
+bool rtac_make_adm_callback(uint32_t *payload, u32 payload_size)
+{
+	if (atomic_read(&rtac_adm_apr_data.cmd_state) != 1)
+		return false;
+
+	pr_debug("%s\n", __func__);
+	/* Offset data for in-band payload */
+	rtac_copy_adm_payload_to_user(payload, payload_size);
+	atomic_set(&rtac_adm_apr_data.cmd_state, 0);
+	wake_up(&rtac_adm_apr_data.cmd_wait);
+	return true;
+}
+
+void rtac_copy_adm_payload_to_user(void *payload, u32 payload_size)
+{
+	pr_debug("%s\n", __func__);
+	rtac_adm_payload_size = payload_size;
+
+	memcpy(rtac_adm_buffer, &payload_size, sizeof(u32));
+	if (payload_size != 0) {
+		if (payload_size > rtac_adm_user_buf_size) {
+			pr_err("%s: Buffer set not big enough for "
+				"returned data, buf size = %d, "
+				"ret data = %d\n", __func__,
+				rtac_adm_user_buf_size, payload_size);
+			goto done;
+		}
+		memcpy(rtac_adm_buffer + sizeof(u32), payload, payload_size);
+	}
+done:
+	return;
+}
+
+u32 send_adm_apr(void *buf, u32 opcode)
+{
+	s32				result;
+	u32				count = 0;
+	u32				bytes_returned = 0;
+	u32				port_id = 0;
+	u32				copp_id;
+	u32				payload_size;
+	struct apr_hdr			adm_params;
+	pr_debug("%s\n", __func__);
+
+	if (copy_from_user(&count, (void *)buf, sizeof(count))) {
+			pr_err("%s: Copy to user failed! buf = 0x%x\n",
+			       __func__, (unsigned int)buf);
+			result = -EFAULT;
+			goto done;
+	}
+
+	if (count <= 0) {
+		pr_err("%s: Invalid buffer size = %d\n", __func__, count);
+		goto done;
+	}
+
+	if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy payload size from user buffer\n",
+			__func__);
+		goto done;
+	}
+
+
+	if ((payload_size < 0) ||
+		(payload_size > MAX_PAYLOAD_SIZE)) {
+
+			pr_err("%s: Invalid payload size = %d\n",
+				__func__, payload_size);
+		goto done;
+	}
+
+	if (copy_from_user(&copp_id, buf + 2 * sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy port id from user buffer\n",
+			__func__);
+		goto done;
+	}
+
+	for (port_id = 0; port_id < AFE_MAX_PORTS; port_id++) {
+		if (adm_get_copp_id(port_id) == copp_id)
+			break;
+	}
+	if (port_id >= AFE_MAX_PORTS) {
+		pr_err("%s: Invalid Port ID = %d\n", __func__, port_id);
+		goto done;
+	}
+
+	mutex_lock(&rtac_adm_apr_mutex);
+	if (rtac_adm_apr_data.apr_handle == NULL) {
+		pr_err("%s: APR not initialized\n", __func__);
+		goto err;
+	}
+
+	/* Set globals for copy of returned payload */
+	rtac_adm_user_buf_size = count;
+	/* Copy buffer to in-band payload */
+	if (copy_from_user(rtac_adm_buffer + sizeof(adm_params),
+			buf + 3 * sizeof(u32), payload_size)) {
+		pr_err("%s: Could not copy payload from user buffer\n",
+			__func__);
+		goto err;
+	}
+
+	/* Pack header */
+	adm_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(20), APR_PKT_VER);
+	adm_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		payload_size);
+	adm_params.src_svc = APR_SVC_ADM;
+	adm_params.src_domain = APR_DOMAIN_APPS;
+	adm_params.src_port = port_id;
+	adm_params.dest_svc = APR_SVC_ADM;
+	adm_params.dest_domain = APR_DOMAIN_ADSP;
+	adm_params.dest_port = adm_get_copp_id(port_id);
+	adm_params.token = port_id;
+	adm_params.opcode = opcode;
+
+	memcpy(rtac_adm_buffer, &adm_params, sizeof(adm_params));
+	atomic_set(&rtac_adm_apr_data.cmd_state, 1);
+
+	pr_debug("%s: Sending RTAC command size = %d\n",
+		__func__, adm_params.pkt_size);
+
+	result = apr_send_pkt(rtac_adm_apr_data.apr_handle,
+				(uint32_t *)rtac_adm_buffer);
+	if (result < 0) {
+		pr_err("%s: Set params failed port = %d\n",
+			__func__, port_id);
+		goto err;
+	}
+	/* Wait for the callback */
+	result = wait_event_timeout(rtac_adm_apr_data.cmd_wait,
+		(atomic_read(&rtac_adm_apr_data.cmd_state) == 0),
+		msecs_to_jiffies(TIMEOUT_MS));
+	mutex_unlock(&rtac_adm_apr_mutex);
+	if (!result) {
+		pr_err("%s: Set params timed out port = %d\n",
+			__func__, port_id);
+		goto done;
+	}
+
+	if (rtac_adm_payload_size != 0) {
+		if (copy_to_user(buf, rtac_adm_buffer,
+				rtac_adm_payload_size + sizeof(u32))) {
+			pr_err("%s: Could not copy buffer to user,"
+				"size = %d\n", __func__, payload_size);
+			goto done;
+		}
+	}
+
+	/* Return data written for SET & data read for GET */
+	if (opcode == ADM_CMD_GET_PARAMS)
+		bytes_returned = rtac_adm_payload_size;
+	else
+		bytes_returned = payload_size;
+done:
+	return bytes_returned;
+err:
+	mutex_unlock(&rtac_adm_apr_mutex);
+	return bytes_returned;
+}
+
+
+/* ASM APR */
+void rtac_set_asm_handle(u32 session_id, void *handle)
+{
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&rtac_asm_apr_mutex);
+	rtac_asm_apr_data[session_id].apr_handle = handle;
+	mutex_unlock(&rtac_asm_apr_mutex);
+}
+
+bool rtac_make_asm_callback(u32 session_id, uint32_t *payload,
+	u32 payload_size)
+{
+	if (atomic_read(&rtac_asm_apr_data[session_id].cmd_state) != 1)
+		return false;
+
+	pr_debug("%s\n", __func__);
+	/* Offset data for in-band payload */
+	rtac_copy_asm_payload_to_user(payload, payload_size);
+	atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 0);
+	wake_up(&rtac_asm_apr_data[session_id].cmd_wait);
+	return true;
+}
+
+void rtac_copy_asm_payload_to_user(void *payload, u32 payload_size)
+{
+	pr_debug("%s\n", __func__);
+	rtac_asm_payload_size = payload_size;
+
+	memcpy(rtac_asm_buffer, &payload_size, sizeof(u32));
+	if (payload_size) {
+		if (payload_size > rtac_asm_user_buf_size) {
+			pr_err("%s: Buffer set not big enough for "
+				"returned data, buf size = %d, "
+				"ret data = %d\n", __func__,
+				rtac_asm_user_buf_size, payload_size);
+			goto done;
+		}
+		memcpy(rtac_asm_buffer + sizeof(u32), payload, payload_size);
+	}
+done:
+	return;
+}
+
+u32 send_rtac_asm_apr(void *buf, u32 opcode)
+{
+	s32				result;
+	u32				count = 0;
+	u32				bytes_returned = 0;
+	u32				session_id = 0;
+	u32				payload_size;
+	struct apr_hdr			asm_params;
+	pr_debug("%s\n", __func__);
+
+	if (copy_from_user(&count, (void *)buf, sizeof(count))) {
+			pr_err("%s: Copy to user failed! buf = 0x%x\n",
+			       __func__, (unsigned int)buf);
+			result = -EFAULT;
+			goto done;
+	}
+
+	if (count <= 0) {
+		pr_err("%s: Invalid buffer size = %d\n", __func__, count);
+		goto done;
+	}
+
+	if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy payload size from user buffer\n",
+			__func__);
+		goto done;
+	}
+
+	if ((payload_size < 0) ||
+		(payload_size > MAX_PAYLOAD_SIZE)) {
+
+			pr_err("%s: Invalid payload size = %d\n",
+				__func__, payload_size);
+		goto done;
+	}
+
+	if (copy_from_user(&session_id, buf + 2 * sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy session id from user buffer\n",
+			__func__);
+		goto done;
+	}
+	if (session_id >= AFE_MAX_PORTS) {
+		pr_err("%s: Invalid Session = %d\n", __func__, session_id);
+		goto done;
+	}
+
+	mutex_lock(&rtac_asm_apr_mutex);
+	if (rtac_asm_apr_data[session_id].apr_handle == NULL) {
+		pr_err("%s: APR not initialized\n", __func__);
+		goto err;
+	}
+
+	/* Set globals for copy of returned payload */
+	rtac_asm_user_buf_size = count;
+
+	/* Copy buffer to in-band payload */
+	if (copy_from_user(rtac_asm_buffer + sizeof(asm_params),
+			buf + 3 * sizeof(u32), payload_size)) {
+		pr_err("%s: Could not copy payload from user buffer\n",
+			__func__);
+		goto err;
+	}
+
+	/* Pack header */
+	asm_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(20), APR_PKT_VER);
+	asm_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		payload_size);
+	asm_params.src_svc = q6asm_get_apr_service_id(session_id);
+	asm_params.src_domain = APR_DOMAIN_APPS;
+	asm_params.src_port = (session_id << 8) | 0x0001;
+	asm_params.dest_svc = APR_SVC_ASM;
+	asm_params.dest_domain = APR_DOMAIN_ADSP;
+	asm_params.dest_port = (session_id << 8) | 0x0001;
+	asm_params.token = session_id;
+	asm_params.opcode = opcode;
+
+	memcpy(rtac_asm_buffer, &asm_params, sizeof(asm_params));
+	atomic_set(&rtac_asm_apr_data[session_id].cmd_state, 1);
+
+	pr_debug("%s: Sending RTAC command size = %d, session_id=%d\n",
+		__func__, asm_params.pkt_size, session_id);
+
+	result = apr_send_pkt(rtac_asm_apr_data[session_id].apr_handle,
+				(uint32_t *)rtac_asm_buffer);
+	if (result < 0) {
+		pr_err("%s: Set params failed session = %d\n",
+			__func__, session_id);
+		goto err;
+	}
+
+	/* Wait for the callback */
+	result = wait_event_timeout(rtac_asm_apr_data[session_id].cmd_wait,
+		(atomic_read(&rtac_asm_apr_data[session_id].cmd_state) == 0),
+		5 * HZ);
+	mutex_unlock(&rtac_asm_apr_mutex);
+	if (!result) {
+		pr_err("%s: Set params timed out session = %d\n",
+			__func__, session_id);
+		goto done;
+	}
+
+	if (rtac_asm_payload_size != 0) {
+		if (copy_to_user(buf, rtac_asm_buffer,
+				rtac_asm_payload_size + sizeof(u32))) {
+			pr_err("%s: Could not copy buffer to user,"
+				"size = %d\n", __func__, payload_size);
+			goto done;
+		}
+	}
+
+	/* Return data written for SET & data read for GET */
+	if (opcode == ASM_STREAM_CMD_GET_PP_PARAMS)
+		bytes_returned = rtac_asm_payload_size;
+	else
+		bytes_returned = payload_size;
+done:
+	return bytes_returned;
+err:
+	mutex_unlock(&rtac_asm_apr_mutex);
+	return bytes_returned;
+}
+
+
+/* Voice APR */
+void rtac_set_voice_handle(u32 mode, void *handle)
+{
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&rtac_voice_apr_mutex);
+	rtac_voice_apr_data[mode].apr_handle = handle;
+	mutex_unlock(&rtac_voice_apr_mutex);
+}
+
+bool rtac_make_voice_callback(u32 mode, uint32_t *payload, u32 payload_size)
+{
+	if ((atomic_read(&rtac_voice_apr_data[mode].cmd_state) != 1) ||
+			(mode < 0) || (mode >= RTAC_VOICE_MODES))
+		return false;
+
+	pr_debug("%s\n", __func__);
+	/* Offset data for in-band payload */
+	rtac_copy_voice_payload_to_user(payload, payload_size);
+	atomic_set(&rtac_voice_apr_data[mode].cmd_state, 0);
+	wake_up(&rtac_voice_apr_data[mode].cmd_wait);
+	return true;
+}
+
+void rtac_copy_voice_payload_to_user(void *payload, u32 payload_size)
+{
+	pr_debug("%s\n", __func__);
+	rtac_voice_payload_size = payload_size;
+
+	memcpy(rtac_voice_buffer, &payload_size, sizeof(u32));
+	if (payload_size) {
+		if (payload_size > rtac_voice_user_buf_size) {
+			pr_err("%s: Buffer set not big enough for "
+				"returned data, buf size = %d, "
+				"ret data = %d\n", __func__,
+				rtac_voice_user_buf_size, payload_size);
+			goto done;
+		}
+		memcpy(rtac_voice_buffer + sizeof(u32), payload, payload_size);
+	}
+done:
+	return;
+}
+
+u32 send_voice_apr(u32 mode, void *buf, u32 opcode)
+{
+	s32				result;
+	u32				count = 0;
+	u32				bytes_returned = 0;
+	u32				payload_size;
+	u16				dest_port;
+	struct apr_hdr			voice_params;
+	pr_debug("%s\n", __func__);
+
+	if (copy_from_user(&count, (void *)buf, sizeof(count))) {
+			pr_err("%s: Copy to user failed! buf = 0x%x\n",
+			       __func__, (unsigned int)buf);
+			result = -EFAULT;
+			goto done;
+	}
+
+	if (count <= 0) {
+		pr_err("%s: Invalid buffer size = %d\n", __func__, count);
+		goto done;
+	}
+
+	if (copy_from_user(&payload_size, buf + sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy payload size from user buffer\n",
+			__func__);
+		goto done;
+	}
+
+	if ((payload_size < 0) ||
+		(payload_size > MAX_PAYLOAD_SIZE)) {
+
+			pr_err("%s: Invalid payload size = %d\n",
+				__func__, payload_size);
+		goto done;
+	}
+
+	if (copy_from_user(&dest_port, buf + 2 * sizeof(u32), sizeof(u32))) {
+		pr_err("%s: Could not copy port id from user buffer\n",
+			__func__);
+		goto done;
+	}
+
+	if ((mode != RTAC_CVP) && (mode != RTAC_CVS)) {
+		pr_err("%s: Invalid Mode for APR, mode = %d\n",
+			__func__, mode);
+		goto done;
+	}
+
+	mutex_lock(&rtac_voice_apr_mutex);
+	if (rtac_voice_apr_data[mode].apr_handle == NULL) {
+		pr_err("%s: APR not initialized\n", __func__);
+		goto err;
+	}
+
+	/* Set globals for copy of returned payload */
+	rtac_voice_user_buf_size = count;
+
+	/* Copy buffer to in-band payload */
+	if (copy_from_user(rtac_voice_buffer + sizeof(voice_params),
+			buf + 3 * sizeof(u32), payload_size)) {
+		pr_err("%s: Could not copy payload from user buffer\n",
+			__func__);
+		goto err;
+	}
+
+	/* Pack header */
+	voice_params.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+		APR_HDR_LEN(20), APR_PKT_VER);
+	voice_params.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+		payload_size);
+	voice_params.src_svc = 0;
+	voice_params.src_domain = APR_DOMAIN_APPS;
+	voice_params.src_port = 0;
+	voice_params.dest_svc = 0;
+	voice_params.dest_domain = APR_DOMAIN_MODEM;
+	voice_params.dest_port = dest_port;
+	voice_params.token = 0;
+	voice_params.opcode = opcode;
+
+	memcpy(rtac_voice_buffer, &voice_params, sizeof(voice_params));
+	atomic_set(&rtac_voice_apr_data[mode].cmd_state, 1);
+
+	pr_debug("%s: Sending RTAC command size = %d, opcode = %x\n",
+		__func__, voice_params.pkt_size, opcode);
+
+	result = apr_send_pkt(rtac_voice_apr_data[mode].apr_handle,
+					(uint32_t *)rtac_voice_buffer);
+	if (result < 0) {
+		pr_err("%s: apr_send_pkt failed opcode = %x\n",
+			__func__, opcode);
+		goto err;
+	}
+	/* Wait for the callback */
+	result = wait_event_timeout(rtac_voice_apr_data[mode].cmd_wait,
+		(atomic_read(&rtac_voice_apr_data[mode].cmd_state) == 0),
+		msecs_to_jiffies(TIMEOUT_MS));
+	mutex_unlock(&rtac_voice_apr_mutex);
+	if (!result) {
+		pr_err("%s: apr_send_pkt timed out opcode = %x\n",
+			__func__, opcode);
+		goto done;
+	}
+
+	if (rtac_voice_payload_size != 0) {
+		if (copy_to_user(buf, rtac_voice_buffer,
+				rtac_voice_payload_size + sizeof(u32))) {
+			pr_err("%s: Could not copy buffer to user,"
+				"size = %d\n", __func__, payload_size);
+			goto done;
+		}
+	}
+
+	/* Return data written for SET & data read for GET */
+	if (opcode == VOICE_CMD_GET_PARAM)
+		bytes_returned = rtac_voice_payload_size;
+	else
+		bytes_returned = payload_size;
+done:
+	return bytes_returned;
+err:
+	mutex_unlock(&rtac_voice_apr_mutex);
+	return bytes_returned;
+}
+
+
+
+static int rtac_ioctl(struct inode *inode, struct file *f,
+		unsigned int cmd, unsigned long arg)
+{
+	s32 result = 0;
+	pr_debug("%s\n", __func__);
+
+	if (arg == 0) {
+		pr_err("%s: No data sent to driver!\n", __func__);
+		result = -EFAULT;
+		goto done;
+	}
+
+	switch (cmd) {
+	case AUDIO_GET_RTAC_DEV_CTRL_INFO:
+		if (copy_to_user((void *)arg, &rtac_dev_ctl_data,
+						sizeof(rtac_dev_ctl_data)))
+			pr_err("%s: Could not copy to userspace!\n", __func__);
+		else
+			result = sizeof(rtac_dev_ctl_data);
+		break;
+	case AUDIO_GET_RTAC_ADM_INFO:
+		if (copy_to_user((void *)arg, &rtac_adm_data,
+						sizeof(rtac_adm_data)))
+			pr_err("%s: Could not copy to userspace!\n", __func__);
+		else
+			result = sizeof(rtac_adm_data);
+		break;
+	case AUDIO_GET_RTAC_VOICE_INFO:
+		if (copy_to_user((void *)arg, &rtac_voice_data,
+						sizeof(rtac_voice_data)))
+			pr_err("%s: Could not copy to userspace!\n", __func__);
+		else
+			result = sizeof(rtac_voice_data);
+		break;
+	case AUDIO_GET_RTAC_ADM_CAL:
+		result = send_adm_apr((void *)arg, ADM_CMD_GET_PARAMS);
+		break;
+	case AUDIO_SET_RTAC_ADM_CAL:
+		result = send_adm_apr((void *)arg, ADM_CMD_SET_PARAMS);
+		break;
+	case AUDIO_GET_RTAC_ASM_CAL:
+		result = send_rtac_asm_apr((void *)arg,
+			ASM_STREAM_CMD_GET_PP_PARAMS);
+		break;
+	case AUDIO_SET_RTAC_ASM_CAL:
+		result = send_rtac_asm_apr((void *)arg,
+			ASM_STREAM_CMD_SET_PP_PARAMS);
+		break;
+	case AUDIO_GET_RTAC_CVS_CAL:
+		result = send_voice_apr(RTAC_CVS, (void *)arg,
+			VOICE_CMD_GET_PARAM);
+		break;
+	case AUDIO_SET_RTAC_CVS_CAL:
+		result = send_voice_apr(RTAC_CVS, (void *)arg,
+			VOICE_CMD_SET_PARAM);
+		break;
+	case AUDIO_GET_RTAC_CVP_CAL:
+		result = send_voice_apr(RTAC_CVP, (void *)arg,
+			VOICE_CMD_GET_PARAM);
+		break;
+	case AUDIO_SET_RTAC_CVP_CAL:
+		result = send_voice_apr(RTAC_CVP, (void *)arg,
+			VOICE_CMD_SET_PARAM);
+		break;
+	default:
+		pr_err("%s: Invalid IOCTL, command = %d!\n",
+		       __func__, cmd);
+	}
+done:
+	return result;
+}
+
+
+static const struct file_operations rtac_fops = {
+	.owner = THIS_MODULE,
+	.open = rtac_open,
+	.release = rtac_release,
+	.ioctl = rtac_ioctl,
+};
+
+struct miscdevice rtac_misc = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "msm_rtac",
+	.fops	= &rtac_fops,
+};
+
+static int __init rtac_init(void)
+{
+	int i = 0;
+	pr_debug("%s\n", __func__);
+
+	/* Dev ctrl */
+	memset(&rtac_dev_ctl_data, 0, sizeof(rtac_dev_ctl_data));
+	mutex_init(&rtac_dev_ctrl_mutex);
+
+	/* ADM */
+	memset(&rtac_adm_data, 0, sizeof(rtac_adm_data));
+	rtac_adm_apr_data.apr_handle = NULL;
+	atomic_set(&rtac_adm_apr_data.cmd_state, 0);
+	init_waitqueue_head(&rtac_adm_apr_data.cmd_wait);
+	mutex_init(&rtac_adm_mutex);
+	mutex_init(&rtac_adm_apr_mutex);
+
+	rtac_adm_buffer = kmalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+	if (rtac_adm_buffer == NULL) {
+		pr_err("%s: Could not allocate payload of size = %d\n",
+			__func__, RTAC_BUF_SIZE);
+		goto nomem;
+	}
+
+	/* ASM */
+	for (i = 0; i < SESSION_MAX+1; i++) {
+		rtac_asm_apr_data[i].apr_handle = NULL;
+		atomic_set(&rtac_asm_apr_data[i].cmd_state, 0);
+		init_waitqueue_head(&rtac_asm_apr_data[i].cmd_wait);
+	}
+	mutex_init(&rtac_asm_apr_mutex);
+
+	rtac_asm_buffer = kmalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+	if (rtac_asm_buffer == NULL) {
+		pr_err("%s: Could not allocate payload of size = %d\n",
+			__func__, RTAC_BUF_SIZE);
+		goto nomem;
+	}
+
+	/* Voice */
+	memset(&rtac_voice_data, 0, sizeof(rtac_voice_data));
+	for (i = 0; i < RTAC_VOICE_MODES; i++) {
+		rtac_voice_apr_data[i].apr_handle = NULL;
+		atomic_set(&rtac_voice_apr_data[i].cmd_state, 0);
+		init_waitqueue_head(&rtac_voice_apr_data[i].cmd_wait);
+	}
+	mutex_init(&rtac_voice_mutex);
+	mutex_init(&rtac_voice_apr_mutex);
+
+	rtac_voice_buffer = kmalloc(RTAC_BUF_SIZE, GFP_KERNEL);
+	if (rtac_voice_buffer == NULL) {
+		pr_err("%s: Could not allocate payload of size = %d\n",
+			__func__, RTAC_BUF_SIZE);
+		goto nomem;
+	}
+
+	return misc_register(&rtac_misc);
+nomem:
+	return -ENOMEM;
+}
+
+module_init(rtac_init);
+
+MODULE_DESCRIPTION("MSM 8x60 Real-Time Audio Calibration driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
new file mode 100644
index 0000000..eb394a3
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.c
@@ -0,0 +1,382 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <mach/clk.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <sound/apr_audio.h>
+#include <sound/q6afe.h>
+#include "snddev_ecodec.h"
+
+#define ECODEC_SAMPLE_RATE 8000
+
+/* Context for each external codec device */
+struct snddev_ecodec_state {
+	struct snddev_ecodec_data *data;
+	u32 sample_rate;
+};
+
+/* Global state for the driver */
+struct snddev_ecodec_drv_state {
+	struct mutex dev_lock;
+	int ref_cnt;		/* ensure one rx device at a time */
+	struct clk *ecodec_clk;
+};
+
+static struct snddev_ecodec_drv_state snddev_ecodec_drv;
+
+struct aux_pcm_state {
+	unsigned int dout;
+	unsigned int din;
+	unsigned int syncout;
+	unsigned int clkin_a;
+};
+
+static struct aux_pcm_state the_aux_pcm_state;
+
+static int aux_pcm_gpios_request(void)
+{
+	int rc = 0;
+
+	pr_debug("%s\n", __func__);
+	rc = gpio_request(the_aux_pcm_state.dout, "AUX PCM DOUT");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for AUX PCM DOUT failed\n", __func__);
+		return rc;
+	}
+
+	rc = gpio_request(the_aux_pcm_state.din, "AUX PCM DIN");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for AUX PCM DIN failed\n", __func__);
+		gpio_free(the_aux_pcm_state.dout);
+		return rc;
+	}
+
+	rc = gpio_request(the_aux_pcm_state.syncout, "AUX PCM SYNC OUT");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for AUX PCM SYNC OUT failed\n",
+				__func__);
+		gpio_free(the_aux_pcm_state.dout);
+		gpio_free(the_aux_pcm_state.din);
+		return rc;
+	}
+
+	rc = gpio_request(the_aux_pcm_state.clkin_a, "AUX PCM CLKIN A");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for AUX PCM CLKIN A failed\n",
+				__func__);
+		gpio_free(the_aux_pcm_state.dout);
+		gpio_free(the_aux_pcm_state.din);
+		gpio_free(the_aux_pcm_state.syncout);
+		return rc;
+	}
+
+	return rc;
+}
+
+static void aux_pcm_gpios_free(void)
+{
+	pr_debug("%s\n", __func__);
+	gpio_free(the_aux_pcm_state.dout);
+	gpio_free(the_aux_pcm_state.din);
+	gpio_free(the_aux_pcm_state.syncout);
+	gpio_free(the_aux_pcm_state.clkin_a);
+}
+
+static int get_aux_pcm_gpios(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct resource *res;
+
+	/* Claim all of the GPIOs. */
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "aux_pcm_dout");
+	if (!res) {
+		pr_err("%s: failed to get gpio AUX PCM DOUT\n", __func__);
+		return -ENODEV;
+	}
+
+	the_aux_pcm_state.dout = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "aux_pcm_din");
+	if (!res) {
+		pr_err("%s: failed to get gpio AUX PCM DIN\n", __func__);
+		return -ENODEV;
+	}
+
+	the_aux_pcm_state.din = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+					   "aux_pcm_syncout");
+	if (!res) {
+		pr_err("%s: failed to get gpio AUX PCM SYNC OUT\n", __func__);
+		return -ENODEV;
+	}
+
+	the_aux_pcm_state.syncout = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+					   "aux_pcm_clkin_a");
+	if (!res) {
+		pr_err("%s: failed to get gpio AUX PCM CLKIN A\n", __func__);
+		return -ENODEV;
+	}
+
+	the_aux_pcm_state.clkin_a = res->start;
+
+	return rc;
+}
+
+static int aux_pcm_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	rc = get_aux_pcm_gpios(pdev);
+	if (rc < 0) {
+		pr_err("%s: GPIO configuration failed\n", __func__);
+		return -ENODEV;
+	}
+	return rc;
+}
+
+static struct platform_driver aux_pcm_driver = {
+	.probe = aux_pcm_probe,
+	.driver = { .name = "msm_aux_pcm"}
+};
+
+static int snddev_ecodec_open(struct msm_snddev_info *dev_info)
+{
+	int rc;
+	struct snddev_ecodec_drv_state *drv = &snddev_ecodec_drv;
+	union afe_port_config afe_config;
+
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&drv->dev_lock);
+
+	if (dev_info->opened) {
+		pr_err("%s: ERROR: %s already opened\n", __func__,
+				dev_info->name);
+		mutex_unlock(&drv->dev_lock);
+		return -EBUSY;
+	}
+
+	if (drv->ref_cnt != 0) {
+		pr_debug("%s: opened %s\n", __func__, dev_info->name);
+		drv->ref_cnt++;
+		mutex_unlock(&drv->dev_lock);
+		return 0;
+	}
+
+	pr_info("%s: opening %s\n", __func__, dev_info->name);
+
+	rc = aux_pcm_gpios_request();
+	if (rc < 0) {
+		pr_err("%s: GPIO request failed\n", __func__);
+		return rc;
+	}
+
+	clk_reset(drv->ecodec_clk, CLK_RESET_ASSERT);
+
+	afe_config.pcm.mode = AFE_PCM_CFG_MODE_PCM;
+	afe_config.pcm.sync = AFE_PCM_CFG_SYNC_INT;
+	afe_config.pcm.frame = AFE_PCM_CFG_FRM_256BPF;
+	afe_config.pcm.quant = AFE_PCM_CFG_QUANT_LINEAR_NOPAD;
+	afe_config.pcm.slot = 0;
+	afe_config.pcm.data = AFE_PCM_CFG_CDATAOE_MASTER;
+
+	rc = afe_open(PCM_RX, &afe_config, ECODEC_SAMPLE_RATE);
+	if (rc < 0) {
+		pr_err("%s: afe open failed for PCM_RX\n", __func__);
+		goto err_rx_afe;
+	}
+
+	rc = afe_open(PCM_TX, &afe_config, ECODEC_SAMPLE_RATE);
+	if (rc < 0) {
+		pr_err("%s: afe open failed for PCM_TX\n", __func__);
+		goto err_tx_afe;
+	}
+
+	rc = clk_set_rate(drv->ecodec_clk, 2048000);
+	if (rc < 0) {
+		pr_err("%s: clk_set_rate failed\n", __func__);
+		goto err_clk;
+	}
+
+	clk_enable(drv->ecodec_clk);
+
+	clk_reset(drv->ecodec_clk, CLK_RESET_DEASSERT);
+
+	drv->ref_cnt++;
+	mutex_unlock(&drv->dev_lock);
+
+	return 0;
+
+err_clk:
+	afe_close(PCM_TX);
+err_tx_afe:
+	afe_close(PCM_RX);
+err_rx_afe:
+	aux_pcm_gpios_free();
+	mutex_unlock(&drv->dev_lock);
+	return -ENODEV;
+}
+
+int snddev_ecodec_close(struct msm_snddev_info *dev_info)
+{
+	struct snddev_ecodec_drv_state *drv = &snddev_ecodec_drv;
+
+	pr_debug("%s: closing %s\n", __func__, dev_info->name);
+
+	mutex_lock(&drv->dev_lock);
+
+	if (!dev_info->opened) {
+		pr_err("%s: ERROR: %s is not opened\n", __func__,
+				dev_info->name);
+		mutex_unlock(&drv->dev_lock);
+		return -EPERM;
+	}
+
+	drv->ref_cnt--;
+
+	if (drv->ref_cnt == 0) {
+
+		pr_info("%s: closing all devices\n", __func__);
+
+		clk_disable(drv->ecodec_clk);
+		aux_pcm_gpios_free();
+
+		afe_close(PCM_RX);
+		afe_close(PCM_TX);
+	}
+
+	mutex_unlock(&drv->dev_lock);
+
+	return 0;
+}
+
+int snddev_ecodec_set_freq(struct msm_snddev_info *dev_info, u32 rate)
+{
+	int rc = 0;
+
+	if (!dev_info) {
+		rc = -EINVAL;
+		goto error;
+	}
+	return ECODEC_SAMPLE_RATE;
+
+error:
+	return rc;
+}
+
+static int snddev_ecodec_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct snddev_ecodec_data *pdata;
+	struct msm_snddev_info *dev_info;
+	struct snddev_ecodec_state *ecodec;
+
+	if (!pdev || !pdev->dev.platform_data) {
+		printk(KERN_ALERT "Invalid caller\n");
+		rc = -1;
+		goto error;
+	}
+	pdata = pdev->dev.platform_data;
+
+	ecodec = kzalloc(sizeof(struct snddev_ecodec_state), GFP_KERNEL);
+	if (!ecodec) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	dev_info = kzalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
+	if (!dev_info) {
+		kfree(ecodec);
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	dev_info->name = pdata->name;
+	dev_info->copp_id = pdata->copp_id;
+	dev_info->private_data = (void *)ecodec;
+	dev_info->dev_ops.open = snddev_ecodec_open;
+	dev_info->dev_ops.close = snddev_ecodec_close;
+	dev_info->dev_ops.set_freq = snddev_ecodec_set_freq;
+	dev_info->dev_ops.enable_sidetone = NULL;
+	dev_info->capability = pdata->capability;
+	dev_info->opened = 0;
+
+	msm_snddev_register(dev_info);
+
+	ecodec->data = pdata;
+	ecodec->sample_rate = ECODEC_SAMPLE_RATE;	/* Default to 8KHz */
+error:
+	return rc;
+}
+
+struct platform_driver snddev_ecodec_driver = {
+	.probe = snddev_ecodec_probe,
+	.driver = {.name = "msm_snddev_ecodec"}
+};
+
+int __init snddev_ecodec_init(void)
+{
+	int rc = 0;
+	struct snddev_ecodec_drv_state *drv = &snddev_ecodec_drv;
+
+	mutex_init(&drv->dev_lock);
+	drv->ref_cnt = 0;
+
+	drv->ecodec_clk = clk_get(NULL, "pcm_clk");
+	if (IS_ERR(drv->ecodec_clk)) {
+		pr_err("%s: could not get pcm_clk\n", __func__);
+		return PTR_ERR(drv->ecodec_clk);
+	}
+
+	rc = platform_driver_register(&aux_pcm_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: platform_driver_register for aux pcm failed\n",
+				__func__);
+		goto error_aux_pcm_platform_driver;
+	}
+
+	rc = platform_driver_register(&snddev_ecodec_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: platform_driver_register for ecodec failed\n",
+				__func__);
+		goto error_ecodec_platform_driver;
+	}
+
+	return 0;
+
+error_ecodec_platform_driver:
+	platform_driver_unregister(&aux_pcm_driver);
+error_aux_pcm_platform_driver:
+	clk_put(drv->ecodec_clk);
+
+	pr_err("%s: encounter error\n", __func__);
+	return -ENODEV;
+}
+
+device_initcall(snddev_ecodec_init);
+
+MODULE_DESCRIPTION("ECodec Sound Device driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.h b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.h
new file mode 100644
index 0000000..b102de0
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_ecodec.h
@@ -0,0 +1,26 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __MACH_QDSP6V2_SNDDEV_ECODEC_H
+#define __MACH_QDSP6V2_SNDDEV_ECODEC_H
+#include <mach/qdsp5v2/audio_def.h>
+
+struct snddev_ecodec_data {
+	u32 capability; /* RX or TX */
+	const char *name;
+	u32 copp_id; /* audpp routing */
+	u8 channel_mode;
+	u32 conf_pcm_ctl_val;
+	u32 conf_aux_codec_intf;
+	u32 conf_data_format_padding_val;
+};
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_hdmi.c b/arch/arm/mach-msm/qdsp6v2/snddev_hdmi.c
new file mode 100644
index 0000000..4eeb654
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_hdmi.c
@@ -0,0 +1,198 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <mach/debug_mm.h>
+#include <sound/q6afe.h>
+#include <sound/apr_audio.h>
+#include "snddev_hdmi.h"
+
+static DEFINE_MUTEX(snddev_hdmi_lock);
+static int snddev_hdmi_active;
+
+static int snddev_hdmi_open(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+	union afe_port_config afe_config;
+	struct snddev_hdmi_data *snddev_hdmi_data;
+
+	if (!dev_info) {
+		pr_err("msm_snddev_info is null\n");
+		return -EINVAL;
+	}
+
+	snddev_hdmi_data = dev_info->private_data;
+
+	mutex_lock(&snddev_hdmi_lock);
+
+	if (snddev_hdmi_active) {
+		pr_err("HDMI snddev already active\n");
+		mutex_unlock(&snddev_hdmi_lock);
+		return -EBUSY;
+	}
+
+	if (snddev_hdmi_data->on_apps) {
+		snddev_hdmi_active = 1;
+		pr_debug("%s open done\n", dev_info->name);
+		mutex_unlock(&snddev_hdmi_lock);
+		return 0;
+	}
+
+	afe_config.hdmi.channel_mode = snddev_hdmi_data->channel_mode;
+	afe_config.hdmi.bitwidth = 16;
+	afe_config.hdmi.data_type = 0;
+	rc = afe_open(snddev_hdmi_data->copp_id, &afe_config,
+		dev_info->sample_rate);
+
+	if (rc < 0) {
+		pr_err("afe_open failed\n");
+		mutex_unlock(&snddev_hdmi_lock);
+		return -EINVAL;
+	}
+	snddev_hdmi_active = 1;
+
+	pr_debug("%s open done\n", dev_info->name);
+
+	mutex_unlock(&snddev_hdmi_lock);
+
+	return 0;
+}
+
+static int snddev_hdmi_close(struct msm_snddev_info *dev_info)
+{
+
+	struct snddev_hdmi_data *snddev_hdmi_data;
+
+	if (!dev_info) {
+		pr_err("msm_snddev_info is null\n");
+		return -EINVAL;
+	}
+
+	snddev_hdmi_data = dev_info->private_data;
+
+	if (!dev_info->opened) {
+		pr_err("calling close device with out opening the"
+		       " device\n");
+		return -EPERM;
+	}
+	mutex_lock(&snddev_hdmi_lock);
+
+	if (!snddev_hdmi_active) {
+		pr_err("HDMI snddev not active\n");
+		mutex_unlock(&snddev_hdmi_lock);
+		return -EPERM;
+	}
+	snddev_hdmi_active = 0;
+
+	if (snddev_hdmi_data->on_apps) {
+		pr_debug("%s open done\n", dev_info->name);
+
+		mutex_unlock(&snddev_hdmi_lock);
+		return 0;
+	}
+
+
+	afe_close(HDMI_RX);
+
+	pr_debug("%s closed\n", dev_info->name);
+	mutex_unlock(&snddev_hdmi_lock);
+
+	return 0;
+}
+
+static int snddev_hdmi_set_freq(struct msm_snddev_info *dev_info, u32 req_freq)
+{
+	if (req_freq != 48000) {
+		pr_debug("Unsupported Frequency:%d\n", req_freq);
+		return -EINVAL;
+	}
+	return 48000;
+}
+
+static int snddev_hdmi_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct snddev_hdmi_data *pdata;
+	struct msm_snddev_info *dev_info;
+
+	if (!pdev || !pdev->dev.platform_data) {
+		printk(KERN_ALERT "Invalid caller\n");
+		return -ENODEV;
+	}
+
+	pdata = pdev->dev.platform_data;
+	if (!(pdata->capability & SNDDEV_CAP_RX)) {
+		pr_err("invalid device data either RX or TX\n");
+		return -ENODEV;
+	}
+
+	dev_info = kzalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
+	if (!dev_info) {
+		pr_err("unable to allocate memeory for msm_snddev_info\n");
+		return -ENOMEM;
+	}
+
+	dev_info->name = pdata->name;
+	dev_info->copp_id = pdata->copp_id;
+	dev_info->acdb_id = pdata->acdb_id;
+	dev_info->private_data = (void *)pdata;
+	dev_info->dev_ops.open = snddev_hdmi_open;
+	dev_info->dev_ops.close = snddev_hdmi_close;
+	dev_info->dev_ops.set_freq = snddev_hdmi_set_freq;
+	dev_info->capability = pdata->capability;
+	dev_info->opened = 0;
+	msm_snddev_register(dev_info);
+	dev_info->sample_rate = pdata->default_sample_rate;
+
+	pr_debug("probe done for %s\n", pdata->name);
+	return rc;
+}
+
+static struct platform_driver snddev_hdmi_driver = {
+	.probe = snddev_hdmi_probe,
+	.driver = {.name = "snddev_hdmi"}
+};
+
+static int __init snddev_hdmi_init(void)
+{
+	s32 rc;
+
+	rc = platform_driver_register(&snddev_hdmi_driver);
+	if (IS_ERR_VALUE(rc)) {
+
+		pr_err("platform_driver_register failed.\n");
+		goto error_platform_driver;
+	}
+
+	pr_debug("snddev_hdmi_init : done\n");
+
+	return 0;
+
+error_platform_driver:
+
+	pr_err("encounterd error\n");
+	return -ENODEV;
+}
+
+module_init(snddev_hdmi_init);
+
+MODULE_DESCRIPTION("HDMI Sound Device driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_hdmi.h b/arch/arm/mach-msm/qdsp6v2/snddev_hdmi.h
new file mode 100644
index 0000000..cc69033
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_hdmi.h
@@ -0,0 +1,25 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __MACH_QDSP6_V2_SNDDEV_HDMI_H
+#define __MACH_QDSP6_V2_SNDDEV_HDMI_H
+
+struct snddev_hdmi_data {
+	u32 capability;		/* RX or TX */
+	const char *name;
+	u32 copp_id;		/* audpp routing */
+	u32 acdb_id;		/* Audio Cal purpose */
+	u8 channel_mode;
+	u32 default_sample_rate;
+	u32 on_apps;
+};
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
new file mode 100644
index 0000000..0abc9ff
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.c
@@ -0,0 +1,1087 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/msm-adie-codec.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/wakelock.h>
+#include <linux/pmic8058-othc.h>
+#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <asm/uaccess.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <mach/qdsp6v2/audio_acdb.h>
+#include <mach/vreg.h>
+#include <mach/pmic.h>
+#include <mach/debug_mm.h>
+#include <sound/q6afe.h>
+#include <sound/apr_audio.h>
+#include "snddev_icodec.h"
+
+#define SNDDEV_ICODEC_PCM_SZ 32 /* 16 bit / sample stereo mode */
+#define SNDDEV_ICODEC_MUL_FACTOR 3 /* Multi by 8 Shift by 3  */
+#define SNDDEV_ICODEC_CLK_RATE(freq) \
+	(((freq) * (SNDDEV_ICODEC_PCM_SZ)) << (SNDDEV_ICODEC_MUL_FACTOR))
+#define SNDDEV_LOW_POWER_MODE 0
+#define SNDDEV_HIGH_POWER_MODE 1
+/* Voltage required for S4 in microVolts, 2.2V or 2200000microvolts */
+#define SNDDEV_VREG_8058_S4_VOLTAGE (2200000)
+/* Load Current required for S4 in microAmps,
+   36mA - 56mA */
+#define SNDDEV_VREG_LOW_POWER_LOAD (36000)
+#define SNDDEV_VREG_HIGH_POWER_LOAD (56000)
+
+int msm_codec_i2s_slave_mode;
+
+/* Context for each internal codec sound device */
+struct snddev_icodec_state {
+	struct snddev_icodec_data *data;
+	struct adie_codec_path *adie_path;
+	u32 sample_rate;
+	u32 enabled;
+};
+
+/* Global state for the driver */
+struct snddev_icodec_drv_state {
+	struct mutex rx_lock;
+	struct mutex lb_lock;
+	struct mutex tx_lock;
+	u32 rx_active; /* ensure one rx device at a time */
+	u32 tx_active; /* ensure one tx device at a time */
+	struct clk *rx_osrclk;
+	struct clk *rx_bitclk;
+	struct clk *tx_osrclk;
+	struct clk *tx_bitclk;
+
+	struct wake_lock rx_idlelock;
+	struct wake_lock tx_idlelock;
+
+	/* handle to pmic8058 regulator smps4 */
+	struct regulator *snddev_vreg;
+};
+
+static struct snddev_icodec_drv_state snddev_icodec_drv;
+
+struct regulator *vreg_init(void)
+{
+	int rc;
+	struct regulator *vreg_ptr;
+
+	vreg_ptr = regulator_get(NULL, "8058_s4");
+	if (IS_ERR(vreg_ptr)) {
+		pr_err("%s: regulator_get 8058_s4 failed\n", __func__);
+		return NULL;
+	}
+
+	rc = regulator_set_voltage(vreg_ptr, SNDDEV_VREG_8058_S4_VOLTAGE,
+				SNDDEV_VREG_8058_S4_VOLTAGE);
+	if (rc == 0)
+		return vreg_ptr;
+	else
+		return NULL;
+}
+
+static void vreg_deinit(struct regulator *vreg)
+{
+	regulator_put(vreg);
+}
+
+static void vreg_mode_vote(struct regulator *vreg, int enable, int mode)
+{
+	int rc;
+	if (enable) {
+		rc = regulator_enable(vreg);
+		if (rc != 0)
+			pr_err("%s:Enabling regulator failed\n", __func__);
+		else {
+			if (mode)
+				regulator_set_optimum_mode(vreg,
+						SNDDEV_VREG_HIGH_POWER_LOAD);
+			else
+				regulator_set_optimum_mode(vreg,
+						SNDDEV_VREG_LOW_POWER_LOAD);
+		}
+	} else {
+		rc = regulator_disable(vreg);
+		if (rc != 0)
+			pr_err("%s:Disabling regulator failed\n", __func__);
+	}
+}
+
+struct msm_cdcclk_ctl_state {
+	unsigned int rx_mclk;
+	unsigned int rx_mclk_requested;
+	unsigned int tx_mclk;
+	unsigned int tx_mclk_requested;
+};
+
+static struct msm_cdcclk_ctl_state the_msm_cdcclk_ctl_state;
+
+static int msm_snddev_rx_mclk_request(void)
+{
+	int rc = 0;
+
+	rc = gpio_request(the_msm_cdcclk_ctl_state.rx_mclk,
+		"MSM_SNDDEV_RX_MCLK");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for MSM SNDDEV RX failed\n", __func__);
+		return rc;
+	}
+	the_msm_cdcclk_ctl_state.rx_mclk_requested = 1;
+	return rc;
+}
+static int msm_snddev_tx_mclk_request(void)
+{
+	int rc = 0;
+
+	rc = gpio_request(the_msm_cdcclk_ctl_state.tx_mclk,
+		"MSM_SNDDEV_TX_MCLK");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for MSM SNDDEV TX failed\n", __func__);
+		return rc;
+	}
+	the_msm_cdcclk_ctl_state.tx_mclk_requested = 1;
+	return rc;
+}
+static void msm_snddev_rx_mclk_free(void)
+{
+	if (the_msm_cdcclk_ctl_state.rx_mclk_requested) {
+		gpio_free(the_msm_cdcclk_ctl_state.rx_mclk);
+		the_msm_cdcclk_ctl_state.rx_mclk_requested = 0;
+	}
+}
+static void msm_snddev_tx_mclk_free(void)
+{
+	if (the_msm_cdcclk_ctl_state.tx_mclk_requested) {
+		gpio_free(the_msm_cdcclk_ctl_state.tx_mclk);
+		the_msm_cdcclk_ctl_state.tx_mclk_requested = 0;
+	}
+}
+static int get_msm_cdcclk_ctl_gpios(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct resource *res;
+
+	/* Claim all of the GPIOs. */
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+			"msm_snddev_rx_mclk");
+	if (!res) {
+		pr_err("%s: failed to get gpio MSM SNDDEV RX\n", __func__);
+		return -ENODEV;
+	}
+	the_msm_cdcclk_ctl_state.rx_mclk = res->start;
+	the_msm_cdcclk_ctl_state.rx_mclk_requested = 0;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+			"msm_snddev_tx_mclk");
+	if (!res) {
+		pr_err("%s: failed to get gpio MSM SNDDEV TX\n", __func__);
+		return -ENODEV;
+	}
+	the_msm_cdcclk_ctl_state.tx_mclk = res->start;
+	the_msm_cdcclk_ctl_state.tx_mclk_requested = 0;
+
+	return rc;
+}
+static int msm_cdcclk_ctl_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	rc = get_msm_cdcclk_ctl_gpios(pdev);
+	if (rc < 0) {
+		pr_err("%s: GPIO configuration failed\n", __func__);
+		return -ENODEV;
+	}
+	return rc;
+}
+static struct platform_driver msm_cdcclk_ctl_driver = {
+	.probe = msm_cdcclk_ctl_probe,
+	.driver = { .name = "msm_cdcclk_ctl"}
+};
+
+static int snddev_icodec_open_lb(struct snddev_icodec_state *icodec)
+{
+	int trc;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	/* Voting for low power is ok here as all use cases are
+	 * supported in low power mode.
+	 */
+	if (drv->snddev_vreg)
+		vreg_mode_vote(drv->snddev_vreg, 1,
+					SNDDEV_LOW_POWER_MODE);
+
+	if (icodec->data->voltage_on)
+		icodec->data->voltage_on();
+
+	trc = adie_codec_open(icodec->data->profile, &icodec->adie_path);
+	if (IS_ERR_VALUE(trc))
+		pr_err("%s: adie codec open failed\n", __func__);
+	else
+		adie_codec_setpath(icodec->adie_path,
+					icodec->sample_rate, 256);
+
+	if (icodec->adie_path)
+		adie_codec_proceed_stage(icodec->adie_path,
+					ADIE_CODEC_DIGITAL_ANALOG_READY);
+
+	if (icodec->data->pamp_on)
+		icodec->data->pamp_on();
+
+	icodec->enabled = 1;
+
+	return 0;
+}
+static int initialize_msm_icodec_gpios(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct resource *res;
+	int i = 0;
+	int *reg_defaults = pdev->dev.platform_data;
+
+	while ((res = platform_get_resource(pdev, IORESOURCE_IO, i))) {
+		rc = gpio_request(res->start, res->name);
+		if (rc) {
+			pr_err("%s: icodec gpio %d request failed\n", __func__,
+				res->start);
+			goto err;
+		} else {
+			/* This platform data structure only works if all gpio
+			 * resources are to be used only in output mode.
+			 * If gpio resources are added which are to be used in
+			 * input mode, then the platform data structure will
+			 * have to be changed.
+			 */
+
+			gpio_direction_output(res->start, reg_defaults[i]);
+			gpio_free(res->start);
+		}
+		i++;
+	}
+err:
+	return rc;
+}
+static int msm_icodec_gpio_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	rc = initialize_msm_icodec_gpios(pdev);
+	if (rc < 0) {
+		pr_err("%s: GPIO configuration failed\n", __func__);
+		return -ENODEV;
+	}
+	return rc;
+}
+static struct platform_driver msm_icodec_gpio_driver = {
+	.probe = msm_icodec_gpio_probe,
+	.driver = { .name = "msm_icodec_gpio"}
+};
+
+static int snddev_icodec_open_rx(struct snddev_icodec_state *icodec)
+{
+	int trc;
+	int afe_channel_mode;
+	union afe_port_config afe_config;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	wake_lock(&drv->rx_idlelock);
+
+	if (drv->snddev_vreg) {
+		if (!strcmp(icodec->data->name, "headset_stereo_rx"))
+			vreg_mode_vote(drv->snddev_vreg, 1,
+					SNDDEV_LOW_POWER_MODE);
+		else
+			vreg_mode_vote(drv->snddev_vreg, 1,
+					SNDDEV_HIGH_POWER_MODE);
+	}
+	msm_snddev_rx_mclk_request();
+
+	drv->rx_osrclk = clk_get(0, "i2s_spkr_osr_clk");
+	if (IS_ERR(drv->rx_osrclk))
+		pr_err("%s master clock Error\n", __func__);
+
+	trc =  clk_set_rate(drv->rx_osrclk,
+			SNDDEV_ICODEC_CLK_RATE(icodec->sample_rate));
+	if (IS_ERR_VALUE(trc)) {
+		pr_err("ERROR setting m clock1\n");
+		goto error_invalid_freq;
+	}
+
+	clk_enable(drv->rx_osrclk);
+	drv->rx_bitclk = clk_get(0, "i2s_spkr_bit_clk");
+	if (IS_ERR(drv->rx_bitclk))
+		pr_err("%s clock Error\n", __func__);
+
+	/* Master clock = Sample Rate * OSR rate bit clock
+	 * OSR Rate bit clock = bit/sample * channel master
+	 * clock / bit clock = divider value = 8
+	 */
+	if (msm_codec_i2s_slave_mode) {
+		pr_info("%s: configuring bit clock for slave mode\n",
+				__func__);
+		trc =  clk_set_rate(drv->rx_bitclk, 0);
+	} else
+		trc =  clk_set_rate(drv->rx_bitclk, 8);
+
+	if (IS_ERR_VALUE(trc)) {
+		pr_err("ERROR setting m clock1\n");
+		goto error_adie;
+	}
+	clk_enable(drv->rx_bitclk);
+
+	if (icodec->data->voltage_on)
+		icodec->data->voltage_on();
+
+	/* Configure ADIE */
+	trc = adie_codec_open(icodec->data->profile, &icodec->adie_path);
+	if (IS_ERR_VALUE(trc))
+		pr_err("%s: adie codec open failed\n", __func__);
+	else
+		adie_codec_setpath(icodec->adie_path,
+					icodec->sample_rate, 256);
+	/* OSR default to 256, can be changed for power optimization
+	 * If OSR is to be changed, need clock API for setting the divider
+	 */
+
+	switch (icodec->data->channel_mode) {
+	case 2:
+		afe_channel_mode = MSM_AFE_STEREO;
+		break;
+	case 1:
+	default:
+		afe_channel_mode = MSM_AFE_MONO;
+		break;
+	}
+	afe_config.mi2s.channel = afe_channel_mode;
+	afe_config.mi2s.bitwidth = 16;
+	afe_config.mi2s.line = 1;
+	if (msm_codec_i2s_slave_mode)
+		afe_config.mi2s.ws = 0;
+	else
+		afe_config.mi2s.ws = 1;
+
+	trc = afe_open(icodec->data->copp_id, &afe_config, icodec->sample_rate);
+
+	/* Enable ADIE */
+	if (icodec->adie_path) {
+		adie_codec_proceed_stage(icodec->adie_path,
+					ADIE_CODEC_DIGITAL_READY);
+		adie_codec_proceed_stage(icodec->adie_path,
+					ADIE_CODEC_DIGITAL_ANALOG_READY);
+	}
+
+	if (msm_codec_i2s_slave_mode)
+		adie_codec_set_master_mode(icodec->adie_path, 1);
+	else
+		adie_codec_set_master_mode(icodec->adie_path, 0);
+
+	/* Enable power amplifier */
+	if (icodec->data->pamp_on) {
+		if (icodec->data->pamp_on()) {
+			pr_err("%s: Error turning on rx power\n", __func__);
+			goto error_pamp;
+		}
+	}
+
+	icodec->enabled = 1;
+
+	wake_unlock(&drv->rx_idlelock);
+	return 0;
+
+error_pamp:
+error_adie:
+	clk_disable(drv->rx_osrclk);
+error_invalid_freq:
+
+	pr_err("%s: encounter error\n", __func__);
+
+	wake_unlock(&drv->rx_idlelock);
+	return -ENODEV;
+}
+
+static int snddev_icodec_open_tx(struct snddev_icodec_state *icodec)
+{
+	int trc;
+	int afe_channel_mode;
+	union afe_port_config afe_config;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;;
+
+	wake_lock(&drv->tx_idlelock);
+
+	if (drv->snddev_vreg)
+		vreg_mode_vote(drv->snddev_vreg, 1, SNDDEV_HIGH_POWER_MODE);
+
+	/* Reuse pamp_on for TX platform-specific setup  */
+	if (icodec->data->pamp_on) {
+		if (icodec->data->pamp_on()) {
+			pr_err("%s: Error turning on tx power\n", __func__);
+			goto error_pamp;
+		}
+	}
+
+	msm_snddev_tx_mclk_request();
+
+	drv->tx_osrclk = clk_get(0, "i2s_mic_osr_clk");
+	if (IS_ERR(drv->tx_osrclk))
+		pr_err("%s master clock Error\n", __func__);
+
+	trc =  clk_set_rate(drv->tx_osrclk,
+			SNDDEV_ICODEC_CLK_RATE(icodec->sample_rate));
+	if (IS_ERR_VALUE(trc)) {
+		pr_err("ERROR setting m clock1\n");
+		goto error_invalid_freq;
+	}
+
+	clk_enable(drv->tx_osrclk);
+	drv->tx_bitclk = clk_get(0, "i2s_mic_bit_clk");
+	if (IS_ERR(drv->tx_bitclk))
+		pr_err("%s clock Error\n", __func__);
+
+	/* Master clock = Sample Rate * OSR rate bit clock
+	 * OSR Rate bit clock = bit/sample * channel master
+	 * clock / bit clock = divider value = 8
+	 */
+	if (msm_codec_i2s_slave_mode) {
+		pr_info("%s: configuring bit clock for slave mode\n",
+				__func__);
+		trc =  clk_set_rate(drv->tx_bitclk, 0);
+	} else
+		trc =  clk_set_rate(drv->tx_bitclk, 8);
+
+	clk_enable(drv->tx_bitclk);
+
+	/* Enable ADIE */
+	trc = adie_codec_open(icodec->data->profile, &icodec->adie_path);
+	if (IS_ERR_VALUE(trc))
+		pr_err("%s: adie codec open failed\n", __func__);
+	else
+		adie_codec_setpath(icodec->adie_path,
+					icodec->sample_rate, 256);
+
+	switch (icodec->data->channel_mode) {
+	case 2:
+		afe_channel_mode = MSM_AFE_STEREO;
+		break;
+	case 1:
+	default:
+		afe_channel_mode = MSM_AFE_MONO;
+		break;
+	}
+	afe_config.mi2s.channel = afe_channel_mode;
+	afe_config.mi2s.bitwidth = 16;
+	afe_config.mi2s.line = 1;
+	if (msm_codec_i2s_slave_mode)
+		afe_config.mi2s.ws = 0;
+	else
+		afe_config.mi2s.ws = 1;
+
+	trc = afe_open(icodec->data->copp_id, &afe_config, icodec->sample_rate);
+
+	if (icodec->adie_path) {
+		adie_codec_proceed_stage(icodec->adie_path,
+					ADIE_CODEC_DIGITAL_READY);
+		adie_codec_proceed_stage(icodec->adie_path,
+					ADIE_CODEC_DIGITAL_ANALOG_READY);
+	}
+
+	if (msm_codec_i2s_slave_mode)
+		adie_codec_set_master_mode(icodec->adie_path, 1);
+	else
+		adie_codec_set_master_mode(icodec->adie_path, 0);
+
+	icodec->enabled = 1;
+
+	wake_unlock(&drv->tx_idlelock);
+	return 0;
+
+error_invalid_freq:
+
+	if (icodec->data->pamp_off)
+		icodec->data->pamp_off();
+
+	pr_err("%s: encounter error\n", __func__);
+error_pamp:
+	wake_unlock(&drv->tx_idlelock);
+	return -ENODEV;
+}
+
+static int snddev_icodec_close_lb(struct snddev_icodec_state *icodec)
+{
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	/* Disable power amplifier */
+	if (icodec->data->pamp_off)
+		icodec->data->pamp_off();
+
+	if (drv->snddev_vreg)
+		vreg_mode_vote(drv->snddev_vreg, 0, SNDDEV_LOW_POWER_MODE);
+
+	if (icodec->adie_path) {
+		adie_codec_proceed_stage(icodec->adie_path,
+			ADIE_CODEC_DIGITAL_OFF);
+		adie_codec_close(icodec->adie_path);
+		icodec->adie_path = NULL;
+	}
+
+	if (icodec->data->voltage_off)
+		icodec->data->voltage_off();
+
+	return 0;
+}
+
+static int snddev_icodec_close_rx(struct snddev_icodec_state *icodec)
+{
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	wake_lock(&drv->rx_idlelock);
+
+	if (drv->snddev_vreg)
+		vreg_mode_vote(drv->snddev_vreg, 0, SNDDEV_HIGH_POWER_MODE);
+
+	/* Disable power amplifier */
+	if (icodec->data->pamp_off)
+		icodec->data->pamp_off();
+
+	/* Disable ADIE */
+	if (icodec->adie_path) {
+		adie_codec_proceed_stage(icodec->adie_path,
+			ADIE_CODEC_DIGITAL_OFF);
+		adie_codec_close(icodec->adie_path);
+		icodec->adie_path = NULL;
+	}
+
+	afe_close(icodec->data->copp_id);
+
+	if (icodec->data->voltage_off)
+		icodec->data->voltage_off();
+
+	clk_disable(drv->rx_bitclk);
+	clk_disable(drv->rx_osrclk);
+
+	msm_snddev_rx_mclk_free();
+
+	icodec->enabled = 0;
+
+	wake_unlock(&drv->rx_idlelock);
+	return 0;
+}
+
+static int snddev_icodec_close_tx(struct snddev_icodec_state *icodec)
+{
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	wake_lock(&drv->tx_idlelock);
+
+	if (drv->snddev_vreg)
+		vreg_mode_vote(drv->snddev_vreg, 0, SNDDEV_HIGH_POWER_MODE);
+
+	/* Disable ADIE */
+	if (icodec->adie_path) {
+		adie_codec_proceed_stage(icodec->adie_path,
+					ADIE_CODEC_DIGITAL_OFF);
+		adie_codec_close(icodec->adie_path);
+		icodec->adie_path = NULL;
+	}
+
+	afe_close(icodec->data->copp_id);
+
+	clk_disable(drv->tx_bitclk);
+	clk_disable(drv->tx_osrclk);
+
+	msm_snddev_tx_mclk_free();
+
+	/* Reuse pamp_off for TX platform-specific setup  */
+	if (icodec->data->pamp_off)
+		icodec->data->pamp_off();
+
+	icodec->enabled = 0;
+
+	wake_unlock(&drv->tx_idlelock);
+	return 0;
+}
+
+static int snddev_icodec_set_device_volume_impl(
+		struct msm_snddev_info *dev_info, u32 volume)
+{
+	struct snddev_icodec_state *icodec;
+
+	int rc = 0;
+
+	icodec = dev_info->private_data;
+
+	if (icodec->data->dev_vol_type & SNDDEV_DEV_VOL_DIGITAL) {
+
+		rc = adie_codec_set_device_digital_volume(icodec->adie_path,
+				icodec->data->channel_mode, volume);
+		if (rc < 0) {
+			pr_err("%s: unable to set_device_digital_volume for"
+				"%s volume in percentage = %u\n",
+				__func__, dev_info->name, volume);
+			return rc;
+		}
+
+	} else if (icodec->data->dev_vol_type & SNDDEV_DEV_VOL_ANALOG) {
+		rc = adie_codec_set_device_analog_volume(icodec->adie_path,
+				icodec->data->channel_mode, volume);
+		if (rc < 0) {
+			pr_err("%s: unable to set_device_analog_volume for"
+				"%s volume in percentage = %u\n",
+				__func__, dev_info->name, volume);
+			return rc;
+		}
+	} else {
+		pr_err("%s: Invalid device volume control\n", __func__);
+		return -EPERM;
+	}
+	return rc;
+}
+
+static int snddev_icodec_open(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+	struct snddev_icodec_state *icodec;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	if (!dev_info) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	icodec = dev_info->private_data;
+
+	if (icodec->data->capability & SNDDEV_CAP_RX) {
+		mutex_lock(&drv->rx_lock);
+		if (drv->rx_active) {
+			mutex_unlock(&drv->rx_lock);
+			rc = -EBUSY;
+			goto error;
+		}
+		rc = snddev_icodec_open_rx(icodec);
+
+		if (!IS_ERR_VALUE(rc)) {
+			drv->rx_active = 1;
+			if ((icodec->data->dev_vol_type & (
+				SNDDEV_DEV_VOL_DIGITAL |
+				SNDDEV_DEV_VOL_ANALOG)))
+				rc = snddev_icodec_set_device_volume_impl(
+						dev_info, dev_info->dev_volume);
+		}
+		mutex_unlock(&drv->rx_lock);
+	} else if (icodec->data->capability & SNDDEV_CAP_LB) {
+		mutex_lock(&drv->lb_lock);
+		rc = snddev_icodec_open_lb(icodec);
+
+		if (!IS_ERR_VALUE(rc)) {
+			if ((icodec->data->dev_vol_type & (
+				SNDDEV_DEV_VOL_DIGITAL |
+				SNDDEV_DEV_VOL_ANALOG)))
+				rc = snddev_icodec_set_device_volume_impl(
+						dev_info, dev_info->dev_volume);
+		}
+
+		mutex_unlock(&drv->lb_lock);
+	} else {
+		mutex_lock(&drv->tx_lock);
+		if (drv->tx_active) {
+			mutex_unlock(&drv->tx_lock);
+			rc = -EBUSY;
+			goto error;
+		}
+		rc = snddev_icodec_open_tx(icodec);
+
+		if (!IS_ERR_VALUE(rc)) {
+			drv->tx_active = 1;
+			if ((icodec->data->dev_vol_type & (
+				SNDDEV_DEV_VOL_DIGITAL |
+				SNDDEV_DEV_VOL_ANALOG)))
+				rc = snddev_icodec_set_device_volume_impl(
+						dev_info, dev_info->dev_volume);
+		}
+		mutex_unlock(&drv->tx_lock);
+	}
+error:
+	return rc;
+}
+
+static int snddev_icodec_close(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+	struct snddev_icodec_state *icodec;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+	if (!dev_info) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	icodec = dev_info->private_data;
+
+	if (icodec->data->capability & SNDDEV_CAP_RX) {
+		mutex_lock(&drv->rx_lock);
+		if (!drv->rx_active) {
+			mutex_unlock(&drv->rx_lock);
+			rc = -EPERM;
+			goto error;
+		}
+		rc = snddev_icodec_close_rx(icodec);
+		if (!IS_ERR_VALUE(rc))
+			drv->rx_active = 0;
+		mutex_unlock(&drv->rx_lock);
+	} else if (icodec->data->capability & SNDDEV_CAP_LB) {
+		mutex_lock(&drv->lb_lock);
+		rc = snddev_icodec_close_lb(icodec);
+		mutex_unlock(&drv->lb_lock);
+	} else {
+		mutex_lock(&drv->tx_lock);
+		if (!drv->tx_active) {
+			mutex_unlock(&drv->tx_lock);
+			rc = -EPERM;
+			goto error;
+		}
+		rc = snddev_icodec_close_tx(icodec);
+		if (!IS_ERR_VALUE(rc))
+			drv->tx_active = 0;
+		mutex_unlock(&drv->tx_lock);
+	}
+
+error:
+	return rc;
+}
+
+static int snddev_icodec_check_freq(u32 req_freq)
+{
+	int rc = -EINVAL;
+
+	if ((req_freq != 0) && (req_freq >= 8000) && (req_freq <= 48000)) {
+		if ((req_freq == 8000) || (req_freq == 11025) ||
+			(req_freq == 12000) || (req_freq == 16000) ||
+			(req_freq == 22050) || (req_freq == 24000) ||
+			(req_freq == 32000) || (req_freq == 44100) ||
+			(req_freq == 48000)) {
+				rc = 0;
+		} else
+			pr_info("%s: Unsupported Frequency:%d\n", __func__,
+								req_freq);
+	}
+	return rc;
+}
+
+static int snddev_icodec_set_freq(struct msm_snddev_info *dev_info, u32 rate)
+{
+	int rc;
+	struct snddev_icodec_state *icodec;
+
+	if (!dev_info) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	icodec = dev_info->private_data;
+	if (adie_codec_freq_supported(icodec->data->profile, rate) != 0) {
+		rc = -EINVAL;
+		goto error;
+	} else {
+		if (snddev_icodec_check_freq(rate) != 0) {
+			rc = -EINVAL;
+			goto error;
+		} else
+			icodec->sample_rate = rate;
+	}
+
+	if (icodec->enabled) {
+		snddev_icodec_close(dev_info);
+		snddev_icodec_open(dev_info);
+	}
+
+	return icodec->sample_rate;
+
+error:
+	return rc;
+}
+
+static int snddev_icodec_enable_sidetone(struct msm_snddev_info *dev_info,
+	u32 enable, uint16_t gain)
+{
+	int rc = 0;
+	struct snddev_icodec_state *icodec;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	if (!dev_info) {
+		pr_err("invalid dev_info\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	icodec = dev_info->private_data;
+
+	if (icodec->data->capability & SNDDEV_CAP_RX) {
+		mutex_lock(&drv->rx_lock);
+		if (!drv->rx_active || !dev_info->opened) {
+			pr_err("dev not active\n");
+			rc = -EPERM;
+			mutex_unlock(&drv->rx_lock);
+			goto error;
+		}
+		rc = afe_sidetone(PRIMARY_I2S_TX, PRIMARY_I2S_RX, enable, gain);
+		if (rc < 0)
+			pr_err("%s: AFE command sidetone failed\n", __func__);
+		mutex_unlock(&drv->rx_lock);
+	} else {
+		rc = -EINVAL;
+		pr_err("rx device only\n");
+	}
+
+error:
+	return rc;
+
+}
+static int snddev_icodec_enable_anc(struct msm_snddev_info *dev_info,
+	u32 enable)
+{
+	int rc = 0;
+	struct adie_codec_anc_data *reg_writes;
+	struct acdb_cal_block cal_block;
+	struct snddev_icodec_state *icodec;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+
+	pr_info("%s: enable=%d\n", __func__, enable);
+
+	if (!dev_info) {
+		pr_err("invalid dev_info\n");
+		rc = -EINVAL;
+		goto error;
+	}
+	icodec = dev_info->private_data;
+
+	if ((icodec->data->capability & SNDDEV_CAP_RX) &&
+		(icodec->data->capability & SNDDEV_CAP_ANC)) {
+		mutex_lock(&drv->rx_lock);
+
+		if (!drv->rx_active || !dev_info->opened) {
+			pr_err("dev not active\n");
+			rc = -EPERM;
+			mutex_unlock(&drv->rx_lock);
+			goto error;
+		}
+		if (enable) {
+			get_anc_cal(&cal_block);
+			reg_writes = (struct adie_codec_anc_data *)
+				cal_block.cal_kvaddr;
+
+			if (reg_writes == NULL) {
+				pr_err("error, no calibration data\n");
+				rc = -1;
+				mutex_unlock(&drv->rx_lock);
+				goto error;
+			}
+
+			rc = adie_codec_enable_anc(icodec->adie_path,
+			1, reg_writes);
+		} else {
+			rc = adie_codec_enable_anc(icodec->adie_path,
+			0, NULL);
+		}
+		mutex_unlock(&drv->rx_lock);
+	} else {
+		rc = -EINVAL;
+		pr_err("rx and ANC device only\n");
+	}
+
+error:
+	return rc;
+
+}
+
+int snddev_icodec_set_device_volume(struct msm_snddev_info *dev_info,
+		u32 volume)
+{
+	struct snddev_icodec_state *icodec;
+	struct mutex *lock;
+	struct snddev_icodec_drv_state *drv = &snddev_icodec_drv;
+	int rc = -EPERM;
+
+	if (!dev_info) {
+		pr_info("%s : device not intilized.\n", __func__);
+		return  -EINVAL;
+	}
+
+	icodec = dev_info->private_data;
+
+	if (!(icodec->data->dev_vol_type & (SNDDEV_DEV_VOL_DIGITAL
+				| SNDDEV_DEV_VOL_ANALOG))) {
+
+		pr_info("%s : device %s does not support device volume "
+				"control.", __func__, dev_info->name);
+		return -EPERM;
+	}
+	dev_info->dev_volume =  volume;
+
+	if (icodec->data->capability & SNDDEV_CAP_RX)
+		lock = &drv->rx_lock;
+	else if (icodec->data->capability & SNDDEV_CAP_LB)
+		lock = &drv->lb_lock;
+	else
+		lock = &drv->tx_lock;
+
+	mutex_lock(lock);
+
+	rc = snddev_icodec_set_device_volume_impl(dev_info,
+			dev_info->dev_volume);
+	mutex_unlock(lock);
+	return rc;
+}
+
+static int snddev_icodec_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct snddev_icodec_data *pdata;
+	struct msm_snddev_info *dev_info;
+	struct snddev_icodec_state *icodec;
+
+	if (!pdev || !pdev->dev.platform_data) {
+		printk(KERN_ALERT "Invalid caller\n");
+		rc = -1;
+		goto error;
+	}
+	pdata = pdev->dev.platform_data;
+	if ((pdata->capability & SNDDEV_CAP_RX) &&
+	   (pdata->capability & SNDDEV_CAP_TX)) {
+		pr_err("%s: invalid device data either RX or TX\n", __func__);
+		goto error;
+	}
+	icodec = kzalloc(sizeof(struct snddev_icodec_state), GFP_KERNEL);
+	if (!icodec) {
+		rc = -ENOMEM;
+		goto error;
+	}
+	dev_info = kmalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
+	if (!dev_info) {
+		kfree(icodec);
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	dev_info->name = pdata->name;
+	dev_info->copp_id = pdata->copp_id;
+	dev_info->private_data = (void *) icodec;
+	dev_info->dev_ops.open = snddev_icodec_open;
+	dev_info->dev_ops.close = snddev_icodec_close;
+	dev_info->dev_ops.set_freq = snddev_icodec_set_freq;
+	dev_info->dev_ops.set_device_volume = snddev_icodec_set_device_volume;
+	dev_info->capability = pdata->capability;
+	dev_info->opened = 0;
+	msm_snddev_register(dev_info);
+	icodec->data = pdata;
+	icodec->sample_rate = pdata->default_sample_rate;
+	dev_info->sample_rate = pdata->default_sample_rate;
+	dev_info->channel_mode = pdata->channel_mode;
+	if (pdata->capability & SNDDEV_CAP_RX)
+		dev_info->dev_ops.enable_sidetone =
+			snddev_icodec_enable_sidetone;
+	else
+		dev_info->dev_ops.enable_sidetone = NULL;
+
+	if (pdata->capability & SNDDEV_CAP_ANC) {
+		dev_info->dev_ops.enable_anc =
+		snddev_icodec_enable_anc;
+	} else {
+		dev_info->dev_ops.enable_anc = NULL;
+	}
+error:
+	return rc;
+}
+
+static int snddev_icodec_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver snddev_icodec_driver = {
+  .probe = snddev_icodec_probe,
+  .remove = snddev_icodec_remove,
+  .driver = { .name = "snddev_icodec" }
+};
+
+module_param(msm_codec_i2s_slave_mode, bool, 0);
+MODULE_PARM_DESC(msm_codec_i2s_slave_mode, "Set MSM to I2S slave clock mode");
+
+static int __init snddev_icodec_init(void)
+{
+	s32 rc;
+	struct snddev_icodec_drv_state *icodec_drv = &snddev_icodec_drv;
+
+	rc = platform_driver_register(&snddev_icodec_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: platform_driver_register for snddev icodec failed\n",
+					__func__);
+		goto error_snddev_icodec_driver;
+	}
+
+	rc = platform_driver_register(&msm_cdcclk_ctl_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: platform_driver_register for msm snddev failed\n",
+					__func__);
+		goto error_msm_cdcclk_ctl_driver;
+	}
+
+	rc = platform_driver_register(&msm_icodec_gpio_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: platform_driver_register for msm snddev gpio failed\n",
+					__func__);
+		goto error_msm_icodec_gpio_driver;
+	}
+
+	mutex_init(&icodec_drv->rx_lock);
+	mutex_init(&icodec_drv->lb_lock);
+	mutex_init(&icodec_drv->tx_lock);
+	icodec_drv->rx_active = 0;
+	icodec_drv->tx_active = 0;
+	icodec_drv->snddev_vreg = vreg_init();
+
+	wake_lock_init(&icodec_drv->tx_idlelock, WAKE_LOCK_IDLE,
+			"snddev_tx_idle");
+	wake_lock_init(&icodec_drv->rx_idlelock, WAKE_LOCK_IDLE,
+			"snddev_rx_idle");
+	return 0;
+error_msm_icodec_gpio_driver:
+	platform_driver_unregister(&msm_cdcclk_ctl_driver);
+error_msm_cdcclk_ctl_driver:
+	platform_driver_unregister(&snddev_icodec_driver);
+error_snddev_icodec_driver:
+	return -ENODEV;
+}
+
+static void __exit snddev_icodec_exit(void)
+{
+	struct snddev_icodec_drv_state *icodec_drv = &snddev_icodec_drv;
+
+	platform_driver_unregister(&snddev_icodec_driver);
+	platform_driver_unregister(&msm_cdcclk_ctl_driver);
+	platform_driver_unregister(&msm_icodec_gpio_driver);
+
+	clk_put(icodec_drv->rx_osrclk);
+	clk_put(icodec_drv->tx_osrclk);
+	if (icodec_drv->snddev_vreg) {
+		vreg_deinit(icodec_drv->snddev_vreg);
+		icodec_drv->snddev_vreg = NULL;
+	}
+	return;
+}
+
+module_init(snddev_icodec_init);
+module_exit(snddev_icodec_exit);
+
+MODULE_DESCRIPTION("ICodec Sound Device driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_icodec.h b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.h
new file mode 100644
index 0000000..8d5613f
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_icodec.h
@@ -0,0 +1,35 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __MACH_QDSP6V2_SNDDEV_ICODEC_H
+#define __MACH_QDSP6V2_SNDDEV_ICODEC_H
+#include <linux/mfd/msm-adie-codec.h>
+#include <mach/qdsp5v2/audio_def.h>
+#include <mach/pmic.h>
+
+struct snddev_icodec_data {
+	u32 capability; /* RX or TX */
+	const char *name;
+	u32 copp_id; /* audpp routing */
+	/* Adie profile */
+	struct adie_codec_dev_profile *profile;
+	/* Afe setting */
+	u8 channel_mode;
+	u32 default_sample_rate;
+	int (*pamp_on) (void);
+	void (*pamp_off) (void);
+	int (*voltage_on) (void);
+	void (*voltage_off) (void);
+	u32 dev_vol_type;
+};
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
new file mode 100644
index 0000000..db27d9e
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.c
@@ -0,0 +1,462 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/debugfs.h>
+#include <asm/uaccess.h>
+#include <mach/board.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <sound/q6afe.h>
+#include <sound/apr_audio.h>
+#include "snddev_mi2s.h"
+
+#define SNDDEV_MI2S_PCM_SZ 32 /* 16 bit / sample stereo mode */
+#define SNDDEV_MI2S_MUL_FACTOR 3 /* Multi by 8 Shift by 3  */
+#define SNDDEV_MI2S_CLK_RATE(freq) \
+	(((freq) * (SNDDEV_MI2S_PCM_SZ)) << (SNDDEV_MI2S_MUL_FACTOR))
+
+
+/* Global state for the driver */
+struct snddev_mi2s_drv_state {
+
+	struct clk *tx_osrclk;
+	struct clk *tx_bitclk;
+	int mi2s_ws;
+	int mi2s_mclk;
+	int mi2s_sclk;
+	int fm_mi2s_sd;
+};
+
+static struct snddev_mi2s_drv_state snddev_mi2s_drv;
+
+static struct msm_mi2s_gpio_data *mi2s_gpio;
+
+static int mi2s_gpios_request(void)
+{
+	int rc = 0;
+
+	pr_debug("%s\n", __func__);
+	rc = gpio_request(snddev_mi2s_drv.mi2s_ws, "MI2S_WS");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for MI2S_WS failed\n", __func__);
+		return rc;
+	}
+
+	rc = gpio_request(snddev_mi2s_drv.mi2s_sclk, "MI2S_SCLK");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for MI2S_SCLK failed\n", __func__);
+		gpio_free(snddev_mi2s_drv.mi2s_sclk);
+		return rc;
+	}
+
+	rc = gpio_request(snddev_mi2s_drv.mi2s_mclk, "MI2S_MCLK");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for MI2S_MCLK failed\n",
+			__func__);
+		gpio_free(snddev_mi2s_drv.mi2s_ws);
+		gpio_free(snddev_mi2s_drv.mi2s_sclk);
+		return rc;
+	}
+
+	rc = gpio_request(snddev_mi2s_drv.fm_mi2s_sd, "FM_MI2S_SD");
+	if (rc < 0) {
+		pr_err("%s: GPIO request for FM_MI2S_SD failed\n",
+			__func__);
+		gpio_free(snddev_mi2s_drv.mi2s_ws);
+		gpio_free(snddev_mi2s_drv.mi2s_sclk);
+		gpio_free(snddev_mi2s_drv.mi2s_mclk);
+		return rc;
+	}
+
+	return rc;
+}
+
+static void mi2s_gpios_free(void)
+{
+	pr_debug("%s\n", __func__);
+	gpio_free(snddev_mi2s_drv.mi2s_ws);
+	gpio_free(snddev_mi2s_drv.mi2s_sclk);
+	gpio_free(snddev_mi2s_drv.mi2s_mclk);
+	gpio_free(snddev_mi2s_drv.fm_mi2s_sd);
+}
+
+static int mi2s_get_gpios(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct resource *res;
+
+	/* Claim all of the GPIOs. */
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "mi2s_ws");
+	if (!res) {
+		pr_err("%s: failed to get gpio MI2S_WS\n", __func__);
+		return -ENODEV;
+	}
+
+	snddev_mi2s_drv.mi2s_ws = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "mi2s_sclk");
+	if (!res) {
+		pr_err("%s: failed to get gpio MI2S_SCLK\n", __func__);
+		return -ENODEV;
+	}
+
+	snddev_mi2s_drv.mi2s_sclk = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+					   "mi2s_mclk");
+	if (!res) {
+		pr_err("%s: failed to get gpio MI2S_MCLK\n", __func__);
+		return -ENODEV;
+	}
+
+	snddev_mi2s_drv.mi2s_mclk = res->start;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO,
+					   "fm_mi2s_sd");
+	if (!res) {
+		pr_err("%s: failed to get gpio FM_MI2S_SD\n", __func__);
+		return -ENODEV;
+	}
+
+	snddev_mi2s_drv.fm_mi2s_sd = res->start;
+
+	return rc;
+}
+
+static int mi2s_fm_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+
+	rc = mi2s_get_gpios(pdev);
+	if (rc < 0) {
+		pr_err("%s: GPIO configuration failed\n", __func__);
+		return rc;
+	}
+
+	mi2s_gpio = (struct msm_mi2s_gpio_data *)(pdev->dev.platform_data);
+	return rc;
+}
+
+static struct platform_driver mi2s_fm_driver = {
+	.probe = mi2s_fm_probe,
+	.driver = { .name = "msm_mi2s"}
+};
+
+static u8 num_of_bits_set(u8 sd_line_mask)
+{
+	u8 num_bits_set = 0;
+
+	while (sd_line_mask) {
+
+		if (sd_line_mask & 1)
+			num_bits_set++;
+		sd_line_mask = sd_line_mask >> 1;
+	}
+	return num_bits_set;
+}
+
+static int snddev_mi2s_open(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+	union afe_port_config afe_config;
+	u8 channels;
+	u8 num_of_sd_lines = 0;
+	struct snddev_mi2s_drv_state *drv = &snddev_mi2s_drv;
+	struct snddev_mi2s_data *snddev_mi2s_data = dev_info->private_data;
+
+	if (!dev_info) {
+		pr_err("%s:  msm_snddev_info is null\n", __func__);
+		return -EINVAL;
+	}
+
+	/* set up osr clk */
+	drv->tx_osrclk = clk_get(0, "mi2s_osr_clk");
+	if (IS_ERR(drv->tx_osrclk))
+		pr_err("%s master clock Error\n", __func__);
+
+	rc =  clk_set_rate(drv->tx_osrclk,
+			 SNDDEV_MI2S_CLK_RATE(dev_info->sample_rate));
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("ERROR setting osr clock\n");
+		return -ENODEV;
+	}
+	clk_enable(drv->tx_osrclk);
+
+	/* set up bit clk */
+	drv->tx_bitclk = clk_get(0, "mi2s_bit_clk");
+	if (IS_ERR(drv->tx_bitclk))
+		pr_err("%s clock Error\n", __func__);
+
+	rc =  clk_set_rate(drv->tx_bitclk, 8);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("ERROR setting bit clock\n");
+		clk_disable(drv->tx_osrclk);
+		return -ENODEV;
+	}
+	clk_enable(drv->tx_bitclk);
+
+	afe_config.mi2s.bitwidth = 16;
+
+	if (snddev_mi2s_data->channel_mode == 1)
+		channels = AFE_MI2S_MONO;
+	else if (snddev_mi2s_data->channel_mode == 2)
+		channels = AFE_MI2S_STEREO;
+	else if (snddev_mi2s_data->channel_mode == 4)
+		channels = AFE_MI2S_4CHANNELS;
+	else if (snddev_mi2s_data->channel_mode == 6)
+		channels = AFE_MI2S_6CHANNELS;
+	else if (snddev_mi2s_data->channel_mode == 8)
+		channels = AFE_MI2S_8CHANNELS;
+	else {
+		pr_err("ERROR: Invalid MI2S channel mode\n");
+		goto error_invalid_data;
+	}
+
+	num_of_sd_lines = num_of_bits_set(snddev_mi2s_data->sd_lines);
+
+	switch (num_of_sd_lines) {
+	case 1:
+		switch (snddev_mi2s_data->sd_lines) {
+		case MI2S_SD0:
+			afe_config.mi2s.line = AFE_I2S_SD0;
+			break;
+		case MI2S_SD1:
+			afe_config.mi2s.line = AFE_I2S_SD1;
+			break;
+		case MI2S_SD2:
+			afe_config.mi2s.line = AFE_I2S_SD2;
+			break;
+		case MI2S_SD3:
+			afe_config.mi2s.line = AFE_I2S_SD3;
+			break;
+		default:
+			pr_err("%s: invalid SD line\n",
+			__func__);
+			goto error_invalid_data;
+		}
+		if (channels != AFE_MI2S_STEREO &&
+		channels != AFE_MI2S_MONO) {
+			pr_err("%s: for one SD line, channel "
+			"must be 1 or 2\n", __func__);
+			goto error_invalid_data;
+		}
+		afe_config.mi2s.channel = channels;
+		break;
+	case 2:
+		switch (snddev_mi2s_data->sd_lines) {
+		case MI2S_SD0 | MI2S_SD1:
+			afe_config.mi2s.line = AFE_I2S_QUAD01;
+			break;
+		case MI2S_SD2 | MI2S_SD3:
+			afe_config.mi2s.line = AFE_I2S_QUAD23;
+			break;
+		default:
+			pr_err("%s: invalid SD line\n",
+			__func__);
+			goto error_invalid_data;
+		}
+		if (channels != AFE_MI2S_4CHANNELS) {
+			pr_err("%s: for two SD lines, channel "
+			"must be 1 and 2 or 3 and 4\n", __func__);
+			goto error_invalid_data;
+		}
+		break;
+	case 3:
+		switch (snddev_mi2s_data->sd_lines) {
+		case MI2S_SD0 | MI2S_SD1 | MI2S_SD2:
+			afe_config.mi2s.line = AFE_I2S_6CHS;
+			break;
+		default:
+			pr_err("%s: invalid SD lines\n",
+			__func__);
+			goto error_invalid_data;
+		}
+		if (channels != AFE_MI2S_6CHANNELS) {
+			pr_err("%s: for three SD lines, lines "
+			"must be 1, 2, and 3\n", __func__);
+			goto error_invalid_data;
+		}
+		break;
+	case 4:
+		switch (snddev_mi2s_data->sd_lines) {
+		case MI2S_SD0 | MI2S_SD1 | MI2S_SD2 | MI2S_SD3:
+			afe_config.mi2s.line = AFE_I2S_8CHS;
+			break;
+		default:
+			pr_err("%s: invalid SD lines\n",
+			__func__);
+			goto error_invalid_data;
+		}
+
+		if (channels != AFE_MI2S_8CHANNELS) {
+			pr_err("%s: for four SD lines, lines "
+			"must be 1, 2, 3, and 4\n", __func__);
+			goto error_invalid_data;
+		}
+		break;
+	default:
+		pr_err("%s: invalid SD lines\n", __func__);
+		goto error_invalid_data;
+	}
+	afe_config.mi2s.ws = 1;
+	rc = afe_open(snddev_mi2s_data->copp_id, &afe_config,
+		dev_info->sample_rate);
+
+	if (rc < 0) {
+		pr_err("%s:  afe_open failed\n", __func__);
+		goto error_invalid_data;
+	}
+
+	/*enable fm gpio here*/
+	rc = mi2s_gpios_request();
+	if (rc < 0) {
+		pr_err("%s: GPIO request failed\n", __func__);
+		return rc;
+	}
+
+	pr_info("%s:  afe_open  done\n", __func__);
+
+	return rc;
+
+error_invalid_data:
+
+	clk_disable(drv->tx_bitclk);
+	clk_disable(drv->tx_osrclk);
+	return -EINVAL;
+}
+
+static int snddev_mi2s_close(struct msm_snddev_info *dev_info)
+{
+
+	struct snddev_mi2s_drv_state *mi2s_drv = &snddev_mi2s_drv;
+	struct snddev_mi2s_data *snddev_mi2s_data = dev_info->private_data;
+
+	if (!dev_info) {
+		pr_err("%s:  msm_snddev_info is null\n", __func__);
+		return -EINVAL;
+	}
+
+	if (!dev_info->opened) {
+		pr_err(" %s: calling close device with out opening the"
+		       " device\n", __func__);
+		return -EIO;
+	}
+	afe_close(snddev_mi2s_data->copp_id);
+	clk_disable(mi2s_drv->tx_bitclk);
+	clk_disable(mi2s_drv->tx_osrclk);
+
+	mi2s_gpios_free();
+
+	pr_info("%s:\n", __func__);
+
+	return 0;
+}
+
+static int snddev_mi2s_set_freq(struct msm_snddev_info *dev_info, u32 req_freq)
+{
+	if (req_freq != 48000) {
+		pr_info("%s: Unsupported Frequency:%d\n", __func__, req_freq);
+		return -EINVAL;
+	}
+	return 48000;
+}
+
+
+static int snddev_mi2s_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct snddev_mi2s_data *pdata;
+	struct msm_snddev_info *dev_info;
+
+	if (!pdev || !pdev->dev.platform_data) {
+		printk(KERN_ALERT "Invalid caller\n");
+		return -ENODEV;
+	}
+
+	pdata = pdev->dev.platform_data;
+
+	dev_info = kzalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
+	if (!dev_info) {
+		pr_err("%s: uneable to allocate memeory for msm_snddev_info\n",
+		       __func__);
+
+		return -ENOMEM;
+	}
+
+	dev_info->name = pdata->name;
+	dev_info->copp_id = pdata->copp_id;
+	dev_info->dev_ops.open = snddev_mi2s_open;
+	dev_info->dev_ops.close = snddev_mi2s_close;
+	dev_info->private_data = (void *)pdata;
+	dev_info->dev_ops.set_freq = snddev_mi2s_set_freq;
+	dev_info->capability = pdata->capability;
+	dev_info->opened = 0;
+	dev_info->sample_rate = pdata->sample_rate;
+	msm_snddev_register(dev_info);
+
+	return rc;
+}
+
+static struct platform_driver snddev_mi2s_driver = {
+	.probe = snddev_mi2s_probe,
+	.driver = {.name = "snddev_mi2s"}
+};
+
+static int __init snddev_mi2s_init(void)
+{
+	s32 rc = 0;
+
+	rc = platform_driver_register(&mi2s_fm_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: platform_driver_register for mi2s_fm_driver failed\n",
+				__func__);
+		goto error_mi2s_fm_platform_driver;
+	}
+
+	rc = platform_driver_register(&snddev_mi2s_driver);
+	if (IS_ERR_VALUE(rc)) {
+
+		pr_err("%s: platform_driver_register failed\n", __func__);
+		goto error_platform_driver;
+	}
+
+	return rc;
+
+error_platform_driver:
+	platform_driver_unregister(&mi2s_fm_driver);
+error_mi2s_fm_platform_driver:
+	pr_err("%s: encounter error\n", __func__);
+	return -ENODEV;
+}
+
+static void __exit snddev_mi2s_exit(void)
+{
+	struct snddev_mi2s_drv_state *mi2s_drv = &snddev_mi2s_drv;
+
+	platform_driver_unregister(&snddev_mi2s_driver);
+	clk_put(mi2s_drv->tx_osrclk);
+	clk_put(mi2s_drv->tx_bitclk);
+	return;
+}
+
+
+module_init(snddev_mi2s_init);
+module_exit(snddev_mi2s_exit);
+
+MODULE_DESCRIPTION("MI2S Sound Device driver");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.h b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.h
new file mode 100644
index 0000000..d369c96
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_mi2s.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __MACH_QDSP6_V2_SNDDEV_MI2S_H
+#define __MACH_QDSP6_V2_SNDDEV_MI2S_H
+
+struct snddev_mi2s_data {
+	u32 capability; /* RX or TX */
+	const char *name;
+	u32 copp_id; /* audpp routing */
+	u16 channel_mode;
+	u16 sd_lines;
+	u32 sample_rate;
+};
+
+#define MI2S_SD0 (1 << 0)
+#define MI2S_SD1 (1 << 1)
+#define MI2S_SD2 (1 << 2)
+#define MI2S_SD3 (1 << 3)
+
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_virtual.c b/arch/arm/mach-msm/qdsp6v2/snddev_virtual.c
new file mode 100644
index 0000000..f48aa0e
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_virtual.c
@@ -0,0 +1,172 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <mach/qdsp6v2/audio_dev_ctl.h>
+#include <sound/q6afe.h>
+#include <linux/slab.h>
+#include "snddev_virtual.h"
+
+static DEFINE_MUTEX(snddev_virtual_lock);
+
+static int snddev_virtual_open(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&snddev_virtual_lock);
+
+	if (!dev_info)  {
+		pr_err("%s: NULL dev_info\n", __func__);
+
+		rc = -EINVAL;
+		goto done;
+	}
+
+	if (!dev_info->opened) {
+		rc = afe_start_pseudo_port(dev_info->copp_id);
+	} else {
+		pr_err("%s: Pseudo port 0x%x is already open\n",
+		       __func__, dev_info->copp_id);
+
+		rc = -EBUSY;
+	}
+
+done:
+	mutex_unlock(&snddev_virtual_lock);
+
+	return rc;
+}
+
+static int snddev_virtual_close(struct msm_snddev_info *dev_info)
+{
+	int rc = 0;
+
+	pr_debug("%s\n", __func__);
+
+	mutex_lock(&snddev_virtual_lock);
+
+	if (!dev_info) {
+		pr_err("%s: NULL dev_info\n", __func__);
+
+		rc = -EINVAL;
+		goto done;
+	}
+
+	if (dev_info->opened) {
+		rc = afe_stop_pseudo_port(dev_info->copp_id);
+	} else {
+		pr_err("%s: Pseudo port 0x%x is not open\n",
+		       __func__, dev_info->copp_id);
+
+		rc = -EPERM;
+	}
+
+done:
+	mutex_unlock(&snddev_virtual_lock);
+
+	return rc;
+}
+
+static int snddev_virtual_set_freq(struct msm_snddev_info *dev_info, u32 rate)
+{
+	int rc = 0;
+
+	if (!dev_info)
+		rc = -EINVAL;
+
+	return rate;
+}
+
+static int snddev_virtual_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct snddev_virtual_data *pdata;
+	struct msm_snddev_info *dev_info;
+
+	pr_debug("%s\n", __func__);
+
+	if (!pdev || !pdev->dev.platform_data) {
+		pr_err("%s: Invalid caller\n", __func__);
+
+		rc = -EPERM;
+		goto done;
+	}
+
+	pdata = pdev->dev.platform_data;
+
+	dev_info = kmalloc(sizeof(struct msm_snddev_info), GFP_KERNEL);
+	if (!dev_info) {
+		pr_err("%s: Out of memory\n", __func__);
+
+		rc = -ENOMEM;
+		goto done;
+	}
+
+	dev_info->name = pdata->name;
+	dev_info->copp_id = pdata->copp_id;
+	dev_info->private_data = (void *) NULL;
+	dev_info->dev_ops.open = snddev_virtual_open;
+	dev_info->dev_ops.close = snddev_virtual_close;
+	dev_info->dev_ops.set_freq = snddev_virtual_set_freq;
+	dev_info->capability = pdata->capability;
+	dev_info->sample_rate = 48000;
+	dev_info->opened = 0;
+	dev_info->sessions = 0;
+
+	msm_snddev_register(dev_info);
+
+done:
+	return rc;
+}
+
+static int snddev_virtual_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static struct platform_driver snddev_virtual_driver = {
+	.probe = snddev_virtual_probe,
+	.remove = snddev_virtual_remove,
+	.driver = { .name = "snddev_virtual" }
+};
+
+static int __init snddev_virtual_init(void)
+{
+	int rc = 0;
+
+	pr_debug("%s\n", __func__);
+
+	rc = platform_driver_register(&snddev_virtual_driver);
+	if (IS_ERR_VALUE(rc)) {
+		pr_err("%s: Platform driver register failure\n", __func__);
+
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __exit snddev_virtual_exit(void)
+{
+	platform_driver_unregister(&snddev_virtual_driver);
+
+	return;
+}
+
+module_init(snddev_virtual_init);
+module_exit(snddev_virtual_exit);
+
+MODULE_DESCRIPTION("Virtual Sound Device driver");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/mach-msm/qdsp6v2/snddev_virtual.h b/arch/arm/mach-msm/qdsp6v2/snddev_virtual.h
new file mode 100644
index 0000000..dec4d07
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/snddev_virtual.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __MACH_QDSP6V2_SNDDEV_VIRTUAL_H
+#define __MACH_QDSP6V2_SNDDEV_VIRTUAL_H
+
+struct snddev_virtual_data {
+	u32 capability; /* RX or TX */
+	const char *name;
+	u32 copp_id; /* Audpp routing */
+};
+#endif
diff --git a/arch/arm/mach-msm/qdsp6v2/timpani_profile_8x60.h b/arch/arm/mach-msm/qdsp6v2/timpani_profile_8x60.h
new file mode 100644
index 0000000..7197391
--- /dev/null
+++ b/arch/arm/mach-msm/qdsp6v2/timpani_profile_8x60.h
@@ -0,0 +1,3100 @@
+/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __MACH_QDSP6V2_TIMPANI_PROFILE_H
+#define __MACH_QDSP6V2_TIMPANI_PROFILE_H
+
+/*
+ * TX Device Profiles
+ */
+
+/* Analog MIC */
+/* AMIC Primary mono */
+#define AMIC_PRI_MONO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xD0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3A98}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+
+/* AMIC Secondary mono */
+#define AMIC_SEC_MONO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAC, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3A98 },\
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAC, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* AMIC dual */
+#define AMIC_DUAL_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xB0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAC, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAC, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+/*
+ * Digital MIC
+ */
+/* DMIC1 Primary (DMIC 1 - TX1) */
+#define DMIC1_PRI_MONO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* DMIC1 Secondary - (DMIC 2 - TX1) */
+#define DMIC1_SEC_MONO_OSR_64 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x12)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT,    0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* DMIC Dual Primary (DMIC 1/2 - TX1) */
+#define DMIC1_PRI_STEREO_OSR_256 \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x19)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)} }
+
+/* DMIC2 Dual Primary (DMIC 3/4 - TX2 - Left/Right) */
+#define DMIC2_SEC_DUAL_OSR_64 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA6, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA7, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x22)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x96, 0xFF, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0xF0, 0xE0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT,    0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA6, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA7, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HS_DMIC2_STEREO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x19)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/*
+ *  LINE IN
+ */
+#define LINEIN_PRI_MONO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT,    0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LINEIN_PRI_STEREO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0xA2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LINEIN_SEC_MONO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA6, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA7, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x2E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x96, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0xF0, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x18, 0xFF, 0xA2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA6, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA7, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x18, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LINEIN_SEC_STEREO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA6, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA7, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x2E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x96, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0xF0, 0xE0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x18, 0xFF, 0xA2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x19, 0xFF, 0xA2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA6, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA7, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x18, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x19, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LINEIN_SEC_STEREO_OSR_64 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA6, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA7, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x22)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x96, 0xFF, 0x18)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0xF0, 0xE0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x18, 0xFF, 0xA2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x19, 0xFF, 0xA2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA6, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA7, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0xC0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x18, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x19, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/*
+ * AUX IN
+ */
+#define AUXIN_MONO_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xA1)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* Headset MIC */
+#define HEADSET_AMIC2_TX_MONO_PRI_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xC8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3A98 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/*
+ * RX Device Profiles
+ */
+
+/* RX EAR */
+#define EAR_PRI_MONO_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define EAR_SEC_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* ANC Headset: Speakers on Primary Rx, Noise Microphones on Secondary Tx */
+
+#define ANC_HEADSET_CPLS_AMIC1_AUXL_RX1_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x95, 0xFF, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9B, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x18, 0xFF, 0xD0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x19, 0xFF, 0xC1)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xC0, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xD0, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x18, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x19, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x09, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0A, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/*
+ *  RX HPH PRIMARY
+ */
+
+/* RX HPH CLASS AB CAPLESS */
+
+#define HEADSET_AB_CPLS_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HPH_PRI_AB_CPLS_MONO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on HEADSET_AB_CPLS_48000_OSR_256, change 0x83 */
+/* change 0x31 */
+#define HPH_PRI_AB_CPLS_MONO_LEFT \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xC5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on HEADSET_AB_CPLS_48000_OSR_256 */
+/* add 0x8A to mute rx1 left 0x01 */
+/* change 0x31 */
+#define HPH_PRI_AB_CPLS_MONO_RIGHT \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0D)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x35)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define FTM_HPH_PRI_AB_CPLS_MONO_LB_LEFT \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xC5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x3C)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define FTM_HPH_PRI_AB_CPLS_MONO_LB_RIGHT \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0D)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x35)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* This is for differential signaling, which is a test mode. */
+#define HPH_PRI_AB_CPLS_DIFF \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x06)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HPH_PRI_AB_CPLS_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* RX HPH CLASS AB LEGACY */
+
+#define HPH_PRI_AB_LEG_MONO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0xF9)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HP_PRI_AB_LEG_DIFF \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0xF9)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HPH_PRI_AB_LEG_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x09)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x186A0}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xF9)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x27)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* RX HPH CLASS D LEGACY */
+
+#define HPH_PRI_D_LEG_DIFF \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0x90, 0x90)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0A, 0x0A)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HPH_PRI_D_LEG_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x21, 0xFF, 0x60)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x22, 0xFF, 0xE1)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x26, 0xFF, 0xD0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2D, 0xFF, 0x6F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2E, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3F, 0xFF, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x40, 0xFF, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x41, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x42, 0xFF, 0xBB)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x43, 0xFF, 0xF2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x44, 0xF7, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x45, 0xFF, 0xFF)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x46, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x47, 0xFF, 0xF2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x48, 0xF7, 0x37)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x49, 0xFF, 0xFF)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4A, 0xFF, 0x77)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0x8C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x0A)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/*
+ * RX HPH SECONDARY
+ */
+
+/* RX HPH CLASS AB CAPLESS */
+#define HPH_SEC_AB_CPLS_MONO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define HPH_SEC_AB_CPLS_DIFF \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HPH_SEC_AB_CPLS_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA5, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA5, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* RX HPH CLASS AB LEGACY */
+#define HPH_SEC_AB_LEG_MONO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0xF9)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HPH_SEC_AB_LEG_DIFF \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0xF9)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define HPH_SEC_AB_LEG_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA5, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0xF9)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA5, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* RX HPH CLASS D LEGACY */
+
+#define HPH_SEC_D_LEG_DIFF \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0x50, 0x50)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0A, 0x0A)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000},\
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HPH_SEC_D_LEG_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA5, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0x50, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0A, 0x0A)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* RX LINE OUT PRIMARY */
+/* spkr phone mono rx */
+#define LINEOUT_PRI_MONO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x58, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LINEOUT_PRI_DIFF \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x06)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x24, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0x10)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LINEOUT_PRI_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x58, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0c)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* RX LINE OUT SECONDARY */
+#define LINEOUT_SEC_MONO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x58, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LINEOUT_SEC_DIFF \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x48, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x48, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x58, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LINEOUT_SEC_STEREO \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA5, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x29, 0xFF, 0xC2)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x48, 0x48)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x58, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA5, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x48, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define SPEAKER_PRI_STEREO_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF},	\
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* RX AUX */
+#define AUXOUT_PRI_MONO_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x20, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 50000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x07)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x20, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define AUXOUT_SEC_MONO_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA1, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x98, 0xFF, 0x02)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x28, 0xFF, 0xCA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x40, 0x40)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 50000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x07)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x30, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA4, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAA, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x40, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_AUXPGA_HPH_AB_CPLS_STEREO \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2F, 0xFF, 0x44)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x30, 0xFF, 0x92)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xAA)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x90, 0x90)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFD, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define LB_AUXPGA_LO_STEREO \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x2F, 0xFF, 0x44)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x30, 0xFF, 0x92)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xAA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x90, 0x90)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0xF0, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x90, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+/*
+ * LB Device Profiles
+ */
+
+/* EAR */
+#define LB_EAR_PRI_MONO \
+	{{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x04, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x04, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* HPH CLASS AB CAPLESS */
+#define LB_HPH_AB_CPLS_PRI_MONO \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_HPH_AB_CPLS_PRI_DIFF \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x10, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define SPEAKER_HPH_AB_CPL_PRI_STEREO_48000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF},	\
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_HPH_AB_CPLS_PRI_STEREO \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x90, 0x90)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xAA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x90, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* HPH CLASS AB LEGACY */
+#define LB_HPH_AB_LEG_PRI_MONO \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xFC)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_PHP_AB_LEG_PRI_DIFF \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x10, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xFC)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x08, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_HPH_AB_LEG_PRI_STEREO \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x90, 0x90)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xAA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x59)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xFC)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x90, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* HPH CLASS D LEGACY */
+#define LB_HPH_D_LEG_PRI_DIFF \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x3A, 0x2A)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x3F, 0x2F)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_HPH_D_LEG_PRI_STEREO \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xAA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0xA6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x3A, 0x3A)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 300000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x3F, 0x3F)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3E, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* LINE OUT */
+#define LB_LINEOUT_PRI_MONO \
+	{{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x58, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_LINEOUT_PRI_DIFF \
+	{{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x80, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x10, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x58, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x80, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x10, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define LB_LINEOUT_PRI_STEREO \
+	{{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x90, 0x90)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xAA)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x58, 0x58)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 100000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFF, 0xA4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x90, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* AUX OUT */
+#define LB_AUXOUT_PRI_MONO \
+	{{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0xE0, 0x80)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x38, 0xFF, 0xA0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 50000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x07)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x33, 0x30, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0xE0, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* TTY RX */
+#define TTY_HEADSET_MONO_RX_8000_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x06)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x45)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0xC5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x27, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x08)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* TTY TX */
+#define TTY_HEADSET_MONO_TX_OSR_256 \
+	{{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* FTM devices */
+/* from HPH_PRI_AB_CPLS_DIFF */
+#define HEADSET_MONO_DIFF_RX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x06)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x4C, 0xFF, 0x29)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x55)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xBB8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFC, 0xF5)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x04)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE2, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3C, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3D, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on SPEAKER_PRI_STEREO_48000_OSR_256 */
+/* change 0x8A */
+#define FTM_SPKR_L_RX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF},	\
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on SPEAKER_PRI_STEREO_48000_OSR_256 */
+/* change 0x8A */
+#define SPKR_R_RX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3B, 0x24, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF},	\
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on SPEAKER_PRI_STEREO_48000_OSR_256 */
+#define FTM_SPKR_RX_LB \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x06)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0x30, 0x30)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF},	\
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+
+#define SPKR_MONO_DIFF_RX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x85, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0x6F, 0x6C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xB7, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x08)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x48)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x1388}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0xF8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x10)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x1C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFE, 0x3C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE0, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xE1, 0xFC, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0xF8, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x3A, 0x24, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* from AMIC_PRI_MONO_OSR_256, change TxFE (reg 0x0D) */
+#define LINEIN_MONO_L_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xD4)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3A98}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* from AMIC_PRI_MONO_OSR_256, change TxFE (reg 0x0D) */
+#define LINEIN_MONO_R_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0xD6)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3A98}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* from AMIC_PRI_MONO_OSR_256 */
+#define AUX_IN_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xC1)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3A98}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* AUXOUT_PRI_MONO_8000_OSR_256 */
+#define AUX_OUT_RX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},	\
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x20, 0x20)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 50000}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x07)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x32, 0x07, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x20, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* from DMIC1_PRI_MONO_OSR_256 */
+#define DMIC1_LEFT_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define DMIC1_RIGHT_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x06)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define DMIC1_LEFT_AND_RIGHT_TX DMIC1_PRI_STEREO_OSR_256
+
+#define DMIC2_LEFT_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x0A)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define DMIC2_RIGHT_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define DMIC2_LEFT_AND_RIGHT_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0x1F, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0x3F, 0x21)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0x3F, 0x24)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x39, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA8, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x3F, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x92, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#define HANDSET_MIC1_AUX_IN \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xB0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0xA1)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on AMIC_PRI_MONO_OSR_256 */
+#define FTM_HANDSET_LB_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xD0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x00)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0x3A98}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8B, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8C, 0x07, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA0, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xAB, 0x09, 0x09)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on HEADSET_AMIC2_TX_MONO_PRI_OSR_256 */
+#define FTM_HEADSET_LB_TX \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xC8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8B, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8C, 0x07, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA0, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on EAR_PRI_MONO_8000_OSR_256 */
+#define EAR_PRI_MONO_LB \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x02, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0F)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x02, 0x02)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x97, 0xFF, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0x60, 0x60)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x24, 0xFF, 0x4C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x03, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x84, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x0E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x81, 0xFF, 0x3C)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0x0F, 0x03)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x31, 0x03, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x39, 0x01, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+/* based on AMIC_DUAL_OSR_256 */
+#define FTM_AMIC_DUAL_HANDSET_TX_LB \
+	{{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_FLASH_IMAGE},  \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x05)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x80, 0x05, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0x30)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0xAC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x82, 0xFF, 0x1E)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA3, 0x01, 0x01)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x93, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x94, 0xFF, 0x1B)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x99, 0x0F, 0x04)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x9F, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0xB0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0xA8)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0xBC)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x65)}, \
+	{ADIE_CODEC_ACTION_DELAY_WAIT, 0xbb8 }, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x0C)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x86, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x87, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xC0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0xA0, 0x03, 0x03)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_ANALOG_READY}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x8A, 0xF0, 0xF0)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x83, 0x0C, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_ANALOG_OFF}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0D, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x0E, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x14, 0xFF, 0x64)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x11, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_ENTRY, ADIE_CODEC_PACK_ENTRY(0x12, 0xFF, 0x00)}, \
+	{ADIE_CODEC_ACTION_STAGE_REACHED, ADIE_CODEC_DIGITAL_OFF} }
+
+#endif