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, ®ion);
+ 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, ¶m);
+ 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, ¶m);
+ 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(®ion->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(®ion->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(®ion->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, ¶m);
+ 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(®ion->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(®ion->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, ®ion);
+ 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, ¶m);
+ 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(®ion->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, ®ion);
+ 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, ¶m);
+ 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, ¶m);
+ 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(®ion->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(®ion->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(®ion->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, ®ion);
+ 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, ¶m);
+ 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, ¶m);
+ 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(®ion->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(®ion->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(®ion->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, ®ion);
+ 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, ¶m);
+ 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, ¶m);
+ 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(®ion->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(®ion->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(®ion->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