]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
sound: qcom: add dsp support to apq8064
authorSrinivas Kandagatla <srinivas.kandagatla@linaro.org>
Mon, 7 Dec 2015 12:01:09 +0000 (12:01 +0000)
committerSrinivas Kandagatla <srinivas.kandagatla@linaro.org>
Thu, 14 Jan 2016 11:51:23 +0000 (11:51 +0000)
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
39 files changed:
include/linux/msm_audio.h [new file with mode: 0644]
include/linux/msm_audio_acdb.h [new file with mode: 0644]
include/sound/apr_audio.h [new file with mode: 0644]
include/sound/msm-dai-q6.h [new file with mode: 0644]
include/sound/msm_hdmi_audio.h [new file with mode: 0644]
include/sound/q6adm.h [new file with mode: 0644]
include/sound/q6afe.h [new file with mode: 0644]
include/sound/q6asm.h [new file with mode: 0644]
include/sound/qdsp6v2/apr.h [new file with mode: 0644]
include/sound/qdsp6v2/apr_tal.h [new file with mode: 0644]
include/sound/qdsp6v2/audio_acdb.h [new file with mode: 0644]
include/sound/qdsp6v2/audio_def.h [new file with mode: 0644]
include/sound/qdsp6v2/audio_dev_ctl.h [new file with mode: 0644]
include/sound/qdsp6v2/dsp_debug.h [new file with mode: 0644]
include/sound/qdsp6v2/q6voice.h [new file with mode: 0644]
include/sound/qdsp6v2/rtac.h [new file with mode: 0644]
sound/soc/qcom/Kconfig
sound/soc/qcom/Makefile
sound/soc/qcom/apq8064.c [new file with mode: 0644]
sound/soc/qcom/msm-dai-fe.c [new file with mode: 0644]
sound/soc/qcom/msm-dai-q6-hdmi.c [new file with mode: 0644]
sound/soc/qcom/msm-pcm-q6.c [new file with mode: 0644]
sound/soc/qcom/msm-pcm-q6.h [new file with mode: 0644]
sound/soc/qcom/msm-pcm-routing.c [new file with mode: 0644]
sound/soc/qcom/msm-pcm-routing.h [new file with mode: 0644]
sound/soc/qcom/qdsp6/Makefile [new file with mode: 0644]
sound/soc/qcom/qdsp6/core/Makefile [new file with mode: 0644]
sound/soc/qcom/qdsp6/core/apr.c [new file with mode: 0644]
sound/soc/qcom/qdsp6/core/apr_tal.c [new file with mode: 0644]
sound/soc/qcom/qdsp6/core/apr_v1.c [new file with mode: 0644]
sound/soc/qcom/qdsp6/core/audio_acdb.c [new file with mode: 0644]
sound/soc/qcom/qdsp6/core/dsp_debug.c [new file with mode: 0644]
sound/soc/qcom/qdsp6/core/q6audio_common.h [new file with mode: 0644]
sound/soc/qcom/qdsp6/core/q6core.c [new file with mode: 0644]
sound/soc/qcom/qdsp6/core/q6core.h [new file with mode: 0644]
sound/soc/qcom/qdsp6/core/rtac.c [new file with mode: 0644]
sound/soc/qcom/qdsp6/q6adm.c [new file with mode: 0644]
sound/soc/qcom/qdsp6/q6afe.c [new file with mode: 0644]
sound/soc/qcom/qdsp6/q6asm.c [new file with mode: 0644]

diff --git a/include/linux/msm_audio.h b/include/linux/msm_audio.h
new file mode 100644 (file)
index 0000000..04d4e5b
--- /dev/null
@@ -0,0 +1,367 @@
+/* include/linux/msm_audio.h
+ *
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (c) 2012 The Linux Foundation. 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.
+ *
+ */
+
+#ifndef __LINUX_MSM_AUDIO_H
+#define __LINUX_MSM_AUDIO_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/* PCM Audio */
+
+#define AUDIO_IOCTL_MAGIC 'a'
+
+#define AUDIO_START        _IOW(AUDIO_IOCTL_MAGIC, 0, unsigned)
+#define AUDIO_STOP         _IOW(AUDIO_IOCTL_MAGIC, 1, unsigned)
+#define AUDIO_FLUSH        _IOW(AUDIO_IOCTL_MAGIC, 2, unsigned)
+#define AUDIO_GET_CONFIG   _IOR(AUDIO_IOCTL_MAGIC, 3, unsigned)
+#define AUDIO_SET_CONFIG   _IOW(AUDIO_IOCTL_MAGIC, 4, unsigned)
+#define AUDIO_GET_STATS    _IOR(AUDIO_IOCTL_MAGIC, 5, unsigned)
+#define AUDIO_ENABLE_AUDPP _IOW(AUDIO_IOCTL_MAGIC, 6, unsigned)
+#define AUDIO_SET_ADRC     _IOW(AUDIO_IOCTL_MAGIC, 7, unsigned)
+#define AUDIO_SET_EQ       _IOW(AUDIO_IOCTL_MAGIC, 8, unsigned)
+#define AUDIO_SET_RX_IIR   _IOW(AUDIO_IOCTL_MAGIC, 9, unsigned)
+#define AUDIO_SET_VOLUME   _IOW(AUDIO_IOCTL_MAGIC, 10, unsigned)
+#define AUDIO_PAUSE        _IOW(AUDIO_IOCTL_MAGIC, 11, unsigned)
+#define AUDIO_PLAY_DTMF    _IOW(AUDIO_IOCTL_MAGIC, 12, unsigned)
+#define AUDIO_GET_EVENT    _IOR(AUDIO_IOCTL_MAGIC, 13, unsigned)
+#define AUDIO_ABORT_GET_EVENT _IOW(AUDIO_IOCTL_MAGIC, 14, unsigned)
+#define AUDIO_REGISTER_PMEM _IOW(AUDIO_IOCTL_MAGIC, 15, unsigned)
+#define AUDIO_DEREGISTER_PMEM _IOW(AUDIO_IOCTL_MAGIC, 16, unsigned)
+#define AUDIO_ASYNC_WRITE _IOW(AUDIO_IOCTL_MAGIC, 17, unsigned)
+#define AUDIO_ASYNC_READ _IOW(AUDIO_IOCTL_MAGIC, 18, unsigned)
+#define AUDIO_SET_INCALL _IOW(AUDIO_IOCTL_MAGIC, 19, struct msm_voicerec_mode)
+#define AUDIO_GET_NUM_SND_DEVICE _IOR(AUDIO_IOCTL_MAGIC, 20, unsigned)
+#define AUDIO_GET_SND_DEVICES _IOWR(AUDIO_IOCTL_MAGIC, 21, \
+                               struct msm_snd_device_list)
+#define AUDIO_ENABLE_SND_DEVICE _IOW(AUDIO_IOCTL_MAGIC, 22, unsigned)
+#define AUDIO_DISABLE_SND_DEVICE _IOW(AUDIO_IOCTL_MAGIC, 23, unsigned)
+#define AUDIO_ROUTE_STREAM _IOW(AUDIO_IOCTL_MAGIC, 24, \
+                               struct msm_audio_route_config)
+#define AUDIO_GET_PCM_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 30, unsigned)
+#define AUDIO_SET_PCM_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 31, unsigned)
+#define AUDIO_SWITCH_DEVICE  _IOW(AUDIO_IOCTL_MAGIC, 32, unsigned)
+#define AUDIO_SET_MUTE       _IOW(AUDIO_IOCTL_MAGIC, 33, unsigned)
+#define AUDIO_UPDATE_ACDB    _IOW(AUDIO_IOCTL_MAGIC, 34, unsigned)
+#define AUDIO_START_VOICE    _IOW(AUDIO_IOCTL_MAGIC, 35, unsigned)
+#define AUDIO_STOP_VOICE     _IOW(AUDIO_IOCTL_MAGIC, 36, unsigned)
+#define AUDIO_REINIT_ACDB    _IOW(AUDIO_IOCTL_MAGIC, 39, unsigned)
+#define AUDIO_OUTPORT_FLUSH  _IOW(AUDIO_IOCTL_MAGIC, 40, unsigned short)
+#define AUDIO_SET_ERR_THRESHOLD_VALUE _IOW(AUDIO_IOCTL_MAGIC, 41, \
+                                       unsigned short)
+#define AUDIO_GET_BITSTREAM_ERROR_INFO _IOR(AUDIO_IOCTL_MAGIC, 42, \
+                              struct msm_audio_bitstream_error_info)
+
+#define AUDIO_SET_SRS_TRUMEDIA_PARAM _IOW(AUDIO_IOCTL_MAGIC, 43, unsigned)
+
+/* Qualcomm extensions */
+#define AUDIO_SET_STREAM_CONFIG   _IOW(AUDIO_IOCTL_MAGIC, 80, \
+                               struct msm_audio_stream_config)
+#define AUDIO_GET_STREAM_CONFIG   _IOR(AUDIO_IOCTL_MAGIC, 81, \
+                               struct msm_audio_stream_config)
+#define AUDIO_GET_SESSION_ID _IOR(AUDIO_IOCTL_MAGIC, 82, unsigned short)
+#define AUDIO_GET_STREAM_INFO   _IOR(AUDIO_IOCTL_MAGIC, 83, \
+                              struct msm_audio_bitstream_info)
+#define AUDIO_SET_PAN       _IOW(AUDIO_IOCTL_MAGIC, 84, unsigned)
+#define AUDIO_SET_QCONCERT_PLUS       _IOW(AUDIO_IOCTL_MAGIC, 85, unsigned)
+#define AUDIO_SET_MBADRC       _IOW(AUDIO_IOCTL_MAGIC, 86, unsigned)
+#define AUDIO_SET_VOLUME_PATH   _IOW(AUDIO_IOCTL_MAGIC, 87, \
+                                    struct msm_vol_info)
+#define AUDIO_SET_MAX_VOL_ALL _IOW(AUDIO_IOCTL_MAGIC, 88, unsigned)
+#define AUDIO_ENABLE_AUDPRE  _IOW(AUDIO_IOCTL_MAGIC, 89, unsigned)
+#define AUDIO_SET_AGC        _IOW(AUDIO_IOCTL_MAGIC, 90, unsigned)
+#define AUDIO_SET_NS         _IOW(AUDIO_IOCTL_MAGIC, 91, unsigned)
+#define AUDIO_SET_TX_IIR     _IOW(AUDIO_IOCTL_MAGIC, 92, unsigned)
+#define AUDIO_GET_BUF_CFG    _IOW(AUDIO_IOCTL_MAGIC, 93, \
+                                       struct msm_audio_buf_cfg)
+#define AUDIO_SET_BUF_CFG    _IOW(AUDIO_IOCTL_MAGIC, 94, \
+                                       struct msm_audio_buf_cfg)
+#define AUDIO_SET_ACDB_BLK _IOW(AUDIO_IOCTL_MAGIC, 95,  \
+                                       struct msm_acdb_cmd_device)
+#define AUDIO_GET_ACDB_BLK _IOW(AUDIO_IOCTL_MAGIC, 96,  \
+                                       struct msm_acdb_cmd_device)
+
+#define AUDIO_REGISTER_ION _IOW(AUDIO_IOCTL_MAGIC, 97, unsigned)
+#define AUDIO_DEREGISTER_ION _IOW(AUDIO_IOCTL_MAGIC, 98, unsigned)
+
+#define        AUDIO_MAX_COMMON_IOCTL_NUM      100
+
+
+#define HANDSET_MIC                    0x01
+#define HANDSET_SPKR                   0x02
+#define HEADSET_MIC                    0x03
+#define HEADSET_SPKR_MONO              0x04
+#define HEADSET_SPKR_STEREO            0x05
+#define SPKR_PHONE_MIC                 0x06
+#define SPKR_PHONE_MONO                        0x07
+#define SPKR_PHONE_STEREO              0x08
+#define BT_SCO_MIC                     0x09
+#define BT_SCO_SPKR                    0x0A
+#define BT_A2DP_SPKR                   0x0B
+#define TTY_HEADSET_MIC                        0x0C
+#define TTY_HEADSET_SPKR               0x0D
+
+/* Default devices are not supported in a */
+/* device switching context. Only supported */
+/* for stream devices. */
+/* DO NOT USE */
+#define DEFAULT_TX                     0x0E
+#define DEFAULT_RX                     0x0F
+
+#define BT_A2DP_TX                     0x10
+
+#define HEADSET_MONO_PLUS_SPKR_MONO_RX         0x11
+#define HEADSET_MONO_PLUS_SPKR_STEREO_RX       0x12
+#define HEADSET_STEREO_PLUS_SPKR_MONO_RX       0x13
+#define HEADSET_STEREO_PLUS_SPKR_STEREO_RX     0x14
+
+#define I2S_RX                         0x20
+#define I2S_TX                         0x21
+
+#define ADRC_ENABLE            0x0001
+#define EQ_ENABLE              0x0002
+#define IIR_ENABLE             0x0004
+#define QCONCERT_PLUS_ENABLE   0x0008
+#define MBADRC_ENABLE          0x0010
+#define SRS_ENABLE             0x0020
+#define SRS_DISABLE    0x0040
+
+#define AGC_ENABLE             0x0001
+#define NS_ENABLE              0x0002
+#define TX_IIR_ENABLE          0x0004
+#define FLUENCE_ENABLE         0x0008
+
+#define VOC_REC_UPLINK         0x00
+#define VOC_REC_DOWNLINK       0x01
+#define VOC_REC_BOTH           0x02
+
+struct msm_audio_config {
+       uint32_t buffer_size;
+       uint32_t buffer_count;
+       uint32_t channel_count;
+       uint32_t sample_rate;
+       uint32_t type;
+       uint32_t meta_field;
+       uint32_t bits;
+       uint32_t unused[3];
+};
+
+struct msm_audio_stream_config {
+       uint32_t buffer_size;
+       uint32_t buffer_count;
+};
+
+struct msm_audio_buf_cfg{
+       uint32_t meta_info_enable;
+       uint32_t frames_per_buf;
+};
+
+struct msm_audio_stats {
+       uint32_t byte_count;
+       uint32_t sample_count;
+       uint32_t unused[2];
+};
+
+struct msm_audio_ion_info {
+       int fd;
+       void *vaddr;
+};
+
+struct msm_audio_pmem_info {
+       int fd;
+       void *vaddr;
+};
+
+struct msm_audio_aio_buf {
+       void *buf_addr;
+       uint32_t buf_len;
+       uint32_t data_len;
+       void *private_data;
+       unsigned short mfield_sz; /*only useful for data has meta field */
+};
+
+/* Audio routing */
+
+#define SND_IOCTL_MAGIC 's'
+
+#define SND_MUTE_UNMUTED 0
+#define SND_MUTE_MUTED   1
+
+struct msm_mute_info {
+       uint32_t mute;
+       uint32_t path;
+};
+
+struct msm_vol_info {
+       uint32_t vol;
+       uint32_t path;
+};
+
+struct msm_voicerec_mode {
+       uint32_t rec_mode;
+};
+
+struct msm_snd_device_config {
+       uint32_t device;
+       uint32_t ear_mute;
+       uint32_t mic_mute;
+};
+
+#define SND_SET_DEVICE _IOW(SND_IOCTL_MAGIC, 2, struct msm_device_config *)
+
+#define SND_METHOD_VOICE 0
+
+struct msm_snd_volume_config {
+       uint32_t device;
+       uint32_t method;
+       uint32_t volume;
+};
+
+#define SND_SET_VOLUME _IOW(SND_IOCTL_MAGIC, 3, struct msm_snd_volume_config *)
+
+/* Returns the number of SND endpoints supported. */
+
+#define SND_GET_NUM_ENDPOINTS _IOR(SND_IOCTL_MAGIC, 4, unsigned *)
+
+struct msm_snd_endpoint {
+       int id; /* input and output */
+       char name[64]; /* output only */
+};
+
+/* Takes an index between 0 and one less than the number returned by
+ * SND_GET_NUM_ENDPOINTS, and returns the SND index and name of a
+ * SND endpoint.  On input, the .id field contains the number of the
+ * endpoint, and on exit it contains the SND index, while .name contains
+ * the description of the endpoint.
+ */
+
+#define SND_GET_ENDPOINT _IOWR(SND_IOCTL_MAGIC, 5, struct msm_snd_endpoint *)
+
+
+#define SND_AVC_CTL _IOW(SND_IOCTL_MAGIC, 6, unsigned *)
+#define SND_AGC_CTL _IOW(SND_IOCTL_MAGIC, 7, unsigned *)
+
+struct msm_audio_pcm_config {
+       uint32_t pcm_feedback;  /* 0 - disable > 0 - enable */
+       uint32_t buffer_count;  /* Number of buffers to allocate */
+       uint32_t buffer_size;   /* Size of buffer for capturing of
+                                  PCM samples */
+};
+
+#define AUDIO_EVENT_SUSPEND 0
+#define AUDIO_EVENT_RESUME 1
+#define AUDIO_EVENT_WRITE_DONE 2
+#define AUDIO_EVENT_READ_DONE   3
+#define AUDIO_EVENT_STREAM_INFO 4
+#define AUDIO_EVENT_BITSTREAM_ERROR_INFO 5
+
+#define AUDIO_CODEC_TYPE_MP3 0
+#define AUDIO_CODEC_TYPE_AAC 1
+
+struct msm_audio_bitstream_info {
+       uint32_t codec_type;
+       uint32_t chan_info;
+       uint32_t sample_rate;
+       uint32_t bit_stream_info;
+       uint32_t bit_rate;
+       uint32_t unused[3];
+};
+
+struct msm_audio_bitstream_error_info {
+       uint32_t dec_id;
+       uint32_t err_msg_indicator;
+       uint32_t err_type;
+};
+
+union msm_audio_event_payload {
+       struct msm_audio_aio_buf aio_buf;
+       struct msm_audio_bitstream_info stream_info;
+       struct msm_audio_bitstream_error_info error_info;
+       int reserved;
+};
+
+struct msm_audio_event {
+       int event_type;
+       int timeout_ms;
+       union msm_audio_event_payload event_payload;
+};
+
+#define MSM_SNDDEV_CAP_RX 0x1
+#define MSM_SNDDEV_CAP_TX 0x2
+#define MSM_SNDDEV_CAP_VOICE 0x4
+
+struct msm_snd_device_info {
+       uint32_t dev_id;
+       uint32_t dev_cap; /* bitmask describe capability of device */
+       char dev_name[64];
+};
+
+struct msm_snd_device_list {
+       uint32_t  num_dev; /* Indicate number of device info to be retrieved */
+       struct msm_snd_device_info *list;
+};
+
+struct msm_dtmf_config {
+       uint16_t path;
+       uint16_t dtmf_hi;
+       uint16_t dtmf_low;
+       uint16_t duration;
+       uint16_t tx_gain;
+       uint16_t rx_gain;
+       uint16_t mixing;
+};
+
+#define AUDIO_ROUTE_STREAM_VOICE_RX 0
+#define AUDIO_ROUTE_STREAM_VOICE_TX 1
+#define AUDIO_ROUTE_STREAM_PLAYBACK 2
+#define AUDIO_ROUTE_STREAM_REC      3
+
+struct msm_audio_route_config {
+       uint32_t stream_type;
+       uint32_t stream_id;
+       uint32_t dev_id;
+};
+
+#define AUDIO_MAX_EQ_BANDS 12
+
+struct msm_audio_eq_band {
+       uint16_t     band_idx; /* The band index, 0 .. 11 */
+       uint32_t     filter_type; /* Filter band type */
+       uint32_t     center_freq_hz; /* Filter band center frequency */
+       uint32_t     filter_gain; /* Filter band initial gain (dB) */
+                       /* Range is +12 dB to -12 dB with 1dB increments. */
+       uint32_t     q_factor;
+} __attribute__ ((packed));
+
+struct msm_audio_eq_stream_config {
+       uint32_t        enable; /* Number of consequtive bands specified */
+       uint32_t        num_bands;
+       struct msm_audio_eq_band        eq_bands[AUDIO_MAX_EQ_BANDS];
+} __attribute__ ((packed));
+
+struct msm_acdb_cmd_device {
+       uint32_t     command_id;
+       uint32_t     device_id;
+       uint32_t     network_id;
+       uint32_t     sample_rate_id;      /* Actual sample rate value */
+       uint32_t     interface_id;        /* See interface id's above */
+       uint32_t     algorithm_block_id;  /* See enumerations above */
+       uint32_t     total_bytes;         /* Length in bytes used by buffer */
+       uint32_t     *phys_buf;           /* Physical Address of data */
+};
+
+
+#endif
diff --git a/include/linux/msm_audio_acdb.h b/include/linux/msm_audio_acdb.h
new file mode 100644 (file)
index 0000000..e7f06b5
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef __MSM_AUDIO_ACDB_H
+#define __MSM_AUDIO_ACDB_H
+
+#include <linux/msm_audio.h>
+
+#define AUDIO_SET_VOCPROC_CAL          _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+0), unsigned)
+#define AUDIO_SET_VOCPROC_STREAM_CAL   _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+1), unsigned)
+#define AUDIO_SET_VOCPROC_VOL_CAL      _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+2), unsigned)
+#define AUDIO_SET_AUDPROC_RX_CAL       _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+3), unsigned)
+#define AUDIO_SET_AUDPROC_RX_STREAM_CAL        _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+4), unsigned)
+#define AUDIO_SET_AUDPROC_RX_VOL_CAL   _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+5), unsigned)
+#define AUDIO_SET_AUDPROC_TX_CAL       _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+6), unsigned)
+#define AUDIO_SET_AUDPROC_TX_STREAM_CAL        _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+7), unsigned)
+#define AUDIO_SET_AUDPROC_TX_VOL_CAL   _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+8), unsigned)
+#define AUDIO_SET_SIDETONE_CAL         _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+9), unsigned)
+#define AUDIO_SET_ANC_CAL              _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+10), unsigned)
+#define AUDIO_SET_VOICE_RX_TOPOLOGY    _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+11), unsigned)
+#define AUDIO_SET_VOICE_TX_TOPOLOGY    _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+12), unsigned)
+#define AUDIO_SET_ADM_RX_TOPOLOGY      _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+13), unsigned)
+#define AUDIO_SET_ADM_TX_TOPOLOGY      _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+14), unsigned)
+#define AUDIO_SET_ASM_TOPOLOGY _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+15), unsigned)
+#define AUDIO_SET_AFE_TX_CAL           _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+16), unsigned)
+#define AUDIO_SET_AFE_RX_CAL           _IOW(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_COMMON_IOCTL_NUM+17), unsigned)
+
+
+#define        AUDIO_MAX_ACDB_IOCTL    (AUDIO_MAX_COMMON_IOCTL_NUM+30)
+
+/* ACDB structures */
+struct cal_block {
+       uint32_t        cal_size;       /* Size of Cal Data */
+       uint32_t        cal_offset;     /* offset pointer to Cal Data */
+};
+
+struct sidetone_cal {
+       uint16_t        enable;
+       uint16_t        gain;
+};
+
+/* For Real-Time Audio Calibration */
+#define AUDIO_GET_RTAC_ADM_INFO                _IOR(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_ACDB_IOCTL+1), unsigned)
+#define AUDIO_GET_RTAC_VOICE_INFO      _IOR(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_ACDB_IOCTL+2), unsigned)
+#define AUDIO_GET_RTAC_ADM_CAL _IOWR(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_ACDB_IOCTL+3), unsigned)
+#define AUDIO_SET_RTAC_ADM_CAL _IOWR(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_ACDB_IOCTL+4), unsigned)
+#define AUDIO_GET_RTAC_ASM_CAL _IOWR(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_ACDB_IOCTL+5), unsigned)
+#define AUDIO_SET_RTAC_ASM_CAL _IOWR(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_ACDB_IOCTL+6), unsigned)
+#define AUDIO_GET_RTAC_CVS_CAL _IOWR(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_ACDB_IOCTL+7), unsigned)
+#define AUDIO_SET_RTAC_CVS_CAL _IOWR(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_ACDB_IOCTL+8), unsigned)
+#define AUDIO_GET_RTAC_CVP_CAL _IOWR(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_ACDB_IOCTL+9), unsigned)
+#define AUDIO_SET_RTAC_CVP_CAL _IOWR(AUDIO_IOCTL_MAGIC, \
+                       (AUDIO_MAX_ACDB_IOCTL+10), unsigned)
+
+#define        AUDIO_MAX_RTAC_IOCTL    (AUDIO_MAX_ACDB_IOCTL+20)
+
+#endif /* __MSM_AUDIO_ACDB_H */
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
new file mode 100644 (file)
index 0000000..d3c8a4f
--- /dev/null
@@ -0,0 +1,1675 @@
+/*
+ *
+ * Copyright (c) 2010-2013, The Linux Foundation. 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 _APR_AUDIO_H_
+#define _APR_AUDIO_H_
+
+/* ASM opcodes without APR payloads*/
+#include <sound/qdsp6v2/apr.h>
+
+/*
+ * Audio Front End (AFE)
+ */
+
+/* Port ID. Update afe_get_port_index when a new port is added here. */
+#define PRIMARY_I2S_RX 0               /* index = 0 */
+#define PRIMARY_I2S_TX 1               /* index = 1 */
+#define PCM_RX 2                       /* index = 2 */
+#define PCM_TX 3                       /* index = 3 */
+#define SECONDARY_I2S_RX 4             /* index = 4 */
+#define SECONDARY_I2S_TX 5             /* index = 5 */
+#define MI2S_RX 6                      /* index = 6 */
+#define MI2S_TX 7                      /* index = 7 */
+#define HDMI_RX 8                      /* index = 8 */
+#define RSVD_2 9                       /* index = 9 */
+#define RSVD_3 10                      /* index = 10 */
+#define DIGI_MIC_TX 11                 /* index = 11 */
+#define VOICE_RECORD_RX 0x8003         /* index = 12 */
+#define VOICE_RECORD_TX 0x8004         /* index = 13 */
+#define VOICE_PLAYBACK_TX 0x8005       /* index = 14 */
+
+/* Slimbus Multi channel port id pool  */
+#define SLIMBUS_0_RX           0x4000          /* index = 15 */
+#define SLIMBUS_0_TX           0x4001          /* index = 16 */
+#define SLIMBUS_1_RX           0x4002          /* index = 17 */
+#define SLIMBUS_1_TX           0x4003          /* index = 18 */
+#define SLIMBUS_2_RX           0x4004
+#define SLIMBUS_2_TX           0x4005
+#define SLIMBUS_3_RX           0x4006
+#define SLIMBUS_3_TX           0x4007
+#define SLIMBUS_4_RX           0x4008
+#define SLIMBUS_4_TX           0x4009          /* index = 24 */
+
+#define INT_BT_SCO_RX 0x3000           /* index = 25 */
+#define INT_BT_SCO_TX 0x3001           /* index = 26 */
+#define INT_BT_A2DP_RX 0x3002          /* index = 27 */
+#define INT_FM_RX 0x3004               /* index = 28 */
+#define INT_FM_TX 0x3005               /* index = 29 */
+#define RT_PROXY_PORT_001_RX   0x2000    /* index = 30 */
+#define RT_PROXY_PORT_001_TX   0x2001    /* index = 31 */
+#define SECONDARY_PCM_RX 12                    /* index = 32 */
+#define SECONDARY_PCM_TX 13                    /* index = 33 */
+
+
+#define AFE_PORT_INVALID 0xFFFF
+#define SLIMBUS_EXTPROC_RX AFE_PORT_INVALID
+
+#define AFE_PORT_CMD_START 0x000100ca
+
+#define AFE_EVENT_RTPORT_START 0
+#define AFE_EVENT_RTPORT_STOP 1
+#define AFE_EVENT_RTPORT_LOW_WM 2
+#define AFE_EVENT_RTPORT_HI_WM 3
+
+struct afe_port_start_command {
+       struct apr_hdr hdr;
+       u16 port_id;
+       u16 gain;               /* Q13 */
+       u32 sample_rate;        /* 8 , 16, 48khz */
+} __attribute__ ((packed));
+
+#define AFE_PORT_CMD_STOP 0x000100cb
+struct afe_port_stop_command {
+       struct apr_hdr hdr;
+       u16 port_id;
+       u16 reserved;
+} __attribute__ ((packed));
+
+#define AFE_PORT_CMD_APPLY_GAIN 0x000100cc
+struct afe_port_gain_command {
+       struct apr_hdr hdr;
+       u16 port_id;
+       u16     gain;/* Q13 */
+} __attribute__ ((packed));
+
+#define AFE_PORT_CMD_SIDETONE_CTL 0x000100cd
+struct afe_port_sidetone_command {
+       struct apr_hdr hdr;
+       u16 rx_port_id;         /* Primary i2s tx = 1 */
+                               /* PCM tx = 3 */
+                               /* Secondary i2s tx = 5 */
+                               /* Mi2s tx = 7 */
+                               /* Digital mic tx = 11 */
+       u16 tx_port_id;         /* Primary i2s rx = 0 */
+                               /* PCM rx = 2 */
+                               /* Secondary i2s rx = 4 */
+                               /* Mi2S rx = 6 */
+                               /* HDMI rx = 8 */
+       u16 gain;               /* Q13 */
+       u16 enable;             /* 1 = enable, 0 = disable */
+} __attribute__ ((packed));
+
+#define AFE_PORT_CMD_LOOPBACK 0x000100ce
+struct afe_loopback_command {
+       struct apr_hdr hdr;
+       u16 tx_port_id;         /* Primary i2s rx = 0 */
+                               /* PCM rx = 2 */
+                               /* Secondary i2s rx = 4 */
+                               /* Mi2S rx = 6 */
+                               /* HDMI rx = 8 */
+       u16 rx_port_id;         /* Primary i2s tx = 1 */
+                               /* PCM tx = 3 */
+                               /* Secondary i2s tx = 5 */
+                               /* Mi2s tx = 7 */
+                               /* Digital mic tx = 11 */
+       u16 mode;               /* Default -1, DSP will conver
+                                       the tx to rx format */
+       u16 enable;             /* 1 = enable, 0 = disable */
+} __attribute__ ((packed));
+
+#define AFE_PSEUDOPORT_CMD_START 0x000100cf
+struct afe_pseudoport_start_command {
+       struct apr_hdr hdr;
+       u16 port_id;            /* Pseudo Port 1 = 0x8000 */
+                               /* Pseudo Port 2 = 0x8001 */
+                               /* Pseudo Port 3 = 0x8002 */
+       u16 timing;             /* FTRT = 0 , AVTimer = 1, */
+} __attribute__ ((packed));
+
+#define AFE_PSEUDOPORT_CMD_STOP 0x000100d0
+struct afe_pseudoport_stop_command {
+       struct apr_hdr hdr;
+       u16 port_id;            /* Pseudo Port 1 = 0x8000 */
+                               /* Pseudo Port 2 = 0x8001 */
+                               /* Pseudo Port 3 = 0x8002 */
+       u16 reserved;
+} __attribute__ ((packed));
+
+#define AFE_CMD_GET_ACTIVE_PORTS 0x000100d1
+
+
+#define AFE_CMD_GET_ACTIVE_HANDLES_FOR_PORT 0x000100d2
+struct afe_get_active_handles_command {
+       struct apr_hdr hdr;
+       u16 port_id;
+       u16 reserved;
+} __attribute__ ((packed));
+
+#define AFE_PCM_CFG_MODE_PCM                   0x0
+#define AFE_PCM_CFG_MODE_AUX                   0x1
+#define AFE_PCM_CFG_SYNC_EXT                   0x0
+#define AFE_PCM_CFG_SYNC_INT                   0x1
+#define AFE_PCM_CFG_FRM_8BPF                   0x0
+#define AFE_PCM_CFG_FRM_16BPF                  0x1
+#define AFE_PCM_CFG_FRM_32BPF                  0x2
+#define AFE_PCM_CFG_FRM_64BPF                  0x3
+#define AFE_PCM_CFG_FRM_128BPF                 0x4
+#define AFE_PCM_CFG_FRM_256BPF                 0x5
+#define AFE_PCM_CFG_QUANT_ALAW_NOPAD           0x0
+#define AFE_PCM_CFG_QUANT_MULAW_NOPAD          0x1
+#define AFE_PCM_CFG_QUANT_LINEAR_NOPAD         0x2
+#define AFE_PCM_CFG_QUANT_ALAW_PAD             0x3
+#define AFE_PCM_CFG_QUANT_MULAW_PAD            0x4
+#define AFE_PCM_CFG_QUANT_LINEAR_PAD           0x5
+#define AFE_PCM_CFG_CDATAOE_MASTER             0x0
+#define AFE_PCM_CFG_CDATAOE_SHARE              0x1
+
+struct afe_port_pcm_cfg {
+       u16     mode;   /* PCM (short sync) = 0, AUXPCM (long sync) = 1 */
+       u16     sync;   /* external = 0 , internal = 1 */
+       u16     frame;  /* 8 bpf = 0 */
+                       /* 16 bpf = 1 */
+                       /* 32 bpf = 2 */
+                       /* 64 bpf = 3 */
+                       /* 128 bpf = 4 */
+                       /* 256 bpf = 5 */
+       u16     quant;
+       u16     slot;   /* Slot for PCM stream , 0 - 31 */
+       u16     data;   /* 0, PCM block is the only master */
+                       /* 1, PCM block is shares to driver data out signal */
+                       /*    other master                                  */
+       u16     reserved;
+} __attribute__ ((packed));
+
+enum {
+       AFE_I2S_SD0 = 1,
+       AFE_I2S_SD1,
+       AFE_I2S_SD2,
+       AFE_I2S_SD3,
+       AFE_I2S_QUAD01,
+       AFE_I2S_QUAD23,
+       AFE_I2S_6CHS,
+       AFE_I2S_8CHS,
+};
+
+#define AFE_MI2S_MONO 0
+#define AFE_MI2S_STEREO 3
+#define AFE_MI2S_4CHANNELS 4
+#define AFE_MI2S_6CHANNELS 6
+#define AFE_MI2S_8CHANNELS 8
+
+struct afe_port_mi2s_cfg {
+       u16     bitwidth;       /* 16,24,32 */
+       u16     line;           /* Called ChannelMode in documentation */
+                               /* i2s_sd0 = 1 */
+                               /* i2s_sd1 = 2 */
+                               /* i2s_sd2 = 3 */
+                               /* i2s_sd3 = 4 */
+                               /* i2s_quad01 = 5 */
+                               /* i2s_quad23 = 6 */
+                               /* i2s_6chs = 7 */
+                               /* i2s_8chs = 8 */
+       u16     channel;        /* Called MonoStereo in documentation */
+                               /* i2s mono = 0 */
+                               /* i2s mono right = 1 */
+                               /* i2s mono left = 2 */
+                               /* i2s stereo = 3 */
+       u16     ws;             /* 0, word select signal from external source */
+                               /* 1, word select signal from internal source */
+       u16     format; /* don't touch this field if it is not for */
+                               /* AFE_PORT_CMD_I2S_CONFIG opcode */
+} __attribute__ ((packed));
+
+struct afe_port_hdmi_cfg {
+       u16     bitwidth;       /* 16,24,32 */
+       u16     channel_mode;   /* HDMI Stereo = 0 */
+                               /* HDMI_3Point1 (4-ch) = 1 */
+                               /* HDMI_5Point1 (6-ch) = 2 */
+                               /* HDMI_6Point1 (8-ch) = 3 */
+       u16     data_type;      /* HDMI_Linear = 0 */
+                               /* HDMI_non_Linear = 1 */
+} __attribute__ ((packed));
+
+
+struct afe_port_hdmi_multi_ch_cfg {
+       u16     data_type;              /* HDMI_Linear = 0 */
+                                       /* HDMI_non_Linear = 1 */
+       u16     channel_allocation;     /* The default is 0 (Stereo) */
+       u16     reserved;               /* must be set to 0 */
+} __packed;
+
+
+/* Slimbus Device Ids */
+#define AFE_SLIMBUS_DEVICE_1           0x0
+#define AFE_SLIMBUS_DEVICE_2           0x1
+#define AFE_PORT_MAX_AUDIO_CHAN_CNT    16
+
+struct afe_port_slimbus_cfg {
+       u16     slimbus_dev_id;         /* SLIMBUS Device id.*/
+
+       u16     slave_dev_pgd_la;       /* Slave ported generic device
+                                       * logical address.
+                                       */
+       u16     slave_dev_intfdev_la;   /* Slave interface device logical
+                                       * address.
+                                       */
+       u16     bit_width;              /**  bit width of the samples, 16, 24.*/
+
+       u16     data_format;            /** data format.*/
+
+       u16     num_channels;           /** Number of channels.*/
+
+       /** Slave port mapping for respective channels.*/
+       u16     slave_port_mapping[AFE_PORT_MAX_AUDIO_CHAN_CNT];
+
+       u16     reserved;
+} __packed;
+
+struct afe_port_slimbus_sch_cfg {
+       u16     slimbus_dev_id;         /* SLIMBUS Device id.*/
+       u16     bit_width;              /**  bit width of the samples, 16, 24.*/
+       u16     data_format;            /** data format.*/
+       u16     num_channels;           /** Number of channels.*/
+       u16     reserved;
+       /** Slave channel  mapping for respective channels.*/
+       u8      slave_ch_mapping[8];
+} __packed;
+
+struct afe_port_rtproxy_cfg {
+       u16     bitwidth;       /* 16,24,32 */
+       u16     interleaved;    /* interleaved = 1 */
+                               /* Noninterleaved = 0 */
+       u16     frame_sz;       /* 5ms buffers = 160bytes */
+       u16     jitter;         /* 10ms of jitter = 320 */
+       u16     lw_mark;        /* Low watermark in bytes for triggering event*/
+       u16     hw_mark;        /* High watermark bytes for triggering event*/
+       u16     rsvd;
+       int     num_ch;         /* 1 to 8 */
+} __packed;
+
+#define AFE_PORT_AUDIO_IF_CONFIG 0x000100d3
+#define AFE_PORT_AUDIO_SLIM_SCH_CONFIG 0x000100e4
+#define AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG       0x000100D9
+#define AFE_PORT_CMD_I2S_CONFIG        0x000100E7
+
+union afe_port_config {
+       struct afe_port_pcm_cfg           pcm;
+       struct afe_port_mi2s_cfg          mi2s;
+       struct afe_port_hdmi_cfg          hdmi;
+       struct afe_port_hdmi_multi_ch_cfg hdmi_multi_ch;
+       struct afe_port_slimbus_cfg       slimbus;
+       struct afe_port_slimbus_sch_cfg   slim_sch;
+       struct afe_port_rtproxy_cfg       rtproxy;
+} __attribute__((packed));
+
+struct afe_audioif_config_command {
+       struct apr_hdr hdr;
+       u16 port_id;
+       union afe_port_config port;
+} __attribute__ ((packed));
+
+#define AFE_TEST_CODEC_LOOPBACK_CTL 0x000100d5
+struct afe_codec_loopback_command {
+       u16     port_inf;       /* Primary i2s = 0 */
+                               /* PCM = 2 */
+                               /* Secondary i2s = 4 */
+                               /* Mi2s = 6 */
+       u16     enable;         /* 0, disable. 1, enable */
+} __attribute__ ((packed));
+
+
+#define AFE_PARAM_ID_SIDETONE_GAIN     0x00010300
+struct afe_param_sidetone_gain {
+       u16 gain;
+       u16 reserved;
+} __attribute__ ((packed));
+
+#define AFE_PARAM_ID_SAMPLING_RATE     0x00010301
+struct afe_param_sampling_rate {
+       u32 sampling_rate;
+} __attribute__ ((packed));
+
+
+#define AFE_PARAM_ID_CHANNELS          0x00010302
+struct afe_param_channels {
+       u16 channels;
+       u16 reserved;
+} __attribute__ ((packed));
+
+
+#define AFE_PARAM_ID_LOOPBACK_GAIN     0x00010303
+struct afe_param_loopback_gain {
+       u16 gain;
+       u16 reserved;
+} __attribute__ ((packed));
+
+/* Parameter ID used to configure and enable/disable the loopback path. The
+ * difference with respect to the existing API, AFE_PORT_CMD_LOOPBACK, is that
+ * it allows Rx port to be configured as source port in loopback path. Port-id
+ * in AFE_PORT_CMD_SET_PARAM cmd is the source port whcih can be Tx or Rx port.
+ * In addition, we can configure the type of routing mode to handle different
+ * use cases.
+*/
+enum {
+       /* Regular loopback from source to destination port */
+       LB_MODE_DEFAULT = 1,
+       /* Sidetone feed from Tx source to Rx destination port */
+       LB_MODE_SIDETONE,
+       /* Echo canceller reference, voice + audio + DTMF */
+       LB_MODE_EC_REF_VOICE_AUDIO,
+       /* Echo canceller reference, voice alone */
+       LB_MODE_EC_REF_VOICE
+};
+
+#define AFE_PARAM_ID_LOOPBACK_CONFIG 0x0001020B
+#define AFE_API_VERSION_LOOPBACK_CONFIG 0x1
+struct afe_param_loopback_cfg {
+       /* Minor version used for tracking the version of the configuration
+        * interface.
+        */
+       uint32_t loopback_cfg_minor_version;
+
+       /* Destination Port Id. */
+       uint16_t dst_port_id;
+
+       /* Specifies data path type from src to dest port. Supported values:
+        * LB_MODE_DEFAULT
+        * LB_MODE_SIDETONE
+        * LB_MODE_EC_REF_VOICE_AUDIO
+        * LB_MODE_EC_REF_VOICE
+        */
+       uint16_t routing_mode;
+
+       /* Specifies whether to enable (1) or disable (0) an AFE loopback. */
+       uint16_t enable;
+
+       /* Reserved for 32-bit alignment. This field must be set to 0. */
+       uint16_t reserved;
+} __packed;
+
+#define AFE_MODULE_ID_PORT_INFO                0x00010200
+/* Module ID for the loopback-related parameters. */
+#define AFE_MODULE_LOOPBACK           0x00010205
+struct afe_param_payload_base {
+       u32 module_id;
+       u32 param_id;
+       u16 param_size;
+       u16 reserved;
+} __packed;
+
+struct afe_param_payload {
+       struct afe_param_payload_base base;
+       union {
+               struct afe_param_sidetone_gain sidetone_gain;
+               struct afe_param_sampling_rate sampling_rate;
+               struct afe_param_channels      channels;
+               struct afe_param_loopback_gain loopback_gain;
+               struct afe_param_loopback_cfg loopback_cfg;
+       } __attribute__((packed)) param;
+} __attribute__ ((packed));
+
+#define AFE_PORT_CMD_SET_PARAM         0x000100dc
+
+struct afe_port_cmd_set_param {
+       struct apr_hdr hdr;
+       u16 port_id;
+       u16 payload_size;
+       u32 payload_address;
+       struct afe_param_payload payload;
+} __attribute__ ((packed));
+
+struct afe_port_cmd_set_param_no_payload {
+       struct apr_hdr hdr;
+       u16 port_id;
+       u16 payload_size;
+       u32 payload_address;
+} __packed;
+
+#define AFE_EVENT_GET_ACTIVE_PORTS 0x00010100
+struct afe_get_active_ports_rsp {
+       u16     num_ports;
+       u16     port_id;
+} __attribute__ ((packed));
+
+
+#define AFE_EVENT_GET_ACTIVE_HANDLES 0x00010102
+struct afe_get_active_handles_rsp {
+       u16     port_id;
+       u16     num_handles;
+       u16     mode;           /* 0, voice rx */
+                               /* 1, voice tx */
+                               /* 2, audio rx */
+                               /* 3, audio tx */
+       u16     handle;
+} __attribute__ ((packed));
+
+#define AFE_SERVICE_CMD_MEMORY_MAP 0x000100DE
+struct afe_cmd_memory_map {
+       struct apr_hdr hdr;
+       u32 phy_addr;
+       u32 mem_sz;
+       u16 mem_id;
+       u16 rsvd;
+} __packed;
+
+#define AFE_SERVICE_CMD_MEMORY_UNMAP 0x000100DF
+struct afe_cmd_memory_unmap {
+       struct apr_hdr hdr;
+       u32 phy_addr;
+} __packed;
+
+#define AFE_SERVICE_CMD_REG_RTPORT 0x000100E0
+struct afe_cmd_reg_rtport {
+       struct apr_hdr hdr;
+       u16 port_id;
+       u16 rsvd;
+} __packed;
+
+#define AFE_SERVICE_CMD_UNREG_RTPORT 0x000100E1
+struct afe_cmd_unreg_rtport {
+       struct apr_hdr hdr;
+       u16 port_id;
+       u16 rsvd;
+} __packed;
+
+#define AFE_SERVICE_CMD_RTPORT_WR 0x000100E2
+struct afe_cmd_rtport_wr {
+       struct apr_hdr hdr;
+       u16 port_id;
+       u16 rsvd;
+       u32 buf_addr;
+       u32 bytes_avail;
+} __packed;
+
+#define AFE_SERVICE_CMD_RTPORT_RD 0x000100E3
+struct afe_cmd_rtport_rd {
+       struct apr_hdr hdr;
+       u16 port_id;
+       u16 rsvd;
+       u32 buf_addr;
+       u32 bytes_avail;
+} __packed;
+
+#define AFE_EVENT_RT_PROXY_PORT_STATUS 0x00010105
+
+#define ADM_MAX_COPPS 5
+
+#define ADM_SERVICE_CMD_GET_COPP_HANDLES                 0x00010300
+struct adm_get_copp_handles_command {
+       struct apr_hdr hdr;
+} __attribute__ ((packed));
+
+#define ADM_CMD_MATRIX_MAP_ROUTINGS                      0x00010301
+struct adm_routings_session {
+       u16 id;
+       u16 num_copps;
+       u16 copp_id[ADM_MAX_COPPS+1]; /*Padding if numCopps is odd */
+} __packed;
+
+struct adm_routings_command {
+       struct apr_hdr hdr;
+       u32 path; /* 0 = Rx, 1 Tx */
+       u32 num_sessions;
+       struct adm_routings_session session[8];
+} __attribute__ ((packed));
+
+
+#define ADM_CMD_MATRIX_RAMP_GAINS                        0x00010302
+struct adm_ramp_gain {
+       struct apr_hdr hdr;
+       u16 session_id;
+       u16 copp_id;
+       u16 initial_gain;
+       u16 gain_increment;
+       u16 ramp_duration;
+       u16 reserved;
+} __attribute__ ((packed));
+
+struct adm_ramp_gains_command {
+       struct apr_hdr hdr;
+       u32 id;
+       u32 num_gains;
+       struct adm_ramp_gain gains[ADM_MAX_COPPS];
+} __attribute__ ((packed));
+
+
+#define ADM_CMD_COPP_OPEN                                0x00010304
+struct adm_copp_open_command {
+       struct apr_hdr hdr;
+       u16 flags;
+       u16 mode; /* 1-RX, 2-Live TX, 3-Non Live TX */
+       u16 endpoint_id1;
+       u16 endpoint_id2;
+       u32 topology_id;
+       u16 channel_config;
+       u16 reserved;
+       u32 rate;
+} __attribute__ ((packed));
+
+#define ADM_CMD_COPP_CLOSE                               0x00010305
+
+#define ADM_CMD_MULTI_CHANNEL_COPP_OPEN                  0x00010310
+#define ADM_CMD_MULTI_CHANNEL_COPP_OPEN_V3               0x00010333
+struct adm_multi_ch_copp_open_command {
+       struct apr_hdr hdr;
+       u16 flags;
+       u16 mode; /* 1-RX, 2-Live TX, 3-Non Live TX */
+       u16 endpoint_id1;
+       u16 endpoint_id2;
+       u32 topology_id;
+       u16 channel_config;
+       u16 reserved;
+       u32 rate;
+       u8 dev_channel_mapping[8];
+} __packed;
+#define ADM_CMD_MEMORY_MAP                             0x00010C30
+struct adm_cmd_memory_map{
+       struct apr_hdr  hdr;
+       u32             buf_add;
+       u32             buf_size;
+       u16             mempool_id;
+       u16             reserved;
+} __attribute__((packed));
+
+#define ADM_CMD_MEMORY_UNMAP                           0x00010C31
+struct adm_cmd_memory_unmap{
+       struct apr_hdr  hdr;
+       u32             buf_add;
+} __attribute__((packed));
+
+#define ADM_CMD_MEMORY_MAP_REGIONS                     0x00010C47
+struct adm_memory_map_regions{
+       u32             phys;
+       u32             buf_size;
+} __attribute__((packed));
+
+struct adm_cmd_memory_map_regions{
+       struct apr_hdr  hdr;
+       u16             mempool_id;
+       u16             nregions;
+} __attribute__((packed));
+
+#define ADM_CMD_MEMORY_UNMAP_REGIONS                   0x00010C48
+struct adm_memory_unmap_regions{
+       u32             phys;
+} __attribute__((packed));
+
+struct adm_cmd_memory_unmap_regions{
+       struct apr_hdr  hdr;
+       u16             nregions;
+       u16             reserved;
+} __attribute__((packed));
+
+#define DEFAULT_COPP_TOPOLOGY                          0x00010be3
+#define DEFAULT_POPP_TOPOLOGY                          0x00010be4
+#define VPM_TX_SM_ECNS_COPP_TOPOLOGY                   0x00010F71
+#define VPM_TX_DM_FLUENCE_COPP_TOPOLOGY                        0x00010F72
+#define VPM_TX_QMIC_FLUENCE_COPP_TOPOLOGY              0x00010F75
+
+#define LOWLATENCY_POPP_TOPOLOGY                       0x00010C68
+#define LOWLATENCY_COPP_TOPOLOGY                       0x00010312
+#define PCM_BITS_PER_SAMPLE                            16
+
+#define ASM_OPEN_WRITE_PERF_MODE_BIT                   (1<<28)
+#define ASM_OPEN_READ_PERF_MODE_BIT                    (1<<29)
+#define ADM_MULTI_CH_COPP_OPEN_PERF_MODE_BIT           (1<<13)
+
+/* SRS TRUMEDIA GUIDS */
+/* topology */
+#define SRS_TRUMEDIA_TOPOLOGY_ID                       0x00010D90
+/* module */
+#define SRS_TRUMEDIA_MODULE_ID                         0x10005010
+/* parameters */
+#define SRS_TRUMEDIA_PARAMS                            0x10005011
+#define SRS_TRUMEDIA_PARAMS_WOWHD                      0x10005012
+#define SRS_TRUMEDIA_PARAMS_CSHP                       0x10005013
+#define SRS_TRUMEDIA_PARAMS_HPF                                0x10005014
+#define SRS_TRUMEDIA_PARAMS_PEQ                                0x10005015
+#define SRS_TRUMEDIA_PARAMS_HL                         0x10005016
+
+#define ASM_MAX_EQ_BANDS 12
+
+struct asm_eq_band {
+       u32 band_idx; /* The band index, 0 .. 11 */
+       u32 filter_type; /* Filter band type */
+       u32 center_freq_hz; /* Filter band center frequency */
+       u32 filter_gain; /* Filter band initial gain (dB) */
+                       /* Range is +12 dB to -12 dB with 1dB increments. */
+       u32 q_factor;
+} __attribute__ ((packed));
+
+struct asm_equalizer_params {
+       u32 enable;
+       u32 num_bands;
+       struct asm_eq_band eq_bands[ASM_MAX_EQ_BANDS];
+} __attribute__ ((packed));
+
+struct asm_master_gain_params {
+       u16 master_gain;
+       u16 padding;
+} __attribute__ ((packed));
+
+struct asm_lrchannel_gain_params {
+       u16 left_gain;
+       u16 right_gain;
+} __attribute__ ((packed));
+
+struct asm_mute_params {
+       u32 muteflag;
+} __attribute__ ((packed));
+
+struct asm_softvolume_params {
+       u32 period;
+       u32 step;
+       u32 rampingcurve;
+} __attribute__ ((packed));
+
+struct asm_softpause_params {
+       u32 enable;
+       u32 period;
+       u32 step;
+       u32 rampingcurve;
+} __packed;
+
+struct asm_pp_param_data_hdr {
+       u32 module_id;
+       u32 param_id;
+       u16 param_size;
+       u16 reserved;
+} __attribute__ ((packed));
+
+struct asm_pp_params_command {
+       struct apr_hdr  hdr;
+       u32    *payload;
+       u32     payload_size;
+       struct  asm_pp_param_data_hdr params;
+} __attribute__ ((packed));
+
+#define EQUALIZER_MODULE_ID            0x00010c27
+#define EQUALIZER_PARAM_ID             0x00010c28
+
+#define VOLUME_CONTROL_MODULE_ID       0x00010bfe
+#define MASTER_GAIN_PARAM_ID           0x00010bff
+#define L_R_CHANNEL_GAIN_PARAM_ID      0x00010c00
+#define MUTE_CONFIG_PARAM_ID 0x00010c01
+#define SOFT_PAUSE_PARAM_ID 0x00010D6A
+#define SOFT_VOLUME_PARAM_ID 0x00010C29
+
+#define IIR_FILTER_ENABLE_PARAM_ID 0x00010c03
+#define IIR_FILTER_PREGAIN_PARAM_ID 0x00010c04
+#define IIR_FILTER_CONFIG_PARAM_ID 0x00010c05
+
+#define MBADRC_MODULE_ID 0x00010c06
+#define MBADRC_ENABLE_PARAM_ID 0x00010c07
+#define MBADRC_CONFIG_PARAM_ID 0x00010c08
+
+
+#define ADM_CMD_SET_PARAMS                               0x00010306
+#define ADM_CMD_GET_PARAMS                               0x0001030B
+#define ADM_CMDRSP_GET_PARAMS                            0x0001030C
+struct adm_set_params_command {
+       struct apr_hdr          hdr;
+       u32                     payload;
+       u32                     payload_size;
+} __attribute__ ((packed));
+
+
+#define ADM_CMD_TAP_COPP_PCM                             0x00010307
+struct adm_tap_copp_pcm_command {
+       struct apr_hdr hdr;
+} __attribute__ ((packed));
+
+
+/* QDSP6 to Client messages
+*/
+#define ADM_SERVICE_CMDRSP_GET_COPP_HANDLES              0x00010308
+struct adm_get_copp_handles_respond {
+       struct apr_hdr hdr;
+       u32 handles;
+       u32 copp_id;
+} __attribute__ ((packed));
+
+#define ADM_CMDRSP_COPP_OPEN                             0x0001030A
+struct adm_copp_open_respond {
+       u32 status;
+       u16 copp_id;
+       u16 reserved;
+} __attribute__ ((packed));
+
+#define ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN               0x00010311
+#define ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN_V3            0x00010334
+
+
+#define ASM_STREAM_PRIORITY_NORMAL     0
+#define ASM_STREAM_PRIORITY_LOW                1
+#define ASM_STREAM_PRIORITY_HIGH       2
+#define ASM_STREAM_PRIORITY_RESERVED   3
+
+#define ASM_END_POINT_DEVICE_MATRIX    0
+#define ASM_END_POINT_STREAM           1
+
+#define AAC_ENC_MODE_AAC_LC            0x02
+#define AAC_ENC_MODE_AAC_P             0x05
+#define AAC_ENC_MODE_EAAC_P            0x1D
+
+#define ASM_STREAM_CMD_CLOSE                             0x00010BCD
+#define ASM_STREAM_CMD_FLUSH                             0x00010BCE
+#define ASM_STREAM_CMD_SET_PP_PARAMS                     0x00010BCF
+#define ASM_STREAM_CMD_GET_PP_PARAMS                     0x00010BD0
+#define ASM_STREAM_CMDRSP_GET_PP_PARAMS                  0x00010BD1
+#define ASM_SESSION_CMD_PAUSE                            0x00010BD3
+#define ASM_SESSION_CMD_GET_SESSION_TIME                 0x00010BD4
+#define ASM_DATA_CMD_EOS                                 0x00010BDB
+#define ASM_DATA_EVENT_EOS                               0x00010BDD
+
+#define ASM_SERVICE_CMD_GET_STREAM_HANDLES               0x00010C0B
+#define ASM_STREAM_CMD_FLUSH_READBUFS                    0x00010C09
+
+#define ASM_SESSION_EVENT_RX_UNDERFLOW                  0x00010C17
+#define ASM_SESSION_EVENT_TX_OVERFLOW                   0x00010C18
+#define ASM_SERVICE_CMD_GET_WALLCLOCK_TIME               0x00010C19
+#define ASM_DATA_CMDRSP_EOS                              0x00010C1C
+
+/* ASM Data structures */
+
+/* common declarations */
+struct asm_pcm_cfg {
+       u16 ch_cfg;
+       u16 bits_per_sample;
+       u32 sample_rate;
+       u16 is_signed;
+       u16 interleaved;
+};
+
+#define PCM_CHANNEL_NULL 0
+
+/* Front left channel. */
+#define PCM_CHANNEL_FL    1
+
+/* Front right channel. */
+#define PCM_CHANNEL_FR    2
+
+/* Front center channel. */
+#define PCM_CHANNEL_FC    3
+
+/* Left surround channel.*/
+#define PCM_CHANNEL_LS   4
+
+/* Right surround channel.*/
+#define PCM_CHANNEL_RS   5
+
+/* Low frequency effect channel. */
+#define PCM_CHANNEL_LFE  6
+
+/* Center surround channel; Rear center channel. */
+#define PCM_CHANNEL_CS   7
+
+/* Left back channel; Rear left channel. */
+#define PCM_CHANNEL_LB   8
+
+/* Right back channel; Rear right channel. */
+#define PCM_CHANNEL_RB   9
+
+/* Top surround channel. */
+#define PCM_CHANNEL_TS   10
+
+/* Center vertical height channel.*/
+#define PCM_CHANNEL_CVH  11
+
+/* Mono surround channel.*/
+#define PCM_CHANNEL_MS   12
+
+/* Front left of center. */
+#define PCM_CHANNEL_FLC  13
+
+/* Front right of center. */
+#define PCM_CHANNEL_FRC  14
+
+/* Rear left of center. */
+#define PCM_CHANNEL_RLC  15
+
+/* Rear right of center. */
+#define PCM_CHANNEL_RRC  16
+
+#define PCM_FORMAT_MAX_NUM_CHANNEL  8
+
+/* Maximum number of channels supported
+ * in ASM_ENCDEC_DEC_CHAN_MAP command
+ */
+#define MAX_CHAN_MAP_CHANNELS 16
+/*
+ *  Multiple-channel PCM decoder format block structure used in the
+ *  #ASM_STREAM_CMD_OPEN_WRITE command.
+ *  The data must be in little-endian format.
+ */
+struct asm_multi_channel_pcm_fmt_blk {
+
+       u16 num_channels;       /*
+                                * Number of channels.
+                                * Supported values:1 to 8
+                                */
+
+       u16 bits_per_sample;    /*
+                                * Number of bits per sample per channel.
+                                * Supported values: 16, 24 When used for
+                                * playback, the client must send 24-bit
+                                * samples packed in 32-bit words. The
+                                * 24-bit samples must be placed in the most
+                                * significant 24 bits of the 32-bit word. When
+                                * used for recording, the aDSP sends 24-bit
+                                * samples packed in 32-bit words. The 24-bit
+                                * samples are placed in the most significant
+                                * 24 bits of the 32-bit word.
+                                */
+
+       u32 sample_rate;        /*
+                                * Number of samples per second
+                                * (in Hertz). Supported values:
+                                * 2000 to 48000
+                                */
+
+       u16 is_signed;          /*
+                                * Flag that indicates the samples
+                                * are signed (1).
+                                */
+
+       u16 is_interleaved;     /*
+                                * Flag that indicates whether the channels are
+                                * de-interleaved (0) or interleaved (1).
+                                * Interleaved format means corresponding
+                                * samples from the left and right channels are
+                                * interleaved within the buffer.
+                                * De-interleaved format means samples from
+                                * each channel are contiguous in the buffer.
+                                * The samples from one channel immediately
+                                * follow those of the previous channel.
+                                */
+
+       u8 channel_mapping[8];  /*
+                                * Supported values:
+                                * PCM_CHANNEL_NULL, PCM_CHANNEL_FL,
+                                * PCM_CHANNEL_FR, PCM_CHANNEL_FC,
+                                * PCM_CHANNEL_LS, PCM_CHANNEL_RS,
+                                * PCM_CHANNEL_LFE, PCM_CHANNEL_CS,
+                                * PCM_CHANNEL_LB, PCM_CHANNEL_RB,
+                                * PCM_CHANNEL_TS, PCM_CHANNEL_CVH,
+                                * PCM_CHANNEL_MS, PCM_CHANNEL_FLC,
+                                * PCM_CHANNEL_FRC, PCM_CHANNEL_RLC,
+                                * PCM_CHANNEL_RRC.
+                                * Channel[i] mapping describes channel I. Each
+                                * element i of the array describes channel I
+                                * inside the buffer where  I < num_channels.
+                                * An unused channel is set to zero.
+                                */
+};
+
+struct asm_adpcm_cfg {
+       u16 ch_cfg;
+       u16 bits_per_sample;
+       u32 sample_rate;
+       u32 block_size;
+};
+
+struct asm_yadpcm_cfg {
+       u16 ch_cfg;
+       u16 bits_per_sample;
+       u32 sample_rate;
+};
+
+struct asm_midi_cfg {
+       u32 nMode;
+};
+
+struct asm_wma_cfg {
+       u16 format_tag;
+       u16 ch_cfg;
+       u32 sample_rate;
+       u32 avg_bytes_per_sec;
+       u16 block_align;
+       u16 valid_bits_per_sample;
+       u32 ch_mask;
+       u16 encode_opt;
+       u16 adv_encode_opt;
+       u32 adv_encode_opt2;
+       u32 drc_peak_ref;
+       u32 drc_peak_target;
+       u32 drc_ave_ref;
+       u32 drc_ave_target;
+};
+
+struct asm_wmapro_cfg {
+       u16 format_tag;
+       u16 ch_cfg;
+       u32 sample_rate;
+       u32 avg_bytes_per_sec;
+       u16 block_align;
+       u16 valid_bits_per_sample;
+       u32 ch_mask;
+       u16 encode_opt;
+       u16 adv_encode_opt;
+       u32 adv_encode_opt2;
+       u32 drc_peak_ref;
+       u32 drc_peak_target;
+       u32 drc_ave_ref;
+       u32 drc_ave_target;
+};
+
+struct asm_aac_cfg {
+       u16 format;
+       u16 aot;
+       u16 ep_config;
+       u16 section_data_resilience;
+       u16 scalefactor_data_resilience;
+       u16 spectral_data_resilience;
+       u16 ch_cfg;
+       u16 reserved;
+       u32 sample_rate;
+};
+
+struct asm_amrwbplus_cfg {
+       u32  size_bytes;
+       u32  version;
+       u32  num_channels;
+       u32  amr_band_mode;
+       u32  amr_dtx_mode;
+       u32  amr_frame_fmt;
+       u32  amr_lsf_idx;
+};
+
+struct asm_flac_cfg {
+       u16 stream_info_present;
+       u16 min_blk_size;
+       u16 max_blk_size;
+       u16 ch_cfg;
+       u16 sample_size;
+       u16 sample_rate;
+       u16 md5_sum;
+       u32 ext_sample_rate;
+       u32 min_frame_size;
+       u32 max_frame_size;
+};
+
+struct asm_vorbis_cfg {
+       u32 ch_cfg;
+       u32 bit_rate;
+       u32 min_bit_rate;
+       u32 max_bit_rate;
+       u16 bit_depth_pcm_sample;
+       u16 bit_stream_format;
+};
+
+struct asm_aac_read_cfg {
+       u32 bitrate;
+       u32 enc_mode;
+       u16 format;
+       u16 ch_cfg;
+       u32 sample_rate;
+};
+
+struct asm_amrnb_read_cfg {
+       u16 mode;
+       u16 dtx_mode;
+};
+
+struct asm_amrwb_read_cfg {
+       u16 mode;
+       u16 dtx_mode;
+};
+
+struct asm_evrc_read_cfg {
+       u16 max_rate;
+       u16 min_rate;
+       u16 rate_modulation_cmd;
+       u16 reserved;
+};
+
+struct asm_qcelp13_read_cfg {
+       u16 max_rate;
+       u16 min_rate;
+       u16 reduced_rate_level;
+       u16 rate_modulation_cmd;
+};
+
+struct asm_sbc_read_cfg {
+       u32 subband;
+       u32 block_len;
+       u32 ch_mode;
+       u32 alloc_method;
+       u32 bit_rate;
+       u32 sample_rate;
+};
+
+struct asm_sbc_bitrate {
+       u32 bitrate;
+};
+
+struct asm_immed_decode {
+       u32 mode;
+};
+
+struct asm_sbr_ps {
+       u32 enable;
+};
+
+struct asm_dual_mono {
+       u16 sce_left;
+       u16 sce_right;
+};
+
+struct asm_dec_chan_map {
+       u32 num_channels;                         /* Number of decoder output
+                                                  * channels. A value of 0
+                                                  * indicates native channel
+                                                  * mapping, which is valid
+                                                  * only for NT mode. This
+                                                  * means the output of the
+                                                  * decoder is to be preserved
+                                                  * as is.
+                                                  */
+
+       u8 channel_mapping[MAX_CHAN_MAP_CHANNELS];/* Channel array of size
+                                                  * num_channels. It can grow
+                                                  * till MAX_CHAN_MAP_CHANNELS.
+                                                  * Channel[i] mapping
+                                                  * describes channel I inside
+                                                  * the decoder output buffer.
+                                                  * Valid channel mapping
+                                                  * values are to be present at
+                                                  * the beginning of the array.
+                                                  * All remaining elements of
+                                                  * the array are to be filled
+                                                  * with PCM_CHANNEL_NULL.
+                                                  */
+};
+
+struct asm_encode_cfg_blk {
+       u32 frames_per_buf;
+       u32 format_id;
+       u32 cfg_size;
+       union {
+               struct asm_pcm_cfg          pcm;
+               struct asm_aac_read_cfg     aac;
+               struct asm_amrnb_read_cfg   amrnb;
+               struct asm_evrc_read_cfg    evrc;
+               struct asm_qcelp13_read_cfg qcelp13;
+               struct asm_sbc_read_cfg     sbc;
+               struct asm_amrwb_read_cfg   amrwb;
+               struct asm_multi_channel_pcm_fmt_blk      mpcm;
+       } __attribute__((packed)) cfg;
+};
+
+struct asm_frame_meta_info {
+       u32 offset_to_frame;
+       u32 frame_size;
+       u32 encoded_pcm_samples;
+       u32 msw_ts;
+       u32 lsw_ts;
+       u32 nflags;
+};
+
+/* Stream level commands */
+#define ASM_STREAM_CMD_OPEN_READ                         0x00010BCB
+#define ASM_STREAM_CMD_OPEN_READ_V2_1                    0x00010DB2
+struct asm_stream_cmd_open_read {
+       struct apr_hdr hdr;
+       u32            uMode;
+       u32            src_endpoint;
+       u32            pre_proc_top;
+       u32            format;
+} __attribute__((packed));
+
+struct asm_stream_cmd_open_read_v2_1 {
+       struct apr_hdr hdr;
+       u32            uMode;
+       u32            src_endpoint;
+       u32            pre_proc_top;
+       u32            format;
+       u16            bits_per_sample;
+       u16            reserved;
+} __packed;
+
+/* Supported formats */
+#define LINEAR_PCM   0x00010BE5
+#define DTMF         0x00010BE6
+#define ADPCM        0x00010BE7
+#define YADPCM       0x00010BE8
+#define MP3          0x00010BE9
+#define MPEG4_AAC    0x00010BEA
+#define AMRNB_FS     0x00010BEB
+#define AMRWB_FS     0x00010BEC
+#define V13K_FS      0x00010BED
+#define EVRC_FS      0x00010BEE
+#define EVRCB_FS     0x00010BEF
+#define EVRCWB_FS    0x00010BF0
+#define MIDI         0x00010BF1
+#define SBC          0x00010BF2
+#define WMA_V10PRO   0x00010BF3
+#define WMA_V9       0x00010BF4
+#define AMR_WB_PLUS  0x00010BF5
+#define AC3_DECODER  0x00010BF6
+#define EAC3_DECODER 0x00010C3C
+#define DTS    0x00010D88
+#define DTS_LBR        0x00010DBB
+#define ATRAC  0x00010D89
+#define MAT    0x00010D8A
+#define G711_ALAW_FS 0x00010BF7
+#define G711_MLAW_FS 0x00010BF8
+#define G711_PCM_FS  0x00010BF9
+#define MPEG4_MULTI_AAC 0x00010D86
+#define US_POINT_EPOS_FORMAT 0x00012310
+#define US_RAW_FORMAT        0x0001127C
+#define MULTI_CHANNEL_PCM    0x00010C66
+
+#define ASM_ENCDEC_SBCRATE         0x00010C13
+#define ASM_ENCDEC_IMMDIATE_DECODE 0x00010C14
+#define ASM_ENCDEC_CFG_BLK         0x00010C2C
+
+#define ASM_ENCDEC_SBCRATE         0x00010C13
+#define ASM_ENCDEC_IMMDIATE_DECODE 0x00010C14
+#define ASM_ENCDEC_CFG_BLK         0x00010C2C
+
+#define ASM_STREAM_CMD_OPEN_READ_COMPRESSED               0x00010D95
+struct asm_stream_cmd_open_read_compressed {
+       struct apr_hdr hdr;
+       u32            uMode;
+       u32            frame_per_buf;
+} __packed;
+
+#define ASM_STREAM_CMD_OPEN_WRITE                        0x00010BCA
+#define ASM_STREAM_CMD_OPEN_WRITE_V2_1                   0x00010DB1
+struct asm_stream_cmd_open_write {
+       struct apr_hdr hdr;
+       u32            uMode;
+       u16            sink_endpoint;
+       u16            stream_handle;
+       u32            post_proc_top;
+       u32            format;
+} __attribute__((packed));
+
+#define IEC_61937_MASK 0x00000001
+#define IEC_60958_MASK 0x00000002
+
+#define ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED   0x00010D84
+struct asm_stream_cmd_open_write_compressed {
+       struct apr_hdr hdr;
+       u32     flags;
+       u32     format;
+} __packed;
+
+#define ASM_STREAM_CMD_OPEN_READWRITE                    0x00010BCC
+
+struct asm_stream_cmd_open_read_write {
+       struct apr_hdr     hdr;
+       u32                uMode;
+       u32                post_proc_top;
+       u32                write_format;
+       u32                read_format;
+} __attribute__((packed));
+
+#define ASM_STREAM_CMD_OPEN_LOOPBACK   0x00010D6E
+struct asm_stream_cmd_open_loopback {
+       struct apr_hdr         hdr;
+       u32                    mode_flags;
+/* Mode flags.
+ * Bit 0-31: reserved; client should set these bits to 0
+ */
+       u16                    src_endpointype;
+       /* Endpoint type. 0 = Tx Matrix */
+       u16                    sink_endpointype;
+       /* Endpoint type. 0 = Rx Matrix */
+       u32                    postprocopo_id;
+/* Postprocessor topology ID. Specifies the topology of
+ * postprocessing algorithms.
+ */
+} __packed;
+
+#define ADM_CMD_CONNECT_AFE_PORT 0x00010320
+#define ADM_CMD_DISCONNECT_AFE_PORT 0x00010321
+
+struct adm_cmd_connect_afe_port {
+       struct apr_hdr     hdr;
+       u8      mode; /*mode represent the interface is for RX or TX*/
+       u8      session_id; /*ASM session ID*/
+       u16     afe_port_id;
+} __packed;
+
+#define ADM_CMD_CONNECT_AFE_PORT_V2 0x00010332
+
+struct adm_cmd_connect_afe_port_v2 {
+       struct apr_hdr     hdr;
+       u8      mode; /*mode represent the interface is for RX or TX*/
+       u8      session_id; /*ASM session ID*/
+       u16     afe_port_id;
+       u32     num_channels;
+       u32     sampleing_rate;
+} __packed;
+
+#define ASM_STREAM_CMD_SET_ENCDEC_PARAM                  0x00010C10
+#define ASM_STREAM_CMD_GET_ENCDEC_PARAM                  0x00010C11
+#define ASM_ENCDEC_CFG_BLK_ID                           0x00010C2C
+#define ASM_ENABLE_SBR_PS                               0x00010C63
+#define ASM_CONFIGURE_DUAL_MONO                         0x00010C64
+struct asm_stream_cmd_encdec_cfg_blk{
+       struct apr_hdr              hdr;
+       u32                         param_id;
+       u32                         param_size;
+       struct asm_encode_cfg_blk   enc_blk;
+} __attribute__((packed));
+
+struct asm_stream_cmd_encdec_sbc_bitrate{
+       struct apr_hdr hdr;
+       u32            param_id;
+               struct asm_sbc_bitrate      sbc_bitrate;
+} __attribute__((packed));
+
+struct asm_stream_cmd_encdec_immed_decode{
+       struct apr_hdr hdr;
+       u32            param_id;
+       u32            param_size;
+       struct asm_immed_decode dec;
+} __attribute__((packed));
+
+struct asm_stream_cmd_encdec_sbr{
+       struct apr_hdr hdr;
+       u32            param_id;
+       u32            param_size;
+       struct asm_sbr_ps sbr_ps;
+} __attribute__((packed));
+
+struct asm_stream_cmd_encdec_dualmono {
+       struct apr_hdr hdr;
+       u32            param_id;
+       u32            param_size;
+       struct asm_dual_mono channel_map;
+} __packed;
+
+#define ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG        0x00010DD8
+
+/* Structure for AAC decoder stereo coefficient setting. */
+
+struct asm_aac_stereo_mix_coeff_selection_param {
+       struct apr_hdr                          hdr;
+       u32                                     param_id;
+       u32                                     param_size;
+       u32                                     aac_stereo_mix_coeff_flag;
+} __packed;
+
+#define ASM_ENCDEC_DEC_CHAN_MAP                                 0x00010D82
+struct asm_stream_cmd_encdec_channelmap {
+       struct apr_hdr hdr;
+       u32            param_id;
+       u32            param_size;
+       struct asm_dec_chan_map chan_map;
+} __packed;
+
+#define ASM_STREAM _CMD_ADJUST_SAMPLES                   0x00010C0A
+struct asm_stream_cmd_adjust_samples{
+       struct apr_hdr hdr;
+       u16            nsamples;
+       u16            reserved;
+} __attribute__((packed));
+
+#define ASM_STREAM_CMD_TAP_POPP_PCM                      0x00010BF9
+struct asm_stream_cmd_tap_popp_pcm{
+       struct apr_hdr hdr;
+       u16            enable;
+       u16            reserved;
+       u32            module_id;
+} __attribute__((packed));
+
+/*  Session Level commands */
+#define ASM_SESSION_CMD_MEMORY_MAP                     0x00010C32
+struct asm_stream_cmd_memory_map{
+       struct apr_hdr  hdr;
+       u32             buf_add;
+       u32             buf_size;
+       u16             mempool_id;
+       u16             reserved;
+} __attribute__((packed));
+
+#define ASM_SESSION_CMD_MEMORY_UNMAP                   0x00010C33
+struct asm_stream_cmd_memory_unmap{
+       struct apr_hdr  hdr;
+       u32             buf_add;
+} __attribute__((packed));
+
+#define ASM_SESSION_CMD_MEMORY_MAP_REGIONS             0x00010C45
+struct asm_memory_map_regions{
+       u32             phys;
+       u32             buf_size;
+} __attribute__((packed));
+
+struct asm_stream_cmd_memory_map_regions{
+       struct apr_hdr  hdr;
+       u16             mempool_id;
+       u16             nregions;
+} __attribute__((packed));
+
+#define ASM_SESSION_CMD_MEMORY_UNMAP_REGIONS           0x00010C46
+struct asm_memory_unmap_regions{
+       u32             phys;
+} __attribute__((packed));
+
+struct asm_stream_cmd_memory_unmap_regions{
+       struct apr_hdr  hdr;
+       u16             nregions;
+       u16             reserved;
+} __attribute__((packed));
+
+#define ASM_SESSION_CMD_RUN                              0x00010BD2
+struct asm_stream_cmd_run{
+       struct apr_hdr hdr;
+       u32            flags;
+       u32            msw_ts;
+       u32            lsw_ts;
+} __attribute__((packed));
+
+/* Session level events */
+#define ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS 0x00010BD5
+struct asm_stream_cmd_reg_rx_underflow_event{
+       struct apr_hdr hdr;
+       u16            enable;
+       u16            reserved;
+} __attribute__((packed));
+
+#define ASM_SESSION_CMD_REGISTER_FOR_TX_OVERFLOW_EVENTS  0x00010BD6
+struct asm_stream_cmd_reg_tx_overflow_event{
+       struct apr_hdr hdr;
+       u16            enable;
+       u16            reserved;
+} __attribute__((packed));
+
+/* Data Path commands */
+#define ASM_DATA_CMD_WRITE                               0x00010BD9
+struct asm_stream_cmd_write{
+       struct apr_hdr     hdr;
+       u32     buf_add;
+       u32     avail_bytes;
+       u32     uid;
+       u32     msw_ts;
+       u32     lsw_ts;
+       u32     uflags;
+} __attribute__((packed));
+
+#define ASM_DATA_CMD_READ                                0x00010BDA
+struct asm_stream_cmd_read{
+       struct apr_hdr     hdr;
+       u32     buf_add;
+       u32     buf_size;
+       u32     uid;
+} __attribute__((packed));
+
+#define ASM_DATA_CMD_READ_COMPRESSED                     0x00010DBF
+struct asm_stream_cmd_read_compressed {
+       struct apr_hdr     hdr;
+       u32     buf_add;
+       u32     buf_size;
+       u32     uid;
+} __packed;
+
+#define ASM_DATA_CMD_MEDIA_FORMAT_UPDATE                 0x00010BDC
+#define ASM_DATA_EVENT_ENC_SR_CM_NOTIFY                  0x00010BDE
+struct asm_stream_media_format_update{
+       struct apr_hdr hdr;
+       u32            format;
+       u32            cfg_size;
+       union {
+               struct asm_pcm_cfg         pcm_cfg;
+               struct asm_adpcm_cfg       adpcm_cfg;
+               struct asm_yadpcm_cfg      yadpcm_cfg;
+               struct asm_midi_cfg        midi_cfg;
+               struct asm_wma_cfg         wma_cfg;
+               struct asm_wmapro_cfg      wmapro_cfg;
+               struct asm_aac_cfg         aac_cfg;
+               struct asm_flac_cfg        flac_cfg;
+               struct asm_vorbis_cfg      vorbis_cfg;
+               struct asm_multi_channel_pcm_fmt_blk multi_ch_pcm_cfg;
+               struct asm_amrwbplus_cfg   amrwbplus_cfg;
+       } __attribute__((packed)) write_cfg;
+} __attribute__((packed));
+
+
+/* Command Responses */
+#define ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM               0x00010C12
+struct asm_stream_cmdrsp_get_readwrite_param{
+       struct apr_hdr hdr;
+       u32            status;
+       u32            param_id;
+       u16            param_size;
+       u16            padding;
+       union {
+               struct asm_sbc_bitrate      sbc_bitrate;
+               struct asm_immed_decode aac_dec;
+       } __attribute__((packed)) read_write_cfg;
+} __attribute__((packed));
+
+
+#define ASM_SESSION_CMDRSP_GET_SESSION_TIME              0x00010BD8
+struct asm_stream_cmdrsp_get_session_time{
+       struct apr_hdr hdr;
+       u32            status;
+       u32            msw_ts;
+       u32            lsw_ts;
+} __attribute__((packed));
+
+#define ASM_DATA_EVENT_WRITE_DONE                        0x00010BDF
+struct asm_data_event_write_done{
+       u32     buf_add;
+       u32            status;
+} __attribute__((packed));
+
+#define ASM_DATA_EVENT_READ_DONE                         0x00010BE0
+struct asm_data_event_read_done{
+       u32            status;
+       u32            buffer_add;
+       u32            enc_frame_size;
+       u32            offset;
+       u32            msw_ts;
+       u32            lsw_ts;
+       u32            flags;
+       u32            num_frames;
+       u32            id;
+} __attribute__((packed));
+
+#define ASM_DATA_EVENT_READ_COMPRESSED_DONE              0x00010DC0
+struct asm_data_event_read_compressed_done {
+       u32            status;
+       u32            buffer_add;
+       u32            enc_frame_size;
+       u32            offset;
+       u32            msw_ts;
+       u32            lsw_ts;
+       u32            flags;
+       u32            num_frames;
+       u32            id;
+} __packed;
+
+#define ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY               0x00010C65
+struct asm_data_event_sr_cm_change_notify {
+       u32            sample_rate;
+       u16                no_of_channels;
+       u16            reserved;
+       u8             channel_map[8];
+} __packed;
+
+/* service level events */
+
+#define ASM_SERVICE_CMDRSP_GET_STREAM_HANDLES            0x00010C1B
+struct asm_svc_cmdrsp_get_strm_handles{
+       struct apr_hdr hdr;
+       u32            num_handles;
+       u32            stream_handles;
+} __attribute__((packed));
+
+
+#define ASM_SERVICE_CMDRSP_GET_WALLCLOCK_TIME            0x00010C1A
+struct asm_svc_cmdrsp_get_wallclock_time{
+       struct apr_hdr hdr;
+       u32            status;
+       u32            msw_ts;
+       u32            lsw_ts;
+} __attribute__((packed));
+
+/*
+ * Error code
+*/
+#define ADSP_EOK          0x00000000 /* Success / completed / no errors. */
+#define ADSP_EFAILED      0x00000001 /* General failure. */
+#define ADSP_EBADPARAM    0x00000002 /* Bad operation parameter(s). */
+#define ADSP_EUNSUPPORTED 0x00000003 /* Unsupported routine/operation. */
+#define ADSP_EVERSION     0x00000004 /* Unsupported version. */
+#define ADSP_EUNEXPECTED  0x00000005 /* Unexpected problem encountered. */
+#define ADSP_EPANIC       0x00000006 /* Unhandled problem occurred. */
+#define ADSP_ENORESOURCE  0x00000007 /* Unable to allocate resource(s). */
+#define ADSP_EHANDLE      0x00000008 /* Invalid handle. */
+#define ADSP_EALREADY     0x00000009 /* Operation is already processed. */
+#define ADSP_ENOTREADY    0x0000000A /* Operation not ready to be processed*/
+#define ADSP_EPENDING     0x0000000B /* Operation is pending completion*/
+#define ADSP_EBUSY        0x0000000C /* Operation could not be accepted or
+                                        processed. */
+#define ADSP_EABORTED     0x0000000D /* Operation aborted due to an error. */
+#define ADSP_EPREEMPTED   0x0000000E /* Operation preempted by higher priority*/
+#define ADSP_ECONTINUE    0x0000000F /* Operation requests intervention
+                                       to complete. */
+#define ADSP_EIMMEDIATE   0x00000010 /* Operation requests immediate
+                                       intervention to complete. */
+#define ADSP_ENOTIMPL     0x00000011 /* Operation is not implemented. */
+#define ADSP_ENEEDMORE    0x00000012 /* Operation needs more data or resources*/
+
+/* SRS TRUMEDIA start */
+#define SRS_ID_GLOBAL  0x00000001
+#define SRS_ID_WOWHD   0x00000002
+#define SRS_ID_CSHP    0x00000003
+#define SRS_ID_HPF     0x00000004
+#define SRS_ID_PEQ     0x00000005
+#define SRS_ID_HL      0x00000006
+
+#define SRS_CMD_UPLOAD         0x7FFF0000
+#define SRS_PARAM_INDEX_MASK   0x80000000
+#define SRS_PARAM_OFFSET_MASK  0x3FFF0000
+#define SRS_PARAM_VALUE_MASK   0x0000FFFF
+
+struct srs_trumedia_params_GLOBAL {
+       uint8_t                  v1;
+       uint8_t                  v2;
+       uint8_t                  v3;
+       uint8_t                  v4;
+       uint8_t                  v5;
+       uint8_t                  v6;
+       uint8_t                  v7;
+       uint8_t                  v8;
+} __packed;
+
+struct srs_trumedia_params_WOWHD {
+       uint32_t                                v1;
+       uint16_t                                v2;
+       uint16_t                                v3;
+       uint16_t                                v4;
+       uint16_t                                v5;
+       uint16_t                                v6;
+       uint16_t                                v7;
+       uint16_t                                v8;
+       uint16_t                                v____A1;
+       uint32_t                                v9;
+       uint16_t                                v10;
+       uint16_t                                v11;
+       uint32_t                                v12[16];
+} __packed;
+
+struct srs_trumedia_params_CSHP {
+       uint32_t                                v1;
+       uint16_t                                v2;
+       uint16_t                                v3;
+       uint16_t                                v4;
+       uint16_t                                v5;
+       uint16_t                                v6;
+       uint16_t                                v____A1;
+       uint32_t                                v7;
+       uint16_t                                v8;
+       uint16_t                                v9;
+       uint32_t                                v10[16];
+} __packed;
+
+struct srs_trumedia_params_HPF {
+       uint32_t                                v1;
+       uint32_t                                v2[26];
+} __packed;
+
+struct srs_trumedia_params_PEQ {
+       uint32_t                                v1;
+       uint16_t                                v2;
+       uint16_t                                v3;
+       uint16_t                                v4;
+       uint16_t                                v____A1;
+       uint32_t                                v5[26];
+       uint32_t                                v6[26];
+} __packed;
+
+struct srs_trumedia_params_HL {
+       uint16_t                                v1;
+       uint16_t                                v2;
+       uint16_t                                v3;
+       uint16_t                                v____A1;
+       int32_t                                 v4;
+       uint32_t                                v5;
+       uint16_t                                v6;
+       uint16_t                                v____A2;
+       uint32_t                                v7;
+} __packed;
+
+struct srs_trumedia_params {
+       struct srs_trumedia_params_GLOBAL       global;
+       struct srs_trumedia_params_WOWHD        wowhd;
+       struct srs_trumedia_params_CSHP         cshp;
+       struct srs_trumedia_params_HPF          hpf;
+       struct srs_trumedia_params_PEQ          peq;
+       struct srs_trumedia_params_HL           hl;
+} __packed;
+int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params);
+/* SRS TruMedia end */
+
+/* SRS Studio Sound 3D start */
+#define SRS_ID_SS3D_GLOBAL     0x00000001
+#define SRS_ID_SS3D_CTRL       0x00000002
+#define SRS_ID_SS3D_FILTER     0x00000003
+
+struct srs_SS3D_params_GLOBAL {
+       uint8_t                  v1;
+       uint8_t                  v2;
+       uint8_t                  v3;
+       uint8_t                  v4;
+       uint8_t                  v5;
+       uint8_t                  v6;
+       uint8_t                  v7;
+       uint8_t                  v8;
+} __packed;
+
+struct srs_SS3D_ctrl_params {
+       uint8_t                         v[236];
+} __packed;
+
+struct srs_SS3D_filter_params {
+       uint8_t                         v[28 + 2752];
+} __packed;
+
+struct srs_SS3D_params {
+       struct srs_SS3D_params_GLOBAL   global;
+       struct srs_SS3D_ctrl_params     ss3d;
+       struct srs_SS3D_filter_params   ss3d_f;
+} __packed;
+
+int srs_ss3d_open(int port_id, int srs_tech_id, void *srs_params);
+/* SRS Studio Sound 3D end */
+#endif /*_APR_AUDIO_H_*/
diff --git a/include/sound/msm-dai-q6.h b/include/sound/msm-dai-q6.h
new file mode 100644 (file)
index 0000000..a39d3dc
--- /dev/null
@@ -0,0 +1,45 @@
+/* Copyright (c) 2011, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_DAI_Q6_PDATA_H__
+
+#define __MSM_DAI_Q6_PDATA_H__
+
+#define MSM_MI2S_SD0 (1 << 0)
+#define MSM_MI2S_SD1 (1 << 1)
+#define MSM_MI2S_SD2 (1 << 2)
+#define MSM_MI2S_SD3 (1 << 3)
+#define MSM_MI2S_CAP_RX 0
+#define MSM_MI2S_CAP_TX 1
+
+struct msm_dai_auxpcm_config {
+       u16 mode;
+       u16 sync;
+       u16 frame;
+       u16 quant;
+       u16 slot;
+       u16 data;
+       int pcm_clk_rate;
+};
+
+struct msm_mi2s_pdata {
+       u16 rx_sd_lines;
+       u16 tx_sd_lines;
+};
+
+struct msm_dai_auxpcm_pdata {
+       const char *clk;
+       struct msm_dai_auxpcm_config mode_8k;
+       struct msm_dai_auxpcm_config mode_16k;
+};
+
+#endif
diff --git a/include/sound/msm_hdmi_audio.h b/include/sound/msm_hdmi_audio.h
new file mode 100644 (file)
index 0000000..8ada49f
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __MSM_HDMI_AUDIO_H
+#define __MSM_HDMI_AUDIO_H
+
+/* Supported HDMI Audio channels */
+#define MSM_HDMI_AUDIO_CHANNEL_2               0
+#define MSM_HDMI_AUDIO_CHANNEL_4               1
+#define MSM_HDMI_AUDIO_CHANNEL_6               2
+#define MSM_HDMI_AUDIO_CHANNEL_8               3
+
+#define TRUE   1
+#define FALSE  0
+
+enum hdmi_supported_sample_rates {
+       HDMI_SAMPLE_RATE_32KHZ,
+       HDMI_SAMPLE_RATE_44_1KHZ,
+       HDMI_SAMPLE_RATE_48KHZ,
+       HDMI_SAMPLE_RATE_88_2KHZ,
+       HDMI_SAMPLE_RATE_96KHZ,
+       HDMI_SAMPLE_RATE_176_4KHZ,
+       HDMI_SAMPLE_RATE_192KHZ
+};
+
+int hdmi_audio_enable(bool on , u32 fifo_water_mark);
+int hdmi_audio_packet_enable(bool on);
+int hdmi_msm_audio_get_sample_rate(void);
+
+#if defined(CONFIG_FB_MSM_HDMI_MSM_PANEL) || defined(CONFIG_DRM_MSM)
+int hdmi_msm_audio_info_setup(bool enabled, u32 num_of_channels,
+       u32 channel_allocation, u32 level_shift, bool down_mix);
+void hdmi_msm_audio_sample_rate_reset(int rate);
+#else
+static inline int hdmi_msm_audio_info_setup(bool enabled,
+       u32 num_of_channels, u32 channel_allocation, u32 level_shift,
+       bool down_mix)
+{
+       return 0;
+}
+static inline void hdmi_msm_audio_sample_rate_reset(int rate)
+{
+}
+#endif
+#endif /* __MSM_HDMI_AUDIO_H*/
diff --git a/include/sound/q6adm.h b/include/sound/q6adm.h
new file mode 100644 (file)
index 0000000..cb3273f
--- /dev/null
@@ -0,0 +1,50 @@
+/* Copyright (c) 2010-2012, The Linux Foundation. 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 __Q6_ADM_H__
+#define __Q6_ADM_H__
+#include <sound/q6afe.h>
+
+#define ADM_PATH_PLAYBACK 0x1
+#define ADM_PATH_LIVE_REC 0x2
+#define ADM_PATH_NONLIVE_REC 0x3
+
+/* multiple copp per stream. */
+struct route_payload {
+       unsigned int copp_ids[AFE_MAX_PORTS];
+       unsigned short num_copps;
+       unsigned int session_id;
+};
+
+int adm_open(int port, int path, int rate, int mode, int topology);
+
+int adm_multi_ch_copp_open(int port, int path, int rate, int mode,
+                               int topology, int perfmode);
+
+int adm_memory_map_regions(uint32_t *buf_add, uint32_t mempool_id,
+                               uint32_t *bufsz, uint32_t bufcnt);
+
+int adm_memory_unmap_regions(uint32_t *buf_add, uint32_t *bufsz,
+                                               uint32_t bufcnt);
+
+int adm_close(int port);
+
+int adm_matrix_map(int session_id, int path, int num_copps,
+                               unsigned int *port_id, int copp_id);
+
+int adm_connect_afe_port(int mode, int session_id, int port_id);
+int adm_disconnect_afe_port(int mode, int session_id, int port_id);
+
+void adm_ec_ref_rx_id(int  port_id);
+
+int adm_get_copp_id(int port_id);
+
+#endif /* __Q6_ADM_H__ */
diff --git a/include/sound/q6afe.h b/include/sound/q6afe.h
new file mode 100644 (file)
index 0000000..1b7a790
--- /dev/null
@@ -0,0 +1,110 @@
+/* Copyright (c) 2010-2012, The Linux Foundation. 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 __Q6AFE_H__
+#define __Q6AFE_H__
+#include <sound/apr_audio.h>
+
+#define MSM_AFE_MONO        0
+#define MSM_AFE_MONO_RIGHT  1
+#define MSM_AFE_MONO_LEFT   2
+#define MSM_AFE_STEREO      3
+#define MSM_AFE_4CHANNELS   4
+#define MSM_AFE_6CHANNELS   6
+#define MSM_AFE_8CHANNELS   8
+
+#define MSM_AFE_I2S_FORMAT_LPCM                0
+#define MSM_AFE_I2S_FORMAT_COMPR               1
+#define MSM_AFE_I2S_FORMAT_IEC60958_LPCM       2
+#define MSM_AFE_I2S_FORMAT_IEC60958_COMPR      3
+
+#define MSM_AFE_PORT_TYPE_RX 0
+#define MSM_AFE_PORT_TYPE_TX 1
+
+#define RT_PROXY_DAI_001_RX    0xE0
+#define RT_PROXY_DAI_001_TX    0xF0
+#define RT_PROXY_DAI_002_RX    0xF1
+#define RT_PROXY_DAI_002_TX    0xE1
+#define VIRTUAL_ID_TO_PORTID(val) ((val & 0xF) | 0x2000)
+
+enum {
+       IDX_PRIMARY_I2S_RX = 0,
+       IDX_PRIMARY_I2S_TX = 1,
+       IDX_PCM_RX = 2,
+       IDX_PCM_TX = 3,
+       IDX_SECONDARY_I2S_RX = 4,
+       IDX_SECONDARY_I2S_TX = 5,
+       IDX_MI2S_RX = 6,
+       IDX_MI2S_TX = 7,
+       IDX_HDMI_RX = 8,
+       IDX_RSVD_2 = 9,
+       IDX_RSVD_3 = 10,
+       IDX_DIGI_MIC_TX = 11,
+       IDX_VOICE_RECORD_RX = 12,
+       IDX_VOICE_RECORD_TX = 13,
+       IDX_VOICE_PLAYBACK_TX = 14,
+       IDX_SLIMBUS_0_RX = 15,
+       IDX_SLIMBUS_0_TX = 16,
+       IDX_SLIMBUS_1_RX = 17,
+       IDX_SLIMBUS_1_TX = 18,
+       IDX_SLIMBUS_2_RX = 19,
+       IDX_SLIMBUS_2_TX = 20,
+       IDX_SLIMBUS_3_RX = 21,
+       IDX_SLIMBUS_3_TX = 22,
+       IDX_SLIMBUS_4_RX = 23,
+       IDX_SLIMBUS_4_TX = 24,
+       IDX_INT_BT_SCO_RX = 25,
+       IDX_INT_BT_SCO_TX = 26,
+       IDX_INT_BT_A2DP_RX = 27,
+       IDX_INT_FM_RX = 28,
+       IDX_INT_FM_TX = 29,
+       IDX_RT_PROXY_PORT_001_RX = 30,
+       IDX_RT_PROXY_PORT_001_TX = 31,
+       IDX_SECONDARY_PCM_RX = 32,
+       IDX_SECONDARY_PCM_TX = 33,
+       AFE_MAX_PORTS
+};
+
+int afe_open(u16 port_id, union afe_port_config *afe_config, int rate);
+int afe_close(int port_id);
+int afe_loopback(u16 enable, u16 rx_port, u16 tx_port);
+int afe_loopback_cfg(u16 enable, u16 dst_port, u16 src_port, u16 mode);
+int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain);
+int afe_loopback_gain(u16 port_id, u16 volume);
+int afe_validate_port(u16 port_id);
+int afe_get_port_index(u16 port_id);
+int afe_start_pseudo_port(u16 port_id);
+int afe_stop_pseudo_port(u16 port_id);
+int afe_cmd_memory_map(u32 dma_addr_p, u32 dma_buf_sz);
+int afe_cmd_memory_map_nowait(u32 dma_addr_p, u32 dma_buf_sz);
+int afe_cmd_memory_unmap(u32 dma_addr_p);
+int afe_cmd_memory_unmap_nowait(u32 dma_addr_p);
+
+int afe_register_get_events(u16 port_id,
+               void (*cb) (uint32_t opcode,
+               uint32_t token, uint32_t *payload, void *priv),
+               void *private_data);
+int afe_unregister_get_events(u16 port_id);
+int afe_rt_proxy_port_write(u32 buf_addr_p, int bytes);
+int afe_rt_proxy_port_read(u32 buf_addr_p, int bytes);
+int afe_port_start(u16 port_id, union afe_port_config *afe_config, u32 rate);
+int afe_port_stop_nowait(int port_id);
+int afe_apply_gain(u16 port_id, u16 gain);
+int afe_q6_interface_prepare(void);
+int afe_get_port_type(u16 port_id);
+/* if port_id is virtual, convert to physical..
+ * if port_id is already physical, return physical
+ */
+int afe_convert_virtual_to_portid(u16 port_id);
+
+int afe_pseudo_port_start_nowait(u16 port_id);
+int afe_pseudo_port_stop_nowait(u16 port_id);
+#endif /* __Q6AFE_H__ */
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
new file mode 100644 (file)
index 0000000..139b501
--- /dev/null
@@ -0,0 +1,334 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. 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 __Q6_ASM_H__
+#define __Q6_ASM_H__
+
+#include <sound/qdsp6v2/apr.h>
+#include <sound/apr_audio.h>
+
+#define IN                      0x000
+#define OUT                     0x001
+#define CH_MODE_MONO            0x001
+#define CH_MODE_STEREO          0x002
+
+#define FORMAT_LINEAR_PCM   0x0000
+#define FORMAT_DTMF         0x0001
+#define FORMAT_ADPCM       0x0002
+#define FORMAT_YADPCM       0x0003
+#define FORMAT_MP3          0x0004
+#define FORMAT_MPEG4_AAC    0x0005
+#define FORMAT_AMRNB       0x0006
+#define FORMAT_AMRWB       0x0007
+#define FORMAT_V13K        0x0008
+#define FORMAT_EVRC        0x0009
+#define FORMAT_EVRCB       0x000a
+#define FORMAT_EVRCWB      0x000b
+#define FORMAT_MIDI        0x000c
+#define FORMAT_SBC         0x000d
+#define FORMAT_WMA_V10PRO   0x000e
+#define FORMAT_WMA_V9      0x000f
+#define FORMAT_AMR_WB_PLUS  0x0010
+#define FORMAT_MPEG4_MULTI_AAC 0x0011
+#define FORMAT_MULTI_CHANNEL_LINEAR_PCM 0x0012
+#define FORMAT_AC3     0x0013
+#define FORMAT_DTS     0x0014
+#define FORMAT_EAC3    0x0015
+#define FORMAT_ATRAC   0x0016
+#define FORMAT_MAT     0x0017
+#define FORMAT_AAC     0x0018
+#define FORMAT_DTS_LBR 0x0019
+
+#define ENCDEC_SBCBITRATE   0x0001
+#define ENCDEC_IMMEDIATE_DECODE 0x0002
+#define ENCDEC_CFG_BLK          0x0003
+
+#define CMD_PAUSE          0x0001
+#define CMD_FLUSH          0x0002
+#define CMD_EOS            0x0003
+#define CMD_CLOSE          0x0004
+#define CMD_OUT_FLUSH      0x0005
+
+/* bit 0:1 represents priority of stream */
+#define STREAM_PRIORITY_NORMAL 0x0000
+#define STREAM_PRIORITY_LOW    0x0001
+#define STREAM_PRIORITY_HIGH   0x0002
+
+/* bit 4 represents META enable of encoded data buffer */
+#define BUFFER_META_ENABLE     0x0010
+
+/* Enable Sample_Rate/Channel_Mode notification event from Decoder */
+#define SR_CM_NOTIFY_ENABLE    0x0004
+
+#define TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */
+#define TUN_READ_IO_MODE  0x0004 /* tunnel read write mode */
+#define ASYNC_IO_MODE    0x0002
+#define SYNC_IO_MODE     0x0001
+#define NO_TIMESTAMP      0xFF00
+#define SET_TIMESTAMP     0x0000
+
+#define SOFT_PAUSE_ENABLE      1
+#define SOFT_PAUSE_DISABLE     0
+
+#define SESSION_MAX    0x08
+
+#define SOFT_PAUSE_PERIOD       30   /* ramp up/down for 30ms */
+#define SOFT_PAUSE_STEP_LINEAR  0    /* Step value 0ms or 0us */
+#define SOFT_PAUSE_STEP         0    /* Step value 0ms or 0us */
+enum {
+       SOFT_PAUSE_CURVE_LINEAR = 0,
+       SOFT_PAUSE_CURVE_EXP,
+       SOFT_PAUSE_CURVE_LOG,
+};
+
+#define SOFT_VOLUME_PERIOD       30   /* ramp up/down for 30ms */
+#define SOFT_VOLUME_STEP_LINEAR  0    /* Step value 0ms or 0us */
+#define SOFT_VOLUME_STEP         0    /* Step value 0ms or 0us */
+enum {
+       SOFT_VOLUME_CURVE_LINEAR = 0,
+       SOFT_VOLUME_CURVE_EXP,
+       SOFT_VOLUME_CURVE_LOG,
+};
+
+typedef void (*app_cb)(uint32_t opcode, uint32_t token,
+                       uint32_t *payload, void *priv);
+
+struct audio_buffer {
+       dma_addr_t phys;
+       void       *data;
+       uint32_t   used;
+       uint32_t   size;/* size of buffer */
+       uint32_t   actual_size; /* actual number of bytes read by DSP */
+       void *mem_buffer;
+};
+
+struct audio_aio_write_param {
+       unsigned long paddr;
+       uint32_t uid;
+       uint32_t len;
+       uint32_t msw_ts;
+       uint32_t lsw_ts;
+       uint32_t flags;
+};
+
+struct audio_aio_read_param {
+       unsigned long paddr;
+       uint32_t len;
+       uint32_t uid;
+};
+
+struct audio_port_data {
+       struct audio_buffer *buf;
+       uint32_t            max_buf_cnt;
+       uint32_t            dsp_buf;
+       uint32_t            cpu_buf;
+       /* read or write locks */
+       struct mutex        lock;
+       spinlock_t          dsp_lock;
+};
+
+struct audio_client {
+       int                    session;
+       /* idx:1 out port, 0: in port*/
+       struct audio_port_data port[2];
+
+       struct apr_svc         *apr;
+       struct mutex           cmd_lock;
+
+       atomic_t                cmd_state;
+       atomic_t                cmd_close_state;
+       atomic_t                time_flag;
+       atomic_t                nowait_cmd_cnt;
+       wait_queue_head_t       cmd_wait;
+       wait_queue_head_t       time_wait;
+
+       app_cb                  cb;
+       void                    *priv;
+       uint32_t         io_mode;
+       uint64_t         time_stamp;
+       atomic_t         cmd_response;
+       bool             perf_mode;
+};
+
+void q6asm_audio_client_free(struct audio_client *ac);
+
+struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv);
+
+struct audio_client *q6asm_get_audio_client(int session_id);
+
+int q6asm_audio_client_buf_alloc(unsigned int dir/* 1:Out,0:In */,
+                               struct audio_client *ac,
+                               unsigned int bufsz,
+                               unsigned int bufcnt);
+int q6asm_audio_client_buf_alloc_contiguous(unsigned int dir
+                               /* 1:Out,0:In */,
+                               struct audio_client *ac,
+                               unsigned int bufsz,
+                               unsigned int bufcnt);
+
+int q6asm_audio_client_buf_free_contiguous(unsigned int dir,
+                       struct audio_client *ac);
+
+int q6asm_open_read(struct audio_client *ac, uint32_t format);
+int q6asm_open_read_v2_1(struct audio_client *ac, uint32_t format);
+
+int q6asm_open_read_compressed(struct audio_client *ac,
+                        uint32_t frames_per_buffer, uint32_t meta_data_mode);
+
+int q6asm_open_write(struct audio_client *ac, uint32_t format);
+
+int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format);
+
+int q6asm_open_read_write(struct audio_client *ac,
+                       uint32_t rd_format,
+                       uint32_t wr_format);
+
+int q6asm_open_loopack(struct audio_client *ac);
+
+int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+                               uint32_t lsw_ts, uint32_t flags);
+int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+                               uint32_t lsw_ts, uint32_t flags);
+
+int q6asm_async_write(struct audio_client *ac,
+                                         struct audio_aio_write_param *param);
+
+int q6asm_async_read(struct audio_client *ac,
+                                         struct audio_aio_read_param *param);
+
+int q6asm_async_read_compressed(struct audio_client *ac,
+                                         struct audio_aio_read_param *param);
+
+int q6asm_read(struct audio_client *ac);
+int q6asm_read_nolock(struct audio_client *ac);
+
+int q6asm_memory_map(struct audio_client *ac, uint32_t buf_add,
+                       int dir, uint32_t bufsz, uint32_t bufcnt);
+
+int q6asm_memory_unmap(struct audio_client *ac, uint32_t buf_add,
+                                                       int dir);
+
+int q6asm_run(struct audio_client *ac, uint32_t flags,
+               uint32_t msw_ts, uint32_t lsw_ts);
+
+int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+               uint32_t msw_ts, uint32_t lsw_ts);
+
+int q6asm_reg_tx_overflow(struct audio_client *ac, uint16_t enable);
+
+int q6asm_cmd(struct audio_client *ac, int cmd);
+
+int q6asm_cmd_nowait(struct audio_client *ac, int cmd);
+
+void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac,
+                               uint32_t *size, uint32_t *idx);
+
+void *q6asm_is_cpu_buf_avail_nolock(int dir, struct audio_client *ac,
+                                       uint32_t *size, uint32_t *idx);
+
+int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac);
+
+/* File format specific configurations to be added below */
+
+int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
+                        uint32_t frames_per_buf,
+                       uint32_t sample_rate, uint32_t channels,
+                        uint32_t bit_rate,
+                        uint32_t mode, uint32_t format);
+
+int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
+                       uint32_t rate, uint32_t channels);
+
+int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac,
+                       uint32_t rate, uint32_t channels);
+
+int q6asm_enc_cfg_blk_multi_ch_pcm(struct audio_client *ac,
+                       uint32_t rate, uint32_t channels);
+
+int q6asm_enable_sbrps(struct audio_client *ac,
+                       uint32_t sbr_ps);
+
+int q6asm_cfg_dual_mono_aac(struct audio_client *ac,
+                       uint16_t sce_left, uint16_t sce_right);
+
+int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff);
+
+int q6asm_set_encdec_chan_map(struct audio_client *ac,
+                       uint32_t num_channels);
+
+int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
+               uint16_t min_rate, uint16_t max_rate,
+               uint16_t reduced_rate_level, uint16_t rate_modulation_cmd);
+
+int q6asm_enc_cfg_blk_evrc(struct audio_client *ac, uint32_t frames_per_buf,
+               uint16_t min_rate, uint16_t max_rate,
+               uint16_t rate_modulation_cmd);
+
+int q6asm_enc_cfg_blk_amrnb(struct audio_client *ac, uint32_t frames_per_buf,
+               uint16_t band_mode, uint16_t dtx_enable);
+
+int q6asm_enc_cfg_blk_amrwb(struct audio_client *ac, uint32_t frames_per_buf,
+               uint16_t band_mode, uint16_t dtx_enable);
+
+int q6asm_media_format_block_pcm(struct audio_client *ac,
+                       uint32_t rate, uint32_t channels);
+
+int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+                               uint32_t rate, uint32_t channels);
+
+int q6asm_media_format_block_aac(struct audio_client *ac,
+                       struct asm_aac_cfg *cfg);
+
+int q6asm_media_format_block_amrwbplus(struct audio_client *ac,
+                                       struct asm_amrwbplus_cfg *cfg);
+
+int q6asm_media_format_block_multi_aac(struct audio_client *ac,
+                       struct asm_aac_cfg *cfg);
+
+int q6asm_media_format_block_wma(struct audio_client *ac,
+                       void *cfg);
+
+int q6asm_media_format_block_wmapro(struct audio_client *ac,
+                       void *cfg);
+
+/* PP specific */
+int q6asm_equalizer(struct audio_client *ac, void *eq);
+
+/* Send Volume Command */
+int q6asm_set_volume(struct audio_client *ac, int volume);
+
+/* Set SoftPause Params */
+int q6asm_set_softpause(struct audio_client *ac,
+                       struct asm_softpause_params *param);
+
+/* Set Softvolume Params */
+int q6asm_set_softvolume(struct audio_client *ac,
+                       struct asm_softvolume_params *param);
+
+/* Send left-right channel gain */
+int q6asm_set_lrgain(struct audio_client *ac, int left_gain, int right_gain);
+
+/* Enable Mute/unmute flag */
+int q6asm_set_mute(struct audio_client *ac, int muteflag);
+
+int q6asm_get_session_time(struct audio_client *ac, uint64_t *tstamp);
+
+/* Client can set the IO mode to either AIO/SIO mode */
+int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode);
+
+/* Get Service ID for APR communication */
+int q6asm_get_apr_service_id(int session_id);
+
+/* Common format block without any payload
+*/
+int q6asm_media_format_block(struct audio_client *ac, uint32_t format);
+
+#endif /* __Q6_ASM_H__ */
diff --git a/include/sound/qdsp6v2/apr.h b/include/sound/qdsp6v2/apr.h
new file mode 100644 (file)
index 0000000..9473989
--- /dev/null
@@ -0,0 +1,169 @@
+/* Copyright (c) 2010-2011, The Linux Foundation. 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 __APR_H_
+#define __APR_H_
+
+#include <linux/mutex.h>
+
+enum apr_subsys_state {
+       APR_SUBSYS_DOWN,
+       APR_SUBSYS_UP,
+       APR_SUBSYS_LOADED,
+};
+
+struct apr_q6 {
+//     void *pil;
+       struct rproc *rproc;
+       atomic_t q6_state;
+       atomic_t modem_state;
+       struct mutex lock;
+};
+
+struct apr_hdr {
+       uint16_t hdr_field;
+       uint16_t pkt_size;
+       uint8_t src_svc;
+       uint8_t src_domain;
+       uint16_t src_port;
+       uint8_t dest_svc;
+       uint8_t dest_domain;
+       uint16_t dest_port;
+       uint32_t token;
+       uint32_t opcode;
+};
+
+#define APR_HDR_LEN(hdr_len) ((hdr_len)/4)
+#define APR_PKT_SIZE(hdr_len, payload_len) ((hdr_len) + (payload_len))
+#define APR_HDR_FIELD(msg_type, hdr_len, ver)\
+       (((msg_type & 0x3) << 8) | ((hdr_len & 0xF) << 4) | (ver & 0xF))
+
+#define APR_HDR_SIZE sizeof(struct apr_hdr)
+
+/* Version */
+#define APR_PKT_VER            0x0
+
+/* Command and Response Types */
+#define APR_MSG_TYPE_EVENT     0x0
+#define APR_MSG_TYPE_CMD_RSP   0x1
+#define APR_MSG_TYPE_SEQ_CMD   0x2
+#define APR_MSG_TYPE_NSEQ_CMD  0x3
+#define APR_MSG_TYPE_MAX       0x04
+
+/* APR Basic Response Message */
+#define APR_BASIC_RSP_RESULT 0x000110E8
+#define APR_RSP_ACCEPTED     0x000100BE
+
+/* Domain IDs */
+#define APR_DOMAIN_SIM 0x1
+#define APR_DOMAIN_PC          0x2
+#define APR_DOMAIN_MODEM       0x3
+#define APR_DOMAIN_ADSP        0x4
+#define APR_DOMAIN_APPS        0x5
+#define APR_DOMAIN_MAX 0x6
+
+/* ADSP service IDs */
+#define APR_SVC_TEST_CLIENT     0x2
+#define APR_SVC_ADSP_CORE      0x3
+#define APR_SVC_AFE            0x4
+#define APR_SVC_VSM            0x5
+#define APR_SVC_VPM            0x6
+#define APR_SVC_ASM            0x7
+#define APR_SVC_ADM            0x8
+#define APR_SVC_ADSP_MVM       0x09
+#define APR_SVC_ADSP_CVS       0x0A
+#define APR_SVC_ADSP_CVP       0x0B
+#define APR_SVC_USM            0x0C
+#define APR_SVC_MAX            0x0D
+
+/* Modem Service IDs */
+#define APR_SVC_MVS            0x3
+#define APR_SVC_MVM            0x4
+#define APR_SVC_CVS            0x5
+#define APR_SVC_CVP            0x6
+#define APR_SVC_SRD            0x7
+
+/* APR Port IDs */
+#define APR_MAX_PORTS          0x40
+
+#define APR_NAME_MAX           0x40
+
+#define RESET_EVENTS           0xFFFFFFFF
+
+#define LPASS_RESTART_EVENT    0x1000
+#define LPASS_RESTART_READY    0x1001
+
+struct apr_client_data {
+       uint16_t reset_event;
+       uint16_t reset_proc;
+       uint16_t payload_size;
+       uint16_t hdr_len;
+       uint16_t msg_type;
+       uint16_t src;
+       uint16_t dest_svc;
+       uint16_t src_port;
+       uint16_t dest_port;
+       uint32_t token;
+       uint32_t opcode;
+       void *payload;
+};
+
+typedef int32_t (*apr_fn)(struct apr_client_data *data, void *priv);
+
+struct apr_svc {
+       uint16_t id;
+       uint16_t dest_id;
+       uint16_t client_id;
+       uint8_t rvd;
+       uint8_t port_cnt;
+       uint8_t svc_cnt;
+       uint8_t need_reset;
+       apr_fn port_fn[APR_MAX_PORTS];
+       void *port_priv[APR_MAX_PORTS];
+       apr_fn fn;
+       void *priv;
+       struct mutex m_lock;
+       spinlock_t w_lock;
+};
+
+struct apr_client {
+       uint8_t id;
+       uint8_t svc_cnt;
+       uint8_t rvd;
+       struct mutex m_lock;
+       struct apr_svc_ch_dev *handle;
+       struct apr_svc svc[APR_SVC_MAX];
+};
+
+int apr_load_adsp_image(void);
+struct apr_client *apr_get_client(int dest_id, int client_id);
+int apr_wait_for_device_up(int dest_id);
+int apr_get_svc(const char *svc_name, int dest_id, int *client_id,
+               int *svc_idx, int *svc_id);
+void apr_cb_func(void *buf, int len, void *priv);
+struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
+                                       uint32_t src_port, void *priv);
+inline int apr_fill_hdr(void *handle, uint32_t *buf, uint16_t src_port,
+                       uint16_t msg_type, uint16_t dest_port,
+                       uint32_t token, uint32_t opcode, uint16_t len);
+
+int apr_send_pkt(void *handle, uint32_t *buf);
+int apr_deregister(void *handle);
+void change_q6_state(int state);
+void q6audio_dsp_not_responding(void);
+void apr_reset(void *handle);
+enum apr_subsys_state apr_get_modem_state(void);
+void apr_set_modem_state(enum apr_subsys_state state);
+enum apr_subsys_state apr_get_q6_state(void);
+int apr_set_q6_state(enum apr_subsys_state state);
+void apr_set_subsys_state(void);
+#endif
diff --git a/include/sound/qdsp6v2/apr_tal.h b/include/sound/qdsp6v2/apr_tal.h
new file mode 100644 (file)
index 0000000..69170b9
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright (c) 2010-2011, The Linux Foundation. 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 __APR_TAL_H_
+#define __APR_TAL_H_
+
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+
+/* APR Client IDs */
+#define APR_CLIENT_AUDIO       0x0
+#define APR_CLIENT_VOICE       0x1
+#define APR_CLIENT_MAX 0x2
+
+#define APR_DL_SMD    0
+#define APR_DL_MAX    1
+
+#define APR_DEST_MODEM 0
+#define APR_DEST_QDSP6 1
+#define APR_DEST_MAX   2
+
+#define APR_MAX_BUF   8192
+
+#define APR_OPEN_TIMEOUT_MS 5000
+
+typedef void (*apr_svc_cb_fn)(void *buf, int len, void *priv);
+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 apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data, int len);
+int apr_tal_close(struct apr_svc_ch_dev *apr_ch);
+struct apr_svc_ch_dev {
+       struct qcom_smd_channel *ch;
+       spinlock_t         lock;
+       apr_svc_cb_fn      func;
+       char               data[APR_MAX_BUF];
+       wait_queue_head_t  wait;
+       void               *priv;
+       wait_queue_head_t  dest;
+       uint32_t           dest_state;
+};
+
+#endif
diff --git a/include/sound/qdsp6v2/audio_acdb.h b/include/sound/qdsp6v2/audio_acdb.h
new file mode 100644 (file)
index 0000000..9af653c
--- /dev/null
@@ -0,0 +1,61 @@
+/* Copyright (c) 2010-2012, The Linux Foundation. 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_ACDB_H
+#define _AUDIO_ACDB_H
+
+#include <linux/msm_audio_acdb.h>
+#include <sound/q6adm.h>
+enum {
+       RX_CAL,
+       TX_CAL,
+       MAX_AUDPROC_TYPES
+};
+
+struct acdb_cal_block {
+       uint32_t                cal_size;
+       uint32_t                cal_kvaddr;
+       uint32_t                cal_paddr;
+};
+
+struct acdb_atomic_cal_block {
+       atomic_t                cal_size;
+       atomic_t                cal_kvaddr;
+       atomic_t                cal_paddr;
+};
+
+struct acdb_cal_data {
+       uint32_t                        num_cal_blocks;
+       struct acdb_atomic_cal_block    *cal_blocks;
+};
+
+uint32_t get_voice_rx_topology(void);
+uint32_t get_voice_tx_topology(void);
+uint32_t get_adm_rx_topology(void);
+uint32_t get_adm_tx_topology(void);
+uint32_t get_asm_topology(void);
+void get_all_voice_cal(struct acdb_cal_block *cal_block);
+void get_all_cvp_cal(struct acdb_cal_block *cal_block);
+void get_all_vocproc_cal(struct acdb_cal_block *cal_block);
+void get_all_vocstrm_cal(struct acdb_cal_block *cal_block);
+void get_all_vocvol_cal(struct acdb_cal_block *cal_block);
+void get_anc_cal(struct acdb_cal_block *cal_block);
+void get_afe_cal(int32_t path, struct acdb_cal_block *cal_block);
+void get_audproc_cal(int32_t path, struct acdb_cal_block *cal_block);
+void get_audstrm_cal(int32_t path, struct acdb_cal_block *cal_block);
+void get_audvol_cal(int32_t path, struct acdb_cal_block *cal_block);
+void get_vocproc_cal(struct acdb_cal_data *cal_data);
+void get_vocstrm_cal(struct acdb_cal_data *cal_data);
+void get_vocvol_cal(struct acdb_cal_data *cal_data);
+void get_sidetone_cal(struct sidetone_cal *cal_data);
+
+#endif
diff --git a/include/sound/qdsp6v2/audio_def.h b/include/sound/qdsp6v2/audio_def.h
new file mode 100644 (file)
index 0000000..35a4d5c
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (c) 2009,2011, The Linux Foundation. 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_QDSP5_V2_AUDIO_DEF_H
+#define _MACH_QDSP5_V2_AUDIO_DEF_H
+
+/* Define sound device capability */
+#define SNDDEV_CAP_RX 0x1 /* RX direction */
+#define SNDDEV_CAP_TX 0x2 /* TX direction */
+#define SNDDEV_CAP_VOICE 0x4 /* Support voice call */
+#define SNDDEV_CAP_PLAYBACK 0x8 /* Support playback */
+#define SNDDEV_CAP_FM 0x10 /* Support FM radio */
+#define SNDDEV_CAP_TTY 0x20 /* Support TTY */
+#define SNDDEV_CAP_ANC 0x40 /* Support ANC */
+#define SNDDEV_CAP_LB 0x80 /* Loopback */
+#define VOC_NB_INDEX   0
+#define VOC_WB_INDEX   1
+#define VOC_RX_VOL_ARRAY_NUM   2
+
+/* Device volume types . In Current deisgn only one of these are supported. */
+#define SNDDEV_DEV_VOL_DIGITAL  0x1  /* Codec Digital volume control */
+#define SNDDEV_DEV_VOL_ANALOG   0x2  /* Codec Analog volume control */
+
+#define SIDE_TONE_MASK 0x01
+
+#endif /* _MACH_QDSP5_V2_AUDIO_DEF_H */
diff --git a/include/sound/qdsp6v2/audio_dev_ctl.h b/include/sound/qdsp6v2/audio_dev_ctl.h
new file mode 100644 (file)
index 0000000..403dc6e
--- /dev/null
@@ -0,0 +1,221 @@
+/* Copyright (c) 2009-2012, The Linux Foundation. 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_H
+#define __MACH_QDSP6_V2_SNDDEV_H
+#include <sound/qdsp6v2/audio_def.h>
+#include <sound/q6afe.h>
+
+#define AUDIO_DEV_CTL_MAX_DEV 64
+#define DIR_TX 2
+#define DIR_RX 1
+
+#define DEVICE_IGNORE  0xffff
+#define COPP_IGNORE    0xffffffff
+#define SESSION_IGNORE 0x0UL
+
+/* 8 concurrent sessions with Q6 possible,  session:0
+   reserved in DSP */
+#define MAX_SESSIONS 0x09
+
+/* This represents Maximum bit needed for representing sessions
+   per clients, MAX_BIT_PER_CLIENT >= MAX_SESSIONS */
+#define MAX_BIT_PER_CLIENT 16
+
+#define VOICE_STATE_INVALID 0x0
+#define VOICE_STATE_INCALL 0x1
+#define VOICE_STATE_OFFCALL 0x2
+#define ONE_TO_MANY 1
+#define MANY_TO_ONE 2
+
+struct msm_snddev_info {
+       const char *name;
+       u32 capability;
+       u32 copp_id;
+       u32 acdb_id;
+       u32 dev_volume;
+       struct msm_snddev_ops {
+               int (*open)(struct msm_snddev_info *);
+               int (*close)(struct msm_snddev_info *);
+               int (*set_freq)(struct msm_snddev_info *, u32);
+               int (*enable_sidetone)(struct msm_snddev_info *, u32, uint16_t);
+               int (*set_device_volume)(struct msm_snddev_info *, u32);
+               int (*enable_anc)(struct msm_snddev_info *, u32);
+       } dev_ops;
+       u8 opened;
+       void *private_data;
+       bool state;
+       u32 sample_rate;
+       u32 channel_mode;
+       u32 set_sample_rate;
+       u64 sessions;
+       int usage_count;
+       s32 max_voc_rx_vol[VOC_RX_VOL_ARRAY_NUM]; /* [0] is for NB,[1] for WB */
+       s32 min_voc_rx_vol[VOC_RX_VOL_ARRAY_NUM];
+};
+
+struct msm_volume {
+       int volume; /* Volume parameter, in % Scale */
+       int pan;
+};
+
+extern struct msm_volume msm_vol_ctl;
+
+void msm_snddev_register(struct msm_snddev_info *);
+void msm_snddev_unregister(struct msm_snddev_info *);
+int msm_snddev_devcount(void);
+int msm_snddev_query(int dev_id);
+unsigned short msm_snddev_route_dec(int popp_id);
+unsigned short msm_snddev_route_enc(int enc_id);
+
+int msm_snddev_set_dec(int popp_id, int copp_id, int set,
+                                       int rate, int channel_mode);
+int msm_snddev_set_enc(int popp_id, int copp_id, int set,
+                                       int rate, int channel_mode);
+
+int msm_snddev_is_set(int popp_id, int copp_id);
+int msm_get_voc_route(u32 *rx_id, u32 *tx_id);
+int msm_set_voc_route(struct msm_snddev_info *dev_info, int stream_type,
+                       int dev_id);
+int msm_snddev_enable_sidetone(u32 dev_id, u32 enable, uint16_t gain);
+
+int msm_set_copp_id(int session_id, int copp_id);
+
+int msm_clear_copp_id(int session_id, int copp_id);
+
+int msm_clear_session_id(int session_id);
+
+int msm_reset_all_device(void);
+
+int reset_device(void);
+
+int msm_clear_all_session(void);
+
+struct msm_snddev_info *audio_dev_ctrl_find_dev(u32 dev_id);
+
+void msm_release_voc_thread(void);
+
+int snddev_voice_set_volume(int vol, int path);
+
+struct auddev_evt_voc_devinfo {
+       u32 dev_type; /* Rx or Tx */
+       u32 acdb_dev_id; /* acdb id of device */
+       u32 dev_sample;  /* Sample rate of device */
+       s32 max_rx_vol[VOC_RX_VOL_ARRAY_NUM]; /* unit is mb (milibel),
+                                               [0] is for NB, other for WB */
+       s32 min_rx_vol[VOC_RX_VOL_ARRAY_NUM]; /* unit is mb */
+       u32 dev_id; /* registered device id */
+       u32 dev_port_id;
+};
+
+struct auddev_evt_audcal_info {
+       u32 dev_id;
+       u32 acdb_id;
+       u32 sample_rate;
+       u32 dev_type;
+       u32 sessions;
+};
+
+union msm_vol_mute {
+       int vol;
+       bool mute;
+};
+
+struct auddev_evt_voc_mute_info {
+       u32 dev_type;
+       u32 acdb_dev_id;
+       u32 voice_session_id;
+       union msm_vol_mute dev_vm_val;
+};
+
+struct auddev_evt_freq_info {
+       u32 dev_type;
+       u32 acdb_dev_id;
+       u32 sample_rate;
+};
+
+union auddev_evt_data {
+       struct auddev_evt_voc_devinfo voc_devinfo;
+       struct auddev_evt_voc_mute_info voc_vm_info;
+       struct auddev_evt_freq_info freq_info;
+       u32 routing_id;
+       s32 session_vol;
+       s32 voice_state;
+       struct auddev_evt_audcal_info audcal_info;
+       u32 voice_session_id;
+};
+
+struct message_header {
+       uint32_t id;
+       uint32_t data_len;
+};
+
+#define AUDDEV_EVT_DEV_CHG_VOICE 0x01 /* device change event */
+#define AUDDEV_EVT_DEV_RDY 0x02 /* device ready event */
+#define AUDDEV_EVT_DEV_RLS 0x04 /* device released event */
+#define AUDDEV_EVT_REL_PENDING 0x08 /* device release pending */
+#define AUDDEV_EVT_DEVICE_VOL_MUTE_CHG 0x10 /* device volume changed */
+#define AUDDEV_EVT_START_VOICE 0x20 /* voice call start */
+#define AUDDEV_EVT_END_VOICE 0x40 /* voice call end */
+#define AUDDEV_EVT_STREAM_VOL_CHG 0x80 /* device volume changed */
+#define AUDDEV_EVT_FREQ_CHG 0x100 /* Change in freq */
+#define AUDDEV_EVT_VOICE_STATE_CHG 0x200 /* Change in voice state */
+
+#define AUDDEV_CLNT_VOC 0x1 /*Vocoder clients*/
+#define AUDDEV_CLNT_DEC 0x2 /*Decoder clients*/
+#define AUDDEV_CLNT_ENC 0x3 /* Encoder clients */
+#define AUDDEV_CLNT_AUDIOCAL 0x4 /* AudioCalibration client */
+
+#define AUDIO_DEV_CTL_MAX_LISTNER 20 /* Max Listeners Supported */
+
+struct msm_snd_evt_listner {
+       uint32_t evt_id;
+       uint32_t clnt_type;
+       uint32_t clnt_id;
+       void *private_data;
+       void (*auddev_evt_listener)(u32 evt_id,
+               union auddev_evt_data *evt_payload,
+               void *private_data);
+       struct msm_snd_evt_listner *cb_next;
+       struct msm_snd_evt_listner *cb_prev;
+};
+
+struct event_listner {
+       struct msm_snd_evt_listner *cb;
+       u32 num_listner;
+       int state; /* Call state */ /* TODO remove this if not req*/
+};
+
+extern struct event_listner event;
+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 auddev_unregister_evt_listner(u32 clnt_type, u32 clnt_id);
+void mixer_post_event(u32 evt_id, u32 dev_id);
+void broadcast_event(u32 evt_id, u32 dev_id, u64 session_id);
+int auddev_cfg_tx_copp_topology(int session_id, int cfg);
+int msm_snddev_request_freq(int *freq, u32 session_id,
+                       u32 capability, u32 clnt_type);
+int msm_snddev_withdraw_freq(u32 session_id,
+                       u32 capability, u32 clnt_type);
+int msm_device_is_voice(int dev_id);
+int msm_get_voc_freq(int *tx_freq, int *rx_freq);
+int msm_snddev_get_enc_freq(int session_id);
+int msm_set_voice_vol(int dir, s32 volume, u32 session_id);
+int msm_set_voice_mute(int dir, int mute, u32 session_id);
+int msm_get_voice_state(void);
+int msm_enable_incall_recording(int popp_id, int rec_mode, int rate,
+                               int channel_mode);
+int msm_disable_incall_recording(uint32_t popp_id, uint32_t rec_mode);
+#endif
diff --git a/include/sound/qdsp6v2/dsp_debug.h b/include/sound/qdsp6v2/dsp_debug.h
new file mode 100644 (file)
index 0000000..bc1cd9e
--- /dev/null
@@ -0,0 +1,22 @@
+/* Copyright (c) 2010, The Linux Foundation. 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 __DSP_DEBUG_H_
+#define __DSP_DEBUG_H_
+
+typedef int (*dsp_state_cb)(int state);
+int dsp_debug_register(dsp_state_cb ptr);
+
+#define DSP_STATE_CRASHED         0x0
+#define DSP_STATE_CRASH_DUMP_DONE 0x1
+
+#endif
diff --git a/include/sound/qdsp6v2/q6voice.h b/include/sound/qdsp6v2/q6voice.h
new file mode 100644 (file)
index 0000000..7165998
--- /dev/null
@@ -0,0 +1,778 @@
+/* Copyright (c) 2010-2011, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __QDSP6VOICE_H__
+#define __QDSP6VOICE_H__
+
+#include <mach/qdsp6v2/apr.h>
+
+/* Device Event */
+#define DEV_CHANGE_READY                0x1
+
+#define VOICE_CALL_START        0x1
+#define VOICE_CALL_END          0
+
+#define VOICE_DEV_ENABLED       0x1
+#define VOICE_DEV_DISABLED      0
+
+#define MAX_VOC_PKT_SIZE 642
+
+#define SESSION_NAME_LEN 20
+
+struct voice_header {
+       uint32_t id;
+       uint32_t data_len;
+};
+
+struct voice_init {
+       struct voice_header hdr;
+       void *cb_handle;
+};
+
+
+/* Device information payload structure */
+
+struct device_data {
+       uint32_t dev_acdb_id;
+       uint32_t volume; /* in percentage */
+       uint32_t mute;
+       uint32_t sample;
+       uint32_t enabled;
+       uint32_t dev_id;
+       uint32_t dev_port_id;
+};
+
+enum {
+       VOC_INIT = 0,
+       VOC_RUN,
+       VOC_CHANGE,
+       VOC_RELEASE,
+};
+
+/* TO MVM commands */
+#define VSS_IMVM_CMD_CREATE_PASSIVE_CONTROL_SESSION    0x000110FF
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_CREATE_FULL_CONTROL_SESSION       0x000110FE
+/* Create a new full control MVM session. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION               0x0001003C
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_ATTACH_STREAM                     0x0001123C
+/* Attach a stream to the MVM. */
+
+#define VSS_IMVM_CMD_DETACH_STREAM                     0x0001123D
+/* Detach a stream from the MVM. */
+
+#define VSS_IMVM_CMD_ATTACH_VOCPROC                    0x0001123E
+/* Attach a vocproc to the MVM. The MVM will symmetrically connect this vocproc
+ * to all the streams currently attached to it.
+ */
+
+#define VSS_IMVM_CMD_DETACH_VOCPROC                    0x0001123F
+/* Detach a vocproc from the MVM. The MVM will symmetrically disconnect this
+ * vocproc from all the streams to which it is currently attached.
+ */
+
+#define VSS_IMVM_CMD_START_VOICE                       0x00011190
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IMVM_CMD_STOP_VOICE                                0x00011192
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_ATTACH_VOCPROC                 0x000110F8
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_DETACH_VOCPROC                 0x000110F9
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+
+#define VSS_ISTREAM_CMD_SET_TTY_MODE                   0x00011196
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ICOMMON_CMD_SET_NETWORK                    0x0001119C
+/* Set the network type. */
+
+#define VSS_ICOMMON_CMD_SET_VOICE_TIMING               0x000111E0
+/* Set the voice timing parameters. */
+
+struct vss_imvm_cmd_create_control_session_t {
+       char name[SESSION_NAME_LEN];
+       /*
+        * A variable-sized stream name.
+        *
+        * The stream name size is the payload size minus the size of the other
+        * fields.
+        */
+} __packed;
+
+struct vss_istream_cmd_set_tty_mode_t {
+       uint32_t mode;
+       /**<
+       * TTY mode.
+       *
+       * 0 : TTY disabled
+       * 1 : HCO
+       * 2 : VCO
+       * 3 : FULL
+       */
+} __attribute__((packed));
+
+struct vss_istream_cmd_attach_vocproc_t {
+       uint16_t handle;
+       /**< Handle of vocproc being attached. */
+} __attribute__((packed));
+
+struct vss_istream_cmd_detach_vocproc_t {
+       uint16_t handle;
+       /**< Handle of vocproc being detached. */
+} __attribute__((packed));
+
+struct vss_imvm_cmd_attach_stream_t {
+       uint16_t handle;
+       /* The stream handle to attach. */
+} __attribute__((packed));
+
+struct vss_imvm_cmd_detach_stream_t {
+       uint16_t handle;
+       /* The stream handle to detach. */
+} __attribute__((packed));
+
+struct vss_icommon_cmd_set_network_t {
+       uint32_t network_id;
+       /* Network ID. (Refer to VSS_NETWORK_ID_XXX). */
+} __attribute__((packed));
+
+struct vss_icommon_cmd_set_voice_timing_t {
+       uint16_t mode;
+       /*
+        * The vocoder frame synchronization mode.
+        *
+        * 0 : No frame sync.
+        * 1 : Hard VFR (20ms Vocoder Frame Reference interrupt).
+        */
+       uint16_t enc_offset;
+       /*
+        * The offset in microseconds from the VFR to deliver a Tx vocoder
+        * packet. The offset should be less than 20000us.
+        */
+       uint16_t dec_req_offset;
+       /*
+        * The offset in microseconds from the VFR to request for an Rx vocoder
+        * packet. The offset should be less than 20000us.
+        */
+       uint16_t dec_offset;
+       /*
+        * The offset in microseconds from the VFR to indicate the deadline to
+        * receive an Rx vocoder packet. The offset should be less than 20000us.
+        * Rx vocoder packets received after this deadline are not guaranteed to
+        * be processed.
+        */
+} __attribute__((packed));
+
+struct mvm_attach_vocproc_cmd {
+       struct apr_hdr hdr;
+       struct vss_istream_cmd_attach_vocproc_t mvm_attach_cvp_handle;
+} __attribute__((packed));
+
+struct mvm_detach_vocproc_cmd {
+       struct apr_hdr hdr;
+       struct vss_istream_cmd_detach_vocproc_t mvm_detach_cvp_handle;
+} __attribute__((packed));
+
+struct mvm_create_ctl_session_cmd {
+       struct apr_hdr hdr;
+       struct vss_imvm_cmd_create_control_session_t mvm_session;
+} __packed;
+
+struct mvm_set_tty_mode_cmd {
+       struct apr_hdr hdr;
+       struct vss_istream_cmd_set_tty_mode_t tty_mode;
+} __attribute__((packed));
+
+struct mvm_attach_stream_cmd {
+       struct apr_hdr hdr;
+       struct vss_imvm_cmd_attach_stream_t attach_stream;
+} __attribute__((packed));
+
+struct mvm_detach_stream_cmd {
+       struct apr_hdr hdr;
+       struct vss_imvm_cmd_detach_stream_t detach_stream;
+} __attribute__((packed));
+
+struct mvm_set_network_cmd {
+       struct apr_hdr hdr;
+       struct vss_icommon_cmd_set_network_t network;
+} __attribute__((packed));
+
+struct mvm_set_voice_timing_cmd {
+       struct apr_hdr hdr;
+       struct vss_icommon_cmd_set_voice_timing_t timing;
+} __attribute__((packed));
+
+/* TO CVS commands */
+#define VSS_ISTREAM_CMD_CREATE_PASSIVE_CONTROL_SESSION 0x00011140
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_ISTREAM_CMD_CREATE_FULL_CONTROL_SESSION    0x000110F7
+/* Create a new full control stream session. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION               0x0001003C
+
+#define VSS_ISTREAM_CMD_CACHE_CALIBRATION_DATA         0x000110FB
+
+#define VSS_ISTREAM_CMD_SET_MUTE                       0x00011022
+
+#define VSS_ISTREAM_CMD_SET_MEDIA_TYPE                 0x00011186
+/* Set media type on the stream. */
+
+#define VSS_ISTREAM_EVT_SEND_ENC_BUFFER                        0x00011015
+/* Event sent by the stream to its client to provide an encoded packet. */
+
+#define VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER             0x00011017
+/* Event sent by the stream to its client requesting for a decoder packet.
+ * The client should respond with a VSS_ISTREAM_EVT_SEND_DEC_BUFFER event.
+ */
+
+#define VSS_ISTREAM_EVT_SEND_DEC_BUFFER                        0x00011016
+/* Event sent by the client to the stream in response to a
+ * VSS_ISTREAM_EVT_REQUEST_DEC_BUFFER event, providing a decoder packet.
+ */
+
+#define VSS_ISTREAM_CMD_VOC_AMR_SET_ENC_RATE           0x0001113E
+/* Set AMR encoder rate. */
+
+#define VSS_ISTREAM_CMD_VOC_AMRWB_SET_ENC_RATE         0x0001113F
+/* Set AMR-WB encoder rate. */
+
+#define VSS_ISTREAM_CMD_CDMA_SET_ENC_MINMAX_RATE       0x00011019
+/* Set encoder minimum and maximum rate. */
+
+#define VSS_ISTREAM_CMD_SET_ENC_DTX_MODE               0x0001101D
+/* Set encoder DTX mode. */
+
+#define VSS_ISTREAM_CMD_START_RECORD                   0x00011236
+/* Start in-call conversation recording. */
+
+#define VSS_ISTREAM_CMD_STOP_RECORD                    0x00011237
+/* Stop in-call conversation recording. */
+
+#define VSS_ISTREAM_CMD_START_PLAYBACK                 0x00011238
+/* Start in-call music delivery on the Tx voice path. */
+
+#define VSS_ISTREAM_CMD_STOP_PLAYBACK                  0x00011239
+/* Stop the in-call music delivery on the Tx voice path. */
+
+struct vss_istream_cmd_create_passive_control_session_t {
+       char name[SESSION_NAME_LEN];
+       /**<
+       * A variable-sized stream name.
+       *
+       * The stream name size is the payload size minus the size of the other
+       * fields.
+       */
+} __attribute__((packed));
+
+struct vss_istream_cmd_set_mute_t {
+       uint16_t direction;
+       /**<
+       * 0 : TX only
+       * 1 : RX only
+       * 2 : TX and Rx
+       */
+       uint16_t mute_flag;
+       /**<
+       * Mute, un-mute.
+       *
+       * 0 : Silence disable
+       * 1 : Silence enable
+       * 2 : CNG enable. Applicable to TX only. If set on RX behavior
+       *     will be the same as 1
+       */
+} __attribute__((packed));
+
+struct vss_istream_cmd_create_full_control_session_t {
+       uint16_t direction;
+       /*
+        * Stream direction.
+        *
+        * 0 : TX only
+        * 1 : RX only
+        * 2 : TX and RX
+        * 3 : TX and RX loopback
+        */
+       uint32_t enc_media_type;
+       /* Tx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+       uint32_t dec_media_type;
+       /* Rx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+       uint32_t network_id;
+       /* Network ID. (Refer to VSS_NETWORK_ID_XXX). */
+       char name[SESSION_NAME_LEN];
+       /*
+        * A variable-sized stream name.
+        *
+        * The stream name size is the payload size minus the size of the other
+        * fields.
+        */
+} __attribute__((packed));
+
+struct vss_istream_cmd_set_media_type_t {
+       uint32_t rx_media_id;
+       /* Set the Rx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+       uint32_t tx_media_id;
+       /* Set the Tx vocoder type. (Refer to VSS_MEDIA_ID_XXX). */
+} __attribute__((packed));
+
+struct vss_istream_evt_send_enc_buffer_t {
+       uint32_t media_id;
+      /* Media ID of the packet. */
+       uint8_t packet_data[MAX_VOC_PKT_SIZE];
+      /* Packet data buffer. */
+} __attribute__((packed));
+
+struct vss_istream_evt_send_dec_buffer_t {
+       uint32_t media_id;
+      /* Media ID of the packet. */
+       uint8_t packet_data[MAX_VOC_PKT_SIZE];
+      /* Packet data. */
+} __attribute__((packed));
+
+struct vss_istream_cmd_voc_amr_set_enc_rate_t {
+       uint32_t mode;
+       /* Set the AMR encoder rate.
+        *
+        * 0x00000000 : 4.75 kbps
+        * 0x00000001 : 5.15 kbps
+        * 0x00000002 : 5.90 kbps
+        * 0x00000003 : 6.70 kbps
+        * 0x00000004 : 7.40 kbps
+        * 0x00000005 : 7.95 kbps
+        * 0x00000006 : 10.2 kbps
+        * 0x00000007 : 12.2 kbps
+        */
+} __attribute__((packed));
+
+struct vss_istream_cmd_voc_amrwb_set_enc_rate_t {
+       uint32_t mode;
+       /* Set the AMR-WB encoder rate.
+        *
+        * 0x00000000 :  6.60 kbps
+        * 0x00000001 :  8.85 kbps
+        * 0x00000002 : 12.65 kbps
+        * 0x00000003 : 14.25 kbps
+        * 0x00000004 : 15.85 kbps
+        * 0x00000005 : 18.25 kbps
+        * 0x00000006 : 19.85 kbps
+        * 0x00000007 : 23.05 kbps
+        * 0x00000008 : 23.85 kbps
+        */
+} __attribute__((packed));
+
+struct vss_istream_cmd_cdma_set_enc_minmax_rate_t {
+       uint16_t min_rate;
+       /* Set the lower bound encoder rate.
+        *
+        * 0x0000 : Blank frame
+        * 0x0001 : Eighth rate
+        * 0x0002 : Quarter rate
+        * 0x0003 : Half rate
+        * 0x0004 : Full rate
+        */
+       uint16_t max_rate;
+       /* Set the upper bound encoder rate.
+        *
+        * 0x0000 : Blank frame
+        * 0x0001 : Eighth rate
+        * 0x0002 : Quarter rate
+        * 0x0003 : Half rate
+        * 0x0004 : Full rate
+        */
+} __attribute__((packed));
+
+struct vss_istream_cmd_set_enc_dtx_mode_t {
+       uint32_t enable;
+       /* Toggle DTX on or off.
+        *
+        * 0 : Disables DTX
+        * 1 : Enables DTX
+        */
+} __attribute__((packed));
+
+#define VSS_TAP_POINT_NONE                             0x00010F78
+/* Indicates no tapping for specified path. */
+
+#define VSS_TAP_POINT_STREAM_END                       0x00010F79
+/* Indicates that specified path should be tapped at the end of the stream. */
+
+struct vss_istream_cmd_start_record_t {
+       uint32_t rx_tap_point;
+       /* Tap point to use on the Rx path. Supported values are:
+        * VSS_TAP_POINT_NONE : Do not record Rx path.
+        * VSS_TAP_POINT_STREAM_END : Rx tap point is at the end of the stream.
+        */
+       uint32_t tx_tap_point;
+       /* Tap point to use on the Tx path. Supported values are:
+        * VSS_TAP_POINT_NONE : Do not record tx path.
+        * VSS_TAP_POINT_STREAM_END : Tx tap point is at the end of the stream.
+        */
+} __attribute__((packed));
+
+struct cvs_create_passive_ctl_session_cmd {
+       struct apr_hdr hdr;
+       struct vss_istream_cmd_create_passive_control_session_t cvs_session;
+} __attribute__((packed));
+
+struct cvs_create_full_ctl_session_cmd {
+       struct apr_hdr hdr;
+       struct vss_istream_cmd_create_full_control_session_t cvs_session;
+} __attribute__((packed));
+
+struct cvs_destroy_session_cmd {
+       struct apr_hdr hdr;
+} __attribute__((packed));
+
+struct cvs_cache_calibration_data_cmd {
+       struct apr_hdr hdr;
+} __attribute__ ((packed));
+
+struct cvs_set_mute_cmd {
+       struct apr_hdr hdr;
+       struct vss_istream_cmd_set_mute_t cvs_set_mute;
+} __attribute__((packed));
+
+struct cvs_set_media_type_cmd {
+       struct apr_hdr hdr;
+       struct vss_istream_cmd_set_media_type_t media_type;
+} __attribute__((packed));
+
+struct cvs_send_dec_buf_cmd {
+       struct apr_hdr hdr;
+       struct vss_istream_evt_send_dec_buffer_t dec_buf;
+} __attribute__((packed));
+
+struct cvs_set_amr_enc_rate_cmd {
+       struct apr_hdr hdr;
+       struct vss_istream_cmd_voc_amr_set_enc_rate_t amr_rate;
+} __attribute__((packed));
+
+struct cvs_set_amrwb_enc_rate_cmd {
+       struct apr_hdr hdr;
+       struct vss_istream_cmd_voc_amrwb_set_enc_rate_t amrwb_rate;
+} __attribute__((packed));
+
+struct cvs_set_cdma_enc_minmax_rate_cmd {
+       struct apr_hdr hdr;
+       struct vss_istream_cmd_cdma_set_enc_minmax_rate_t cdma_rate;
+} __attribute__((packed));
+
+struct cvs_set_enc_dtx_mode_cmd {
+       struct apr_hdr hdr;
+       struct vss_istream_cmd_set_enc_dtx_mode_t dtx_mode;
+} __attribute__((packed));
+
+struct cvs_start_record_cmd {
+               struct apr_hdr hdr;
+               struct vss_istream_cmd_start_record_t rec_mode;
+} __attribute__((packed));
+
+/* TO CVP commands */
+
+#define VSS_IVOCPROC_CMD_CREATE_FULL_CONTROL_SESSION   0x000100C3
+/**< Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define APRV2_IBASIC_CMD_DESTROY_SESSION               0x0001003C
+
+#define VSS_IVOCPROC_CMD_SET_DEVICE                    0x000100C4
+
+#define VSS_IVOCPROC_CMD_CACHE_CALIBRATION_DATA                0x000110E3
+
+#define VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE        0x000110E4
+
+#define VSS_IVOCPROC_CMD_SET_VP3_DATA                  0x000110EB
+
+#define VSS_IVOCPROC_CMD_SET_RX_VOLUME_INDEX           0x000110EE
+
+#define VSS_IVOCPROC_CMD_ENABLE                                0x000100C6
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IVOCPROC_CMD_DISABLE                       0x000110E1
+/**< No payload. Wait for APRV2_IBASIC_RSP_RESULT response. */
+
+#define VSS_IVOCPROC_TOPOLOGY_ID_NONE                  0x00010F70
+#define VSS_IVOCPROC_TOPOLOGY_ID_TX_SM_ECNS            0x00010F71
+#define VSS_IVOCPROC_TOPOLOGY_ID_TX_DM_FLUENCE         0x00010F72
+
+#define VSS_IVOCPROC_TOPOLOGY_ID_RX_DEFAULT            0x00010F77
+
+/* Newtwork IDs */
+#define VSS_NETWORK_ID_DEFAULT                         0x00010037
+#define VSS_NETWORK_ID_VOIP_NB                         0x00011240
+#define VSS_NETWORK_ID_VOIP_WB                         0x00011241
+#define VSS_NETWORK_ID_VOIP_WV                         0x00011242
+
+/* Media types */
+#define VSS_MEDIA_ID_13K_MODEM         0x00010FC1
+/* Qcelp vocoder modem format */
+#define VSS_MEDIA_ID_EVRC_MODEM                0x00010FC2
+/* 80-VF690-47 CDMA enhanced variable rate vocoder modem format. */
+#define VSS_MEDIA_ID_4GV_NB_MODEM  0x00010FC3
+/* 4GV Narrowband modem format */
+#define VSS_MEDIA_ID_4GV_WB_MODEM  0x00010FC4
+/* 4GV Wideband modem format */
+#define VSS_MEDIA_ID_AMR_NB_MODEM      0x00010FC6
+/* 80-VF690-47 UMTS AMR-NB vocoder modem format. */
+#define VSS_MEDIA_ID_AMR_WB_MODEM      0x00010FC7
+/* 80-VF690-47 UMTS AMR-WB vocoder modem format. */
+#define VSS_MEDIA_ID_EFR_MODEM         0x00010FC8
+/*EFR modem format */
+#define VSS_MEDIA_ID_FR_MODEM          0x00010FC9
+/*FR modem format */
+#define VSS_MEDIA_ID_HR_MODEM          0x00010FCA
+/*HR modem format */
+#define VSS_MEDIA_ID_PCM_NB            0x00010FCB
+/* Linear PCM (16-bit, little-endian). */
+#define VSS_MEDIA_ID_PCM_WB            0x00010FCC
+/* Linear wideband PCM vocoder modem format (16 bits, little endian). */
+#define VSS_MEDIA_ID_G711_ALAW         0x00010FCD
+/* G.711 a-law (contains two 10ms vocoder frames). */
+#define VSS_MEDIA_ID_G711_MULAW                0x00010FCE
+/* G.711 mu-law (contains two 10ms vocoder frames). */
+#define VSS_MEDIA_ID_G729              0x00010FD0
+/* G.729AB (contains two 10ms vocoder frames. */
+
+#define VOICE_CMD_SET_PARAM                            0x00011006
+#define VOICE_CMD_GET_PARAM                            0x00011007
+#define VOICE_EVT_GET_PARAM_ACK                                0x00011008
+
+struct vss_ivocproc_cmd_create_full_control_session_t {
+       uint16_t direction;
+       /*
+        * stream direction.
+        * 0 : TX only
+        * 1 : RX only
+        * 2 : TX and RX
+        */
+       uint32_t tx_port_id;
+       /*
+        * TX device port ID which vocproc will connect to. If not supplying a
+        * port ID set to VSS_IVOCPROC_PORT_ID_NONE.
+        */
+       uint32_t tx_topology_id;
+       /*
+        * Tx leg topology ID. If not supplying a topology ID set to
+        * VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+        */
+       uint32_t rx_port_id;
+       /*
+        * RX device port ID which vocproc will connect to. If not supplying a
+        * port ID set to VSS_IVOCPROC_PORT_ID_NONE.
+        */
+       uint32_t rx_topology_id;
+       /*
+        * Rx leg topology ID. If not supplying a topology ID set to
+        * VSS_IVOCPROC_TOPOLOGY_ID_NONE.
+        */
+       int32_t network_id;
+       /*
+        * Network ID. (Refer to VSS_NETWORK_ID_XXX). If not supplying a network
+        * ID set to VSS_NETWORK_ID_DEFAULT.
+        */
+} __attribute__((packed));
+
+struct vss_ivocproc_cmd_set_device_t {
+       uint32_t tx_port_id;
+       /**<
+       * TX device port ID which vocproc will connect to.
+       * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+       */
+       uint32_t tx_topology_id;
+       /**<
+       * TX leg topology ID.
+       * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+       * pre/post-processing blocks and is pass-through.
+       */
+       int32_t rx_port_id;
+       /**<
+       * RX device port ID which vocproc will connect to.
+       * VSS_IVOCPROC_PORT_ID_NONE means vocproc will not connect to any port.
+       */
+       uint32_t rx_topology_id;
+       /**<
+       * RX leg topology ID.
+       * VSS_IVOCPROC_TOPOLOGY_ID_NONE means vocproc does not contain any
+       * pre/post-processing blocks and is pass-through.
+       */
+} __attribute__((packed));
+
+struct vss_ivocproc_cmd_set_volume_index_t {
+       uint16_t vol_index;
+       /**<
+       * Volume index utilized by the vocproc to index into the volume table
+       * provided in VSS_IVOCPROC_CMD_CACHE_VOLUME_CALIBRATION_TABLE and set
+       * volume on the VDSP.
+       */
+} __attribute__((packed));
+
+struct cvp_create_full_ctl_session_cmd {
+       struct apr_hdr hdr;
+       struct vss_ivocproc_cmd_create_full_control_session_t cvp_session;
+} __attribute__ ((packed));
+
+struct cvp_command {
+       struct apr_hdr hdr;
+} __attribute__((packed));
+
+struct cvp_set_device_cmd {
+       struct apr_hdr hdr;
+       struct vss_ivocproc_cmd_set_device_t cvp_set_device;
+} __attribute__ ((packed));
+
+struct cvp_cache_calibration_data_cmd {
+       struct apr_hdr hdr;
+} __attribute__((packed));
+
+struct cvp_cache_volume_calibration_table_cmd {
+       struct apr_hdr hdr;
+} __attribute__((packed));
+
+struct cvp_set_vp3_data_cmd {
+       struct apr_hdr hdr;
+} __attribute__((packed));
+
+struct cvp_set_rx_volume_index_cmd {
+       struct apr_hdr hdr;
+       struct vss_ivocproc_cmd_set_volume_index_t cvp_set_vol_idx;
+} __attribute__((packed));
+
+/* CB for up-link packets. */
+typedef void (*ul_cb_fn)(uint8_t *voc_pkt,
+                        uint32_t pkt_len,
+                        void *private_data);
+
+/* CB for down-link packets. */
+typedef void (*dl_cb_fn)(uint8_t *voc_pkt,
+                        uint32_t *pkt_len,
+                        void *private_data);
+
+struct q_min_max_rate {
+       uint32_t min_rate;
+       uint32_t max_rate;
+};
+
+struct mvs_driver_info {
+       uint32_t media_type;
+       uint32_t rate;
+       uint32_t network_type;
+       uint32_t dtx_mode;
+       struct q_min_max_rate q_min_max_rate;
+       ul_cb_fn ul_cb;
+       dl_cb_fn dl_cb;
+       void *private_data;
+};
+
+struct incall_rec_info {
+       uint32_t pending;
+       uint32_t rec_mode;
+};
+
+struct incall_music_info {
+       uint32_t pending;
+       uint32_t playing;
+};
+
+struct voice_data {
+       int voc_state;/*INIT, CHANGE, RELEASE, RUN */
+
+       wait_queue_head_t mvm_wait;
+       wait_queue_head_t cvs_wait;
+       wait_queue_head_t cvp_wait;
+
+       /* cache the values related to Rx and Tx */
+       struct device_data dev_rx;
+       struct device_data dev_tx;
+
+       /* call status */
+       int v_call_status; /* Start or End */
+
+       u32 mvm_state;
+       u32 cvs_state;
+       u32 cvp_state;
+
+       /* Handle to MVM */
+       u16 mvm_handle;
+       /* Handle to CVS */
+       u16 cvs_handle;
+       /* Handle to CVP */
+       u16 cvp_handle;
+
+       struct mutex lock;
+
+       struct incall_rec_info rec_info;
+
+       struct incall_music_info music_info;
+
+       u16 session_id;
+};
+
+#define MAX_VOC_SESSIONS 2
+#define SESSION_ID_BASE 0xFFF0
+
+struct common_data {
+       uint32_t voc_path;
+       uint32_t adsp_version;
+       uint32_t device_events;
+
+       /* These default values are for all devices */
+       uint32_t default_mute_val;
+       uint32_t default_vol_val;
+       uint32_t default_sample_val;
+
+       /* APR to MVM in the modem */
+       void *apr_mvm;
+       /* APR to CVS in the modem */
+       void *apr_cvs;
+       /* APR to CVP in the modem */
+       void *apr_cvp;
+
+       /* APR to MVM in the Q6 */
+       void *apr_q6_mvm;
+       /* APR to CVS in the Q6 */
+       void *apr_q6_cvs;
+       /* APR to CVP in the Q6 */
+       void *apr_q6_cvp;
+
+       struct mutex common_lock;
+
+       struct mvs_driver_info mvs_info;
+
+       struct voice_data voice[MAX_VOC_SESSIONS];
+};
+
+int voice_set_voc_path_full(uint32_t set);
+
+void voice_register_mvs_cb(ul_cb_fn ul_cb,
+                          dl_cb_fn dl_cb,
+                          void *private_data);
+
+void voice_config_vocoder(uint32_t media_type,
+                         uint32_t rate,
+                         uint32_t network_type,
+                         uint32_t dtx_mode,
+                         struct q_min_max_rate q_min_max_rate);
+
+int voice_start_record(uint32_t rec_mode, uint32_t set);
+
+int voice_start_playback(uint32_t set);
+
+u16 voice_get_session_id(const char *name);
+#endif
diff --git a/include/sound/qdsp6v2/rtac.h b/include/sound/qdsp6v2/rtac.h
new file mode 100644 (file)
index 0000000..07be428
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (c) 2011, The Linux Foundation. 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 __RTAC_H__
+#define __RTAC_H__
+
+/* Voice Modes */
+#define RTAC_CVP               0
+#define RTAC_CVS               1
+#define RTAC_VOICE_MODES       2
+
+void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id);
+void rtac_remove_adm_device(u32 port_id);
+void rtac_remove_popp_from_adm_devices(u32 popp_id);
+void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
+       u32 tx_afe_port, u32 session_id);
+void rtac_remove_voice(u32 cvs_handle);
+void rtac_set_adm_handle(void *handle);
+bool rtac_make_adm_callback(uint32_t *payload, u32 payload_size);
+void rtac_copy_adm_payload_to_user(void *payload, u32 payload_size);
+void rtac_set_asm_handle(u32 session_id, void *handle);
+bool rtac_make_asm_callback(u32 session_id, uint32_t *payload,
+       u32 payload_size);
+void rtac_copy_asm_payload_to_user(void *payload, u32 payload_size);
+void rtac_set_voice_handle(u32 mode, void *handle);
+bool rtac_make_voice_callback(u32 mode, uint32_t *payload, u32 payload_size);
+void rtac_copy_voice_payload_to_user(void *payload, u32 payload_size);
+
+#endif
index 3cc252e55468eaabf529d60978eaa3c52158b25e..c393530cbff4a99f95e6a2e0c00df97944052517 100644 (file)
@@ -40,3 +40,65 @@ config SND_SOC_APQ8016_SBC
           Support for Qualcomm Technologies LPASS audio block in
           APQ8016 SOC-based systems.
           Say Y if you want to use audio devices on MI2S.
+
+menu "QCOM QDSP Audio support"
+
+config SND_MSM_DAI_SOC
+       tristate
+
+config SND_MSM_SOC
+       tristate "SoC Audio for the MSM series chips"
+       select SND_MSM_DAI_SOC
+       select SND_MSM_SOC_MSM7K
+       default n
+       help
+         To add support for ALSA PCM driver for MSM board.
+
+config SND_SOC_MSM_QDSP6_HDMI_AUDIO
+       tristate "Soc QDSP6 HDMI Audio DAI driver"
+       default n
+       help
+        To support HDMI Audio on MSM8960 over QDSP6.
+
+config SND_SOC_MSM_QDSP6_INTF
+       bool "SoC Q6 audio driver for MSM8960"
+       default n
+       help
+        To add support for SoC audio on MSM8960.
+
+config SND_SOC_MSM_QDSP6V2_INTF
+       bool "SoC Q6 audio driver for MSM8974"
+       help
+        To add support for SoC audio on MSM8974.
+        This will enable all the platform specific
+        interactions towards DSP. It includes asm,
+        adm and afe interfaces on the DSP.
+
+
+config SND_SOC_QDSP6
+       tristate "SoC ALSA audio driver for QDSP6"
+       select SND_SOC_MSM_QDSP6_INTF
+       default n
+       help
+        To add support for MSM QDSP6 Soc Audio.
+
+config SND_SOC_QDSP6V2
+       tristate "SoC ALSA audio driver for QDSP6V2"
+       select SND_SOC_MSM_QDSP6V2_INTF
+       help
+        To add support for MSM QDSP6V2 Soc Audio.
+        This will enable sound soc platform specific
+        audio drivers. This includes q6asm, q6adm,
+        q6afe interfaces to DSP using apr.
+
+config SND_SOC_MSM8960
+       tristate "SoC Machine driver for MSM8960 and APQ8064 boards"
+       select SND_SOC_QDSP6
+       select SND_SOC_MSM_STUB
+       select SND_SOC_MSM_HOSTLESS_PCM
+       select SND_SOC_MSM_QDSP6_HDMI_AUDIO if FB_MSM_HDMI_MSM_PANEL
+       default n
+       help
+        To add support for SoC audio on MSM8960 and APQ8064 boards
+
+endmenu
index 79e5c50a8f71b85a1ae4d2e118fea62a6c5b7e82..a313fdf8ce1c6d9fd0a5c10560455530fedc0def 100644 (file)
@@ -15,3 +15,12 @@ snd-soc-apq8016-sbc-objs := apq8016_sbc.o
 
 obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
 obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
+
+# for MSM 8960 sound card driver
+obj-$(CONFIG_SND_SOC_MSM_QDSP6_INTF) += qdsp6/
+snd-soc-qdsp6-objs :=  msm-pcm-q6.o msm-pcm-routing.o msm-dai-fe.o 
+obj-$(CONFIG_SND_SOC_MSM_QDSP6_HDMI_AUDIO) += msm-dai-q6-hdmi.o
+obj-$(CONFIG_SND_SOC_QDSP6) += snd-soc-qdsp6.o
+
+snd-soc-msm8960-objs := apq8064.o 
+obj-$(CONFIG_SND_SOC_MSM8960) += snd-soc-msm8960.o
diff --git a/sound/soc/qcom/apq8064.c b/sound/soc/qcom/apq8064.c
new file mode 100644 (file)
index 0000000..4738109
--- /dev/null
@@ -0,0 +1,170 @@
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+
+#include <linux/pm_runtime.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include "msm-pcm-routing.h"
+
+static int msm_hdmi_rx_ch = 2;
+static int hdmi_rate_variable;
+
+static const char *hdmi_rx_ch_text[] = {"Two", "Three", "Four", "Five",
+       "Six", "Seven", "Eight"};
+static const char * const hdmi_rate[] = {"Default", "Variable"};
+
+static const struct soc_enum msm_enum[] = {
+       SOC_ENUM_SINGLE_EXT(7, hdmi_rx_ch_text),
+       SOC_ENUM_SINGLE_EXT(2, hdmi_rate),
+};
+
+static int msm_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       pr_debug("%s: msm_hdmi_rx_ch  = %d\n", __func__,
+                       msm_hdmi_rx_ch);
+       ucontrol->value.integer.value[0] = msm_hdmi_rx_ch - 2;
+       return 0;
+}
+
+static int msm_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       msm_hdmi_rx_ch = ucontrol->value.integer.value[0] + 2;
+
+       pr_debug("%s: msm_hdmi_rx_ch = %d\n", __func__,
+               msm_hdmi_rx_ch);
+       return 1;
+}
+       
+static int msm_hdmi_rate_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       hdmi_rate_variable = ucontrol->value.integer.value[0];
+       pr_debug("%s: hdmi_rate_variable = %d\n", __func__, hdmi_rate_variable);
+       return 0;
+}
+
+static int msm_hdmi_rate_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       ucontrol->value.integer.value[0] = hdmi_rate_variable;
+       return 0;
+}
+
+static const struct snd_kcontrol_new tabla_msm_controls[] = {
+       SOC_ENUM_EXT("HDMI_RX Channels", msm_enum[0],
+               msm_hdmi_rx_ch_get, msm_hdmi_rx_ch_put),
+       SOC_ENUM_EXT("HDMI RX Rate", msm_enum[1],
+                                       msm_hdmi_rate_get,
+                                       msm_hdmi_rate_put),
+};
+
+int msm_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
+                                       struct snd_pcm_hw_params *params)
+{
+       struct snd_interval *rate = hw_param_interval(params,
+                                       SNDRV_PCM_HW_PARAM_RATE);
+
+       struct snd_interval *channels = hw_param_interval(params,
+                                       SNDRV_PCM_HW_PARAM_CHANNELS);
+
+       pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
+                       channels->min, channels->max);
+
+       if (!hdmi_rate_variable)
+               rate->min = rate->max = 48000;
+       channels->min = channels->max = msm_hdmi_rx_ch;
+       if (channels->max < 2)
+               channels->min = channels->max = 2;
+
+       return 0;
+}
+
+/* Digital audio interface glue - connects codec <---> CPU */
+static struct snd_soc_dai_link msm_dai[] = {
+       /* FrontEnd DAI Links */
+       {
+               .name = "MultiMedia1 PCM",
+               .stream_name = "MultiMedia1 Playback",
+               .cpu_dai_name   = "MultiMedia1",
+               .platform_name  = "soc:msm_pcm",
+               .dynamic = 1,
+               .dpcm_playback = 1,
+               .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
+               .codec_dai_name = "snd-soc-dummy-dai",
+               .codec_name = "snd-soc-dummy",
+               .ignore_suspend = 1,
+               .ignore_pmdown_time = 1, /* this dainlink has playback support */
+               .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1,
+               .be_hw_params_fixup = msm_hdmi_be_hw_params_fixup,
+
+       },
+       /* HDMI BACK END DAI Link */
+       {
+               .name = LPASS_BE_HDMI,
+               .stream_name = "HDMI Playback",
+               .cpu_dai_name = "HDMI",
+               .platform_name = "soc:msm_pcm_routing",
+               .codec_name = "hdmi-audio-codec.0.auto",
+               .codec_dai_name = "i2s-hifi",
+               .no_pcm = 1,
+               .dpcm_playback = 1,
+               .be_id = MSM_BACKEND_DAI_HDMI_RX,
+               .be_hw_params_fixup = msm_hdmi_be_hw_params_fixup,
+
+       },
+};
+
+static struct snd_soc_card snd_soc_card_msm = {
+       .name           = "apq8064-tabla-snd-card",
+       .dai_link       = msm_dai,
+       .num_links      = ARRAY_SIZE(msm_dai),
+       .owner          = THIS_MODULE,
+       .controls = tabla_msm_controls,
+       .num_controls = ARRAY_SIZE(tabla_msm_controls),
+};
+
+static int msm_snd_apq8064_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       snd_soc_card_msm.dev = &pdev->dev;
+       ret = snd_soc_register_card(&snd_soc_card_msm);
+       if (ret)
+               dev_err(&pdev->dev, "Error: snd_soc_register_card failed (%d)!\n", ret);
+
+       return ret;
+
+}
+
+static  int msm_snd_apq8064_remove(struct platform_device *pdev)
+{
+       return 0;
+}
+
+static const struct of_device_id msm_snd_apq8064_dt_match[] = {
+       {.compatible = "qcom,snd-apq8064"},
+       {}
+};
+
+static struct platform_driver msm_snd_apq8064_driver = {
+       .probe  = msm_snd_apq8064_probe,
+       .remove = msm_snd_apq8064_remove,
+       .driver = {
+               .name = "msm-snd-apq8064",
+               .owner = THIS_MODULE,
+               .of_match_table = msm_snd_apq8064_dt_match,
+       },
+};
+module_platform_driver(msm_snd_apq8064_driver);
+/* Module information */
+
+MODULE_DESCRIPTION("ALSA SoC msm");
+MODULE_LICENSE("GPL v2");
+
diff --git a/sound/soc/qcom/msm-dai-fe.c b/sound/soc/qcom/msm-dai-fe.c
new file mode 100644 (file)
index 0000000..e0f3bbe
--- /dev/null
@@ -0,0 +1,101 @@
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+       8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+       .count = ARRAY_SIZE(supported_sample_rates),
+       .list = supported_sample_rates,
+       .mask = 0,
+};
+
+static int multimedia_startup(struct snd_pcm_substream *substream,
+       struct snd_soc_dai *dai)
+{
+       snd_pcm_hw_constraint_list(substream->runtime, 0,
+               SNDRV_PCM_HW_PARAM_RATE,
+               &constraints_sample_rates);
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops msm_fe_Multimedia_dai_ops = {
+       .startup        = multimedia_startup,
+};
+
+static struct snd_soc_dai_driver msm_fe_dais[] = {
+       {
+               .name = "MultiMedia1",
+               .id = 1,
+               .playback = {
+                       .stream_name = "MultiMedia1 Playback",
+                       .rates = (SNDRV_PCM_RATE_8000_48000|
+                                       SNDRV_PCM_RATE_KNOT),
+                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                       .channels_min = 1,
+                       .channels_max = 6,
+                       .rate_min =     8000,
+                       .rate_max =     48000,
+               },
+               .ops = &msm_fe_Multimedia_dai_ops,
+       },
+};
+
+static const struct snd_soc_component_driver msm_dai_fe_component = {
+        .name           = "msm-dai-fe",
+};
+
+static  int msm_fe_dai_dev_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       ret = snd_soc_register_component(&pdev->dev, &msm_dai_fe_component, msm_fe_dais, 1);
+
+       return ret;
+}
+
+static  int msm_fe_dai_dev_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_component(&pdev->dev);
+       return 0;
+}
+
+static const struct of_device_id msm_dai_fe_dt_match[] = {
+       {.compatible = "qcom,msm-dai-fe"},
+       {}
+};
+
+static struct platform_driver msm_fe_dai_driver = {
+       .probe  = msm_fe_dai_dev_probe,
+       .remove = msm_fe_dai_dev_remove,
+       .driver = {
+               .name = "msm-dai-fe",
+               .owner = THIS_MODULE,
+               .of_match_table = msm_dai_fe_dt_match,
+       },
+};
+module_platform_driver(msm_fe_dai_driver);
+/* Module information */
+MODULE_DESCRIPTION("MSM Frontend DAI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/msm-dai-q6-hdmi.c b/sound/soc/qcom/msm-dai-q6-hdmi.c
new file mode 100644 (file)
index 0000000..064052f
--- /dev/null
@@ -0,0 +1,298 @@
+/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/apr_audio.h>
+#include <sound/q6afe.h>
+#include <sound/q6adm.h>
+#include <sound/msm-dai-q6.h>
+#include <sound/msm_hdmi_audio.h>
+
+enum {
+       STATUS_PORT_STARTED, /* track if AFE port has started */
+       STATUS_MAX
+};
+
+struct msm_dai_q6_hdmi_dai_data {
+       DECLARE_BITMAP(status_mask, STATUS_MAX);
+       u32 rate;
+       u32 channels;
+       union afe_port_config port_config;
+};
+
+static int msm_dai_q6_hdmi_format_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+
+       struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
+       int value = ucontrol->value.integer.value[0];
+       dai_data->port_config.hdmi_multi_ch.data_type = value;
+       pr_debug("%s: value = %d\n", __func__, value);
+       return 0;
+}
+
+static int msm_dai_q6_hdmi_format_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+
+       struct msm_dai_q6_hdmi_dai_data *dai_data = kcontrol->private_data;
+       ucontrol->value.integer.value[0] =
+               dai_data->port_config.hdmi_multi_ch.data_type;
+       return 0;
+}
+
+/* HDMI format field for AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG command
+ *  0: linear PCM
+ *  1: non-linear PCM
+ */
+static const char *hdmi_format[] = {
+       "LPCM",
+       "Compr"
+};
+
+static const struct soc_enum hdmi_config_enum[] = {
+       SOC_ENUM_SINGLE_EXT(2, hdmi_format),
+};
+
+static const struct snd_kcontrol_new hdmi_config_controls[] = {
+       SOC_ENUM_EXT("HDMI RX Format", hdmi_config_enum[0],
+                                msm_dai_q6_hdmi_format_get,
+                                msm_dai_q6_hdmi_format_put),
+};
+/* Current implementation assumes hw_param is called once
+ * This may not be the case but what to do when ADM and AFE
+ * port are already opened and parameter changes
+ */
+static int msm_dai_q6_hdmi_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params,
+                               struct snd_soc_dai *dai)
+{
+       struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
+       u32 channel_allocation = 0;
+       u32 level_shift  = 0; /* 0dB */
+       bool down_mix = FALSE;
+       int sample_rate = 48000;
+
+       dai_data->channels = params_channels(params);
+       dai_data->rate = params_rate(params);
+       dai_data->port_config.hdmi_multi_ch.reserved = 0;
+
+       dai_data->channels = 2;
+       dai_data->rate = 48000;
+       switch (dai_data->rate) {
+       case 48000:
+               sample_rate = HDMI_SAMPLE_RATE_48KHZ;
+               break;
+       case 44100:
+               sample_rate = HDMI_SAMPLE_RATE_44_1KHZ;
+               break;
+       case 32000:
+               sample_rate = HDMI_SAMPLE_RATE_32KHZ;
+               break;
+       }
+
+       switch (dai_data->channels) {
+       case 2:
+               channel_allocation  = 0;
+               dai_data->port_config.hdmi_multi_ch.channel_allocation =
+                       channel_allocation;
+               break;
+       case 6:
+               channel_allocation  = 0x0B;
+               dai_data->port_config.hdmi_multi_ch.channel_allocation =
+                               channel_allocation;
+               break;
+       case 8:
+               channel_allocation  = 0x1F;
+               dai_data->port_config.hdmi_multi_ch.channel_allocation =
+                               channel_allocation;
+               break;
+       default:
+               dev_err(dai->dev, "invalid Channels = %u\n",
+                               dai_data->channels);
+               return -EINVAL;
+       }
+       dev_info(dai->dev, "%s() num_ch = %u rate =%u"
+               " channel_allocation = %u data type = %d\n", __func__,
+               dai_data->channels,
+               dai_data->rate,
+               dai_data->port_config.hdmi_multi_ch.channel_allocation,
+               dai_data->port_config.hdmi_multi_ch.data_type);
+
+       return 0;
+}
+
+static void msm_dai_q6_hdmi_shutdown(struct snd_pcm_substream *substream,
+                               struct snd_soc_dai *dai)
+{
+       struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
+       int rc = 0;
+
+       if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+               pr_info("%s:  afe port not started. dai_data->status_mask"
+                       " = %ld\n", __func__, *dai_data->status_mask);
+               return;
+       }
+
+       rc = afe_close(HDMI_RX); /* can block */
+
+       if (IS_ERR_VALUE(rc))
+               dev_err(dai->dev, "fail to close AFE port\n");
+
+       pr_debug("%s: dai_data->status_mask = %ld\n", __func__,
+                       *dai_data->status_mask);
+
+       clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+}
+
+
+static int msm_dai_q6_hdmi_prepare(struct snd_pcm_substream *substream,
+               struct snd_soc_dai *dai)
+{
+       struct msm_dai_q6_hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev);
+       int rc = 0;
+       dai_data->rate = 48000;
+       dai_data->port_config.hdmi_multi_ch.channel_allocation = 0;
+       dai_data->port_config.hdmi_multi_ch.reserved = 0;
+       dai_data->port_config.hdmi_multi_ch.data_type = 0;
+
+       if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+               rc = afe_port_start(HDMI_RX, &dai_data->port_config,
+                                   dai_data->rate);
+               if (IS_ERR_VALUE(rc))
+                       dev_err(dai->dev, "fail to open AFE port %x\n",
+                               HDMI_RX);
+               else
+                       set_bit(STATUS_PORT_STARTED,
+                               dai_data->status_mask);
+       }
+
+       return rc;
+}
+
+static int msm_dai_q6_hdmi_dai_probe(struct snd_soc_dai *dai)
+{
+       struct msm_dai_q6_hdmi_dai_data *dai_data;
+       const struct snd_kcontrol_new *kcontrol;
+       int rc = 0;
+
+       dai_data = kzalloc(sizeof(struct msm_dai_q6_hdmi_dai_data),
+               GFP_KERNEL);
+
+       if (!dai_data) {
+               dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n",
+               HDMI_RX);
+               rc = -ENOMEM;
+       } else
+               dev_set_drvdata(dai->dev, dai_data);
+
+       kcontrol = &hdmi_config_controls[0];
+
+       rc = snd_ctl_add(dai->component->card->snd_card,
+                                        snd_ctl_new1(kcontrol, dai_data));
+       return rc;
+}
+
+static int msm_dai_q6_hdmi_dai_remove(struct snd_soc_dai *dai)
+{
+       struct msm_dai_q6_hdmi_dai_data *dai_data;
+       int rc;
+
+       dai_data = dev_get_drvdata(dai->dev);
+
+       /* If AFE port is still up, close it */
+       if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
+               rc = afe_close(HDMI_RX); /* can block */
+
+               if (IS_ERR_VALUE(rc))
+                       dev_err(dai->dev, "fail to close AFE port\n");
+
+               clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
+       }
+       kfree(dai_data);
+       snd_soc_unregister_component(dai->dev);
+
+       return 0;
+}
+
+static struct snd_soc_dai_ops msm_dai_q6_hdmi_ops = {
+       .prepare        = msm_dai_q6_hdmi_prepare,
+       .hw_params      = msm_dai_q6_hdmi_hw_params,
+       .shutdown       = msm_dai_q6_hdmi_shutdown,
+};
+
+static struct snd_soc_dai_driver msm_dai_q6_hdmi_hdmi_rx_dai = {
+       .playback = {
+               .stream_name = "HDMI Playback",
+               .rates = SNDRV_PCM_RATE_48000,
+               .formats = SNDRV_PCM_FMTBIT_S16_LE,
+               .channels_min = 2,
+               .channels_max = 6,
+               .rate_max =     48000,
+               .rate_min =     48000,
+       },
+       .ops = &msm_dai_q6_hdmi_ops,
+       .probe = msm_dai_q6_hdmi_dai_probe,
+       .remove = msm_dai_q6_hdmi_dai_remove,
+       .id     = HDMI_RX,
+       .name = "HDMI",
+};
+
+static const struct snd_soc_component_driver msm_hdmi_q6_component = {
+       .name = "msm-dai-q6-hdmi",
+};  
+/* To do: change to register DAIs as batch */
+static  int msm_dai_q6_hdmi_dev_probe(struct platform_device *pdev)
+{
+       int rc = 0;
+
+       dev_info(&pdev->dev, "dev name %s dev-id %d\n",
+                       dev_name(&pdev->dev), pdev->id);
+
+       rc = snd_soc_register_component(&pdev->dev, &msm_hdmi_q6_component,
+                               &msm_dai_q6_hdmi_hdmi_rx_dai, 1);
+       return rc;
+}
+
+static  int msm_dai_q6_hdmi_dev_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_component(&pdev->dev);
+       return 0;
+}
+
+static const struct of_device_id msm_dai_hdmi_dt_match[] = {
+       {.compatible = "qcom,msm-dai-q6-hdmi"},
+       {}
+};
+static struct platform_driver msm_dai_q6_hdmi_driver = {
+       .probe  = msm_dai_q6_hdmi_dev_probe,
+       .remove = msm_dai_q6_hdmi_dev_remove,
+       .driver = {
+               .name = "msm-dai-q6-hdmi",
+               .owner = THIS_MODULE,
+               .of_match_table = msm_dai_hdmi_dt_match,
+       },
+};
+
+module_platform_driver(msm_dai_q6_hdmi_driver);
+/* Module information */
+MODULE_DESCRIPTION("MSM DSP HDMI DAI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/msm-pcm-q6.c b/sound/soc/qcom/msm-pcm-q6.c
new file mode 100644 (file)
index 0000000..68eaf60
--- /dev/null
@@ -0,0 +1,851 @@
+/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <asm/dma.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/q6afe.h>
+#include <sound/q6adm.h>
+#include <sound/msm-dai-q6.h>
+#include <sound/msm_hdmi_audio.h>
+#include "msm-pcm-q6.h"
+#include "msm-pcm-routing.h"
+
+static struct audio_locks the_locks;
+
+extern int q6_hdmi_prepare(struct snd_pcm_substream *substream);
+struct snd_msm {
+       struct snd_card *card;
+       struct snd_pcm *pcm;
+};
+
+#define PLAYBACK_NUM_PERIODS   8
+#define PLAYBACK_PERIOD_SIZE   2048
+#define CAPTURE_MIN_NUM_PERIODS 2
+#define CAPTURE_MAX_NUM_PERIODS 16
+#define CAPTURE_MAX_PERIOD_SIZE 4096
+#define CAPTURE_MIN_PERIOD_SIZE 320
+
+static struct snd_pcm_hardware msm_pcm_hardware_capture = {
+       .info =                 (SNDRV_PCM_INFO_MMAP |
+                               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                               SNDRV_PCM_INFO_MMAP_VALID |
+                               SNDRV_PCM_INFO_INTERLEAVED |
+                               SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+       .formats =              SNDRV_PCM_FMTBIT_S16_LE,
+       .rates =                SNDRV_PCM_RATE_8000_48000,
+       .rate_min =             8000,
+       .rate_max =             48000,
+       .channels_min =         1,
+       .channels_max =         4,
+       .buffer_bytes_max =     CAPTURE_MAX_NUM_PERIODS *
+                               CAPTURE_MAX_PERIOD_SIZE,
+       .period_bytes_min =     CAPTURE_MIN_PERIOD_SIZE,
+       .period_bytes_max =     CAPTURE_MAX_PERIOD_SIZE,
+       .periods_min =          CAPTURE_MIN_NUM_PERIODS,
+       .periods_max =          CAPTURE_MAX_NUM_PERIODS,
+       .fifo_size =            0,
+};
+
+static struct snd_pcm_hardware msm_pcm_hardware_playback = {
+       .info =                 (SNDRV_PCM_INFO_MMAP |
+                               SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                               SNDRV_PCM_INFO_MMAP_VALID |
+                               SNDRV_PCM_INFO_INTERLEAVED |
+                               SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
+       .formats =              SNDRV_PCM_FMTBIT_S16_LE,
+       .rates =                SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
+       .rate_min =             8000,
+       .rate_max =             48000,
+       .channels_min =         1,
+       .channels_max =         2,
+       .buffer_bytes_max =     PLAYBACK_NUM_PERIODS * PLAYBACK_PERIOD_SIZE,
+       .period_bytes_min =     PLAYBACK_PERIOD_SIZE,
+       .period_bytes_max =     PLAYBACK_PERIOD_SIZE,
+       .periods_min =          PLAYBACK_NUM_PERIODS,
+       .periods_max =          PLAYBACK_NUM_PERIODS,
+       .fifo_size =            0,
+};
+
+/* Conventional and unconventional sample rate supported */
+static unsigned int supported_sample_rates[] = {
+       8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+static uint32_t in_frame_info[CAPTURE_MAX_NUM_PERIODS][2];
+
+static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
+       .count = ARRAY_SIZE(supported_sample_rates),
+       .list = supported_sample_rates,
+       .mask = 0,
+};
+
+static void msm_pcm_route_event_handler(enum msm_pcm_routing_event event,
+                                       void *priv_data)
+{
+       struct msm_audio *prtd = priv_data;
+
+       BUG_ON(!prtd);
+
+       pr_debug("%s: event %x\n", __func__, event);
+
+       switch (event) {
+       case MSM_PCM_RT_EVT_BUF_RECFG:
+               q6asm_cmd(prtd->audio_client, CMD_PAUSE);
+               q6asm_cmd(prtd->audio_client, CMD_FLUSH);
+               q6asm_run(prtd->audio_client, 0, 0, 0);
+       default:
+               break;
+       }
+}
+
+static void event_handler(uint32_t opcode,
+               uint32_t token, uint32_t *payload, void *priv)
+{
+       struct msm_audio *prtd = priv;
+       struct snd_pcm_substream *substream = prtd->substream;
+       uint32_t *ptrmem = (uint32_t *)payload;
+       int i = 0;
+       uint32_t idx = 0;
+       uint32_t size = 0;
+
+       pr_debug("%s\n", __func__);
+       switch (opcode) {
+       case ASM_DATA_EVENT_WRITE_DONE: {
+               pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
+               pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
+               prtd->pcm_irq_pos += prtd->pcm_count;
+               if (atomic_read(&prtd->start))
+                       snd_pcm_period_elapsed(substream);
+               atomic_inc(&prtd->out_count);
+               wake_up(&the_locks.write_wait);
+               if (!atomic_read(&prtd->start))
+                       break;
+               if (!prtd->mmap_flag)
+                       break;
+               if (q6asm_is_cpu_buf_avail_nolock(IN,
+                               prtd->audio_client,
+                               &size, &idx)) {
+                       pr_debug("%s:writing %d bytes of buffer to dsp 2\n",
+                                       __func__, prtd->pcm_count);
+                       q6asm_write_nolock(prtd->audio_client,
+                               prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+               }
+               break;
+       }
+       case ASM_DATA_CMDRSP_EOS:
+               pr_debug("ASM_DATA_CMDRSP_EOS\n");
+               prtd->cmd_ack = 1;
+               wake_up(&the_locks.eos_wait);
+               break;
+       case ASM_DATA_EVENT_READ_DONE: {
+               pr_debug("ASM_DATA_EVENT_READ_DONE\n");
+               pr_debug("token = 0x%08x\n", token);
+               for (i = 0; i < 8; i++, ++ptrmem)
+                       pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
+               in_frame_info[token][0] = payload[2];
+               in_frame_info[token][1] = payload[3];
+
+               /* assume data size = 0 during flushing */
+               if (in_frame_info[token][0]) {
+                       prtd->pcm_irq_pos += in_frame_info[token][0];
+                       pr_debug("pcm_irq_pos=%d\n", prtd->pcm_irq_pos);
+                       if (atomic_read(&prtd->start))
+                               snd_pcm_period_elapsed(substream);
+                       if (atomic_read(&prtd->in_count) <= prtd->periods)
+                               atomic_inc(&prtd->in_count);
+                       wake_up(&the_locks.read_wait);
+                       if (prtd->mmap_flag &&
+                           q6asm_is_cpu_buf_avail_nolock(OUT,
+                               prtd->audio_client,
+                               &size, &idx))
+                               q6asm_read_nolock(prtd->audio_client);
+               } else {
+                       pr_debug("%s: reclaim flushed buf in_count %x\n",
+                                __func__, atomic_read(&prtd->in_count));
+                       atomic_inc(&prtd->in_count);
+                       if (atomic_read(&prtd->in_count) == prtd->periods) {
+                               pr_info("%s: reclaimed all bufs\n", __func__);
+                               if (atomic_read(&prtd->start))
+                                       snd_pcm_period_elapsed(substream);
+                               wake_up(&the_locks.read_wait);
+                       }
+               }
+
+               break;
+       }
+       case APR_BASIC_RSP_RESULT: {
+               switch (payload[0]) {
+               case ASM_SESSION_CMD_RUN:
+                       if (substream->stream
+                               != SNDRV_PCM_STREAM_PLAYBACK) {
+                               atomic_set(&prtd->start, 1);
+                               break;
+                       }
+                       if (prtd->mmap_flag) {
+                               pr_debug("%s:writing %d bytes"
+                                       " of buffer to dsp\n",
+                                       __func__,
+                                       prtd->pcm_count);
+                               q6asm_write_nolock(prtd->audio_client,
+                                       prtd->pcm_count,
+                                       0, 0, NO_TIMESTAMP);
+                       } else {
+                               while (atomic_read(&prtd->out_needed)) {
+                                       pr_debug("%s:writing %d bytes"
+                                                " of buffer to dsp\n",
+                                               __func__,
+                                               prtd->pcm_count);
+                                       q6asm_write_nolock(prtd->audio_client,
+                                               prtd->pcm_count,
+                                               0, 0, NO_TIMESTAMP);
+                                       atomic_dec(&prtd->out_needed);
+                                       wake_up(&the_locks.write_wait);
+                               };
+                       }
+                       atomic_set(&prtd->start, 1);
+                       break;
+               default:
+                       break;
+               }
+       }
+       break;
+       default:
+               pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
+               break;
+       }
+}
+
+static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct msm_audio *prtd = runtime->private_data;
+       int ret;
+
+       pr_debug("%s\n", __func__);
+       prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+       prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+       prtd->pcm_irq_pos = 0;
+       /* rate and channels are sent to audio driver */
+       prtd->samp_rate = runtime->rate;
+       prtd->channel_mode = runtime->channels;
+       if (prtd->enabled)
+               return 0;
+
+       ret = q6asm_media_format_block_pcm(prtd->audio_client, runtime->rate,
+                               runtime->channels);
+       if (ret < 0)
+               pr_info("%s: CMD Format block failed\n", __func__);
+
+       atomic_set(&prtd->out_count, runtime->periods);
+
+       prtd->enabled = 1;
+       prtd->cmd_ack = 0;
+
+       return 0;
+}
+
+static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct msm_audio *prtd = runtime->private_data;
+       int ret = 0;
+       int i = 0;
+       pr_debug("%s\n", __func__);
+       prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
+       prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
+       prtd->pcm_irq_pos = 0;
+
+       /* rate and channels are sent to audio driver */
+       prtd->samp_rate = runtime->rate;
+       prtd->channel_mode = runtime->channels;
+
+       if (prtd->enabled)
+               return 0;
+
+       pr_debug("Samp_rate = %d\n", prtd->samp_rate);
+       pr_debug("Channel = %d\n", prtd->channel_mode);
+       if (prtd->channel_mode > 2) {
+               ret = q6asm_enc_cfg_blk_multi_ch_pcm(prtd->audio_client,
+               prtd->samp_rate, prtd->channel_mode);
+       } else {
+               ret = q6asm_enc_cfg_blk_pcm(prtd->audio_client,
+               prtd->samp_rate, prtd->channel_mode);
+       }
+
+       if (ret < 0)
+               pr_debug("%s: cmd cfg pcm was block failed", __func__);
+
+       for (i = 0; i < runtime->periods; i++)
+               q6asm_read(prtd->audio_client);
+       prtd->periods = runtime->periods;
+
+       prtd->enabled = 1;
+
+       return ret;
+}
+
+static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       int ret = 0;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct msm_audio *prtd = runtime->private_data;
+
+       switch (cmd) {
+       case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_RESUME:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               pr_debug("%s: Trigger start\n", __func__);
+               q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+               break;
+       case SNDRV_PCM_TRIGGER_STOP:
+               pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
+               atomic_set(&prtd->start, 0);
+               if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
+                       break;
+               prtd->cmd_ack = 0;
+               q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+               break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
+               q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+               atomic_set(&prtd->start, 0);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int msm_pcm_open(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+       struct msm_audio *prtd;
+       int ret = 0;
+
+       pr_debug("%s\n", __func__);
+       prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
+       if (prtd == NULL) {
+               pr_err("Failed to allocate memory for msm_audio\n");
+               return -ENOMEM;
+       }
+       prtd->substream = substream;
+       prtd->audio_client = q6asm_audio_client_alloc(
+                               (app_cb)event_handler, prtd);
+       if (!prtd->audio_client) {
+               pr_info("%s: Could not allocate memory\n", __func__);
+               kfree(prtd);
+               return -ENOMEM;
+       }
+       prtd->audio_client->perf_mode = false;
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               runtime->hw = msm_pcm_hardware_playback;
+               snd_soc_set_runtime_hwparams(substream, &msm_pcm_hardware_playback);
+               if(snd_pcm_hw_constraint_integer(runtime,
+                                               SNDRV_PCM_HW_PARAM_PERIODS) < 0)
+                       pr_err("%s Failed to set hw periods\n", __func__);
+
+               if(snd_pcm_hw_constraint_integer(runtime,
+                                               SNDRV_PCM_HW_PARAM_PERIOD_SIZE) < 0)
+                       pr_err("%s Failed to set hw period size\n", __func__);
+
+               ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM);
+               if (ret < 0) {
+                       pr_err("%s: pcm out open failed\n", __func__);
+                       q6asm_audio_client_free(prtd->audio_client);
+                       kfree(prtd);
+                       return -ENOMEM;
+               }
+
+               pr_debug("%s: session ID %d\n", __func__,
+                       prtd->audio_client->session);
+               prtd->session_id = prtd->audio_client->session;
+               msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
+                       prtd->audio_client->perf_mode,
+                       prtd->session_id, substream->stream);
+               prtd->cmd_ack = 1;
+
+       }
+       /* Capture path */
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               runtime->hw = msm_pcm_hardware_capture;
+       }
+
+       ret = snd_pcm_hw_constraint_list(runtime, 0,
+                               SNDRV_PCM_HW_PARAM_RATE,
+                               &constraints_sample_rates);
+       if (ret < 0)
+               pr_err("snd_pcm_hw_constraint_list failed\n");
+       /* Ensure that buffer size is a multiple of period size */
+       ret = snd_pcm_hw_constraint_integer(runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0)
+               pr_err("snd_pcm_hw_constraint_integer failed\n");
+
+       if (snd_pcm_hw_constraint_step(substream->runtime, 0,
+                        SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+                        2048) <0)
+               pr_err("snd_pcm_hw_constraint_integer  period bytes failed\n");
+
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               ret = snd_pcm_hw_constraint_minmax(runtime,
+                       SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+                       CAPTURE_MIN_NUM_PERIODS * CAPTURE_MIN_PERIOD_SIZE,
+                       CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE);
+               if (ret < 0) {
+                       pr_err("constraint for buffer bytes min max ret = %d\n",
+                                                                       ret);
+               }
+       }
+
+       prtd->dsp_cnt = 0;
+       runtime->private_data = prtd;
+
+       return 0;
+}
+
+static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
+       snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+       int ret = 0;
+       int fbytes = 0;
+       int xfer = 0;
+       char *bufptr = NULL;
+       void *data = NULL;
+       uint32_t idx = 0;
+       uint32_t size = 0;
+
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct msm_audio *prtd = runtime->private_data;
+
+       fbytes = frames_to_bytes(runtime, frames);
+       pr_debug("%s: prtd->out_count = %d\n",
+                               __func__, atomic_read(&prtd->out_count));
+       ret = wait_event_timeout(the_locks.write_wait,
+                       (atomic_read(&prtd->out_count)), 5 * HZ);
+       if (ret < 0) {
+               pr_err("%s: wait_event_timeout failed\n", __func__);
+               goto fail;
+       }
+
+       if (!atomic_read(&prtd->out_count)) {
+               pr_err("%s: pcm stopped out_count 0\n", __func__);
+               return 0;
+       }
+
+       data = q6asm_is_cpu_buf_avail(IN, prtd->audio_client, &size, &idx);
+       bufptr = data;
+       if (bufptr) {
+               xfer = fbytes;
+               pr_debug("%s:fbytes =%d: xfer=%d size=%d bufptr=%p buf=%p\n",
+                                       __func__, fbytes, xfer, size, bufptr, buf);
+               if (copy_from_user(bufptr, buf, xfer)) {
+                       ret = -EFAULT;
+                       goto fail;
+               }
+               buf += xfer;
+               fbytes -= xfer;
+               pr_debug("%s:fbytes = %d: xfer=%d\n", __func__, fbytes, xfer);
+               if (atomic_read(&prtd->start)) {
+                       pr_debug("%s:writing %d bytes of buffer to dsp\n",
+                                       __func__, xfer);
+                       ret = q6asm_write(prtd->audio_client, xfer,
+                                               0, 0, NO_TIMESTAMP);
+                       if (ret < 0) {
+                               ret = -EFAULT;
+                               goto fail;
+                       }
+               } else
+                       atomic_inc(&prtd->out_needed);
+               atomic_dec(&prtd->out_count);
+       }
+fail:
+       return  ret;
+}
+
+static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+       struct msm_audio *prtd = runtime->private_data;
+       int dir = 0;
+       int ret = 0;
+
+       pr_debug("%s\n", __func__);
+
+       dir = IN;
+       ret = wait_event_timeout(the_locks.eos_wait,
+                               prtd->cmd_ack, 5 * HZ);
+       if (ret < 0)
+               pr_err("%s: CMD_EOS failed\n", __func__);
+       q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+       q6asm_audio_client_buf_free_contiguous(dir,
+                               prtd->audio_client);
+
+       msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+                       SNDRV_PCM_STREAM_PLAYBACK);
+       q6asm_audio_client_free(prtd->audio_client);
+       kfree(prtd);
+       return 0;
+}
+
+static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
+                int channel, snd_pcm_uframes_t hwoff, void __user *buf,
+                                                snd_pcm_uframes_t frames)
+{
+       int ret = 0;
+       int fbytes = 0;
+       int xfer;
+       char *bufptr;
+       void *data = NULL;
+       static uint32_t idx;
+       static uint32_t size;
+       uint32_t offset = 0;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct msm_audio *prtd = substream->runtime->private_data;
+
+
+       pr_debug("%s\n", __func__);
+       fbytes = frames_to_bytes(runtime, frames);
+
+       pr_debug("appl_ptr %d\n", (int)runtime->control->appl_ptr);
+       pr_debug("hw_ptr %d\n", (int)runtime->status->hw_ptr);
+       pr_debug("avail_min %d\n", (int)runtime->control->avail_min);
+
+       ret = wait_event_timeout(the_locks.read_wait,
+                       (atomic_read(&prtd->in_count)), 5 * HZ);
+       if (ret < 0) {
+               pr_debug("%s: wait_event_timeout failed\n", __func__);
+               goto fail;
+       }
+       if (!atomic_read(&prtd->in_count)) {
+               pr_debug("%s: pcm stopped in_count 0\n", __func__);
+               return 0;
+       }
+       pr_debug("Checking if valid buffer is available...%08x\n",
+                                               (unsigned int) data);
+       data = q6asm_is_cpu_buf_avail(OUT, prtd->audio_client, &size, &idx);
+       bufptr = data;
+       pr_debug("Size = %d\n", size);
+       pr_debug("fbytes = %d\n", fbytes);
+       pr_debug("idx = %d\n", idx);
+       if (bufptr) {
+               xfer = fbytes;
+               if (xfer > size)
+                       xfer = size;
+               offset = in_frame_info[idx][1];
+               pr_debug("Offset value = %d\n", offset);
+               if (copy_to_user(buf, bufptr+offset, xfer)) {
+                       pr_err("Failed to copy buf to user\n");
+                       ret = -EFAULT;
+                       goto fail;
+               }
+               fbytes -= xfer;
+               size -= xfer;
+               in_frame_info[idx][1] += xfer;
+               pr_debug("%s:fbytes = %d: size=%d: xfer=%d\n",
+                                       __func__, fbytes, size, xfer);
+               pr_debug(" Sending next buffer to dsp\n");
+               memset(&in_frame_info[idx], 0,
+                       sizeof(uint32_t) * 2);
+               atomic_dec(&prtd->in_count);
+               ret = q6asm_read(prtd->audio_client);
+               if (ret < 0) {
+                       pr_err("q6asm read failed\n");
+                       ret = -EFAULT;
+                       goto fail;
+               }
+       } else
+               pr_err("No valid buffer\n");
+
+       pr_debug("Returning from capture_copy... %d\n", ret);
+fail:
+       return ret;
+}
+
+static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+       struct msm_audio *prtd = runtime->private_data;
+       int dir = OUT;
+
+       pr_debug("%s\n", __func__);
+       if (prtd->audio_client) {
+               q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+               q6asm_audio_client_buf_free_contiguous(dir,
+                               prtd->audio_client);
+               q6asm_audio_client_free(prtd->audio_client);
+       }
+
+       msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
+               SNDRV_PCM_STREAM_CAPTURE);
+       kfree(prtd);
+
+       return 0;
+}
+
+static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
+        snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
+{
+       int ret = 0;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
+       else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
+       return ret;
+}
+
+static int msm_pcm_close(struct snd_pcm_substream *substream)
+{
+       int ret = 0;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               ret = msm_pcm_playback_close(substream);
+       else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               ret = msm_pcm_capture_close(substream);
+       return ret;
+}
+static int msm_pcm_prepare(struct snd_pcm_substream *substream)
+{
+       int ret = 0;
+       //q6_hdmi_prepare(substream);
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               ret = msm_pcm_playback_prepare(substream);
+       else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+               ret = msm_pcm_capture_prepare(substream);
+       return ret;
+}
+
+static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
+{
+
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct msm_audio *prtd = runtime->private_data;
+
+       if (prtd->pcm_irq_pos >= prtd->pcm_size)
+               prtd->pcm_irq_pos = 0;
+
+       pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
+       return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
+}
+
+static int msm_pcm_mmap(struct snd_pcm_substream *substream,
+                               struct vm_area_struct *vma)
+{
+       int result = 0;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct msm_audio *prtd = runtime->private_data;
+
+       pr_debug("%s\n", __func__);
+       prtd->mmap_flag = 1;
+
+       if (runtime->dma_addr && runtime->dma_bytes) {
+               vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+               result = remap_pfn_range(vma, vma->vm_start,
+                               runtime->dma_addr >> PAGE_SHIFT,
+                               runtime->dma_bytes,
+                               vma->vm_page_prot);
+       } else {
+               pr_err("Physical address or size of buf is NULL");
+               return -EINVAL;
+       }
+
+       return result;
+}
+
+static int msm_pcm_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct msm_audio *prtd = runtime->private_data;
+       struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
+       struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
+       struct audio_buffer *buf;
+       int dir, ret;
+       int format = FORMAT_LINEAR_PCM;
+       struct msm_pcm_routing_evt event;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               dir = IN;
+       else
+               dir = OUT;
+
+       /*capture path*/
+       if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+               if (params_channels(params) > 2)
+                       format = FORMAT_MULTI_CHANNEL_LINEAR_PCM;
+               pr_debug("%s format = :0x%x\n", __func__, format);
+
+               ret = q6asm_open_read(prtd->audio_client, format);
+               if (ret < 0) {
+                       pr_err("%s: q6asm_open_read failed\n", __func__);
+                       q6asm_audio_client_free(prtd->audio_client);
+                       prtd->audio_client = NULL;
+                       return -ENOMEM;
+               }
+
+               pr_debug("%s: session ID %d\n", __func__,
+                       prtd->audio_client->session);
+               prtd->session_id = prtd->audio_client->session;
+               event.event_func = msm_pcm_route_event_handler;
+               event.priv_data = (void *) prtd;
+               msm_pcm_routing_reg_phy_stream_v2(soc_prtd->dai_link->be_id,
+                                                 prtd->audio_client->perf_mode,
+                                                 prtd->session_id,
+                                                 substream->stream, event);
+       }
+
+       if (dir == OUT) {
+               ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+                       prtd->audio_client,
+                       (params_buffer_bytes(params) / params_periods(params)),
+                               params_periods(params));
+               pr_debug("buff bytes = %d, period size = %d,\
+                       period count = %d\n", params_buffer_bytes(params),
+                       params_periods(params),
+                       params_buffer_bytes(params) / params_periods(params));
+       } else {
+               ret = q6asm_audio_client_buf_alloc_contiguous(dir,
+                       prtd->audio_client,
+                       runtime->hw.period_bytes_min,
+                       runtime->hw.periods_max);
+               pr_debug("buff bytes = %d, period size = %d,\
+                       period count = %d\n", params_buffer_bytes(params),
+                       params_periods(params),
+                       params_buffer_bytes(params) / params_periods(params));
+       }
+
+       if (ret < 0) {
+               pr_err("Audio Start: Buffer Allocation failed \
+                                       rc = %d\n", ret);
+               return -ENOMEM;
+       }
+       buf = prtd->audio_client->port[dir].buf;
+       if (buf == NULL || buf[0].data == NULL)
+               return -ENOMEM;
+
+       pr_debug("%s:buf = %p\n", __func__, buf);
+       dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
+       dma_buf->dev.dev = substream->pcm->card->dev;
+       dma_buf->private_data = NULL;
+       dma_buf->area = buf[0].data;
+       dma_buf->addr =  buf[0].phys;
+       dma_buf->bytes = runtime->hw.buffer_bytes_max;
+       if (dir == IN)
+               dma_buf->bytes = runtime->hw.buffer_bytes_max;
+       else
+               dma_buf->bytes = params_buffer_bytes(params);
+
+       if (!dma_buf->area)
+               return -ENOMEM;
+
+       snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+       return 0;
+}
+
+static struct snd_pcm_ops msm_pcm_ops = {
+       .open           = msm_pcm_open,
+       .copy           = msm_pcm_copy,
+       .hw_params      = msm_pcm_hw_params,
+       .close          = msm_pcm_close,
+       .ioctl          = snd_pcm_lib_ioctl,
+       .prepare        = msm_pcm_prepare,
+       .trigger        = msm_pcm_trigger,
+       .pointer        = msm_pcm_pointer,
+       .mmap           = msm_pcm_mmap,
+};
+
+static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_card *card = rtd->card->snd_card;
+
+       if (!card->dev->coherent_dma_mask)
+               card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+       return 0;
+}
+
+static struct snd_soc_platform_driver msm_soc_platform = {
+       .ops            = &msm_pcm_ops,
+       .pcm_new        = msm_asoc_pcm_new,
+};
+
+static  int msm_pcm_probe(struct platform_device *pdev)
+{
+       int ret;
+       pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
+       init_waitqueue_head(&the_locks.enable_wait);
+       init_waitqueue_head(&the_locks.eos_wait);
+       init_waitqueue_head(&the_locks.write_wait);
+       init_waitqueue_head(&the_locks.read_wait);
+       ret = snd_soc_register_platform(&pdev->dev,
+                                  &msm_soc_platform);
+       return ret;
+}
+
+static int msm_pcm_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static const struct of_device_id msm_pcm_dt_match[] = {
+       {.compatible = "qcom,msm-pcm-dsp"},
+       {}
+};
+
+static struct platform_driver msm_pcm_driver = {
+       .driver = {
+               .name = "msm-pcm-dsp",
+               .owner = THIS_MODULE,
+               .of_match_table = msm_pcm_dt_match,
+       },
+       .probe = msm_pcm_probe,
+       .remove = msm_pcm_remove,
+};
+
+static int __init msm_soc_platform_init(void)
+{
+
+       return platform_driver_register(&msm_pcm_driver);
+}
+module_init(msm_soc_platform_init);
+
+static void __exit msm_soc_platform_exit(void)
+{
+       platform_driver_unregister(&msm_pcm_driver);
+}
+module_exit(msm_soc_platform_exit);
+
+MODULE_DESCRIPTION("PCM module platform driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("platform:msm-pcm-dsp");
diff --git a/sound/soc/qcom/msm-pcm-q6.h b/sound/soc/qcom/msm-pcm-q6.h
new file mode 100644 (file)
index 0000000..0522f54
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 Google, Inc.
+ * Copyright (C) 2008 HTC Corporation
+ * Copyright (c) 2008-2009,2011 The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * See the GNU General Public License for more details.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you can find it at http://www.fsf.org.
+ */
+
+#ifndef _MSM_PCM_H
+#define _MSM_PCM_H
+#include <sound/apr_audio.h>
+#include <sound/q6asm.h>
+
+
+/* Support unconventional sample rates 12000, 24000 as well */
+#define USE_RATE                \
+                       (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT)
+
+extern int copy_count;
+
+struct buffer {
+       void *data;
+       unsigned size;
+       unsigned used;
+       unsigned addr;
+};
+
+struct buffer_rec {
+       void *data;
+       unsigned int size;
+       unsigned int read;
+       unsigned int addr;
+};
+
+struct audio_locks {
+       spinlock_t event_lock;
+       wait_queue_head_t read_wait;
+       wait_queue_head_t write_wait;
+       wait_queue_head_t eos_wait;
+       wait_queue_head_t enable_wait;
+       wait_queue_head_t flush_wait;
+};
+
+struct msm_audio {
+       struct snd_pcm_substream *substream;
+       unsigned int pcm_size;
+       unsigned int pcm_count;
+       unsigned int pcm_irq_pos;       /* IRQ position */
+       uint16_t source; /* Encoding source bit mask */
+
+       struct audio_client *audio_client;
+
+       uint16_t session_id;
+
+       uint32_t samp_rate;
+       uint32_t channel_mode;
+       uint32_t dsp_cnt;
+
+       int abort; /* set when error, like sample rate mismatch */
+
+       int enabled;
+       int close_ack;
+       int cmd_ack;
+       atomic_t start;
+       atomic_t stop;
+       atomic_t out_count;
+       atomic_t in_count;
+       atomic_t out_needed;
+       atomic_t eos;
+       int out_head;
+       int periods;
+       int mmap_flag;
+       atomic_t pending_buffer;
+       int cmd_interrupt;
+       bool meta_data_mode;
+};
+
+struct output_meta_data_st {
+       uint32_t meta_data_length;
+       uint32_t frame_size;
+       uint32_t timestamp_lsw;
+       uint32_t timestamp_msw;
+       uint32_t reserved[12];
+};
+
+#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/qcom/msm-pcm-routing.c b/sound/soc/qcom/msm-pcm-routing.c
new file mode 100644 (file)
index 0000000..2778580
--- /dev/null
@@ -0,0 +1,894 @@
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/bitops.h>
+#include <linux/mutex.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/q6adm.h>
+#include <sound/q6asm.h>
+#include <sound/q6afe.h>
+#include <sound/tlv.h>
+#include "msm-pcm-routing.h"
+
+struct msm_pcm_routing_bdai_data {
+       u16 port_id; /* AFE port ID */
+       u8 active; /* track if this backend is enabled */
+       unsigned long fe_sessions; /* Front-end sessions */
+       unsigned long port_sessions; /* track Tx BE ports -> Rx BE */
+       unsigned int  sample_rate;
+       unsigned int  channel;
+       bool perf_mode;
+};
+
+struct msm_pcm_routing_fdai_data {
+       u16 be_srate; /* track prior backend sample rate for flushing purpose */
+       int strm_id; /* ASM stream ID */
+       struct msm_pcm_routing_evt event_info;
+};
+
+#define INVALID_SESSION -1
+#define SESSION_TYPE_RX 0
+#define SESSION_TYPE_TX 1
+
+static DEFINE_MUTEX(routing_lock);
+
+static int srs_alsa_ctrl_ever_called;
+
+#define INT_RX_VOL_MAX_STEPS 0x2000
+#define INT_RX_VOL_GAIN 0x2000
+#define INT_RX_LR_VOL_MAX_STEPS 0x20002000
+
+static const DECLARE_TLV_DB_LINEAR(fm_rx_vol_gain, 0,
+                       INT_RX_VOL_MAX_STEPS);
+
+static const DECLARE_TLV_DB_LINEAR(lpa_rx_vol_gain, 0,
+                       INT_RX_LR_VOL_MAX_STEPS);
+
+static const DECLARE_TLV_DB_LINEAR(multimedia2_rx_vol_gain, 0,
+                       INT_RX_VOL_MAX_STEPS);
+
+static const DECLARE_TLV_DB_LINEAR(multimedia5_rx_vol_gain, 0,
+                       INT_RX_VOL_MAX_STEPS);
+
+static const DECLARE_TLV_DB_LINEAR(compressed_rx_vol_gain, 0,
+                       INT_RX_LR_VOL_MAX_STEPS);
+
+/* Equal to Frontend after last of the MULTIMEDIA SESSIONS */
+#define MAX_EQ_SESSIONS                MSM_FRONTEND_DAI_CS_VOICE
+
+enum {
+       EQ_BAND1 = 0,
+       EQ_BAND2,
+       EQ_BAND3,
+       EQ_BAND4,
+       EQ_BAND5,
+       EQ_BAND6,
+       EQ_BAND7,
+       EQ_BAND8,
+       EQ_BAND9,
+       EQ_BAND10,
+       EQ_BAND11,
+       EQ_BAND12,
+       EQ_BAND_MAX,
+};
+
+struct msm_audio_eq_band {
+       uint16_t     band_idx; /* The band index, 0 .. 11 */
+       uint32_t     filter_type; /* Filter band type */
+       uint32_t     center_freq_hz; /* Filter band center frequency */
+       uint32_t     filter_gain; /* Filter band initial gain (dB) */
+                       /* Range is +12 dB to -12 dB with 1dB increments. */
+       uint32_t     q_factor;
+} __packed;
+
+struct msm_audio_eq_stream_config {
+       uint32_t        enable; /* Number of consequtive bands specified */
+       uint32_t        num_bands;
+       struct msm_audio_eq_band        eq_bands[EQ_BAND_MAX];
+} __packed;
+
+struct msm_audio_eq_stream_config      eq_data[MAX_EQ_SESSIONS];
+
+static void msm_send_eq_values(int eq_idx);
+/* This array is indexed by back-end DAI ID defined in msm-pcm-routing.h
+ * If new back-end is defined, add new back-end DAI ID at the end of enum
+ */
+
+union srs_trumedia_params_u {
+       struct srs_trumedia_params srs_params;
+       unsigned short int raw_params[1];
+};
+static union srs_trumedia_params_u msm_srs_trumedia_params[2];
+static int srs_port_id = -1;
+
+static void srs_send_params(int port_id, unsigned int techs,
+               int param_block_idx) {
+       /* only send commands to dsp if srs alsa ctrl was used
+          at least one time */
+       if (!srs_alsa_ctrl_ever_called)
+               return;
+
+       pr_debug("SRS %s: called, port_id = %d, techs flags = %u,"
+                       " paramblockidx %d", __func__, port_id, techs,
+                       param_block_idx);
+       /* force all if techs is set to 1 */
+       if (techs == 1)
+               techs = 0xFFFFFFFF;
+
+       if (techs & (1 << SRS_ID_WOWHD))
+               srs_trumedia_open(port_id, SRS_ID_WOWHD,
+       (void *)&msm_srs_trumedia_params[param_block_idx].srs_params.wowhd);
+       if (techs & (1 << SRS_ID_CSHP))
+               srs_trumedia_open(port_id, SRS_ID_CSHP,
+       (void *)&msm_srs_trumedia_params[param_block_idx].srs_params.cshp);
+       if (techs & (1 << SRS_ID_HPF))
+               srs_trumedia_open(port_id, SRS_ID_HPF,
+       (void *)&msm_srs_trumedia_params[param_block_idx].srs_params.hpf);
+       if (techs & (1 << SRS_ID_PEQ))
+               srs_trumedia_open(port_id, SRS_ID_PEQ,
+       (void *)&msm_srs_trumedia_params[param_block_idx].srs_params.peq);
+       if (techs & (1 << SRS_ID_HL))
+               srs_trumedia_open(port_id, SRS_ID_HL,
+       (void *)&msm_srs_trumedia_params[param_block_idx].srs_params.hl);
+       if (techs & (1 << SRS_ID_GLOBAL))
+               srs_trumedia_open(port_id, SRS_ID_GLOBAL,
+       (void *)&msm_srs_trumedia_params[param_block_idx].srs_params.global);
+}
+
+static struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = {
+       { PRIMARY_I2S_RX, 0, 0, 0, 0, 0},
+       { PRIMARY_I2S_TX, 0, 0, 0, 0, 0},
+       { SLIMBUS_0_RX, 0, 0, 0, 0, 0},
+       { SLIMBUS_0_TX, 0, 0, 0, 0, 0},
+       { HDMI_RX, 0, 0, 0, 0, 0},
+       { INT_BT_SCO_RX, 0, 0, 0, 0, 0},
+       { INT_BT_SCO_TX, 0, 0, 0, 0, 0},
+       { INT_FM_RX, 0, 0, 0, 0, 0},
+       { INT_FM_TX, 0, 0, 0, 0, 0},
+       { RT_PROXY_PORT_001_RX, 0, 0, 0, 0, 0},
+       { RT_PROXY_PORT_001_TX, 0, 0, 0, 0, 0},
+       { PCM_RX, 0, 0, 0, 0, 0},
+       { PCM_TX, 0, 0, 0, 0, 0},
+       { VOICE_PLAYBACK_TX, 0, 0, 0, 0, 0},
+       { VOICE_RECORD_RX, 0, 0, 0, 0, 0},
+       { VOICE_RECORD_TX, 0, 0, 0, 0, 0},
+       { MI2S_RX, 0, 0, 0, 0, 0},
+       { MI2S_TX, 0, 0, 0, 0},
+       { SECONDARY_I2S_RX, 0, 0, 0, 0, 0},
+       { SLIMBUS_1_RX, 0, 0, 0, 0, 0},
+       { SLIMBUS_1_TX, 0, 0, 0, 0, 0},
+       { SLIMBUS_4_RX, 0, 0, 0, 0, 0},
+       { SLIMBUS_4_TX, 0, 0, 0, 0, 0},
+       { SLIMBUS_3_RX, 0, 0, 0, 0, 0},
+       { SLIMBUS_3_TX, 0, 0, 0, 0, 0},
+       { SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
+       { SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
+       { SLIMBUS_EXTPROC_RX, 0, 0, 0, 0, 0},
+       { SECONDARY_PCM_RX, 0, 0, 0, 0, 0},
+       { SECONDARY_PCM_TX, 0, 0, 0, 0, 0},
+};
+
+/* Track ASM playback & capture sessions of DAI */
+static struct msm_pcm_routing_fdai_data
+       fe_dai_map[MSM_FRONTEND_DAI_MM_SIZE][2] = {
+       /* MULTIMEDIA1 */
+       {{0, INVALID_SESSION, {NULL, NULL} },
+       {0, INVALID_SESSION, {NULL, NULL} } },
+       /* MULTIMEDIA2 */
+       {{0, INVALID_SESSION, {NULL, NULL} },
+       {0, INVALID_SESSION, {NULL, NULL} } },
+       /* MULTIMEDIA3 */
+       {{0, INVALID_SESSION, {NULL, NULL} },
+       {0, INVALID_SESSION, {NULL, NULL} } },
+       /* MULTIMEDIA4 */
+       {{0, INVALID_SESSION, {NULL, NULL} },
+       {0, INVALID_SESSION,  {NULL, NULL} } },
+       /* MULTIMEDIA5 */
+       {{0, INVALID_SESSION, {NULL, NULL} },
+       {0, INVALID_SESSION, {NULL, NULL} } },
+       /* MULTIMEDIA6 */
+       {{0, INVALID_SESSION, {NULL, NULL} },
+       {0, INVALID_SESSION, {NULL, NULL} } },
+       /* MULTIMEDIA7*/
+       {{0, INVALID_SESSION, {NULL, NULL} },
+       {0, INVALID_SESSION, {NULL, NULL} } },
+       /* MULTIMEDIA8 */
+       {{0, INVALID_SESSION, {NULL, NULL} },
+       {0, INVALID_SESSION, {NULL, NULL} } },
+};
+
+static uint8_t is_be_dai_extproc(int be_dai)
+{
+       if (be_dai == MSM_BACKEND_DAI_EXTPROC_RX ||
+          be_dai == MSM_BACKEND_DAI_EXTPROC_TX ||
+          be_dai == MSM_BACKEND_DAI_EXTPROC_EC_TX)
+               return 1;
+       else
+               return 0;
+}
+
+static void msm_pcm_routing_build_matrix(int fedai_id, int dspst_id,
+       int path_type)
+{
+       int i, port_type;
+       struct route_payload payload;
+
+       payload.num_copps = 0;
+       port_type = (path_type == ADM_PATH_PLAYBACK ?
+               MSM_AFE_PORT_TYPE_RX : MSM_AFE_PORT_TYPE_TX);
+
+       for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+               if (!is_be_dai_extproc(i) &&
+                  (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
+                  (msm_bedais[i].active) &&
+                  (test_bit(fedai_id, &msm_bedais[i].fe_sessions)))
+                       payload.copp_ids[payload.num_copps++] =
+                                       msm_bedais[i].port_id;
+       }
+
+       if (payload.num_copps)
+               adm_matrix_map(dspst_id, path_type,
+                       payload.num_copps, payload.copp_ids, 0);
+}
+
+void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
+                                       int stream_type, int enable)
+{
+       int i, session_type, path_type, port_type;
+       u32 mode = 0;
+
+       if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+               /* bad ID assigned in machine driver */
+               pr_err("%s: bad MM ID\n", __func__);
+               return;
+       }
+
+       if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
+               session_type = SESSION_TYPE_RX;
+               path_type = ADM_PATH_PLAYBACK;
+               port_type = MSM_AFE_PORT_TYPE_RX;
+       } else {
+               session_type = SESSION_TYPE_TX;
+               path_type = ADM_PATH_LIVE_REC;
+               port_type = MSM_AFE_PORT_TYPE_TX;
+       }
+
+       mutex_lock(&routing_lock);
+
+       fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
+       for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+               if (!is_be_dai_extproc(i) &&
+                  (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
+                  (msm_bedais[i].active) &&
+                  (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
+                       mode = afe_get_port_type(msm_bedais[i].port_id);
+                       if (enable)
+                               adm_connect_afe_port(mode, dspst_id,
+                                           msm_bedais[i].port_id);
+                       else
+                               adm_disconnect_afe_port(mode, dspst_id,
+                                               msm_bedais[i].port_id);
+
+                       break;
+               }
+       }
+       mutex_unlock(&routing_lock);
+}
+
+void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode, int dspst_id,
+                                                       int stream_type)
+{
+       int i, session_type, path_type, port_type;
+       struct route_payload payload;
+       u32 channels;
+
+       if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+               /* bad ID assigned in machine driver */
+               pr_err("%s: bad MM ID %d\n", __func__, fedai_id);
+               return;
+       }
+
+       if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
+               session_type = SESSION_TYPE_RX;
+               path_type = ADM_PATH_PLAYBACK;
+               port_type = MSM_AFE_PORT_TYPE_RX;
+       } else {
+               session_type = SESSION_TYPE_TX;
+               path_type = ADM_PATH_LIVE_REC;
+               port_type = MSM_AFE_PORT_TYPE_TX;
+       }
+
+       mutex_lock(&routing_lock);
+
+       payload.num_copps = 0; /* only RX needs to use payload */
+       fe_dai_map[fedai_id][session_type].strm_id = dspst_id;
+       /* re-enable EQ if active */
+       if (eq_data[fedai_id].enable)
+               msm_send_eq_values(fedai_id);
+       for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+               if (test_bit(fedai_id, &msm_bedais[i].fe_sessions))
+                       msm_bedais[i].perf_mode = perf_mode;
+               if (!is_be_dai_extproc(i) &&
+                  (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
+                  (msm_bedais[i].active) &&
+                  (test_bit(fedai_id, &msm_bedais[i].fe_sessions))) {
+
+                       channels = msm_bedais[i].channel;
+
+                       if ((stream_type == SNDRV_PCM_STREAM_PLAYBACK) &&
+                               ((channels == 1) || (channels == 2)) &&
+                               msm_bedais[i].perf_mode) {
+                               pr_debug("%s configure COPP to lowlatency mode",
+                                                               __func__);
+                               adm_multi_ch_copp_open(msm_bedais[i].port_id,
+                               path_type,
+                               msm_bedais[i].sample_rate,
+                               msm_bedais[i].channel,
+                               DEFAULT_COPP_TOPOLOGY, msm_bedais[i].perf_mode);
+                       } else if ((stream_type == SNDRV_PCM_STREAM_PLAYBACK) &&
+                               (channels > 2))
+                               adm_multi_ch_copp_open(msm_bedais[i].port_id,
+                               path_type,
+                               msm_bedais[i].sample_rate,
+                               msm_bedais[i].channel,
+                               DEFAULT_COPP_TOPOLOGY, msm_bedais[i].perf_mode);
+                       else
+                               adm_open(msm_bedais[i].port_id,
+                               path_type,
+                               msm_bedais[i].sample_rate,
+                               msm_bedais[i].channel,
+                               DEFAULT_COPP_TOPOLOGY);
+
+                       payload.copp_ids[payload.num_copps++] =
+                               msm_bedais[i].port_id;
+                       srs_port_id = msm_bedais[i].port_id;
+                       srs_send_params(srs_port_id, 1, 0);
+               }
+       }
+       if (payload.num_copps)
+               adm_matrix_map(dspst_id, path_type,
+                       payload.num_copps, payload.copp_ids, 0);
+
+       mutex_unlock(&routing_lock);
+}
+void msm_pcm_routing_reg_phy_stream_v2(int fedai_id, bool perf_mode,
+                                      int dspst_id, int stream_type,
+                                      struct msm_pcm_routing_evt event_info)
+{
+       msm_pcm_routing_reg_phy_stream(fedai_id, perf_mode, dspst_id,
+                                      stream_type);
+
+       if (stream_type == SNDRV_PCM_STREAM_PLAYBACK)
+               fe_dai_map[fedai_id][SESSION_TYPE_RX].event_info = event_info;
+       else
+               fe_dai_map[fedai_id][SESSION_TYPE_TX].event_info = event_info;
+
+}
+
+void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type)
+{
+       int i, port_type, session_type;
+
+       if (fedai_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+               /* bad ID assigned in machine driver */
+               pr_err("%s: bad MM ID\n", __func__);
+               return;
+       }
+
+       if (stream_type == SNDRV_PCM_STREAM_PLAYBACK) {
+               port_type = MSM_AFE_PORT_TYPE_RX;
+               session_type = SESSION_TYPE_RX;
+       } else {
+               port_type = MSM_AFE_PORT_TYPE_TX;
+               session_type = SESSION_TYPE_TX;
+       }
+
+       mutex_lock(&routing_lock);
+
+       for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+               if (!is_be_dai_extproc(i) &&
+                  (afe_get_port_type(msm_bedais[i].port_id) == port_type) &&
+                  (msm_bedais[i].active) &&
+                  (test_bit(fedai_id, &msm_bedais[i].fe_sessions)))
+                       adm_close(msm_bedais[i].port_id);
+       }
+
+       fe_dai_map[fedai_id][session_type].strm_id = INVALID_SESSION;
+       fe_dai_map[fedai_id][session_type].be_srate = 0;
+       mutex_unlock(&routing_lock);
+}
+
+/* Check if FE/BE route is set */
+static bool msm_pcm_routing_route_is_set(u16 be_id, u16 fe_id)
+{
+       bool rc = false;
+
+       if (fe_id > MSM_FRONTEND_DAI_MM_MAX_ID) {
+               /* recheck FE ID in the mixer control defined in this file */
+               pr_err("%s: bad MM ID\n", __func__);
+               return rc;
+       }
+
+       if (test_bit(fe_id, &msm_bedais[be_id].fe_sessions))
+               rc = true;
+
+       return rc;
+}
+
+static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set)
+{
+       int session_type, path_type;
+       u32 channels;
+       struct msm_pcm_routing_fdai_data *fdai;
+
+
+       if (val > MSM_FRONTEND_DAI_MM_MAX_ID) {
+               /* recheck FE ID in the mixer control defined in this file */
+               pr_err("%s: bad MM ID\n", __func__);
+               return;
+       }
+
+       if (afe_get_port_type(msm_bedais[reg].port_id) ==
+               MSM_AFE_PORT_TYPE_RX) {
+               session_type = SESSION_TYPE_RX;
+               path_type = ADM_PATH_PLAYBACK;
+       } else {
+               session_type = SESSION_TYPE_TX;
+               path_type = ADM_PATH_LIVE_REC;
+       }
+
+       mutex_lock(&routing_lock);
+
+       if (set) {
+
+               set_bit(val, &msm_bedais[reg].fe_sessions);
+               fdai = &fe_dai_map[val][session_type];
+               if (msm_bedais[reg].active && fdai->strm_id !=
+                       INVALID_SESSION) {
+                       channels = msm_bedais[reg].channel;
+
+                       if (session_type == SESSION_TYPE_TX && fdai->be_srate &&
+                           (fdai->be_srate != msm_bedais[reg].sample_rate)) {
+                               pr_debug("%s: flush strm %d due diff BE rates\n",
+                                       __func__, fdai->strm_id);
+
+                               if (fdai->event_info.event_func)
+                                       fdai->event_info.event_func(
+                                               MSM_PCM_RT_EVT_BUF_RECFG,
+                                               fdai->event_info.priv_data);
+                               fdai->be_srate = 0; /* might not need it */
+                       }
+
+                       if ((session_type == SESSION_TYPE_RX) &&
+                               ((channels == 1) || (channels == 2))
+                               && msm_bedais[reg].perf_mode) {
+                               adm_multi_ch_copp_open(msm_bedais[reg].port_id,
+                               path_type,
+                               msm_bedais[reg].sample_rate,
+                               channels,
+                               DEFAULT_COPP_TOPOLOGY,
+                               msm_bedais[reg].perf_mode);
+                               pr_debug("%s:configure COPP to lowlatency mode",
+                                                                __func__);
+                       } else if ((session_type == SESSION_TYPE_RX)
+                                       && (channels > 2))
+                               adm_multi_ch_copp_open(msm_bedais[reg].port_id,
+                               path_type,
+                               msm_bedais[reg].sample_rate,
+                               channels,
+                               DEFAULT_COPP_TOPOLOGY,
+                               msm_bedais[reg].perf_mode);
+                       else
+                               adm_open(msm_bedais[reg].port_id,
+                               path_type,
+                               msm_bedais[reg].sample_rate, channels,
+                               DEFAULT_COPP_TOPOLOGY);
+
+                       if (session_type == SESSION_TYPE_RX &&
+                               fdai->event_info.event_func)
+                                       fdai->event_info.event_func(
+                                               MSM_PCM_RT_EVT_DEVSWITCH,
+                                               fdai->event_info.priv_data);
+
+                       msm_pcm_routing_build_matrix(val,
+                               fdai->strm_id, path_type);
+                       srs_port_id = msm_bedais[reg].port_id;
+                       srs_send_params(srs_port_id, 1, 0);
+               }
+       } else {
+               clear_bit(val, &msm_bedais[reg].fe_sessions);
+               fdai = &fe_dai_map[val][session_type];
+               if (msm_bedais[reg].active && fdai->strm_id !=
+                       INVALID_SESSION) {
+                       fdai->be_srate = msm_bedais[reg].sample_rate;
+                       adm_close(msm_bedais[reg].port_id);
+                       msm_pcm_routing_build_matrix(val,
+                               fdai->strm_id, path_type);
+               }
+       }
+
+       mutex_unlock(&routing_lock);
+}
+
+static int msm_routing_get_audio_mixer(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct soc_mixer_control *mc =
+       (struct soc_mixer_control *)kcontrol->private_value;
+
+       if (test_bit(mc->shift, &msm_bedais[mc->reg].fe_sessions))
+               ucontrol->value.integer.value[0] = 1;
+       else
+               ucontrol->value.integer.value[0] = 0;
+
+       pr_debug("%s: reg %x shift %x val %ld\n", __func__, mc->reg, mc->shift,
+       ucontrol->value.integer.value[0]);
+
+       return 0;
+}
+
+static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+
+       struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+       
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       unsigned int mask = (1 << fls(mc->max)) - 1;
+       unsigned short val = (ucontrol->value.integer.value[0] & mask);
+       struct snd_soc_dapm_update update;
+       struct snd_soc_card *card;
+
+       card = dapm->card;
+       update.kcontrol = kcontrol;
+       update.reg = mc->reg;
+       update.mask = mask;
+       update.val = val;
+
+
+       if (ucontrol->value.integer.value[0] &&
+          msm_pcm_routing_route_is_set(mc->reg, mc->shift) == false) {
+               msm_pcm_routing_process_audio(mc->reg, mc->shift, 1);
+               snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, &update);
+       } else if (!ucontrol->value.integer.value[0] &&
+                 msm_pcm_routing_route_is_set(mc->reg, mc->shift) == true) {
+               msm_pcm_routing_process_audio(mc->reg, mc->shift, 0);
+               snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, &update);
+       }
+
+       return 0;
+}
+
+static void msm_send_eq_values(int eq_idx)
+{
+       int result;
+       struct audio_client *ac = q6asm_get_audio_client(
+                               fe_dai_map[eq_idx][SESSION_TYPE_RX].strm_id);
+
+       if (ac == NULL) {
+               pr_err("%s: Could not get audio client for session: %d\n",
+                     __func__, fe_dai_map[eq_idx][SESSION_TYPE_RX].strm_id);
+               goto done;
+       }
+
+       result = q6asm_equalizer(ac, &eq_data[eq_idx]);
+
+       if (result < 0)
+               pr_err("%s: Call to ASM equalizer failed, returned = %d\n",
+                     __func__, result);
+done:
+       return;
+}
+
+static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
+       SOC_SINGLE_EXT("MultiMedia1", MSM_BACKEND_DAI_HDMI_RX,
+       MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer,
+       msm_routing_put_audio_mixer),
+       SOC_SINGLE_EXT("MultiMedia2", MSM_BACKEND_DAI_HDMI_RX,
+       MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer,
+       msm_routing_put_audio_mixer),
+       SOC_SINGLE_EXT("MultiMedia3", MSM_BACKEND_DAI_HDMI_RX,
+       MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer,
+       msm_routing_put_audio_mixer),
+       SOC_SINGLE_EXT("MultiMedia4", MSM_BACKEND_DAI_HDMI_RX,
+       MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
+       msm_routing_put_audio_mixer),
+       SOC_SINGLE_EXT("MultiMedia5", MSM_BACKEND_DAI_HDMI_RX,
+       MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer,
+       msm_routing_put_audio_mixer),
+       SOC_SINGLE_EXT("MultiMedia6", MSM_BACKEND_DAI_HDMI_RX,
+       MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer,
+       msm_routing_put_audio_mixer),
+       SOC_SINGLE_EXT("MultiMedia7", MSM_BACKEND_DAI_HDMI_RX,
+       MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer,
+       msm_routing_put_audio_mixer),
+       SOC_SINGLE_EXT("MultiMedia8", MSM_BACKEND_DAI_HDMI_RX,
+       MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer,
+       msm_routing_put_audio_mixer),
+};
+
+static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
+       /* Frontend AIF */
+       /* Widget name equals to Front-End DAI name<Need confirmation>,
+       * Stream name must contains substring of front-end dai name
+       */
+       SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, 0, 0, 0),
+       SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0),
+       SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0),
+       SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0),
+       SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, 0, 0, 0),
+       SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, 0, 0, 0),
+       SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, 0, 0, 0),
+       SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, 0, 0, 0),
+       /* Backend AIF */
+       /* Stream name equals to backend dai link stream name
+       */
+       SND_SOC_DAPM_AIF_OUT("HDMI", "HDMI Playback", 0, 0, 0 , 0),
+       /* incall */
+       /* Mixer definitions */
+       SND_SOC_DAPM_MIXER("HDMI Mixer", SND_SOC_NOPM, 0, 0,
+       hdmi_mixer_controls, ARRAY_SIZE(hdmi_mixer_controls)),
+       SND_SOC_DAPM_OUTPUT("BE_OUT"),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+       {"HDMI Mixer", "MultiMedia1", "MM_DL1"},
+       {"HDMI Mixer", "MultiMedia2", "MM_DL2"},
+       {"HDMI Mixer", "MultiMedia3", "MM_DL3"},
+       {"HDMI Mixer", "MultiMedia4", "MM_DL4"},
+       {"HDMI Mixer", "MultiMedia5", "MM_DL5"},
+       {"HDMI Mixer", "MultiMedia6", "MM_DL6"},
+       {"HDMI Mixer", "MultiMedia7", "MM_DL7"},
+       {"HDMI Mixer", "MultiMedia8", "MM_DL8"},
+       {"HDMI", NULL, "HDMI Mixer"},
+       {"BE_OUT", NULL, "HDMI Playback"},
+       {"HDMI Playback", NULL, "MultiMedia1 Playback"},
+};
+
+int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,
+                               struct snd_pcm_hw_params *params)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       unsigned int be_id = rtd->dai_link->be_id;
+
+       if (be_id >= MSM_BACKEND_DAI_MAX) {
+               pr_err("%s: unexpected be_id %d\n", __func__, be_id);
+               return -EINVAL;
+       }
+
+       mutex_lock(&routing_lock);
+       msm_bedais[be_id].sample_rate = params_rate(params);
+       msm_bedais[be_id].channel = params_channels(params);
+       mutex_unlock(&routing_lock);
+       return 0;
+}
+
+static int msm_pcm_routing_close(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       unsigned int be_id = rtd->dai_link->be_id;
+       int i, session_type;
+       struct msm_pcm_routing_bdai_data *bedai;
+
+       if (be_id >= MSM_BACKEND_DAI_MAX) {
+               pr_err("%s: unexpected be_id %d\n", __func__, be_id);
+               return -EINVAL;
+       }
+
+       bedai = &msm_bedais[be_id];
+       session_type = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+               0 : 1);
+
+       mutex_lock(&routing_lock);
+
+       for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
+               if (fe_dai_map[i][session_type].strm_id != INVALID_SESSION) {
+                       fe_dai_map[i][session_type].be_srate =
+                               bedai->sample_rate;
+                       adm_close(bedai->port_id);
+                       srs_port_id = -1;
+               }
+       }
+
+       bedai->active = 0;
+       bedai->sample_rate = 0;
+       bedai->channel = 0;
+       bedai->perf_mode = false;
+       mutex_unlock(&routing_lock);
+
+       return 0;
+}
+
+int msm_pcm_routing_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       unsigned int be_id = rtd->dai_link->be_id;
+       int i, path_type, session_type;
+       struct msm_pcm_routing_bdai_data *bedai;
+       u32 channels;
+       bool playback, capture;
+       struct msm_pcm_routing_fdai_data *fdai;
+
+       if (be_id >= MSM_BACKEND_DAI_MAX) {
+               pr_err("%s: unexpected be_id %d\n", __func__, be_id);
+               return -EINVAL;
+       }
+
+       bedai = &msm_bedais[be_id];
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               path_type = ADM_PATH_PLAYBACK;
+               session_type = SESSION_TYPE_RX;
+       } else {
+               path_type = ADM_PATH_LIVE_REC;
+               session_type = SESSION_TYPE_TX;
+       }
+
+       mutex_lock(&routing_lock);
+
+       if (bedai->active == 1)
+               goto done; /* Ignore prepare if back-end already active */
+
+       /* AFE port is not active at this point. However, still
+       * go ahead setting active flag under the notion that
+       * QDSP6 is able to handle ADM starting before AFE port
+       * is started.
+       */
+       bedai->active = 1;
+       playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
+       capture  = substream->stream == SNDRV_PCM_STREAM_CAPTURE;
+
+       for_each_set_bit(i, &bedai->fe_sessions, MSM_FRONTEND_DAI_MM_SIZE) {
+               fdai = &fe_dai_map[i][session_type];
+               if (fdai->strm_id != INVALID_SESSION) {
+                       if (session_type == SESSION_TYPE_TX && fdai->be_srate &&
+                           (fdai->be_srate != bedai->sample_rate)) {
+                               pr_debug("%s: flush strm %d due diff BE rates\n",
+                                       __func__,
+                                       fdai->strm_id);
+
+                               if (fdai->event_info.event_func)
+                                       fdai->event_info.event_func(
+                                               MSM_PCM_RT_EVT_BUF_RECFG,
+                                               fdai->event_info.priv_data);
+                               fdai->be_srate = 0; /* might not need it */
+                       }
+
+                       channels = bedai->channel;
+                       if ((playback || capture)
+                               && ((channels == 2) || (channels == 1)) &&
+                               bedai->perf_mode) {
+                               adm_multi_ch_copp_open(bedai->port_id,
+                               path_type,
+                               bedai->sample_rate,
+                               channels,
+                               DEFAULT_COPP_TOPOLOGY, bedai->perf_mode);
+                               pr_debug("%s:configure COPP to lowlatency mode",
+                                                               __func__);
+                       } else if ((playback || capture)
+                               && (channels > 2))
+                               adm_multi_ch_copp_open(bedai->port_id,
+                               path_type,
+                               bedai->sample_rate,
+                               channels,
+                               DEFAULT_COPP_TOPOLOGY, bedai->perf_mode);
+                       else
+                               adm_open(bedai->port_id,
+                               path_type,
+                               bedai->sample_rate,
+                               channels,
+                               DEFAULT_COPP_TOPOLOGY);
+
+                       msm_pcm_routing_build_matrix(i,
+                               fdai->strm_id, path_type);
+                       srs_port_id = bedai->port_id;
+                       srs_send_params(srs_port_id, 1, 0);
+               }
+       }
+
+done:
+       mutex_unlock(&routing_lock);
+
+       return 0;
+}
+
+static struct snd_pcm_ops msm_routing_pcm_ops = {
+       .hw_params      = msm_pcm_routing_hw_params,
+       .close          = msm_pcm_routing_close,
+       .prepare        = msm_pcm_routing_prepare,
+};
+
+/* Not used but frame seems to require it */
+static int msm_routing_probe(struct snd_soc_platform *platform)
+{
+       return 0;
+}
+
+static int msm_asoc_routing_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+       return 0;
+}
+
+static struct snd_soc_platform_driver msm_soc_routing_platform = {
+       .ops            = &msm_routing_pcm_ops,
+       .probe          = msm_routing_probe,
+       .pcm_new        = msm_asoc_routing_pcm_new,
+       .component_driver =  {
+               .name = "msm-qdsp6-routing-dai",
+               .dapm_widgets = msm_qdsp6_widgets,
+               .num_dapm_widgets = ARRAY_SIZE(msm_qdsp6_widgets),
+               .dapm_routes = intercon,
+               .num_dapm_routes = ARRAY_SIZE(intercon),
+       },
+};
+
+static  int msm_routing_pcm_probe(struct platform_device *pdev)
+{
+       int ret;
+       dev_dbg(&pdev->dev, "dev name %s\n", dev_name(&pdev->dev));
+       ret = snd_soc_register_platform(&pdev->dev,
+                                 &msm_soc_routing_platform);
+       return ret;
+}
+
+static int msm_routing_pcm_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_platform(&pdev->dev);
+       return 0;
+}
+
+static const struct of_device_id msm_routing_dt_match[] = {
+       {.compatible = "qcom,msm-pcm-routing"},
+       {}
+};
+
+static struct platform_driver msm_routing_pcm_driver = {
+       .driver = {
+               .name = "msm-pcm-routing",
+               .owner = THIS_MODULE,
+               .of_match_table = msm_routing_dt_match,
+       },
+       .probe = msm_routing_pcm_probe,
+       .remove = (msm_routing_pcm_remove),
+};
+
+int msm_routing_check_backend_enabled(int fedai_id)
+{
+       int i;
+
+       if (fedai_id >= MSM_FRONTEND_DAI_MM_MAX_ID) {
+               /* bad ID assigned in machine driver */
+               pr_err("%s: bad MM ID\n", __func__);
+               return 0;
+       }
+       for (i = 0; i < MSM_BACKEND_DAI_MAX; i++) {
+               if (test_bit(fedai_id, &msm_bedais[i].fe_sessions))
+                       return msm_bedais[i].active;
+       }
+       return 0;
+}
+module_platform_driver(msm_routing_pcm_driver);
+MODULE_DESCRIPTION("MSM routing platform driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/msm-pcm-routing.h b/sound/soc/qcom/msm-pcm-routing.h
new file mode 100644 (file)
index 0000000..ad63c12
--- /dev/null
@@ -0,0 +1,145 @@
+/* Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef _MSM_PCM_ROUTING_H
+#define _MSM_PCM_ROUTING_H
+#include <sound/apr_audio.h>
+
+#define LPASS_BE_PRI_I2S_RX "PRIMARY_I2S_RX"
+#define LPASS_BE_PRI_I2S_TX "PRIMARY_I2S_TX"
+#define LPASS_BE_SLIMBUS_0_RX "SLIMBUS_0_RX"
+#define LPASS_BE_SLIMBUS_0_TX "SLIMBUS_0_TX"
+#define LPASS_BE_HDMI "HDMI"
+#define LPASS_BE_INT_BT_SCO_RX "INT_BT_SCO_RX"
+#define LPASS_BE_INT_BT_SCO_TX "INT_BT_SCO_TX"
+#define LPASS_BE_INT_FM_RX "INT_FM_RX"
+#define LPASS_BE_INT_FM_TX "INT_FM_TX"
+#define LPASS_BE_AFE_PCM_RX "RT_PROXY_DAI_001_RX"
+#define LPASS_BE_AFE_PCM_TX "RT_PROXY_DAI_002_TX"
+#define LPASS_BE_AUXPCM_RX "AUX_PCM_RX"
+#define LPASS_BE_AUXPCM_TX "AUX_PCM_TX"
+#define LPASS_BE_SEC_AUXPCM_RX "SEC_AUX_PCM_RX"
+#define LPASS_BE_SEC_AUXPCM_TX "SEC_AUX_PCM_TX"
+#define LPASS_BE_VOICE_PLAYBACK_TX "VOICE_PLAYBACK_TX"
+#define LPASS_BE_INCALL_RECORD_RX "INCALL_RECORD_TX"
+#define LPASS_BE_INCALL_RECORD_TX "INCALL_RECORD_RX"
+#define LPASS_BE_SEC_I2S_RX "SECONDARY_I2S_RX"
+
+#define LPASS_BE_MI2S_RX "(Backend) MI2S_RX"
+#define LPASS_BE_MI2S_TX "(Backend) MI2S_TX"
+#define LPASS_BE_STUB_RX "(Backend) STUB_RX"
+#define LPASS_BE_STUB_TX "(Backend) STUB_TX"
+#define LPASS_BE_SLIMBUS_1_RX "(Backend) SLIMBUS_1_RX"
+#define LPASS_BE_SLIMBUS_1_TX "(Backend) SLIMBUS_1_TX"
+#define LPASS_BE_STUB_1_TX "(Backend) STUB_1_TX"
+#define LPASS_BE_SLIMBUS_3_RX "(Backend) SLIMBUS_3_RX"
+#define LPASS_BE_SLIMBUS_3_TX "(Backend) SLIMBUS_3_TX"
+#define LPASS_BE_SLIMBUS_4_RX "(Backend) SLIMBUS_4_RX"
+#define LPASS_BE_SLIMBUS_4_TX "(Backend) SLIMBUS_4_TX"
+
+/* For multimedia front-ends, asm session is allocated dynamically.
+ * Hence, asm session/multimedia front-end mapping has to be maintained.
+ * Due to this reason, additional multimedia front-end must be placed before
+ * non-multimedia front-ends.
+ */
+
+enum {
+       MSM_FRONTEND_DAI_MULTIMEDIA1 = 0,
+       MSM_FRONTEND_DAI_MULTIMEDIA2,
+       MSM_FRONTEND_DAI_MULTIMEDIA3,
+       MSM_FRONTEND_DAI_MULTIMEDIA4,
+       MSM_FRONTEND_DAI_MULTIMEDIA5,
+       MSM_FRONTEND_DAI_MULTIMEDIA6,
+       MSM_FRONTEND_DAI_MULTIMEDIA7,
+       MSM_FRONTEND_DAI_MULTIMEDIA8,
+       MSM_FRONTEND_DAI_CS_VOICE,
+       MSM_FRONTEND_DAI_VOIP,
+       MSM_FRONTEND_DAI_AFE_RX,
+       MSM_FRONTEND_DAI_AFE_TX,
+       MSM_FRONTEND_DAI_VOICE_STUB,
+       MSM_FRONTEND_DAI_VOLTE,
+       MSM_FRONTEND_DAI_VOICE2,
+       MSM_FRONTEND_DAI_VOLTE_STUB,
+       MSM_FRONTEND_DAI_VOICE2_STUB,
+       MSM_FRONTEND_DAI_MAX,
+};
+
+#define MSM_FRONTEND_DAI_MM_SIZE (MSM_FRONTEND_DAI_MULTIMEDIA8 + 1)
+#define MSM_FRONTEND_DAI_MM_MAX_ID MSM_FRONTEND_DAI_MULTIMEDIA8
+
+enum {
+       MSM_BACKEND_DAI_PRI_I2S_RX = 0,
+       MSM_BACKEND_DAI_PRI_I2S_TX,
+       MSM_BACKEND_DAI_SLIMBUS_0_RX,
+       MSM_BACKEND_DAI_SLIMBUS_0_TX,
+       MSM_BACKEND_DAI_HDMI_RX,
+       MSM_BACKEND_DAI_INT_BT_SCO_RX,
+       MSM_BACKEND_DAI_INT_BT_SCO_TX,
+       MSM_BACKEND_DAI_INT_FM_RX,
+       MSM_BACKEND_DAI_INT_FM_TX,
+       MSM_BACKEND_DAI_AFE_PCM_RX,
+       MSM_BACKEND_DAI_AFE_PCM_TX,
+       MSM_BACKEND_DAI_AUXPCM_RX,
+       MSM_BACKEND_DAI_AUXPCM_TX,
+       MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
+       MSM_BACKEND_DAI_INCALL_RECORD_RX,
+       MSM_BACKEND_DAI_INCALL_RECORD_TX,
+       MSM_BACKEND_DAI_MI2S_RX,
+       MSM_BACKEND_DAI_MI2S_TX,
+       MSM_BACKEND_DAI_SEC_I2S_RX,
+       MSM_BACKEND_DAI_SLIMBUS_1_RX,
+       MSM_BACKEND_DAI_SLIMBUS_1_TX,
+       MSM_BACKEND_DAI_SLIMBUS_4_RX,
+       MSM_BACKEND_DAI_SLIMBUS_4_TX,
+       MSM_BACKEND_DAI_SLIMBUS_3_RX,
+       MSM_BACKEND_DAI_SLIMBUS_3_TX,
+       MSM_BACKEND_DAI_EXTPROC_RX,
+       MSM_BACKEND_DAI_EXTPROC_TX,
+       MSM_BACKEND_DAI_EXTPROC_EC_TX,
+       MSM_BACKEND_DAI_SEC_AUXPCM_RX,
+       MSM_BACKEND_DAI_SEC_AUXPCM_TX,
+       MSM_BACKEND_DAI_MAX,
+};
+
+enum msm_pcm_routing_event {
+       MSM_PCM_RT_EVT_BUF_RECFG,
+       MSM_PCM_RT_EVT_DEVSWITCH,
+       MSM_PCM_RT_EVT_MAX,
+};
+/* dai_id: front-end ID,
+ * dspst_id:  DSP audio stream ID
+ * stream_type: playback or capture
+ */
+void msm_pcm_routing_reg_phy_stream(int fedai_id, bool perf_mode,
+                               int dspst_id, int stream_type);
+void msm_pcm_routing_reg_psthr_stream(int fedai_id, int dspst_id,
+               int stream_type, int enable);
+
+struct msm_pcm_routing_evt {
+       void (*event_func)(enum msm_pcm_routing_event, void *);
+       void *priv_data;
+};
+
+void msm_pcm_routing_reg_phy_stream_v2(int fedai_id, bool perf_mode,
+                                      int dspst_id, int stream_type,
+                                      struct msm_pcm_routing_evt event_info);
+
+void msm_pcm_routing_dereg_phy_stream(int fedai_id, int stream_type);
+
+int lpa_set_volume(unsigned volume);
+
+int msm_routing_check_backend_enabled(int fedai_id);
+
+int multi_ch_pcm_set_volume(unsigned volume);
+
+int compressed_set_volume(unsigned volume);
+
+#endif /*_MSM_PCM_H*/
diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile
new file mode 100644 (file)
index 0000000..b636583
--- /dev/null
@@ -0,0 +1,2 @@
+obj-y := q6asm.o q6adm.o q6afe.o
+obj-$(CONFIG_SND_SOC_QDSP6) += core/
diff --git a/sound/soc/qcom/qdsp6/core/Makefile b/sound/soc/qcom/qdsp6/core/Makefile
new file mode 100644 (file)
index 0000000..06089d9
--- /dev/null
@@ -0,0 +1,3 @@
+obj-y += apr.o apr_v1.o apr_tal.o q6core.o dsp_debug.o
+obj-y += audio_acdb.o
+obj-y += rtac.o
diff --git a/sound/soc/qcom/qdsp6/core/apr.c b/sound/soc/qcom/qdsp6/core/apr.c
new file mode 100644 (file)
index 0000000..ae4801e
--- /dev/null
@@ -0,0 +1,649 @@
+/* Copyright (c) 2010-2012, The Linux Foundation. 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/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 <linux/of.h>
+#include <linux/remoteproc.h>
+#include <sound/qdsp6v2/apr.h>
+#include <sound/qdsp6v2/apr_tal.h>
+#include <sound/qdsp6v2/dsp_debug.h>
+
+static struct apr_q6 q6;
+static struct apr_client client[APR_DEST_MAX][APR_CLIENT_MAX];
+
+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;
+};
+
+struct apr_svc_table {
+       char name[64];
+       int idx;
+       int id;
+       int client_id;
+};
+
+static const struct apr_svc_table svc_tbl_audio[] = {
+       {
+               .name = "AFE",
+               .idx = 0,
+               .id = APR_SVC_AFE,
+               .client_id = APR_CLIENT_AUDIO,
+       },
+       {
+               .name = "ASM",
+               .idx = 1,
+               .id = APR_SVC_ASM,
+               .client_id = APR_CLIENT_AUDIO,
+       },
+       {
+               .name = "ADM",
+               .idx = 2,
+               .id = APR_SVC_ADM,
+               .client_id = APR_CLIENT_AUDIO,
+       },
+       {
+               .name = "CORE",
+               .idx = 3,
+               .id = APR_SVC_ADSP_CORE,
+               .client_id = APR_CLIENT_AUDIO,
+       },
+       {
+               .name = "TEST",
+               .idx = 4,
+               .id = APR_SVC_TEST_CLIENT,
+               .client_id = APR_CLIENT_AUDIO,
+       },
+       {
+               .name = "MVM",
+               .idx = 5,
+               .id = APR_SVC_ADSP_MVM,
+               .client_id = APR_CLIENT_AUDIO,
+       },
+       {
+               .name = "CVS",
+               .idx = 6,
+               .id = APR_SVC_ADSP_CVS,
+               .client_id = APR_CLIENT_AUDIO,
+       },
+       {
+               .name = "CVP",
+               .idx = 7,
+               .id = APR_SVC_ADSP_CVP,
+               .client_id = APR_CLIENT_AUDIO,
+       },
+       {
+               .name = "USM",
+               .idx = 8,
+               .id = APR_SVC_USM,
+               .client_id = APR_CLIENT_AUDIO,
+       },
+};
+
+static struct apr_svc_table svc_tbl_voice[] = {
+       {
+               .name = "VSM",
+               .idx = 0,
+               .id = APR_SVC_VSM,
+               .client_id = APR_CLIENT_VOICE,
+       },
+       {
+               .name = "VPM",
+               .idx = 1,
+               .id = APR_SVC_VPM,
+               .client_id = APR_CLIENT_VOICE,
+       },
+       {
+               .name = "MVS",
+               .idx = 2,
+               .id = APR_SVC_MVS,
+               .client_id = APR_CLIENT_VOICE,
+       },
+       {
+               .name = "MVM",
+               .idx = 3,
+               .id = APR_SVC_MVM,
+               .client_id = APR_CLIENT_VOICE,
+       },
+       {
+               .name = "CVS",
+               .idx = 4,
+               .id = APR_SVC_CVS,
+               .client_id = APR_CLIENT_VOICE,
+       },
+       {
+               .name = "CVP",
+               .idx = 5,
+               .id = APR_SVC_CVP,
+               .client_id = APR_CLIENT_VOICE,
+       },
+       {
+               .name = "SRD",
+               .idx = 6,
+               .id = APR_SVC_SRD,
+               .client_id = APR_CLIENT_VOICE,
+       },
+       {
+               .name = "TEST",
+               .idx = 7,
+               .id = APR_SVC_TEST_CLIENT,
+               .client_id = APR_CLIENT_VOICE,
+       },
+};
+
+enum apr_subsys_state apr_get_modem_state(void)
+{
+       return atomic_read(&q6.modem_state);
+}
+
+void apr_set_modem_state(enum apr_subsys_state state)
+{
+       atomic_set(&q6.modem_state, state);
+}
+
+enum apr_subsys_state apr_cmpxchg_modem_state(enum apr_subsys_state prev,
+                                             enum apr_subsys_state new)
+{
+       return atomic_cmpxchg(&q6.modem_state, prev, new);
+}
+
+enum apr_subsys_state apr_get_q6_state(void)
+{
+       return atomic_read(&q6.q6_state);
+}
+EXPORT_SYMBOL_GPL(apr_get_q6_state);
+
+int apr_set_q6_state(enum apr_subsys_state state)
+{
+       pr_debug("%s: setting adsp state %d\n", __func__, state);
+       if (state < APR_SUBSYS_DOWN || state > APR_SUBSYS_LOADED)
+               return -EINVAL;
+       atomic_set(&q6.q6_state, state);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(apr_set_q6_state);
+
+enum apr_subsys_state apr_cmpxchg_q6_state(enum apr_subsys_state prev,
+                                          enum apr_subsys_state new)
+{
+       return atomic_cmpxchg(&q6.q6_state, prev, new);
+}
+
+int apr_wait_for_device_up(int dest_id)
+{
+       int rc = -1;
+       if (dest_id == APR_DEST_MODEM)
+               rc = wait_event_interruptible_timeout(modem_wait,
+                                   (apr_get_modem_state() == APR_SUBSYS_UP),
+                                   (1 * HZ));
+       else if (dest_id == APR_DEST_QDSP6)
+               rc = wait_event_interruptible_timeout(dsp_wait,
+                                   (apr_get_q6_state() == APR_SUBSYS_UP),
+                                   (1 * HZ));
+       else
+               pr_err("%s: unknown dest_id %d\n", __func__, dest_id);
+       /* returns left time */
+       return rc;
+}
+
+int apr_load_adsp_image(void)
+{
+       int rc = 0;
+       struct device_node *np;
+       phandle phandle;
+       const __be32 *list;
+       int size;
+
+       mutex_lock(&q6.lock);
+       if (apr_get_q6_state() == APR_SUBSYS_UP) {
+               np = of_find_compatible_node(NULL, NULL, "qcom,apr");
+               list = of_get_property(np, "rproc", &size);
+               phandle = be32_to_cpup(list++);
+
+               q6.rproc = rproc_get_by_phandle(phandle);
+
+               if (!q6.rproc) {
+                       rc = -ENODEV;
+                       pr_err("APR: Unable to load q6 image, error:%d\n", rc);
+               } else {
+                       rproc_boot(q6.rproc);
+                       apr_set_q6_state(APR_SUBSYS_LOADED);
+                       pr_debug("APR: Image is loaded, stated\n");
+               }
+       } else
+               pr_debug("APR: cannot load state %d\n", apr_get_q6_state());
+       mutex_unlock(&q6.lock);
+       return rc;
+}
+
+struct apr_client *apr_get_client(int dest_id, int client_id)
+{
+       return &client[dest_id][client_id];
+}
+
+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) &&
+           (apr_get_q6_state() != APR_SUBSYS_LOADED)) {
+               pr_err("%s: Still dsp is not Up\n", __func__);
+               return -ENETRESET;
+       } else if ((svc->dest_id == APR_DEST_MODEM) &&
+                  (apr_get_modem_state() == APR_SUBSYS_DOWN)) {
+               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;
+}
+
+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_USM ||
+                   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");
+}
+
+int apr_get_svc(const char *svc_name, int dest_id, int *client_id,
+               int *svc_idx, int *svc_id)
+{
+       int i;
+       int size;
+       struct apr_svc_table *tbl;
+       int ret = 0;
+
+       if (dest_id == APR_DEST_QDSP6) {
+               tbl = (struct apr_svc_table *)&svc_tbl_audio;
+               size = ARRAY_SIZE(svc_tbl_audio);
+       } else {
+               tbl = (struct apr_svc_table *)&svc_tbl_voice;
+               size = ARRAY_SIZE(svc_tbl_voice);
+       }
+
+       for (i = 0; i < size; i++) {
+               if (!strncmp(svc_name, tbl[i].name, strlen(tbl[i].name))) {
+                       *client_id = tbl[i].client_id;
+                       *svc_idx = tbl[i].idx;
+                       *svc_id = tbl[i].id;
+                       break;
+               }
+       }
+
+       pr_debug("%s: svc_name = %s c_id = %d dest_id = %d\n",
+                __func__, svc_name, *client_id, dest_id);
+       if (i == size) {
+               pr_err("%s: APR: Wrong svc name %s\n", __func__, svc_name);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+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);
+
+       if (apr_reset_workqueue == NULL) {
+               pr_err("%s: apr_reset_workqueue is NULL\n", __func__);
+               return;
+       }
+
+       apr_reset_worker = kzalloc(sizeof(struct apr_reset_work),
+                                                       GFP_ATOMIC);
+
+       if (apr_reset_worker == 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);
+}
+
+static 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 __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);
+                       }
+               }
+       apr_set_subsys_state();
+       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)
+{
+       int ret = 0;
+       init_waitqueue_head(&dsp_wait);
+       init_waitqueue_head(&modem_wait);
+       return ret;
+}
+late_initcall(apr_late_init);
diff --git a/sound/soc/qcom/qdsp6/core/apr_tal.c b/sound/soc/qcom/qdsp6/core/apr_tal.c
new file mode 100644 (file)
index 0000000..cca94c6
--- /dev/null
@@ -0,0 +1,177 @@
+/* Copyright (c) 2015, The Linux Foundation. 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/platform_device.h>
+#include <linux/delay.h>
+#include <sound/qdsp6v2/apr_tal.h>
+#include <linux/soc/qcom/smd.h>
+#include <linux/io.h>
+
+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 ret;
+       ret = qcom_smd_send(apr_ch->ch, data, len);
+       if (ret) { 
+               pr_err("apr_tal: Error in write %d\n", ret);
+               return ret;;
+       }
+       return len;
+}
+
+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;
+       pr_err("apr_tal:open\n");
+       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;
+       }
+
+       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_err("apr_tal:open timeout\n");
+                       return NULL;
+               }
+               pr_info("apr_tal:Wakeup done\n");
+               apr_svc_ch[dl][dest][svc].dest_state = 0;
+       }
+
+       rc = wait_event_timeout(apr_svc_ch[dl][dest][svc].wait,
+               (apr_svc_ch[dl][dest][svc].ch->state == SMD_CHANNEL_OPENED), 5 * HZ);
+       if (rc == 0) {
+               pr_err("apr_tal:TIMEOUT for OPEN event\n");
+               apr_tal_close(&apr_svc_ch[dl][dest][svc]);
+               return NULL;
+       }
+       if (!apr_svc_ch[dl][dest][svc].dest_state) {
+               apr_svc_ch[dl][dest][svc].dest_state = 1;
+               pr_info("apr_tal:Waiting for apr svc init\n");
+               msleep(200);
+               pr_info("apr_tal:apr svc init done\n");
+       }
+       apr_svc_ch[dl][dest][svc].func = func;
+       apr_svc_ch[dl][dest][svc].priv = priv;
+
+
+       return &apr_svc_ch[dl][dest][svc];
+}
+
+int apr_tal_close(struct apr_svc_ch_dev *apr_ch)
+{
+       if (!apr_ch->ch)
+               return -EINVAL;
+
+       apr_ch->ch = NULL;
+       apr_ch->func = NULL;
+       apr_ch->priv = NULL;
+       return 0;
+}
+
+
+static int qcom_smd_q6_callback(struct qcom_smd_device *sdev,
+                                const void *data,
+                                size_t count)
+{
+       struct apr_svc_ch_dev *apr_ch = dev_get_drvdata(&sdev->dev);
+
+       memcpy_fromio(apr_ch->data, data, count);
+
+       if (apr_ch->func)
+               apr_ch->func(apr_ch->data, count, apr_ch->priv);
+
+       return 0;
+}
+
+static int qcom_smd_q6_probe(struct qcom_smd_device *sdev)
+{
+       int dest = APR_DEST_QDSP6;
+       int clnt = APR_CLIENT_AUDIO;
+
+       apr_svc_ch[APR_DL_SMD][APR_DEST_QDSP6][APR_CLIENT_AUDIO].ch = sdev->channel;
+
+       pr_info("apr_tal:Q6 Is Up\n");
+       apr_svc_ch[APR_DL_SMD][dest][clnt].dest_state = 1;
+       wake_up(&apr_svc_ch[APR_DL_SMD][dest][clnt].dest);
+
+       dev_set_drvdata(&sdev->dev, &apr_svc_ch[APR_DL_SMD][APR_DEST_QDSP6][APR_CLIENT_AUDIO]);
+
+       return 0;
+}
+
+static void qcom_smd_q6_remove(struct qcom_smd_device *sdev)
+{
+}
+
+
+static const struct of_device_id qcom_smd_q6_of_match[] = {
+       { .compatible = "qcom,apr" },
+       {}
+};
+
+static struct qcom_smd_driver qcom_smd_q6_driver = {
+       .probe = qcom_smd_q6_probe,
+       .remove = qcom_smd_q6_remove,
+       .callback = qcom_smd_q6_callback,
+       .driver  = {
+               .name  = "qcom_smd_q6",
+               .owner = THIS_MODULE,
+               .of_match_table = qcom_smd_q6_of_match,
+       },
+};
+
+static void __exit qcom_smd_q6_exit(void)
+{
+       qcom_smd_driver_unregister(&qcom_smd_q6_driver);
+}
+module_exit(qcom_smd_q6_exit);
+
+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);
+                       }
+       qcom_smd_driver_register(&qcom_smd_q6_driver);
+       return 0;
+}
+device_initcall(apr_tal_init);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_DESCRIPTION("Qualcomm SMD backed apr driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/qdsp6/core/apr_v1.c b/sound/soc/qcom/qdsp6/core/apr_v1.c
new file mode 100644 (file)
index 0000000..1547c0c
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2012, The Linux Foundation. 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/err.h>
+#include <sound/qdsp6v2/apr.h>
+#include <sound/qdsp6v2/apr_tal.h>
+
+struct apr_svc *apr_register(char *dest, char *svc_name, apr_fn svc_fn,
+                            uint32_t src_port, void *priv)
+{
+       struct apr_client *client;
+       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 (!strncmp(dest, "ADSP", 4))
+               dest_id = APR_DEST_QDSP6;
+       else if (!strncmp(dest, "MODEM", 5)) {
+               dest_id = APR_DEST_MODEM;
+       } else {
+               pr_err("APR: wrong destination\n");
+               goto done;
+       }
+
+       if (dest_id == APR_DEST_QDSP6 &&
+           apr_get_q6_state() == APR_SUBSYS_DOWN) {
+               pr_info("%s: Wait for Lpass to bootup\n", __func__);
+               rc = apr_wait_for_device_up(dest_id);
+               if (rc == 0) {
+                       pr_err("%s: DSP is not Up\n", __func__);
+                       return NULL;
+               }
+               pr_info("%s: Lpass Up\n", __func__);
+       } else if (dest_id == APR_DEST_MODEM &&
+                  (apr_get_modem_state() == APR_SUBSYS_DOWN)) {
+               pr_info("%s: Wait for modem to bootup\n", __func__);
+               rc = apr_wait_for_device_up(dest_id);
+               if (rc == 0) {
+                       pr_err("%s: Modem is not Up\n", __func__);
+                       return NULL;
+               }
+               pr_info("%s: modem Up\n", __func__);
+       }
+
+       if (apr_get_svc(svc_name, dest_id, &client_id, &svc_idx, &svc_id)) {
+               pr_err("%s: apr_get_svc failed\n", __func__);
+               goto done;
+       }
+
+       /* APRv1 loads ADSP image automatically */
+       apr_load_adsp_image();
+
+       client = apr_get_client(dest_id, client_id);
+       mutex_lock(&client->m_lock);
+       if (!client->handle) {
+               client->handle = apr_tal_open(client_id, dest_id, APR_DL_SMD,
+                                             apr_cb_func, NULL);
+               if (!client->handle) {
+                       svc = NULL;
+                       pr_err("APR: Unable to open handle\n");
+                       mutex_unlock(&client->m_lock);
+                       goto done;
+               }
+       }
+       mutex_unlock(&client->m_lock);
+       svc = &client->svc[svc_idx];
+       mutex_lock(&svc->m_lock);
+       client->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->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->svc_cnt++;
+                       svc->fn = svc_fn;
+                       if (svc->port_cnt)
+                               svc->svc_cnt++;
+               }
+       }
+
+       mutex_unlock(&svc->m_lock);
+done:
+       return svc;
+}
+
+void apr_set_subsys_state(void)
+{
+       apr_set_q6_state(APR_SUBSYS_UP);
+       apr_set_modem_state(APR_SUBSYS_UP);
+}
diff --git a/sound/soc/qcom/qdsp6/core/audio_acdb.c b/sound/soc/qcom/qdsp6/core/audio_acdb.c
new file mode 100644 (file)
index 0000000..88ca649
--- /dev/null
@@ -0,0 +1,865 @@
+/* Copyright (c) 2010-2012, The Linux Foundation. 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/mm.h>
+#include <sound/qdsp6v2/audio_acdb.h>
+
+
+#define MAX_NETWORKS           15
+
+struct sidetone_atomic_cal {
+       atomic_t        enable;
+       atomic_t        gain;
+};
+
+
+struct acdb_data {
+       struct mutex            acdb_mutex;
+
+       /* ANC Cal */
+       struct acdb_atomic_cal_block    anc_cal;
+
+       /* AudProc Cal */
+       atomic_t                        asm_topology;
+       atomic_t                        adm_topology[MAX_AUDPROC_TYPES];
+       struct acdb_atomic_cal_block    audproc_cal[MAX_AUDPROC_TYPES];
+       struct acdb_atomic_cal_block    audstrm_cal[MAX_AUDPROC_TYPES];
+       struct acdb_atomic_cal_block    audvol_cal[MAX_AUDPROC_TYPES];
+
+       /* VocProc Cal */
+       atomic_t                        voice_rx_topology;
+       atomic_t                        voice_tx_topology;
+       struct acdb_atomic_cal_block    vocproc_cal[MAX_NETWORKS];
+       struct acdb_atomic_cal_block    vocstrm_cal[MAX_NETWORKS];
+       struct acdb_atomic_cal_block    vocvol_cal[MAX_NETWORKS];
+       /* size of cal block tables above*/
+       atomic_t                        vocproc_cal_size;
+       atomic_t                        vocstrm_cal_size;
+       atomic_t                        vocvol_cal_size;
+       /* Total size of cal data for all networks */
+       atomic_t                        vocproc_total_cal_size;
+       atomic_t                        vocstrm_total_cal_size;
+       atomic_t                        vocvol_total_cal_size;
+
+       /* AFE cal */
+       struct acdb_atomic_cal_block    afe_cal[MAX_AUDPROC_TYPES];
+
+       /* Sidetone Cal */
+       struct sidetone_atomic_cal      sidetone_cal;
+
+
+       /* Allocation information */
+//     struct ion_client               *ion_client;
+//     struct ion_handle               *ion_handle;
+       atomic_t                        map_handle;
+       atomic64_t                      paddr;
+       atomic64_t                      kvaddr;
+       atomic64_t                      mem_len;
+};
+
+static struct acdb_data                acdb_data;
+static atomic_t usage_count;
+
+uint32_t get_voice_rx_topology(void)
+{
+       return atomic_read(&acdb_data.voice_rx_topology);
+}
+
+void store_voice_rx_topology(uint32_t topology)
+{
+       atomic_set(&acdb_data.voice_rx_topology, topology);
+}
+
+uint32_t get_voice_tx_topology(void)
+{
+       return atomic_read(&acdb_data.voice_tx_topology);
+}
+
+void store_voice_tx_topology(uint32_t topology)
+{
+       atomic_set(&acdb_data.voice_tx_topology, topology);
+}
+
+uint32_t get_adm_rx_topology(void)
+{
+       return atomic_read(&acdb_data.adm_topology[RX_CAL]);
+}
+
+void store_adm_rx_topology(uint32_t topology)
+{
+       atomic_set(&acdb_data.adm_topology[RX_CAL], topology);
+}
+
+uint32_t get_adm_tx_topology(void)
+{
+       return atomic_read(&acdb_data.adm_topology[TX_CAL]);
+}
+
+void store_adm_tx_topology(uint32_t topology)
+{
+       atomic_set(&acdb_data.adm_topology[TX_CAL], topology);
+}
+
+uint32_t get_asm_topology(void)
+{
+       return atomic_read(&acdb_data.asm_topology);
+}
+
+void store_asm_topology(uint32_t topology)
+{
+       atomic_set(&acdb_data.asm_topology, topology);
+}
+
+void get_all_voice_cal(struct acdb_cal_block *cal_block)
+{
+       cal_block->cal_kvaddr =
+               atomic_read(&acdb_data.vocproc_cal[0].cal_kvaddr);
+       cal_block->cal_paddr =
+               atomic_read(&acdb_data.vocproc_cal[0].cal_paddr);
+       cal_block->cal_size =
+               atomic_read(&acdb_data.vocproc_total_cal_size) +
+               atomic_read(&acdb_data.vocstrm_total_cal_size) +
+               atomic_read(&acdb_data.vocvol_total_cal_size);
+}
+
+void get_all_cvp_cal(struct acdb_cal_block *cal_block)
+{
+       cal_block->cal_kvaddr =
+               atomic_read(&acdb_data.vocproc_cal[0].cal_kvaddr);
+       cal_block->cal_paddr =
+               atomic_read(&acdb_data.vocproc_cal[0].cal_paddr);
+       cal_block->cal_size =
+               atomic_read(&acdb_data.vocproc_total_cal_size) +
+               atomic_read(&acdb_data.vocvol_total_cal_size);
+}
+
+void get_all_vocproc_cal(struct acdb_cal_block *cal_block)
+{
+       cal_block->cal_kvaddr =
+               atomic_read(&acdb_data.vocproc_cal[0].cal_kvaddr);
+       cal_block->cal_paddr =
+               atomic_read(&acdb_data.vocproc_cal[0].cal_paddr);
+       cal_block->cal_size =
+               atomic_read(&acdb_data.vocproc_total_cal_size);
+}
+
+void get_all_vocstrm_cal(struct acdb_cal_block *cal_block)
+{
+       cal_block->cal_kvaddr =
+               atomic_read(&acdb_data.vocstrm_cal[0].cal_kvaddr);
+       cal_block->cal_paddr =
+               atomic_read(&acdb_data.vocstrm_cal[0].cal_paddr);
+       cal_block->cal_size =
+               atomic_read(&acdb_data.vocstrm_total_cal_size);
+}
+
+void get_all_vocvol_cal(struct acdb_cal_block *cal_block)
+{
+       cal_block->cal_kvaddr =
+               atomic_read(&acdb_data.vocvol_cal[0].cal_kvaddr);
+       cal_block->cal_paddr =
+               atomic_read(&acdb_data.vocvol_cal[0].cal_paddr);
+       cal_block->cal_size =
+               atomic_read(&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;
+       }
+
+       cal_block->cal_kvaddr =
+               atomic_read(&acdb_data.anc_cal.cal_kvaddr);
+       cal_block->cal_paddr =
+               atomic_read(&acdb_data.anc_cal.cal_paddr);
+       cal_block->cal_size =
+               atomic_read(&acdb_data.anc_cal.cal_size);
+done:
+       return;
+}
+
+void store_anc_cal(struct cal_block *cal_block)
+{
+       pr_debug("%s,\n", __func__);
+
+       if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+               pr_err("%s: offset %d is > mem_len %ld\n",
+                       __func__, cal_block->cal_offset,
+                       (long)atomic64_read(&acdb_data.mem_len));
+               goto done;
+       }
+
+       atomic_set(&acdb_data.anc_cal.cal_kvaddr,
+               cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+       atomic_set(&acdb_data.anc_cal.cal_paddr,
+               cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+       atomic_set(&acdb_data.anc_cal.cal_size,
+               cal_block->cal_size);
+done:
+       return;
+}
+
+void store_afe_cal(int32_t path, struct cal_block *cal_block)
+{
+       pr_debug("%s, path = %d\n", __func__, path);
+
+       if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+               pr_err("%s: offset %d is > mem_len %ld\n",
+                       __func__, cal_block->cal_offset,
+                       (long)atomic64_read(&acdb_data.mem_len));
+               goto done;
+       }
+       if ((path >= MAX_AUDPROC_TYPES) || (path < 0)) {
+               pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+                       __func__, path);
+               goto done;
+       }
+
+       atomic_set(&acdb_data.afe_cal[path].cal_kvaddr,
+               cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+       atomic_set(&acdb_data.afe_cal[path].cal_paddr,
+               cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+       atomic_set(&acdb_data.afe_cal[path].cal_size,
+               cal_block->cal_size);
+done:
+       return;
+}
+
+void get_afe_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;
+       }
+
+       cal_block->cal_kvaddr =
+               atomic_read(&acdb_data.afe_cal[path].cal_kvaddr);
+       cal_block->cal_paddr =
+               atomic_read(&acdb_data.afe_cal[path].cal_paddr);
+       cal_block->cal_size =
+               atomic_read(&acdb_data.afe_cal[path].cal_size);
+done:
+       return;
+}
+
+void store_audproc_cal(int32_t path, struct cal_block *cal_block)
+{
+       pr_debug("%s, path = %d\n", __func__, path);
+
+       if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+               pr_err("%s: offset %d is > mem_len %ld\n",
+                       __func__, cal_block->cal_offset,
+                       (long)atomic64_read(&acdb_data.mem_len));
+               goto done;
+       }
+       if (path >= MAX_AUDPROC_TYPES) {
+               pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+                       __func__, path);
+               goto done;
+       }
+
+       atomic_set(&acdb_data.audproc_cal[path].cal_kvaddr,
+               cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+       atomic_set(&acdb_data.audproc_cal[path].cal_paddr,
+               cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+       atomic_set(&acdb_data.audproc_cal[path].cal_size,
+               cal_block->cal_size);
+done:
+       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;
+       }
+
+       cal_block->cal_kvaddr =
+               atomic_read(&acdb_data.audproc_cal[path].cal_kvaddr);
+       cal_block->cal_paddr =
+               atomic_read(&acdb_data.audproc_cal[path].cal_paddr);
+       cal_block->cal_size =
+               atomic_read(&acdb_data.audproc_cal[path].cal_size);
+done:
+       return;
+}
+
+void store_audstrm_cal(int32_t path, struct cal_block *cal_block)
+{
+       pr_debug("%s, path = %d\n", __func__, path);
+
+       if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+               pr_err("%s: offset %d is > mem_len %ld\n",
+                       __func__, cal_block->cal_offset,
+                       (long)atomic64_read(&acdb_data.mem_len));
+               goto done;
+       }
+       if (path >= MAX_AUDPROC_TYPES) {
+               pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+                       __func__, path);
+               goto done;
+       }
+
+       atomic_set(&acdb_data.audstrm_cal[path].cal_kvaddr,
+               cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+       atomic_set(&acdb_data.audstrm_cal[path].cal_paddr,
+               cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+       atomic_set(&acdb_data.audstrm_cal[path].cal_size,
+               cal_block->cal_size);
+done:
+       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;
+       }
+
+       cal_block->cal_kvaddr =
+               atomic_read(&acdb_data.audstrm_cal[path].cal_kvaddr);
+       cal_block->cal_paddr =
+               atomic_read(&acdb_data.audstrm_cal[path].cal_paddr);
+       cal_block->cal_size =
+               atomic_read(&acdb_data.audstrm_cal[path].cal_size);
+done:
+       return;
+}
+
+void store_audvol_cal(int32_t path, struct cal_block *cal_block)
+{
+       pr_debug("%s, path = %d\n", __func__, path);
+
+       if (cal_block->cal_offset > atomic64_read(&acdb_data.mem_len)) {
+               pr_err("%s: offset %d is > mem_len %ld\n",
+                       __func__, cal_block->cal_offset,
+                       (long)atomic64_read(&acdb_data.mem_len));
+               goto done;
+       }
+       if (path >= MAX_AUDPROC_TYPES) {
+               pr_err("ACDB=> Bad path sent to %s, path: %d\n",
+                       __func__, path);
+               goto done;
+       }
+
+       atomic_set(&acdb_data.audvol_cal[path].cal_kvaddr,
+               cal_block->cal_offset + atomic64_read(&acdb_data.kvaddr));
+       atomic_set(&acdb_data.audvol_cal[path].cal_paddr,
+               cal_block->cal_offset + atomic64_read(&acdb_data.paddr));
+       atomic_set(&acdb_data.audvol_cal[path].cal_size,
+               cal_block->cal_size);
+done:
+       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;
+       }
+
+       cal_block->cal_kvaddr =
+               atomic_read(&acdb_data.audvol_cal[path].cal_kvaddr);
+       cal_block->cal_paddr =
+               atomic_read(&acdb_data.audvol_cal[path].cal_paddr);
+       cal_block->cal_size =
+               atomic_read(&acdb_data.audvol_cal[path].cal_size);
+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;
+       }
+
+       atomic_set(&acdb_data.vocproc_total_cal_size, 0);
+       for (i = 0; i < len; i++) {
+               if (cal_blocks[i].cal_offset >
+                                       atomic64_read(&acdb_data.mem_len)) {
+                       pr_err("%s: offset %d is > mem_len %ld\n",
+                               __func__, cal_blocks[i].cal_offset,
+                               (long)atomic64_read(&acdb_data.mem_len));
+                       atomic_set(&acdb_data.vocproc_cal[i].cal_size, 0);
+               } else {
+                       atomic_add(cal_blocks[i].cal_size,
+                               &acdb_data.vocproc_total_cal_size);
+                       atomic_set(&acdb_data.vocproc_cal[i].cal_size,
+                               cal_blocks[i].cal_size);
+                       atomic_set(&acdb_data.vocproc_cal[i].cal_paddr,
+                               cal_blocks[i].cal_offset +
+                               atomic64_read(&acdb_data.paddr));
+                       atomic_set(&acdb_data.vocproc_cal[i].cal_kvaddr,
+                               cal_blocks[i].cal_offset +
+                               atomic64_read(&acdb_data.kvaddr));
+               }
+       }
+       atomic_set(&acdb_data.vocproc_cal_size, len);
+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;
+       }
+
+       cal_data->num_cal_blocks = atomic_read(&acdb_data.vocproc_cal_size);
+       cal_data->cal_blocks = &acdb_data.vocproc_cal[0];
+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;
+       }
+
+       atomic_set(&acdb_data.vocstrm_total_cal_size, 0);
+       for (i = 0; i < len; i++) {
+               if (cal_blocks[i].cal_offset >
+                                       atomic64_read(&acdb_data.mem_len)) {
+                       pr_err("%s: offset %d is > mem_len %ld\n",
+                               __func__, cal_blocks[i].cal_offset,
+                               (long)atomic64_read(&acdb_data.mem_len));
+                       atomic_set(&acdb_data.vocstrm_cal[i].cal_size, 0);
+               } else {
+                       atomic_add(cal_blocks[i].cal_size,
+                               &acdb_data.vocstrm_total_cal_size);
+                       atomic_set(&acdb_data.vocstrm_cal[i].cal_size,
+                               cal_blocks[i].cal_size);
+                       atomic_set(&acdb_data.vocstrm_cal[i].cal_paddr,
+                               cal_blocks[i].cal_offset +
+                               atomic64_read(&acdb_data.paddr));
+                       atomic_set(&acdb_data.vocstrm_cal[i].cal_kvaddr,
+                               cal_blocks[i].cal_offset +
+                               atomic64_read(&acdb_data.kvaddr));
+               }
+       }
+       atomic_set(&acdb_data.vocstrm_cal_size, len);
+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;
+       }
+
+       cal_data->num_cal_blocks = atomic_read(&acdb_data.vocstrm_cal_size);
+       cal_data->cal_blocks = &acdb_data.vocstrm_cal[0];
+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;
+       }
+
+       atomic_set(&acdb_data.vocvol_total_cal_size, 0);
+       for (i = 0; i < len; i++) {
+               if (cal_blocks[i].cal_offset >
+                                       atomic64_read(&acdb_data.mem_len)) {
+                       pr_err("%s: offset %d is > mem_len %ld\n",
+                               __func__, cal_blocks[i].cal_offset,
+                               (long)atomic64_read(&acdb_data.mem_len));
+                       atomic_set(&acdb_data.vocvol_cal[i].cal_size, 0);
+               } else {
+                       atomic_add(cal_blocks[i].cal_size,
+                               &acdb_data.vocvol_total_cal_size);
+                       atomic_set(&acdb_data.vocvol_cal[i].cal_size,
+                               cal_blocks[i].cal_size);
+                       atomic_set(&acdb_data.vocvol_cal[i].cal_paddr,
+                               cal_blocks[i].cal_offset +
+                               atomic64_read(&acdb_data.paddr));
+                       atomic_set(&acdb_data.vocvol_cal[i].cal_kvaddr,
+                               cal_blocks[i].cal_offset +
+                               atomic64_read(&acdb_data.kvaddr));
+               }
+       }
+       atomic_set(&acdb_data.vocvol_cal_size, len);
+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;
+       }
+
+       cal_data->num_cal_blocks = atomic_read(&acdb_data.vocvol_cal_size);
+       cal_data->cal_blocks = &acdb_data.vocvol_cal[0];
+done:
+       return;
+}
+
+void store_sidetone_cal(struct sidetone_cal *cal_data)
+{
+       pr_debug("%s\n", __func__);
+
+       atomic_set(&acdb_data.sidetone_cal.enable, cal_data->enable);
+       atomic_set(&acdb_data.sidetone_cal.gain, cal_data->gain);
+}
+
+
+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;
+       }
+
+       cal_data->enable = atomic_read(&acdb_data.sidetone_cal.enable);
+       cal_data->gain = atomic_read(&acdb_data.sidetone_cal.gain);
+done:
+       return;
+}
+
+static int acdb_open(struct inode *inode, struct file *f)
+{
+       s32 result = 0;
+       pr_debug("%s\n", __func__);
+
+       if (atomic64_read(&acdb_data.mem_len)) {
+               pr_debug("%s: ACDB opened but memory allocated, "
+                       "using existing allocation!\n",
+                       __func__);
+       }
+
+       atomic_inc(&usage_count);
+       return result;
+}
+
+static long acdb_ioctl(struct file *f,
+               unsigned int cmd, unsigned long arg)
+{
+       int32_t                 result = 0;
+       int32_t                 size;
+       int32_t                 map_fd;
+       uint32_t                topology;
+       struct cal_block        data[MAX_NETWORKS];
+       pr_debug("%s\n", __func__);
+
+       switch (cmd) {
+
+       case AUDIO_REGISTER_PMEM:
+               pr_debug("AUDIO_REGISTER_PMEM\n");
+               if (atomic_read(&acdb_data.mem_len)) {
+                       //deregister_memory();
+                       pr_debug("Remove the existing memory\n");
+               }
+
+               if (copy_from_user(&map_fd, (void *)arg, sizeof(map_fd))) {
+                       pr_err("%s: fail to copy memory handle!\n", __func__);
+                       result = -EFAULT;
+               } else {
+                       atomic_set(&acdb_data.map_handle, map_fd);
+                       //result = register_memory();
+               }
+               goto done;
+
+       case AUDIO_DEREGISTER_PMEM:
+               pr_debug("AUDIO_DEREGISTER_PMEM\n");
+               //deregister_memory();
+               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_RX_TOPOLOGY:
+               if (copy_from_user(&topology, (void *)arg,
+                               sizeof(topology))) {
+                       pr_err("%s: fail to copy topology!\n", __func__);
+                       result = -EFAULT;
+               }
+               store_adm_rx_topology(topology);
+               goto done;
+       case AUDIO_SET_ADM_TX_TOPOLOGY:
+               if (copy_from_user(&topology, (void *)arg,
+                               sizeof(topology))) {
+                       pr_err("%s: fail to copy topology!\n", __func__);
+                       result = -EFAULT;
+               }
+               store_adm_tx_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:
+               if (size > sizeof(struct cal_block))
+                       pr_err("%s: More Audproc Cal then expected, "
+                               "size received: %d\n", __func__, size);
+               store_audproc_cal(TX_CAL, data);
+               break;
+       case AUDIO_SET_AUDPROC_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(RX_CAL, data);
+               break;
+       case AUDIO_SET_AUDPROC_TX_STREAM_CAL:
+               if (size > sizeof(struct cal_block))
+                       pr_err("%s: More Audproc Cal then expected, "
+                               "size received: %d\n", __func__, size);
+               store_audstrm_cal(TX_CAL, data);
+               break;
+       case AUDIO_SET_AUDPROC_RX_STREAM_CAL:
+               if (size > sizeof(struct cal_block))
+                       pr_err("%s: More Audproc Cal then expected, "
+                               "size received: %d\n", __func__, size);
+               store_audstrm_cal(RX_CAL, data);
+               break;
+       case AUDIO_SET_AUDPROC_TX_VOL_CAL:
+               if (size > sizeof(struct cal_block))
+                       pr_err("%s: More Audproc Cal then expected, "
+                               "size received: %d\n", __func__, size);
+               store_audvol_cal(TX_CAL, data);
+               break;
+       case AUDIO_SET_AUDPROC_RX_VOL_CAL:
+               if (size > sizeof(struct cal_block))
+                       pr_err("%s: More Audproc Cal then expected, "
+                               "size received: %d\n", __func__, size);
+               store_audvol_cal(RX_CAL, data);
+               break;
+       case AUDIO_SET_AFE_TX_CAL:
+               if (size > sizeof(struct cal_block))
+                       pr_err("%s: More AFE Cal then expected, "
+                               "size received: %d\n", __func__, size);
+               store_afe_cal(TX_CAL, data);
+               break;
+       case AUDIO_SET_AFE_RX_CAL:
+               if (size > sizeof(struct cal_block))
+                       pr_err("%s: More AFE Cal then expected, "
+                               "size received: %d\n", __func__, size);
+               store_afe_cal(RX_CAL, 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__);
+
+       if (atomic64_read(&acdb_data.mem_len)) {
+               if (size <= atomic64_read(&acdb_data.mem_len)) {
+                       vma->vm_page_prot = pgprot_noncached(
+                                               vma->vm_page_prot);
+                       result = remap_pfn_range(vma,
+                               vma->vm_start,
+                               atomic64_read(&acdb_data.paddr) >> PAGE_SHIFT,
+                               size,
+                               vma->vm_page_prot);
+               } else {
+                       pr_err("%s: Not enough memory!\n", __func__);
+                       result = -ENOMEM;
+               }
+       } else {
+               pr_err("%s: memory is not allocated, yet!\n", __func__);
+               result = -ENODEV;
+       }
+
+       return result;
+}
+
+static int acdb_release(struct inode *inode, struct file *f)
+{
+       s32 result = 0;
+
+       atomic_dec(&usage_count);
+       atomic_read(&usage_count);
+
+       pr_debug("%s: ref count %d!\n", __func__,
+               atomic_read(&usage_count));
+
+       if (atomic_read(&usage_count) >= 1)
+               result = -EBUSY;
+
+       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/sound/soc/qcom/qdsp6/core/dsp_debug.c b/sound/soc/qcom/qdsp6/core/dsp_debug.c
new file mode 100644 (file)
index 0000000..4e242e3
--- /dev/null
@@ -0,0 +1,259 @@
+/* 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 <linux/platform_device.h>
+#include <asm/atomic.h>
+
+#include <sound/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)
+{
+       int i;
+
+       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 (i = 0; i < 600; i++)
+                       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);
+}
+
+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;
+       void *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 = ioremap(DSP_NMI_ADDR, 0x16);
+               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;
+               if (!ptr) {
+                       pr_err("Unable to map DSP NMI\n");
+                       return -EFAULT;
+               }
+               writel(0x1, (void *)ptr);
+               iounmap(mem_buffer);
+       } 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", __FILE__,
+                               __func__, cmd);
+       }
+
+       return count;
+}
+
+static unsigned copy_ok_count;
+static uint32_t dsp_ram_size;
+static uint32_t dsp_ram_base;
+
+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;
+       void *mem_buffer;
+
+       if ((dsp_ram_base == 0) || (dsp_ram_size == 0)) {
+               pr_err("[%s:%s] Memory Invalid or not initialized, Base = 0x%x,"
+                          " size = 0x%x\n", __FILE__,
+                               __func__, dsp_ram_base, dsp_ram_size);
+               return -EINVAL;
+       }
+
+       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 = ioremap(addr, mapsize);
+               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;
+               if (!ptr) {
+                       pr_err("[%s:%s] map error @ %x\n", __FILE__,
+                                       __func__, addr);
+                       return -EFAULT;
+               }
+               if (copy_to_user(buf, ptr, PAGE_SIZE)) {
+                       iounmap(mem_buffer);
+                       pr_err("[%s:%s] copy error @ %p\n", __FILE__,
+                                       __func__, buf);
+                       return -EFAULT;
+               }
+               copy_ok_count += PAGE_SIZE;
+               iounmap(mem_buffer);
+               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 int dspcrashd_probe(struct platform_device *pdev)
+{
+       int rc = 0;
+       struct resource *res;
+       int *pdata;
+
+       pdata = pdev->dev.platform_data;
+       res = platform_get_resource_byname(pdev, IORESOURCE_DMA,
+                                               "msm_dspcrashd");
+       if (!res) {
+               pr_err("%s: failed to get resources for dspcrashd\n", __func__);
+               return -ENODEV;
+       }
+
+       dsp_ram_base = res->start;
+       dsp_ram_size = res->end - res->start;
+       pr_info("%s: Platform driver values: Base = 0x%x, Size = 0x%x,"
+                "pdata = 0x%x\n", __func__,
+               dsp_ram_base, dsp_ram_size, *pdata);
+       return rc;
+}
+
+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 struct platform_driver dspcrashd_driver = {
+       .probe = dspcrashd_probe,
+       .driver = { .name = "msm_dspcrashd"}
+};
+
+static int __init dsp_init(void)
+{
+       int rc = 0;
+       init_waitqueue_head(&dsp_wait);
+       rc = platform_driver_register(&dspcrashd_driver);
+       if (IS_ERR_VALUE(rc)) {
+               pr_err("%s: platform_driver_register for dspcrashd failed\n",
+                       __func__);
+       }
+       return misc_register(&dsp_misc);
+}
+
+static int __exit dsp_exit(void)
+{
+       platform_driver_unregister(&dspcrashd_driver);
+       return 0;
+}
+
+device_initcall(dsp_init);
diff --git a/sound/soc/qcom/qdsp6/core/q6audio_common.h b/sound/soc/qcom/qdsp6/core/q6audio_common.h
new file mode 100644 (file)
index 0000000..68efafd
--- /dev/null
@@ -0,0 +1,35 @@
+/* Copyright (c) 2012, The Linux Foundation. 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.
+ *
+*/
+
+/* For Decoders */
+#ifndef __Q6_AUDIO_COMMON_H__
+#define __Q6_AUDIO_COMMON_H__
+
+#include <sound/apr_audio.h>
+#include <sound/q6asm.h>
+
+void q6_audio_cb(uint32_t opcode, uint32_t token,
+               uint32_t *payload, void *priv);
+
+void audio_aio_cb(uint32_t opcode, uint32_t token,
+                       uint32_t *payload,  void *audio);
+
+
+/* For Encoders */
+void q6asm_in_cb(uint32_t opcode, uint32_t token,
+               uint32_t *payload, void *priv);
+
+void  audio_in_get_dsp_frames(void *audio,
+               uint32_t token, uint32_t *payload);
+
+#endif /*__Q6_AUDIO_COMMON_H__*/
diff --git a/sound/soc/qcom/qdsp6/core/q6core.c b/sound/soc/qcom/qdsp6/core/q6core.c
new file mode 100644 (file)
index 0000000..e5f1d4e
--- /dev/null
@@ -0,0 +1,406 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. 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 <sound/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;
+
+       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)) {
+               apr_set_q6_state(APR_SUBSYS_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/sound/soc/qcom/qdsp6/core/q6core.h b/sound/soc/qcom/qdsp6/core/q6core.h
new file mode 100644 (file)
index 0000000..97a81cb
--- /dev/null
@@ -0,0 +1,52 @@
+/* Copyright (c) 2011, The Linux Foundation. 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 <sound/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/sound/soc/qcom/qdsp6/core/rtac.c b/sound/soc/qcom/qdsp6/core/rtac.c
new file mode 100644 (file)
index 0000000..175568f
--- /dev/null
@@ -0,0 +1,1046 @@
+/* Copyright (c) 2011, The Linux Foundation. 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 <asm/atomic.h>
+#include <sound/qdsp6v2/audio_acdb.h>
+#include <sound/qdsp6v2/rtac.h>
+#include "q6audio_common.h"
+#include <sound/q6afe.h>
+
+#define CONFIG_RTAC
+#ifndef CONFIG_RTAC
+
+void rtac_add_adm_device(u32 port_id, u32 copp_id, u32 path_id, u32 popp_id) {}
+void rtac_remove_adm_device(u32 port_id) {}
+void rtac_remove_popp_from_adm_devices(u32 popp_id) {}
+void rtac_set_adm_handle(void *handle) {}
+bool rtac_make_adm_callback(uint32_t *payload, u32 payload_size)
+       {return false; }
+void rtac_set_asm_handle(u32 session_id, void *handle) {}
+bool rtac_make_asm_callback(u32 session_id, uint32_t *payload,
+       u32 payload_size) {return false; }
+void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
+       u32 tx_afe_port, u32 session_id) {}
+void rtac_remove_voice(u32 cvs_handle) {}
+void rtac_set_voice_handle(u32 mode, void *handle) {}
+bool rtac_make_voice_callback(u32 mode, uint32_t *payload,
+               u32 payload_size) {return false; }
+
+#else
+
+#define VOICE_CMD_SET_PARAM            0x00011006
+#define VOICE_CMD_GET_PARAM            0x00011007
+#define VOICE_EVT_GET_PARAM_ACK                0x00011008
+
+/* 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];
+
+
+/* ADM info & APR */
+struct rtac_adm_data {
+       uint32_t        topology_id;
+       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_topology_id;
+       uint32_t        rx_topology_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;
+static u32                     voice_session_id[RTAC_MAX_ACTIVE_VOICE_COMBOS];
+
+
+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;
+}
+
+/* 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 copp_id, u32 path_id, u32 popp_id)
+{
+       u32 i = 0;
+       pr_debug("%s: port_id = %d, popp_id = %d\n", __func__, port_id,
+               popp_id);
+
+       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++;
+
+       if (path_id == ADM_PATH_PLAYBACK)
+               rtac_adm_data.device[i].topology_id =
+                                               get_adm_rx_topology();
+       else
+               rtac_adm_data.device[i].topology_id =
+                                               get_adm_tx_topology();
+       rtac_adm_data.device[i].afe_port = port_id;
+       rtac_adm_data.device[i].copp = copp_id;
+       rtac_adm_data.device[i].popp[
+               rtac_adm_data.device[i].num_of_popp++] = popp_id;
+done:
+       mutex_unlock(&rtac_adm_mutex);
+       return;
+}
+
+static void shift_adm_devices(u32 dev_idx)
+{
+       for (; dev_idx < rtac_adm_data.num_of_dev; dev_idx++) {
+               memcpy(&rtac_adm_data.device[dev_idx],
+                       &rtac_adm_data.device[dev_idx + 1],
+                       sizeof(rtac_adm_data.device[dev_idx]));
+               memset(&rtac_adm_data.device[dev_idx + 1], 0,
+                          sizeof(rtac_adm_data.device[dev_idx]));
+       }
+}
+
+static void shift_popp(u32 copp_idx, u32 popp_idx)
+{
+       for (; popp_idx < rtac_adm_data.device[copp_idx].num_of_popp;
+                                                       popp_idx++) {
+               memcpy(&rtac_adm_data.device[copp_idx].popp[popp_idx],
+                       &rtac_adm_data.device[copp_idx].popp[popp_idx + 1],
+                       sizeof(uint32_t));
+               memset(&rtac_adm_data.device[copp_idx].popp[popp_idx + 1], 0,
+                          sizeof(uint32_t));
+       }
+}
+
+void rtac_remove_adm_device(u32 port_id)
+{
+       s32 i;
+       pr_debug("%s: port_id = %d\n", __func__, port_id);
+
+       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) {
+                       memset(&rtac_adm_data.device[i], 0,
+                                  sizeof(rtac_adm_data.device[i]));
+                       rtac_adm_data.num_of_dev--;
+
+                       if (rtac_adm_data.num_of_dev >= 1) {
+                               shift_adm_devices(i);
+                               break;
+                       }
+               }
+       }
+
+       mutex_unlock(&rtac_adm_mutex);
+       return;
+}
+
+void rtac_remove_popp_from_adm_devices(u32 popp_id)
+{
+       s32 i, j;
+       pr_debug("%s: popp_id = %d\n", __func__, popp_id);
+
+       mutex_lock(&rtac_adm_mutex);
+
+       for (i = 0; i < rtac_adm_data.num_of_dev; i++) {
+               for (j = 0; j < rtac_adm_data.device[i].num_of_popp; j++) {
+                       if (rtac_adm_data.device[i].popp[j] == popp_id) {
+                               rtac_adm_data.device[i].popp[j] = 0;
+                               rtac_adm_data.device[i].num_of_popp--;
+                               shift_popp(i, j);
+                       }
+               }
+       }
+
+       mutex_unlock(&rtac_adm_mutex);
+}
+
+/* Voice Info */
+static void set_rtac_voice_data(int idx, u32 cvs_handle, u32 cvp_handle,
+                                       u32 rx_afe_port, u32 tx_afe_port,
+                                       u32 session_id)
+{
+       rtac_voice_data.voice[idx].tx_topology_id = get_voice_tx_topology();
+       rtac_voice_data.voice[idx].rx_topology_id = get_voice_rx_topology();
+       rtac_voice_data.voice[idx].tx_afe_port = tx_afe_port;
+       rtac_voice_data.voice[idx].rx_afe_port = rx_afe_port;
+       rtac_voice_data.voice[idx].cvs_handle = cvs_handle;
+       rtac_voice_data.voice[idx].cvp_handle = cvp_handle;
+
+       /* Store session ID for voice RTAC */
+       voice_session_id[idx] = session_id;
+}
+
+void rtac_add_voice(u32 cvs_handle, u32 cvp_handle, u32 rx_afe_port,
+                       u32 tx_afe_port, u32 session_id)
+{
+       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].cvs_handle ==
+                                                       cvs_handle) {
+                               set_rtac_voice_data(i, cvs_handle, cvp_handle,
+                                       rx_afe_port, tx_afe_port,
+                                       session_id);
+                               goto done;
+                       }
+               }
+       }
+
+       /* Add device */
+       rtac_voice_data.num_of_voice_combos++;
+       set_rtac_voice_data(i, cvs_handle, cvp_handle,
+                               rx_afe_port, tx_afe_port,
+                               session_id);
+done:
+       mutex_unlock(&rtac_voice_mutex);
+       return;
+}
+
+static 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]));
+               voice_session_id[idx] = voice_session_id[idx + 1];
+       }
+}
+
+void rtac_remove_voice(u32 cvs_handle)
+{
+       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].cvs_handle == cvs_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]));
+                       voice_session_id[rtac_voice_data.num_of_voice_combos]
+                               = 0;
+                       break;
+               }
+       }
+       mutex_unlock(&rtac_voice_mutex);
+       return;
+}
+
+static int get_voice_index_cvs(u32 cvs_handle)
+{
+       u32 i;
+
+       for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
+               if (rtac_voice_data.voice[i].cvs_handle == cvs_handle)
+                       return i;
+       }
+
+       pr_err("%s: No voice index for CVS handle %d found returning 0\n",
+              __func__, cvs_handle);
+       return 0;
+}
+
+static int get_voice_index_cvp(u32 cvp_handle)
+{
+       u32 i;
+
+       for (i = 0; i < rtac_voice_data.num_of_voice_combos; i++) {
+               if (rtac_voice_data.voice[i].cvp_handle == cvp_handle)
+                       return i;
+       }
+
+       pr_err("%s: No voice index for CVP handle %d found returning 0\n",
+              __func__, cvp_handle);
+       return 0;
+}
+
+static int get_voice_index(u32 mode, u32 handle)
+{
+       if (mode == RTAC_CVP)
+               return get_voice_index_cvp(handle);
+       if (mode == RTAC_CVS)
+               return get_voice_index_cvs(handle);
+
+       pr_err("%s: Invalid mode %d, returning 0\n",
+              __func__, mode);
+       return 0;
+}
+
+
+/* ADM APR */
+void rtac_set_adm_handle(void *handle)
+{
+       pr_debug("%s: handle = %d\n", __func__, (unsigned int)handle);
+
+       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)
+{
+       pr_debug("%s:cmd_state = %d\n", __func__,
+                       atomic_read(&rtac_adm_apr_data.cmd_state));
+       if (atomic_read(&rtac_adm_apr_data.cmd_state) != 1)
+               return false;
+
+       /* 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_index = 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 > 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_index = 0; port_index < AFE_MAX_PORTS; port_index++) {
+               if (adm_get_copp_id(port_index) == copp_id)
+                       break;
+       }
+       if (port_index >= AFE_MAX_PORTS) {
+               pr_err("%s: Could not find port index for copp = %d\n",
+                      __func__, copp_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 = copp_id;
+       adm_params.dest_svc = APR_SVC_ADM;
+       adm_params.dest_domain = APR_DOMAIN_ADSP;
+       adm_params.dest_port = copp_id;
+       adm_params.token = copp_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, copp = %d\n",
+                       __func__, port_index, copp_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, copp = %d\n",
+                       __func__, port_index, copp_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 > 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 > (SESSION_MAX + 1)) {
+               pr_err("%s: Invalid Session = %d\n", __func__, session_id);
+               goto done;
+       }
+
+       mutex_lock(&rtac_asm_apr_mutex);
+       if (session_id < SESSION_MAX+1) {
+               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));
+       if (session_id < SESSION_MAX+1)
+               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 >= 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;
+       u32     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(payload_size),
+                                               sizeof(payload_size))) {
+               pr_err("%s: Could not copy payload size from user buffer\n",
+                       __func__);
+               goto done;
+       }
+
+       if (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(dest_port),
+                                               sizeof(dest_port))) {
+               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 = voice_session_id[
+                                       get_voice_index(mode, dest_port)];
+       voice_params.dest_svc = 0;
+       voice_params.dest_domain = APR_DOMAIN_MODEM;
+       voice_params.dest_port = (u16)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 long rtac_ioctl(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_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,
+       .unlocked_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__);
+
+       /* 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 = kzalloc(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 = kzalloc(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);
+               kzfree(rtac_adm_buffer);
+               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 = kzalloc(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);
+               kzfree(rtac_adm_buffer);
+               kzfree(rtac_asm_buffer);
+               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");
+
+#endif
diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c
new file mode 100644 (file)
index 0000000..b565411
--- /dev/null
@@ -0,0 +1,1241 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/jiffies.h>
+#include <linux/uaccess.h>
+#include <linux/atomic.h>
+#include <linux/err.h>
+
+#include <sound/qdsp6v2/audio_dev_ctl.h>
+#include <sound/qdsp6v2/audio_acdb.h>
+#include <sound/qdsp6v2/rtac.h>
+
+#include <sound/apr_audio.h>
+#include <sound/q6afe.h>
+
+#define TIMEOUT_MS 1000
+#define AUDIO_RX 0x0
+#define AUDIO_TX 0x1
+
+#define ASM_MAX_SESSION 0x8 /* To do: define in a header */
+#define RESET_COPP_ID 99
+#define INVALID_COPP_ID 0xFF
+
+struct adm_ctl {
+       void *apr;
+       atomic_t copp_id[AFE_MAX_PORTS];
+       atomic_t copp_cnt[AFE_MAX_PORTS];
+       atomic_t copp_stat[AFE_MAX_PORTS];
+       wait_queue_head_t wait;
+       int  ec_ref_rx;
+};
+
+static struct acdb_cal_block mem_addr_audproc[MAX_AUDPROC_TYPES];
+static struct acdb_cal_block mem_addr_audvol[MAX_AUDPROC_TYPES];
+
+static struct adm_ctl                  this_adm;
+
+
+int srs_trumedia_open(int port_id, int srs_tech_id, void *srs_params)
+{
+       struct asm_pp_params_command *open = NULL;
+       int ret = 0, sz = 0;
+       int index;
+
+       pr_debug("SRS - %s", __func__);
+
+       index = afe_get_port_index(port_id);
+
+       if (IS_ERR_VALUE(index)) {
+               pr_err("%s: invald port id\n", __func__);
+               return index;
+       }
+
+       switch (srs_tech_id) {
+       case SRS_ID_GLOBAL: {
+               struct srs_trumedia_params_GLOBAL *glb_params = NULL;
+               sz = sizeof(struct asm_pp_params_command) +
+                       sizeof(struct srs_trumedia_params_GLOBAL);
+               open = kzalloc(sz, GFP_KERNEL);
+               open->payload_size = sizeof(struct srs_trumedia_params_GLOBAL) +
+                                       sizeof(struct asm_pp_param_data_hdr);
+               open->params.param_id = SRS_TRUMEDIA_PARAMS;
+               open->params.param_size =
+                               sizeof(struct srs_trumedia_params_GLOBAL);
+               glb_params = (struct srs_trumedia_params_GLOBAL *)((u8 *)open +
+                               sizeof(struct asm_pp_params_command));
+               memcpy(glb_params, srs_params,
+                       sizeof(struct srs_trumedia_params_GLOBAL));
+               pr_debug("SRS - %s: Global params - 1 = %x, 2 = %x, 3 = %x,"
+                               " 4 = %x, 5 = %x, 6 = %x, 7 = %x, 8 = %x\n",
+                               __func__, (int)glb_params->v1,
+                               (int)glb_params->v2, (int)glb_params->v3,
+                               (int)glb_params->v4, (int)glb_params->v5,
+                               (int)glb_params->v6, (int)glb_params->v7,
+                               (int)glb_params->v8);
+               break;
+       }
+       case SRS_ID_WOWHD: {
+               struct srs_trumedia_params_WOWHD *whd_params = NULL;
+               sz = sizeof(struct asm_pp_params_command) +
+                       sizeof(struct srs_trumedia_params_WOWHD);
+               open = kzalloc(sz, GFP_KERNEL);
+               open->payload_size = sizeof(struct srs_trumedia_params_WOWHD) +
+                                       sizeof(struct asm_pp_param_data_hdr);
+               open->params.param_id = SRS_TRUMEDIA_PARAMS_WOWHD;
+               open->params.param_size =
+                               sizeof(struct srs_trumedia_params_WOWHD);
+               whd_params = (struct srs_trumedia_params_WOWHD *)((u8 *)open +
+                               sizeof(struct asm_pp_params_command));
+               memcpy(whd_params, srs_params,
+                               sizeof(struct srs_trumedia_params_WOWHD));
+               pr_debug("SRS - %s: WOWHD params - 1 = %x, 2 = %x, 3 = %x,"
+                       " 4 = %x, 5 = %x, 6 = %x, 7 = %x, 8 = %x, 9 = %x,"
+                       " 10 = %x, 11 = %x\n", __func__, (int)whd_params->v1,
+                       (int)whd_params->v2, (int)whd_params->v3,
+                       (int)whd_params->v4, (int)whd_params->v5,
+                       (int)whd_params->v6, (int)whd_params->v7,
+                       (int)whd_params->v8, (int)whd_params->v9,
+                       (int)whd_params->v10, (int)whd_params->v11);
+               break;
+       }
+       case SRS_ID_CSHP: {
+               struct srs_trumedia_params_CSHP *chp_params = NULL;
+               sz = sizeof(struct asm_pp_params_command) +
+                       sizeof(struct srs_trumedia_params_CSHP);
+               open = kzalloc(sz, GFP_KERNEL);
+               open->payload_size = sizeof(struct srs_trumedia_params_CSHP) +
+                                       sizeof(struct asm_pp_param_data_hdr);
+               open->params.param_id = SRS_TRUMEDIA_PARAMS_CSHP;
+               open->params.param_size =
+                                       sizeof(struct srs_trumedia_params_CSHP);
+               chp_params = (struct srs_trumedia_params_CSHP *)((u8 *)open +
+                               sizeof(struct asm_pp_params_command));
+               memcpy(chp_params, srs_params,
+                               sizeof(struct srs_trumedia_params_CSHP));
+               pr_debug("SRS - %s: CSHP params - 1 = %x, 2 = %x, 3 = %x,"
+                               " 4 = %x, 5 = %x, 6 = %x, 7 = %x, 8 = %x,"
+                               " 9 = %x\n", __func__, (int)chp_params->v1,
+                               (int)chp_params->v2, (int)chp_params->v3,
+                               (int)chp_params->v4, (int)chp_params->v5,
+                               (int)chp_params->v6, (int)chp_params->v7,
+                               (int)chp_params->v8, (int)chp_params->v9);
+               break;
+       }
+       case SRS_ID_HPF: {
+               struct srs_trumedia_params_HPF *hpf_params = NULL;
+               sz = sizeof(struct asm_pp_params_command) +
+                       sizeof(struct srs_trumedia_params_HPF);
+               open = kzalloc(sz, GFP_KERNEL);
+               open->payload_size = sizeof(struct srs_trumedia_params_HPF) +
+                                       sizeof(struct asm_pp_param_data_hdr);
+               open->params.param_id = SRS_TRUMEDIA_PARAMS_HPF;
+               open->params.param_size =
+                                       sizeof(struct srs_trumedia_params_HPF);
+               hpf_params = (struct srs_trumedia_params_HPF *)((u8 *)open +
+                               sizeof(struct asm_pp_params_command));
+               memcpy(hpf_params, srs_params,
+                       sizeof(struct srs_trumedia_params_HPF));
+               pr_debug("SRS - %s: HPF params - 1 = %x\n", __func__,
+                               (int)hpf_params->v1);
+               break;
+       }
+       case SRS_ID_PEQ: {
+               struct srs_trumedia_params_PEQ *peq_params = NULL;
+               sz = sizeof(struct asm_pp_params_command) +
+                       sizeof(struct srs_trumedia_params_PEQ);
+               open = kzalloc(sz, GFP_KERNEL);
+               open->payload_size = sizeof(struct srs_trumedia_params_PEQ) +
+                                       sizeof(struct asm_pp_param_data_hdr);
+               open->params.param_id = SRS_TRUMEDIA_PARAMS_PEQ;
+               open->params.param_size =
+                                       sizeof(struct srs_trumedia_params_PEQ);
+               peq_params = (struct srs_trumedia_params_PEQ *)((u8 *)open +
+                               sizeof(struct asm_pp_params_command));
+               memcpy(peq_params, srs_params,
+                               sizeof(struct srs_trumedia_params_PEQ));
+               pr_debug("SRS - %s: PEQ params - 1 = %x 2 = %x, 3 = %x,"
+                       " 4 = %x\n", __func__, (int)peq_params->v1,
+                       (int)peq_params->v2, (int)peq_params->v3,
+                       (int)peq_params->v4);
+               break;
+       }
+       case SRS_ID_HL: {
+               struct srs_trumedia_params_HL *hl_params = NULL;
+               sz = sizeof(struct asm_pp_params_command) +
+                       sizeof(struct srs_trumedia_params_HL);
+               open = kzalloc(sz, GFP_KERNEL);
+               open->payload_size = sizeof(struct srs_trumedia_params_HL) +
+                                       sizeof(struct asm_pp_param_data_hdr);
+               open->params.param_id = SRS_TRUMEDIA_PARAMS_HL;
+               open->params.param_size = sizeof(struct srs_trumedia_params_HL);
+               hl_params = (struct srs_trumedia_params_HL *)((u8 *)open +
+                               sizeof(struct asm_pp_params_command));
+               memcpy(hl_params, srs_params,
+                               sizeof(struct srs_trumedia_params_HL));
+               pr_debug("SRS - %s: HL params - 1 = %x, 2 = %x, 3 = %x, 4 = %x,"
+                               " 5 = %x, 6 = %x, 7 = %x\n", __func__,
+                               (int)hl_params->v1, (int)hl_params->v2,
+                               (int)hl_params->v3, (int)hl_params->v4,
+                               (int)hl_params->v5, (int)hl_params->v6,
+                               (int)hl_params->v7);
+               break;
+       }
+       default:
+               goto fail_cmd;
+       }
+
+       open->payload = NULL;
+       open->params.module_id = SRS_TRUMEDIA_MODULE_ID;
+       open->params.reserved = 0;
+       open->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       open->hdr.pkt_size = sz;
+       open->hdr.src_svc = APR_SVC_ADM;
+       open->hdr.src_domain = APR_DOMAIN_APPS;
+       open->hdr.src_port = port_id;
+       open->hdr.dest_svc = APR_SVC_ADM;
+       open->hdr.dest_domain = APR_DOMAIN_ADSP;
+       open->hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+       open->hdr.token = port_id;
+       open->hdr.opcode = ADM_CMD_SET_PARAMS;
+       pr_debug("SRS - %s: Command was sent now check Q6 - port id = %d,"
+                       " size %d, module id %x, param id %x.\n", __func__,
+                       open->hdr.dest_port, open->payload_size,
+                       open->params.module_id, open->params.param_id);
+
+       ret = apr_send_pkt(this_adm.apr, (uint32_t *)open);
+       if (ret < 0) {
+               pr_err("SRS - %s: ADM enable for port %d failed\n", __func__,
+                       port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       /* Wait for the callback with copp id */
+       ret = wait_event_timeout(this_adm.wait, 1,
+                       msecs_to_jiffies(TIMEOUT_MS));
+       if (!ret) {
+               pr_err("SRS - %s: ADM open failed for port %d\n", __func__,
+                       port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+fail_cmd:
+       kfree(open);
+       return ret;
+}
+
+static int32_t adm_callback(struct apr_client_data *data, void *priv)
+{
+       uint32_t *payload;
+       int i, index;
+       payload = data->payload;
+
+       if (data->opcode == RESET_EVENTS) {
+               pr_debug("adm_callback: Reset event is received: %d %d apr[%p]\n",
+                               data->reset_event, data->reset_proc,
+                               this_adm.apr);
+               if (this_adm.apr) {
+                       apr_reset(this_adm.apr);
+                       for (i = 0; i < AFE_MAX_PORTS; i++) {
+                               atomic_set(&this_adm.copp_id[i],
+                                                       RESET_COPP_ID);
+                               atomic_set(&this_adm.copp_cnt[i], 0);
+                               atomic_set(&this_adm.copp_stat[i], 0);
+                       }
+                       this_adm.apr = NULL;
+               }
+               pr_debug("Resetting calibration blocks");
+               for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
+                       /* Device calibration */
+                       mem_addr_audproc[i].cal_size = 0;
+                       mem_addr_audproc[i].cal_kvaddr = 0;
+                       mem_addr_audproc[i].cal_paddr = 0;
+
+                       /* Volume calibration */
+                       mem_addr_audvol[i].cal_size = 0;
+                       mem_addr_audvol[i].cal_kvaddr = 0;
+                       mem_addr_audvol[i].cal_paddr = 0;
+               }
+               return 0;
+       }
+
+       pr_debug("%s: code = 0x%x %x %x size = %d\n", __func__,
+                       data->opcode, payload[0], payload[1],
+                                       data->payload_size);
+
+       if (data->payload_size) {
+               index = afe_get_port_index(data->token);
+               pr_debug("%s: Port ID %d, index %d\n", __func__,
+                       data->token, index);
+               if (index < 0 || index >= AFE_MAX_PORTS) {
+                       pr_err("%s: invalid port idx %d token %d\n",
+                                       __func__, index, data->token);
+                       return 0;
+               }
+               if (data->opcode == APR_BASIC_RSP_RESULT) {
+                       pr_debug("APR_BASIC_RSP_RESULT id %x\n", payload[0]);
+                       switch (payload[0]) {
+                       case ADM_CMD_SET_PARAMS:
+                               if (rtac_make_adm_callback(payload,
+                                               data->payload_size))
+                                       break;
+                       case ADM_CMD_COPP_CLOSE:
+                       case ADM_CMD_MEMORY_MAP:
+                       case ADM_CMD_MEMORY_UNMAP:
+                       case ADM_CMD_MEMORY_MAP_REGIONS:
+                       case ADM_CMD_MEMORY_UNMAP_REGIONS:
+                       case ADM_CMD_MATRIX_MAP_ROUTINGS:
+                       case ADM_CMD_CONNECT_AFE_PORT:
+                       case ADM_CMD_DISCONNECT_AFE_PORT:
+                               atomic_set(&this_adm.copp_stat[index], 1);
+                               wake_up(&this_adm.wait);
+                               break;
+                       default:
+                               pr_err("%s: Unknown Cmd: 0x%x\n", __func__,
+                                                               payload[0]);
+                               break;
+                       }
+                       return 0;
+               }
+
+               switch (data->opcode) {
+               case ADM_CMDRSP_COPP_OPEN:
+               case ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN:
+               case ADM_CMDRSP_MULTI_CHANNEL_COPP_OPEN_V3: {
+                       struct adm_copp_open_respond *open = data->payload;
+                       if (open->copp_id == INVALID_COPP_ID) {
+                               pr_err("%s: invalid coppid rxed %d\n",
+                                       __func__, open->copp_id);
+                               atomic_set(&this_adm.copp_stat[index], 1);
+                               wake_up(&this_adm.wait);
+                               break;
+                       }
+                       atomic_set(&this_adm.copp_id[index], open->copp_id);
+                       atomic_set(&this_adm.copp_stat[index], 1);
+                       pr_debug("%s: coppid rxed=%d\n", __func__,
+                                                       open->copp_id);
+                       wake_up(&this_adm.wait);
+                       }
+                       break;
+               case ADM_CMDRSP_GET_PARAMS:
+                       pr_debug("%s: ADM_CMDRSP_GET_PARAMS\n", __func__);
+                       rtac_make_adm_callback(payload,
+                               data->payload_size);
+                       break;
+               default:
+                       pr_err("%s: Unknown cmd:0x%x\n", __func__,
+                                                       data->opcode);
+                       break;
+               }
+       }
+       return 0;
+}
+
+static int send_adm_cal_block(int port_id, struct acdb_cal_block *aud_cal)
+{
+       s32                             result = 0;
+       struct adm_set_params_command   adm_params;
+       int index = afe_get_port_index(port_id);
+       if (index < 0 || index >= AFE_MAX_PORTS) {
+               pr_err("%s: invalid port idx %d portid %d\n",
+                               __func__, index, port_id);
+               return 0;
+       }
+
+       pr_debug("%s: Port id %d, index %d\n", __func__, port_id, index);
+
+       if (!aud_cal || aud_cal->cal_size == 0) {
+               pr_debug("%s: No ADM cal to send for port_id = %d!\n",
+                       __func__, port_id);
+               result = -EINVAL;
+               goto done;
+       }
+
+       adm_params.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+               APR_HDR_LEN(20), APR_PKT_VER);
+       adm_params.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+               sizeof(adm_params));
+       adm_params.hdr.src_svc = APR_SVC_ADM;
+       adm_params.hdr.src_domain = APR_DOMAIN_APPS;
+       adm_params.hdr.src_port = port_id;
+       adm_params.hdr.dest_svc = APR_SVC_ADM;
+       adm_params.hdr.dest_domain = APR_DOMAIN_ADSP;
+       adm_params.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+       adm_params.hdr.token = port_id;
+       adm_params.hdr.opcode = ADM_CMD_SET_PARAMS;
+       adm_params.payload = aud_cal->cal_paddr;
+       adm_params.payload_size = aud_cal->cal_size;
+
+       atomic_set(&this_adm.copp_stat[index], 0);
+       pr_debug("%s: Sending SET_PARAMS payload = 0x%x, size = %d\n",
+               __func__, adm_params.payload, adm_params.payload_size);
+       result = apr_send_pkt(this_adm.apr, (uint32_t *)&adm_params);
+       if (result < 0) {
+               pr_err("%s: Set params failed port = %d payload = 0x%x\n",
+                       __func__, port_id, aud_cal->cal_paddr);
+               result = -EINVAL;
+               goto done;
+       }
+       /* Wait for the callback */
+       result = wait_event_timeout(this_adm.wait,
+               atomic_read(&this_adm.copp_stat[index]),
+               msecs_to_jiffies(TIMEOUT_MS));
+       if (!result) {
+               pr_err("%s: Set params timed out port = %d, payload = 0x%x\n",
+                       __func__, port_id, aud_cal->cal_paddr);
+               result = -EINVAL;
+               goto done;
+       }
+
+       result = 0;
+done:
+       return result;
+}
+
+static void send_adm_cal(int port_id, int path)
+{
+       int                     result = 0;
+       s32                     acdb_path;
+       struct acdb_cal_block   aud_cal;
+
+       pr_debug("%s\n", __func__);
+
+       /* Maps audio_dev_ctrl path definition to ACDB definition */
+       acdb_path = path - 1;
+
+       pr_debug("%s: Sending audproc cal\n", __func__);
+       get_audproc_cal(acdb_path, &aud_cal);
+
+       /* map & cache buffers used */
+       if (((mem_addr_audproc[acdb_path].cal_paddr != aud_cal.cal_paddr)  &&
+               (aud_cal.cal_size > 0)) ||
+               (aud_cal.cal_size > mem_addr_audproc[acdb_path].cal_size)) {
+
+               if (mem_addr_audproc[acdb_path].cal_paddr != 0)
+                       adm_memory_unmap_regions(
+                               &mem_addr_audproc[acdb_path].cal_paddr,
+                               &mem_addr_audproc[acdb_path].cal_size, 1);
+
+               result = adm_memory_map_regions(&aud_cal.cal_paddr, 0,
+                                       &aud_cal.cal_size, 1);
+               if (result < 0)
+                       pr_err("ADM audproc mmap did not work! path = %d, "
+                               "addr = 0x%x, size = %d\n", acdb_path,
+                               aud_cal.cal_paddr, aud_cal.cal_size);
+               else
+                       mem_addr_audproc[acdb_path] = aud_cal;
+       }
+
+       if (!send_adm_cal_block(port_id, &aud_cal))
+               pr_debug("%s: Audproc cal sent for port id: %d, path %d\n",
+                       __func__, port_id, acdb_path);
+       else
+               pr_debug("%s: Audproc cal not sent for port id: %d, path %d\n",
+                       __func__, port_id, acdb_path);
+
+       pr_debug("%s: Sending audvol cal\n", __func__);
+       get_audvol_cal(acdb_path, &aud_cal);
+
+       /* map & cache buffers used */
+       if (((mem_addr_audvol[acdb_path].cal_paddr != aud_cal.cal_paddr)  &&
+               (aud_cal.cal_size > 0))  ||
+               (aud_cal.cal_size > mem_addr_audvol[acdb_path].cal_size)) {
+               if (mem_addr_audvol[acdb_path].cal_paddr != 0)
+                       adm_memory_unmap_regions(
+                               &mem_addr_audvol[acdb_path].cal_paddr,
+                               &mem_addr_audvol[acdb_path].cal_size, 1);
+
+               result = adm_memory_map_regions(&aud_cal.cal_paddr, 0,
+                                       &aud_cal.cal_size, 1);
+               if (result < 0)
+                       pr_err("ADM audvol mmap did not work! path = %d, "
+                               "addr = 0x%x, size = %d\n", acdb_path,
+                               aud_cal.cal_paddr, aud_cal.cal_size);
+               else
+                       mem_addr_audvol[acdb_path] = aud_cal;
+       }
+
+       if (!send_adm_cal_block(port_id, &aud_cal))
+               pr_debug("%s: Audvol cal sent for port id: %d, path %d\n",
+                       __func__, port_id, acdb_path);
+       else
+               pr_debug("%s: Audvol cal not sent for port id: %d, path %d\n",
+                       __func__, port_id, acdb_path);
+}
+
+int adm_connect_afe_port(int mode, int session_id, int port_id)
+{
+       struct adm_cmd_connect_afe_port cmd;
+       int ret = 0;
+       int index;
+
+       pr_debug("%s: port %d session id:%d mode:%d\n", __func__,
+                               port_id, session_id, mode);
+
+       port_id = afe_convert_virtual_to_portid(port_id);
+
+       if (afe_validate_port(port_id) < 0) {
+               pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+               return -ENODEV;
+       }
+       if (this_adm.apr == NULL) {
+               this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+                                               0xFFFFFFFF, &this_adm);
+               if (this_adm.apr == NULL) {
+                       pr_err("%s: Unable to register ADM\n", __func__);
+                       ret = -ENODEV;
+                       return ret;
+               }
+               rtac_set_adm_handle(this_adm.apr);
+       }
+       index = afe_get_port_index(port_id);
+       pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+
+       cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                       APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       cmd.hdr.pkt_size = sizeof(cmd);
+       cmd.hdr.src_svc = APR_SVC_ADM;
+       cmd.hdr.src_domain = APR_DOMAIN_APPS;
+       cmd.hdr.src_port = port_id;
+       cmd.hdr.dest_svc = APR_SVC_ADM;
+       cmd.hdr.dest_domain = APR_DOMAIN_ADSP;
+       cmd.hdr.dest_port = port_id;
+       cmd.hdr.token = port_id;
+       cmd.hdr.opcode = ADM_CMD_CONNECT_AFE_PORT;
+
+       cmd.mode = mode;
+       cmd.session_id = session_id;
+       cmd.afe_port_id = port_id;
+
+       atomic_set(&this_adm.copp_stat[index], 0);
+       ret = apr_send_pkt(this_adm.apr, (uint32_t *)&cmd);
+       if (ret < 0) {
+               pr_err("%s:ADM enable for port %d failed\n",
+                                       __func__, port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       /* Wait for the callback with copp id */
+       ret = wait_event_timeout(this_adm.wait,
+               atomic_read(&this_adm.copp_stat[index]),
+               msecs_to_jiffies(TIMEOUT_MS));
+       if (!ret) {
+               pr_err("%s ADM connect AFE failed for port %d\n", __func__,
+                                                       port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       atomic_inc(&this_adm.copp_cnt[index]);
+       return 0;
+
+fail_cmd:
+
+       return ret;
+}
+
+int adm_disconnect_afe_port(int mode, int session_id, int port_id)
+{
+       struct adm_cmd_connect_afe_port cmd;
+       int ret = 0;
+       int index;
+
+       pr_debug("%s: port %d session id:%d mode:%d\n", __func__,
+                               port_id, session_id, mode);
+
+       port_id = afe_convert_virtual_to_portid(port_id);
+
+       if (afe_validate_port(port_id) < 0) {
+               pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+               return -ENODEV;
+       }
+       if (this_adm.apr == NULL) {
+               this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+                                               0xFFFFFFFF, &this_adm);
+               if (this_adm.apr == NULL) {
+                       pr_err("%s: Unable to register ADM\n", __func__);
+                       ret = -ENODEV;
+                       return ret;
+               }
+               rtac_set_adm_handle(this_adm.apr);
+       }
+       index = afe_get_port_index(port_id);
+       pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+
+       cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                       APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       cmd.hdr.pkt_size = sizeof(cmd);
+       cmd.hdr.src_svc = APR_SVC_ADM;
+       cmd.hdr.src_domain = APR_DOMAIN_APPS;
+       cmd.hdr.src_port = port_id;
+       cmd.hdr.dest_svc = APR_SVC_ADM;
+       cmd.hdr.dest_domain = APR_DOMAIN_ADSP;
+       cmd.hdr.dest_port = port_id;
+       cmd.hdr.token = port_id;
+       cmd.hdr.opcode = ADM_CMD_DISCONNECT_AFE_PORT;
+
+       cmd.mode = mode;
+       cmd.session_id = session_id;
+       cmd.afe_port_id = port_id;
+
+       atomic_set(&this_adm.copp_stat[index], 0);
+       ret = apr_send_pkt(this_adm.apr, (uint32_t *)&cmd);
+       if (ret < 0) {
+               pr_err("%s:ADM enable for port %d failed\n",
+                                       __func__, port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       /* Wait for the callback with copp id */
+       ret = wait_event_timeout(this_adm.wait,
+               atomic_read(&this_adm.copp_stat[index]),
+               msecs_to_jiffies(TIMEOUT_MS));
+       if (!ret) {
+               pr_err("%s ADM connect AFE failed for port %d\n", __func__,
+                                                       port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       atomic_dec(&this_adm.copp_cnt[index]);
+       return 0;
+
+fail_cmd:
+
+       return ret;
+}
+
+int adm_open(int port_id, int path, int rate, int channel_mode, int topology)
+{
+       struct adm_copp_open_command    open;
+       int ret = 0;
+       int index;
+
+       pr_debug("%s: port %d path:%d rate:%d mode:%d\n", __func__,
+                               port_id, path, rate, channel_mode);
+
+       port_id = afe_convert_virtual_to_portid(port_id);
+
+       if (afe_validate_port(port_id) < 0) {
+               pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+               return -ENODEV;
+       }
+
+       index = afe_get_port_index(port_id);
+       pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+
+       if (this_adm.apr == NULL) {
+               this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+                                               0xFFFFFFFF, &this_adm);
+               if (this_adm.apr == NULL) {
+                       pr_err("%s: Unable to register ADM\n", __func__);
+                       ret = -ENODEV;
+                       return ret;
+               }
+               rtac_set_adm_handle(this_adm.apr);
+       }
+
+
+       /* Create a COPP if port id are not enabled */
+       if (atomic_read(&this_adm.copp_cnt[index]) == 0) {
+
+               open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+               open.hdr.pkt_size = sizeof(open);
+               open.hdr.src_svc = APR_SVC_ADM;
+               open.hdr.src_domain = APR_DOMAIN_APPS;
+               open.hdr.src_port = port_id;
+               open.hdr.dest_svc = APR_SVC_ADM;
+               open.hdr.dest_domain = APR_DOMAIN_ADSP;
+               open.hdr.dest_port = port_id;
+               open.hdr.token = port_id;
+               open.hdr.opcode = ADM_CMD_COPP_OPEN;
+
+               open.mode = path;
+               open.endpoint_id1 = port_id;
+
+               if (this_adm.ec_ref_rx == 0) {
+                       open.endpoint_id2 = 0xFFFF;
+               } else if (this_adm.ec_ref_rx && (path != 1)) {
+                               open.endpoint_id2 = this_adm.ec_ref_rx;
+                               this_adm.ec_ref_rx = 0;
+               }
+
+               pr_debug("%s open.endpoint_id1:%d open.endpoint_id2:%d",
+                       __func__, open.endpoint_id1, open.endpoint_id2);
+               /* convert path to acdb path */
+               if (path == ADM_PATH_PLAYBACK)
+                       open.topology_id = get_adm_rx_topology();
+               else {
+                       open.topology_id = get_adm_tx_topology();
+                       if ((open.topology_id ==
+                               VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
+                           (open.topology_id ==
+                               VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
+                               rate = 16000;
+               }
+
+        if ((open.topology_id  == 0) || (port_id == VOICE_RECORD_RX) || (port_id == VOICE_RECORD_TX))
+          open.topology_id = topology;
+
+               open.channel_config = channel_mode & 0x00FF;
+               open.rate  = rate;
+
+               pr_debug("%s: channel_config=%d port_id=%d rate=%d"
+                       "topology_id=0x%X\n", __func__, open.channel_config,\
+                       open.endpoint_id1, open.rate,\
+                       open.topology_id);
+
+               atomic_set(&this_adm.copp_stat[index], 0);
+
+               ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+               if (ret < 0) {
+                       pr_err("%s:ADM enable for port %d failed\n",
+                                               __func__, port_id);
+                       ret = -EINVAL;
+                       goto fail_cmd;
+               }
+               /* Wait for the callback with copp id */
+               ret = wait_event_timeout(this_adm.wait,
+                       atomic_read(&this_adm.copp_stat[index]),
+                       msecs_to_jiffies(TIMEOUT_MS));
+               if (!ret) {
+                       pr_err("%s ADM open failed for port %d\n", __func__,
+                                                               port_id);
+                       ret = -EINVAL;
+                       goto fail_cmd;
+               }
+       }
+       atomic_inc(&this_adm.copp_cnt[index]);
+       return 0;
+
+fail_cmd:
+
+       return ret;
+}
+
+
+int adm_multi_ch_copp_open(int port_id, int path, int rate, int channel_mode,
+                               int topology, int perfmode)
+{
+       struct adm_multi_ch_copp_open_command open;
+       int ret = 0;
+       int index;
+
+       pr_debug("%s: port %d path:%d rate:%d channel :%d\n", __func__,
+                               port_id, path, rate, channel_mode);
+
+       port_id = afe_convert_virtual_to_portid(port_id);
+
+       if (afe_validate_port(port_id) < 0) {
+               pr_err("%s port idi[%d] is invalid\n", __func__, port_id);
+               return -ENODEV;
+       }
+
+       index = afe_get_port_index(port_id);
+       pr_debug("%s: Port ID %d, index %d\n", __func__, port_id, index);
+
+       if (this_adm.apr == NULL) {
+               this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+                                               0xFFFFFFFF, &this_adm);
+               if (this_adm.apr == NULL) {
+                       pr_err("%s: Unable to register ADM\n", __func__);
+                       ret = -ENODEV;
+                       return ret;
+               }
+               rtac_set_adm_handle(this_adm.apr);
+       }
+
+       /* Create a COPP if port id are not enabled */
+       if (atomic_read(&this_adm.copp_cnt[index]) == 0) {
+
+               open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+
+               open.hdr.pkt_size =
+                       sizeof(struct adm_multi_ch_copp_open_command);
+
+               if (perfmode) {
+                       pr_debug("%s Performance mode", __func__);
+                       open.hdr.opcode = ADM_CMD_MULTI_CHANNEL_COPP_OPEN_V3;
+                       open.flags = ADM_MULTI_CH_COPP_OPEN_PERF_MODE_BIT;
+                       open.reserved = PCM_BITS_PER_SAMPLE;
+               } else {
+                       open.hdr.opcode = ADM_CMD_MULTI_CHANNEL_COPP_OPEN;
+                       open.reserved = 0;
+               }
+
+               memset(open.dev_channel_mapping, 0, 8);
+
+               if (channel_mode == 1)  {
+                       open.dev_channel_mapping[0] = PCM_CHANNEL_FC;
+               } else if (channel_mode == 2) {
+                       open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+                       open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+               } else if (channel_mode == 4) {
+                       open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+                       open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+                       open.dev_channel_mapping[2] = PCM_CHANNEL_RB;
+                       open.dev_channel_mapping[3] = PCM_CHANNEL_LB;
+               } else if (channel_mode == 6) {
+                       open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+                       open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+                       open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+                       open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
+                       open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
+                       open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
+               } else if (channel_mode == 8) {
+                       open.dev_channel_mapping[0] = PCM_CHANNEL_FL;
+                       open.dev_channel_mapping[1] = PCM_CHANNEL_FR;
+                       open.dev_channel_mapping[2] = PCM_CHANNEL_LFE;
+                       open.dev_channel_mapping[3] = PCM_CHANNEL_FC;
+                       open.dev_channel_mapping[4] = PCM_CHANNEL_LB;
+                       open.dev_channel_mapping[5] = PCM_CHANNEL_RB;
+                       open.dev_channel_mapping[6] = PCM_CHANNEL_FLC;
+                       open.dev_channel_mapping[7] = PCM_CHANNEL_FRC;
+               } else {
+                       pr_err("%s invalid num_chan %d\n", __func__,
+                                       channel_mode);
+                       return -EINVAL;
+               }
+               open.hdr.src_svc = APR_SVC_ADM;
+               open.hdr.src_domain = APR_DOMAIN_APPS;
+               open.hdr.src_port = port_id;
+               open.hdr.dest_svc = APR_SVC_ADM;
+               open.hdr.dest_domain = APR_DOMAIN_ADSP;
+               open.hdr.dest_port = port_id;
+               open.hdr.token = port_id;
+
+               open.mode = path;
+               open.endpoint_id1 = port_id;
+
+               if (this_adm.ec_ref_rx == 0) {
+                       open.endpoint_id2 = 0xFFFF;
+               } else if (this_adm.ec_ref_rx && (path != 1)) {
+                               open.endpoint_id2 = this_adm.ec_ref_rx;
+                               this_adm.ec_ref_rx = 0;
+               }
+
+               pr_debug("%s open.endpoint_id1:%d open.endpoint_id2:%d",
+                       __func__, open.endpoint_id1, open.endpoint_id2);
+               /* convert path to acdb path */
+               if (path == ADM_PATH_PLAYBACK)
+                       open.topology_id = get_adm_rx_topology();
+               else {
+                       open.topology_id = get_adm_tx_topology();
+                       if ((open.topology_id ==
+                               VPM_TX_SM_ECNS_COPP_TOPOLOGY) ||
+                           (open.topology_id ==
+                               VPM_TX_DM_FLUENCE_COPP_TOPOLOGY))
+                               rate = 16000;
+               }
+
+        if ((open.topology_id  == 0) || (port_id == VOICE_RECORD_RX) || (port_id == VOICE_RECORD_TX))
+          open.topology_id = topology;
+
+               open.channel_config = channel_mode & 0x00FF;
+               open.rate  = rate;
+
+               pr_debug("%s: channel_config=%d port_id=%d rate=%d"
+                       " topology_id=0x%X\n", __func__, open.channel_config,
+                       open.endpoint_id1, open.rate,
+                       open.topology_id);
+
+               atomic_set(&this_adm.copp_stat[index], 0);
+
+               ret = apr_send_pkt(this_adm.apr, (uint32_t *)&open);
+               if (ret < 0) {
+                       pr_err("%s:ADM enable for port %d failed\n",
+                                               __func__, port_id);
+                       ret = -EINVAL;
+                       goto fail_cmd;
+               }
+               /* Wait for the callback with copp id */
+               ret = wait_event_timeout(this_adm.wait,
+                       atomic_read(&this_adm.copp_stat[index]),
+                       msecs_to_jiffies(TIMEOUT_MS));
+               if (!ret) {
+                       pr_err("%s ADM open failed for port %d\n", __func__,
+                                                               port_id);
+                       ret = -EINVAL;
+                       goto fail_cmd;
+               }
+       }
+       atomic_inc(&this_adm.copp_cnt[index]);
+       return 0;
+
+fail_cmd:
+
+       return ret;
+}
+
+int adm_matrix_map(int session_id, int path, int num_copps,
+                       unsigned int *port_id, int copp_id)
+{
+       struct adm_routings_command     route;
+       int ret = 0, i = 0;
+       /* Assumes port_ids have already been validated during adm_open */
+       int index = afe_get_port_index(copp_id);
+       int copp_cnt;
+
+       if (index < 0 || index >= AFE_MAX_PORTS) {
+               pr_err("%s: invalid port idx %d token %d\n",
+                                       __func__, index, copp_id);
+               return 0;
+       }
+
+       pr_debug("%s: session 0x%x path:%d num_copps:%d port_id[0]:%d\n",
+                __func__, session_id, path, num_copps, port_id[0]);
+
+       route.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       route.hdr.pkt_size = sizeof(route);
+       route.hdr.src_svc = 0;
+       route.hdr.src_domain = APR_DOMAIN_APPS;
+       route.hdr.src_port = copp_id;
+       route.hdr.dest_svc = APR_SVC_ADM;
+       route.hdr.dest_domain = APR_DOMAIN_ADSP;
+       route.hdr.dest_port = atomic_read(&this_adm.copp_id[index]);
+       route.hdr.token = copp_id;
+       route.hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS;
+       route.num_sessions = 1;
+       route.session[0].id = session_id;
+
+       if (num_copps < ADM_MAX_COPPS) {
+               copp_cnt = num_copps;
+       } else {
+               copp_cnt = ADM_MAX_COPPS;
+               /* print out warning for now as playback/capture to/from
+                * COPPs more than maximum allowed is extremely unlikely
+                */
+               pr_warn("%s: max out routable COPPs\n", __func__);
+       }
+
+       route.session[0].num_copps = copp_cnt;
+       for (i = 0; i < copp_cnt; i++) {
+               int tmp;
+               port_id[i] = afe_convert_virtual_to_portid(port_id[i]);
+
+               tmp = afe_get_port_index(port_id[i]);
+
+               pr_debug("%s: port_id[%d]: %d, index: %d\n", __func__, i,
+                        port_id[i], tmp);
+
+               if (tmp >= 0 && tmp < AFE_MAX_PORTS)
+                       route.session[0].copp_id[i] =
+                                       atomic_read(&this_adm.copp_id[tmp]);
+       }
+
+       if (copp_cnt % 2)
+               route.session[0].copp_id[i] = 0;
+
+       switch (path) {
+       case 0x1:
+               route.path = AUDIO_RX;
+               break;
+       case 0x2:
+       case 0x3:
+               route.path = AUDIO_TX;
+               break;
+       default:
+               pr_err("%s: Wrong path set[%d]\n", __func__, path);
+               break;
+       }
+       atomic_set(&this_adm.copp_stat[index], 0);
+
+       ret = apr_send_pkt(this_adm.apr, (uint32_t *)&route);
+       if (ret < 0) {
+               pr_err("%s: ADM routing for port %d failed\n",
+                                       __func__, port_id[0]);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       ret = wait_event_timeout(this_adm.wait,
+                               atomic_read(&this_adm.copp_stat[index]),
+                               msecs_to_jiffies(TIMEOUT_MS));
+       if (!ret) {
+               pr_err("%s: ADM cmd Route failed for port %d\n",
+                                       __func__, port_id[0]);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       for (i = 0; i < num_copps; i++)
+               send_adm_cal(port_id[i], path);
+
+       for (i = 0; i < num_copps; i++) {
+               int tmp;
+               tmp = afe_get_port_index(port_id[i]);
+               if (tmp >= 0 && tmp < AFE_MAX_PORTS)
+                       rtac_add_adm_device(port_id[i],
+                               atomic_read(&this_adm.copp_id[tmp]),
+                               path, session_id);
+               else
+                       pr_debug("%s: Invalid port index %d",
+                               __func__, tmp);
+       }
+       return 0;
+
+fail_cmd:
+
+       return ret;
+}
+
+int adm_memory_map_regions(uint32_t *buf_add, uint32_t mempool_id,
+                               uint32_t *bufsz, uint32_t bufcnt)
+{
+       struct  adm_cmd_memory_map_regions *mmap_regions = NULL;
+       struct  adm_memory_map_regions *mregions = NULL;
+       void    *mmap_region_cmd = NULL;
+       void    *payload = NULL;
+       int     ret = 0;
+       int     i = 0;
+       int     cmd_size = 0;
+
+       pr_debug("%s\n", __func__);
+       if (this_adm.apr == NULL) {
+               this_adm.apr = apr_register("ADSP", "ADM", adm_callback,
+                                               0xFFFFFFFF, &this_adm);
+               if (this_adm.apr == NULL) {
+                       pr_err("%s: Unable to register ADM\n", __func__);
+                       ret = -ENODEV;
+                       return ret;
+               }
+               rtac_set_adm_handle(this_adm.apr);
+       }
+
+       cmd_size = sizeof(struct adm_cmd_memory_map_regions)
+                       + sizeof(struct adm_memory_map_regions) * bufcnt;
+
+       mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+       if (!mmap_region_cmd) {
+               pr_err("%s: allocate mmap_region_cmd failed\n", __func__);
+               return -ENOMEM;
+       }
+       mmap_regions = (struct adm_cmd_memory_map_regions *)mmap_region_cmd;
+       mmap_regions->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                                               APR_HDR_LEN(APR_HDR_SIZE),
+                                                               APR_PKT_VER);
+       mmap_regions->hdr.pkt_size = cmd_size;
+       mmap_regions->hdr.src_port = 0;
+       mmap_regions->hdr.dest_port = 0;
+       mmap_regions->hdr.token = 0;
+       mmap_regions->hdr.opcode = ADM_CMD_MEMORY_MAP_REGIONS;
+       mmap_regions->mempool_id = mempool_id & 0x00ff;
+       mmap_regions->nregions = bufcnt & 0x00ff;
+       pr_debug("%s: map_regions->nregions = %d\n", __func__,
+                               mmap_regions->nregions);
+       payload = ((u8 *) mmap_region_cmd +
+                               sizeof(struct adm_cmd_memory_map_regions));
+       mregions = (struct adm_memory_map_regions *)payload;
+
+       for (i = 0; i < bufcnt; i++) {
+               mregions->phys = buf_add[i];
+               mregions->buf_size = bufsz[i];
+               ++mregions;
+       }
+
+       atomic_set(&this_adm.copp_stat[0], 0);
+       ret = apr_send_pkt(this_adm.apr, (uint32_t *) mmap_region_cmd);
+       if (ret < 0) {
+               pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
+                                       mmap_regions->hdr.opcode, ret);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       ret = wait_event_timeout(this_adm.wait,
+                       atomic_read(&this_adm.copp_stat[0]), 5 * HZ);
+       if (!ret) {
+               pr_err("%s: timeout. waited for memory_map\n", __func__);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+fail_cmd:
+       kfree(mmap_region_cmd);
+       return ret;
+}
+
+int adm_memory_unmap_regions(uint32_t *buf_add, uint32_t *bufsz,
+                                               uint32_t bufcnt)
+{
+       struct  adm_cmd_memory_unmap_regions *unmap_regions = NULL;
+       struct  adm_memory_unmap_regions *mregions = NULL;
+       void    *unmap_region_cmd = NULL;
+       void    *payload = NULL;
+       int     ret = 0;
+       int     i = 0;
+       int     cmd_size = 0;
+
+       pr_debug("%s\n", __func__);
+
+       if (this_adm.apr == NULL) {
+               pr_err("%s APR handle NULL\n", __func__);
+               return -EINVAL;
+       }
+
+       cmd_size = sizeof(struct adm_cmd_memory_unmap_regions)
+                       + sizeof(struct adm_memory_unmap_regions) * bufcnt;
+
+       unmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+       if (!unmap_region_cmd) {
+               pr_err("%s: allocate unmap_region_cmd failed\n", __func__);
+               return -ENOMEM;
+       }
+       unmap_regions = (struct adm_cmd_memory_unmap_regions *)
+                                               unmap_region_cmd;
+       unmap_regions->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                                               APR_HDR_LEN(APR_HDR_SIZE),
+                                                       APR_PKT_VER);
+       unmap_regions->hdr.pkt_size = cmd_size;
+       unmap_regions->hdr.src_port = 0;
+       unmap_regions->hdr.dest_port = 0;
+       unmap_regions->hdr.token = 0;
+       unmap_regions->hdr.opcode = ADM_CMD_MEMORY_UNMAP_REGIONS;
+       unmap_regions->nregions = bufcnt & 0x00ff;
+       unmap_regions->reserved = 0;
+       pr_debug("%s: unmap_regions->nregions = %d\n", __func__,
+                               unmap_regions->nregions);
+       payload = ((u8 *) unmap_region_cmd +
+                       sizeof(struct adm_cmd_memory_unmap_regions));
+       mregions = (struct adm_memory_unmap_regions *)payload;
+
+       for (i = 0; i < bufcnt; i++) {
+               mregions->phys = buf_add[i];
+               ++mregions;
+       }
+       atomic_set(&this_adm.copp_stat[0], 0);
+       ret = apr_send_pkt(this_adm.apr, (uint32_t *) unmap_region_cmd);
+       if (ret < 0) {
+               pr_err("%s: mmap_regions op[0x%x]rc[%d]\n", __func__,
+                               unmap_regions->hdr.opcode, ret);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       ret = wait_event_timeout(this_adm.wait,
+                       atomic_read(&this_adm.copp_stat[0]), 5 * HZ);
+       if (!ret) {
+               pr_err("%s: timeout. waited for memory_unmap\n", __func__);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+fail_cmd:
+       kfree(unmap_region_cmd);
+       return ret;
+}
+
+int adm_get_copp_id(int port_index)
+{
+       pr_debug("%s\n", __func__);
+
+       if (port_index < 0) {
+               pr_err("%s: invalid port_id = %d\n", __func__, port_index);
+               return -EINVAL;
+       }
+
+       return atomic_read(&this_adm.copp_id[port_index]);
+}
+
+void adm_ec_ref_rx_id(int  port_id)
+{
+       this_adm.ec_ref_rx = port_id;
+       pr_debug("%s ec_ref_rx:%d", __func__, this_adm.ec_ref_rx);
+}
+
+int adm_close(int port_id)
+{
+       struct apr_hdr close;
+
+       int ret = 0;
+       int index = 0;
+
+       port_id = afe_convert_virtual_to_portid(port_id);
+
+       index = afe_get_port_index(port_id);
+       if (afe_validate_port(port_id) < 0)
+               return -EINVAL;
+
+       pr_debug("%s port_id=%d index %d\n", __func__, port_id, index);
+
+       if (!(atomic_read(&this_adm.copp_cnt[index]))) {
+               pr_err("%s: copp count for port[%d]is 0\n", __func__, port_id);
+
+               goto fail_cmd;
+       }
+       atomic_dec(&this_adm.copp_cnt[index]);
+       if (!(atomic_read(&this_adm.copp_cnt[index]))) {
+
+               close.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                       APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+               close.pkt_size = sizeof(close);
+               close.src_svc = APR_SVC_ADM;
+               close.src_domain = APR_DOMAIN_APPS;
+               close.src_port = port_id;
+               close.dest_svc = APR_SVC_ADM;
+               close.dest_domain = APR_DOMAIN_ADSP;
+               close.dest_port = atomic_read(&this_adm.copp_id[index]);
+               close.token = port_id;
+               close.opcode = ADM_CMD_COPP_CLOSE;
+
+               atomic_set(&this_adm.copp_id[index], RESET_COPP_ID);
+               atomic_set(&this_adm.copp_stat[index], 0);
+
+
+               pr_debug("%s:coppid %d portid=%d index=%d coppcnt=%d\n",
+                               __func__,
+                               atomic_read(&this_adm.copp_id[index]),
+                               port_id, index,
+                               atomic_read(&this_adm.copp_cnt[index]));
+
+               ret = apr_send_pkt(this_adm.apr, (uint32_t *)&close);
+               if (ret < 0) {
+                       pr_err("%s ADM close failed\n", __func__);
+                       ret = -EINVAL;
+                       goto fail_cmd;
+               }
+
+               ret = wait_event_timeout(this_adm.wait,
+                               atomic_read(&this_adm.copp_stat[index]),
+                               msecs_to_jiffies(TIMEOUT_MS));
+               if (!ret) {
+                       pr_err("%s: ADM cmd Route failed for port %d\n",
+                                               __func__, port_id);
+                       ret = -EINVAL;
+                       goto fail_cmd;
+               }
+
+               rtac_remove_adm_device(port_id);
+       }
+
+fail_cmd:
+       return ret;
+}
+
+static int __init adm_init(void)
+{
+       int i = 0;
+       init_waitqueue_head(&this_adm.wait);
+       this_adm.apr = NULL;
+
+       for (i = 0; i < AFE_MAX_PORTS; i++) {
+               atomic_set(&this_adm.copp_id[i], RESET_COPP_ID);
+               atomic_set(&this_adm.copp_cnt[i], 0);
+               atomic_set(&this_adm.copp_stat[i], 0);
+       }
+       return 0;
+}
+
+device_initcall(adm_init);
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
new file mode 100644 (file)
index 0000000..5935ff3
--- /dev/null
@@ -0,0 +1,1826 @@
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+#include <linux/wait.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <sound/qdsp6v2/audio_acdb.h>
+#include <sound/apr_audio.h>
+#include <sound/q6afe.h>
+
+struct afe_ctl {
+       void *apr;
+       atomic_t state;
+       atomic_t status;
+       wait_queue_head_t wait;
+       struct task_struct *task;
+       void (*tx_cb) (uint32_t opcode,
+               uint32_t token, uint32_t *payload, void *priv);
+       void (*rx_cb) (uint32_t opcode,
+               uint32_t token, uint32_t *payload, void *priv);
+       void *tx_private_data;
+       void *rx_private_data;
+};
+
+static struct afe_ctl this_afe;
+
+static struct acdb_cal_block afe_cal_addr[MAX_AUDPROC_TYPES];
+static int pcm_afe_instance[2];
+static int proxy_afe_instance[2];
+bool afe_close_done[2] = {true, true};
+
+#define TIMEOUT_MS 1000
+#define Q6AFE_MAX_VOLUME 0x3FFF
+
+#define SIZEOF_CFG_CMD(y) \
+               (sizeof(struct apr_hdr) + sizeof(u16) + (sizeof(struct y)))
+
+static int32_t afe_callback(struct apr_client_data *data, void *priv)
+{
+       if (data->opcode == RESET_EVENTS) {
+               pr_debug("q6afe: reset event = %d %d apr[%p]\n",
+                       data->reset_event, data->reset_proc, this_afe.apr);
+               if (this_afe.apr) {
+                       apr_reset(this_afe.apr);
+                       atomic_set(&this_afe.state, 0);
+                       this_afe.apr = NULL;
+               }
+               /* send info to user */
+               pr_debug("task_name = %s pid = %d\n",
+                       this_afe.task->comm, this_afe.task->pid);
+               send_sig(SIGUSR1, this_afe.task, 0);
+               return 0;
+       }
+       if (data->payload_size) {
+               uint32_t *payload;
+               uint16_t port_id = 0;
+               payload = data->payload;
+               pr_debug("%s:opcode = 0x%x cmd = 0x%x status = 0x%x\n",
+                                       __func__, data->opcode,
+                                       payload[0], payload[1]);
+               /* payload[1] contains the error status for response */
+               if (payload[1] != 0) {
+                       atomic_set(&this_afe.status, -1);
+                       pr_err("%s: cmd = 0x%x returned error = 0x%x\n",
+                                       __func__, payload[0], payload[1]);
+               }
+               if (data->opcode == APR_BASIC_RSP_RESULT) {
+                       switch (payload[0]) {
+                       case AFE_PORT_AUDIO_IF_CONFIG:
+                       case AFE_PORT_CMD_I2S_CONFIG:
+                       case AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG:
+                       case AFE_PORT_AUDIO_SLIM_SCH_CONFIG:
+                       case AFE_PORT_CMD_STOP:
+                       case AFE_PORT_CMD_START:
+                       case AFE_PORT_CMD_LOOPBACK:
+                       case AFE_PORT_CMD_SIDETONE_CTL:
+                       case AFE_PORT_CMD_SET_PARAM:
+                       case AFE_PSEUDOPORT_CMD_START:
+                       case AFE_PSEUDOPORT_CMD_STOP:
+                       case AFE_PORT_CMD_APPLY_GAIN:
+                       case AFE_SERVICE_CMD_MEMORY_MAP:
+                       case AFE_SERVICE_CMD_MEMORY_UNMAP:
+                       case AFE_SERVICE_CMD_UNREG_RTPORT:
+                               atomic_set(&this_afe.state, 0);
+                               wake_up(&this_afe.wait);
+                               break;
+                       case AFE_SERVICE_CMD_REG_RTPORT:
+                               break;
+                       case AFE_SERVICE_CMD_RTPORT_WR:
+                               port_id = RT_PROXY_PORT_001_TX;
+                               break;
+                       case AFE_SERVICE_CMD_RTPORT_RD:
+                               port_id = RT_PROXY_PORT_001_RX;
+                               break;
+                       default:
+                               pr_err("Unknown cmd 0x%x\n",
+                                               payload[0]);
+                               break;
+                       }
+               } else if (data->opcode == AFE_EVENT_RT_PROXY_PORT_STATUS) {
+                       port_id = (uint16_t)(0x0000FFFF & payload[0]);
+               }
+               pr_debug("%s:port_id = %x\n", __func__, port_id);
+               switch (port_id) {
+               case RT_PROXY_PORT_001_TX: {
+                       if (this_afe.tx_cb) {
+                               this_afe.tx_cb(data->opcode, data->token,
+                                       data->payload,
+                                       this_afe.tx_private_data);
+                       }
+                       break;
+               }
+               case RT_PROXY_PORT_001_RX: {
+                       if (this_afe.rx_cb) {
+                               this_afe.rx_cb(data->opcode, data->token,
+                                       data->payload,
+                                       this_afe.rx_private_data);
+                       }
+                       break;
+               }
+               default:
+                       break;
+               }
+       }
+       return 0;
+}
+
+int afe_get_port_type(u16 port_id)
+{
+       int ret;
+
+       switch (port_id) {
+       case PRIMARY_I2S_RX:
+       case PCM_RX:
+       case SECONDARY_PCM_RX:
+       case SECONDARY_I2S_RX:
+       case MI2S_RX:
+       case HDMI_RX:
+       case SLIMBUS_0_RX:
+       case SLIMBUS_1_RX:
+       case SLIMBUS_2_RX:
+       case SLIMBUS_3_RX:
+       case INT_BT_SCO_RX:
+       case INT_BT_A2DP_RX:
+       case INT_FM_RX:
+       case VOICE_PLAYBACK_TX:
+       case RT_PROXY_PORT_001_RX:
+       case SLIMBUS_4_RX:
+               ret = MSM_AFE_PORT_TYPE_RX;
+               break;
+
+       case PRIMARY_I2S_TX:
+       case PCM_TX:
+       case SECONDARY_PCM_TX:
+       case SECONDARY_I2S_TX:
+       case MI2S_TX:
+       case DIGI_MIC_TX:
+       case VOICE_RECORD_TX:
+       case SLIMBUS_0_TX:
+       case SLIMBUS_1_TX:
+       case SLIMBUS_2_TX:
+       case SLIMBUS_3_TX:
+       case INT_FM_TX:
+       case VOICE_RECORD_RX:
+       case INT_BT_SCO_TX:
+       case RT_PROXY_PORT_001_TX:
+       case SLIMBUS_4_TX:
+               ret = MSM_AFE_PORT_TYPE_TX;
+               break;
+
+       default:
+               pr_err("%s: invalid port id %d\n", __func__, port_id);
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+int afe_validate_port(u16 port_id)
+{
+       int ret;
+
+       switch (port_id) {
+       case PRIMARY_I2S_RX:
+       case PRIMARY_I2S_TX:
+       case PCM_RX:
+       case PCM_TX:
+       case SECONDARY_PCM_RX:
+       case SECONDARY_PCM_TX:
+       case SECONDARY_I2S_RX:
+       case SECONDARY_I2S_TX:
+       case MI2S_RX:
+       case MI2S_TX:
+       case HDMI_RX:
+       case RSVD_2:
+       case RSVD_3:
+       case DIGI_MIC_TX:
+       case VOICE_RECORD_RX:
+       case VOICE_RECORD_TX:
+       case VOICE_PLAYBACK_TX:
+       case SLIMBUS_0_RX:
+       case SLIMBUS_0_TX:
+       case SLIMBUS_1_RX:
+       case SLIMBUS_1_TX:
+       case SLIMBUS_2_RX:
+       case SLIMBUS_2_TX:
+       case SLIMBUS_3_RX:
+       case SLIMBUS_3_TX:
+       case INT_BT_SCO_RX:
+       case INT_BT_SCO_TX:
+       case INT_BT_A2DP_RX:
+       case INT_FM_RX:
+       case INT_FM_TX:
+       case RT_PROXY_PORT_001_RX:
+       case RT_PROXY_PORT_001_TX:
+       case SLIMBUS_4_RX:
+       case SLIMBUS_4_TX:
+       {
+               ret = 0;
+               break;
+       }
+
+       default:
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+int afe_convert_virtual_to_portid(u16 port_id)
+{
+       int ret;
+
+       /* if port_id is virtual, convert to physical..
+        * if port_id is already physical, return physical
+        */
+       if (afe_validate_port(port_id) < 0) {
+               if (port_id == RT_PROXY_DAI_001_RX ||
+                       port_id == RT_PROXY_DAI_001_TX ||
+                       port_id == RT_PROXY_DAI_002_RX ||
+                       port_id == RT_PROXY_DAI_002_TX)
+                       ret = VIRTUAL_ID_TO_PORTID(port_id);
+               else
+                       ret = -EINVAL;
+       } else
+               ret = port_id;
+
+       return ret;
+}
+
+int afe_get_port_index(u16 port_id)
+{
+       switch (port_id) {
+       case PRIMARY_I2S_RX: return IDX_PRIMARY_I2S_RX;
+       case PRIMARY_I2S_TX: return IDX_PRIMARY_I2S_TX;
+       case PCM_RX: return IDX_PCM_RX;
+       case PCM_TX: return IDX_PCM_TX;
+       case SECONDARY_PCM_RX: return IDX_SECONDARY_PCM_RX;
+       case SECONDARY_PCM_TX: return IDX_SECONDARY_PCM_TX;
+       case SECONDARY_I2S_RX: return IDX_SECONDARY_I2S_RX;
+       case SECONDARY_I2S_TX: return IDX_SECONDARY_I2S_TX;
+       case MI2S_RX: return IDX_MI2S_RX;
+       case MI2S_TX: return IDX_MI2S_TX;
+       case HDMI_RX: return IDX_HDMI_RX;
+       case RSVD_2: return IDX_RSVD_2;
+       case RSVD_3: return IDX_RSVD_3;
+       case DIGI_MIC_TX: return IDX_DIGI_MIC_TX;
+       case VOICE_RECORD_RX: return IDX_VOICE_RECORD_RX;
+       case VOICE_RECORD_TX: return IDX_VOICE_RECORD_TX;
+       case VOICE_PLAYBACK_TX: return IDX_VOICE_PLAYBACK_TX;
+       case SLIMBUS_0_RX: return IDX_SLIMBUS_0_RX;
+       case SLIMBUS_0_TX: return IDX_SLIMBUS_0_TX;
+       case SLIMBUS_1_RX: return IDX_SLIMBUS_1_RX;
+       case SLIMBUS_1_TX: return IDX_SLIMBUS_1_TX;
+       case SLIMBUS_2_RX: return IDX_SLIMBUS_2_RX;
+       case SLIMBUS_2_TX: return IDX_SLIMBUS_2_TX;
+       case SLIMBUS_3_RX: return IDX_SLIMBUS_3_RX;
+       case SLIMBUS_3_TX: return IDX_SLIMBUS_3_TX;
+       case INT_BT_SCO_RX: return IDX_INT_BT_SCO_RX;
+       case INT_BT_SCO_TX: return IDX_INT_BT_SCO_TX;
+       case INT_BT_A2DP_RX: return IDX_INT_BT_A2DP_RX;
+       case INT_FM_RX: return IDX_INT_FM_RX;
+       case INT_FM_TX: return IDX_INT_FM_TX;
+       case RT_PROXY_PORT_001_RX: return IDX_RT_PROXY_PORT_001_RX;
+       case RT_PROXY_PORT_001_TX: return IDX_RT_PROXY_PORT_001_TX;
+       case SLIMBUS_4_RX: return IDX_SLIMBUS_4_RX;
+       case SLIMBUS_4_TX: return IDX_SLIMBUS_4_TX;
+
+       default: return -EINVAL;
+       }
+}
+
+int afe_sizeof_cfg_cmd(u16 port_id)
+{
+       int ret_size;
+       switch (port_id) {
+       case PRIMARY_I2S_RX:
+       case PRIMARY_I2S_TX:
+       case SECONDARY_I2S_RX:
+       case SECONDARY_I2S_TX:
+       case MI2S_RX:
+       case MI2S_TX:
+               ret_size = SIZEOF_CFG_CMD(afe_port_mi2s_cfg);
+               break;
+       case HDMI_RX:
+               ret_size = SIZEOF_CFG_CMD(afe_port_hdmi_multi_ch_cfg);
+               break;
+       case SLIMBUS_0_RX:
+       case SLIMBUS_0_TX:
+       case SLIMBUS_1_RX:
+       case SLIMBUS_1_TX:
+       case SLIMBUS_2_RX:
+       case SLIMBUS_2_TX:
+       case SLIMBUS_3_RX:
+       case SLIMBUS_3_TX:
+       case SLIMBUS_4_RX:
+       case SLIMBUS_4_TX:
+               ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_sch_cfg);
+               break;
+       case RT_PROXY_PORT_001_RX:
+       case RT_PROXY_PORT_001_TX:
+               ret_size = SIZEOF_CFG_CMD(afe_port_rtproxy_cfg);
+               break;
+       case PCM_RX:
+       case PCM_TX:
+       case SECONDARY_PCM_RX:
+       case SECONDARY_PCM_TX:
+       default:
+               ret_size = SIZEOF_CFG_CMD(afe_port_pcm_cfg);
+               break;
+       }
+       return ret_size;
+}
+
+int afe_q6_interface_prepare(void)
+{
+       int ret = 0;
+
+       pr_debug("%s:", __func__);
+
+       if (this_afe.apr == NULL) {
+               this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+                       0xFFFFFFFF, &this_afe);
+               pr_debug("%s: Register AFE\n", __func__);
+               if (this_afe.apr == NULL) {
+                       pr_err("%s: Unable to register AFE\n", __func__);
+                       ret = -ENODEV;
+               }
+       }
+       return ret;
+}
+
+static void afe_send_cal_block(int32_t path, u16 port_id)
+{
+       int                                             result = 0;
+       struct acdb_cal_block                           cal_block;
+       struct afe_port_cmd_set_param_no_payload        afe_cal;
+       pr_debug("%s: path %d\n", __func__, path);
+
+       get_afe_cal(path, &cal_block);
+       if (cal_block.cal_size <= 0) {
+               pr_debug("%s: No AFE cal to send!\n", __func__);
+               goto done;
+       }
+
+       if ((afe_cal_addr[path].cal_paddr != cal_block.cal_paddr) ||
+               (cal_block.cal_size > afe_cal_addr[path].cal_size)) {
+               if (afe_cal_addr[path].cal_paddr != 0)
+                       afe_cmd_memory_unmap(
+                               afe_cal_addr[path].cal_paddr);
+
+               afe_cmd_memory_map(cal_block.cal_paddr, cal_block.cal_size);
+               afe_cal_addr[path].cal_paddr = cal_block.cal_paddr;
+               afe_cal_addr[path].cal_size = cal_block.cal_size;
+       }
+
+       afe_cal.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       afe_cal.hdr.pkt_size = sizeof(afe_cal);
+       afe_cal.hdr.src_port = 0;
+       afe_cal.hdr.dest_port = 0;
+       afe_cal.hdr.token = 0;
+       afe_cal.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
+       afe_cal.port_id = port_id;
+       afe_cal.payload_size = cal_block.cal_size;
+       afe_cal.payload_address = cal_block.cal_paddr;
+
+       pr_debug("%s: AFE cal sent for device port = %d, path = %d, "
+               "cal size = %d, cal addr = 0x%x\n", __func__,
+               port_id, path, cal_block.cal_size, cal_block.cal_paddr);
+
+       atomic_set(&this_afe.state, 1);
+       result = apr_send_pkt(this_afe.apr, (uint32_t *) &afe_cal);
+       if (result < 0) {
+               pr_err("%s: AFE cal for port %d failed\n",
+                       __func__, port_id);
+       }
+
+       result = wait_event_timeout(this_afe.wait,
+                                (atomic_read(&this_afe.state) == 0),
+                                msecs_to_jiffies(TIMEOUT_MS));
+       if (!result) {
+               pr_err("%s: wait_event timeout SET AFE CAL\n", __func__);
+               goto done;
+       }
+
+       pr_debug("%s: AFE cal sent for path %d device!\n", __func__, path);
+done:
+       return;
+}
+
+void afe_send_cal(u16 port_id)
+{
+       pr_debug("%s\n", __func__);
+
+       if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_TX)
+               afe_send_cal_block(TX_CAL, port_id);
+       else if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX)
+               afe_send_cal_block(RX_CAL, port_id);
+}
+
+/* This function sends multi-channel HDMI configuration command and AFE
+ * calibration which is only supported by QDSP6 on 8960 and onward.
+ */
+int afe_port_start(u16 port_id, union afe_port_config *afe_config,
+                  u32 rate)
+{
+       struct afe_port_start_command start;
+       struct afe_audioif_config_command config;
+       int ret;
+
+       if (!afe_config) {
+               pr_err("%s: Error, no configuration data\n", __func__);
+               ret = -EINVAL;
+               return ret;
+       }
+       pr_debug("%s: %d %d\n", __func__, port_id, rate);
+
+       if ((port_id == RT_PROXY_DAI_001_RX) ||
+               (port_id == RT_PROXY_DAI_002_TX)) {
+               pr_debug("%s: before incrementing pcm_afe_instance %d"\
+                               " port_id %d\n", __func__,
+                               pcm_afe_instance[port_id & 0x1], port_id);
+               port_id = VIRTUAL_ID_TO_PORTID(port_id);
+               pcm_afe_instance[port_id & 0x1]++;
+               return 0;
+       }
+       if ((port_id == RT_PROXY_DAI_002_RX) ||
+               (port_id == RT_PROXY_DAI_001_TX)) {
+               pr_debug("%s: before incrementing proxy_afe_instance %d"\
+                               " port_id %d\n", __func__,
+                               proxy_afe_instance[port_id & 0x1], port_id);
+               if (!afe_close_done[port_id & 0x1]) {
+                       /*close pcm dai corresponding to the proxy dai*/
+                       afe_close(port_id - 0x10);
+                       pcm_afe_instance[port_id & 0x1]++;
+                       pr_debug("%s: reconfigure afe port again\n", __func__);
+               }
+               proxy_afe_instance[port_id & 0x1]++;
+               afe_close_done[port_id & 0x1] = false;
+               port_id = VIRTUAL_ID_TO_PORTID(port_id);
+       }
+
+       ret = afe_q6_interface_prepare();
+       if (IS_ERR_VALUE(ret))
+               return ret;
+
+       if (port_id == HDMI_RX) {
+               config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+               config.hdr.pkt_size = afe_sizeof_cfg_cmd(port_id);
+               config.hdr.src_port = 0;
+               config.hdr.dest_port = 0;
+               config.hdr.token = 0;
+               config.hdr.opcode = AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG;
+       } else {
+
+               config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+               config.hdr.pkt_size = afe_sizeof_cfg_cmd(port_id);
+               config.hdr.src_port = 0;
+               config.hdr.dest_port = 0;
+               config.hdr.token = 0;
+               switch (port_id) {
+               case SLIMBUS_0_RX:
+               case SLIMBUS_0_TX:
+               case SLIMBUS_1_RX:
+               case SLIMBUS_1_TX:
+               case SLIMBUS_2_RX:
+               case SLIMBUS_2_TX:
+               case SLIMBUS_3_RX:
+               case SLIMBUS_3_TX:
+               case SLIMBUS_4_RX:
+               case SLIMBUS_4_TX:
+                       config.hdr.opcode = AFE_PORT_AUDIO_SLIM_SCH_CONFIG;
+               break;
+               case MI2S_TX:
+               case MI2S_RX:
+               case SECONDARY_I2S_RX:
+               case SECONDARY_I2S_TX:
+               case PRIMARY_I2S_RX:
+               case PRIMARY_I2S_TX:
+                       /* AFE_PORT_CMD_I2S_CONFIG command is not supported
+                        * in the LPASS EL 1.0. So we have to distiguish
+                        * which AFE command, AFE_PORT_CMD_I2S_CONFIG or
+                        * AFE_PORT_AUDIO_IF_CONFIG     to use. If the format
+                        * is L-PCM, the AFE_PORT_AUDIO_IF_CONFIG is used
+                        * to make the backward compatible.
+                        */
+                       pr_debug("%s: afe_config->mi2s.format = %d\n", __func__,
+                                        afe_config->mi2s.format);
+                       if (afe_config->mi2s.format == MSM_AFE_I2S_FORMAT_LPCM)
+                               config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
+                       else
+                               config.hdr.opcode = AFE_PORT_CMD_I2S_CONFIG;
+               break;
+               default:
+                       config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
+               break;
+               }
+       }
+
+       if (afe_validate_port(port_id) < 0) {
+
+               pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
+                               port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       config.port_id = port_id;
+       config.port = *afe_config;
+
+       atomic_set(&this_afe.state, 1);
+       atomic_set(&this_afe.status, 0);
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
+       if (ret < 0) {
+               pr_err("%s: AFE enable for port %d failed\n", __func__,
+                               port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       ret = wait_event_timeout(this_afe.wait,
+                       (atomic_read(&this_afe.state) == 0),
+                               msecs_to_jiffies(TIMEOUT_MS));
+
+       if (!ret) {
+               pr_err("%s: wait_event timeout IF CONFIG\n", __func__);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       if (atomic_read(&this_afe.status) != 0) {
+               pr_err("%s: config cmd failed\n", __func__);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       /* send AFE cal */
+       afe_send_cal(port_id);
+
+       start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       start.hdr.pkt_size = sizeof(start);
+       start.hdr.src_port = 0;
+       start.hdr.dest_port = 0;
+       start.hdr.token = 0;
+       start.hdr.opcode = AFE_PORT_CMD_START;
+       start.port_id = port_id;
+       start.gain = 0x2000;
+       start.sample_rate = rate;
+
+       atomic_set(&this_afe.state, 1);
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
+
+       if (IS_ERR_VALUE(ret)) {
+               pr_err("%s: AFE enable for port %d failed\n", __func__,
+                               port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       ret = wait_event_timeout(this_afe.wait,
+                       (atomic_read(&this_afe.state) == 0),
+                               msecs_to_jiffies(TIMEOUT_MS));
+       if (!ret) {
+               pr_err("%s: wait_event timeout PORT START\n", __func__);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       if (this_afe.task != current)
+               this_afe.task = current;
+
+       pr_debug("task_name = %s pid = %d\n",
+       this_afe.task->comm, this_afe.task->pid);
+       return 0;
+
+fail_cmd:
+       return ret;
+}
+
+/* This function should be used by 8660 exclusively */
+int afe_open(u16 port_id, union afe_port_config *afe_config, int rate)
+{
+       struct afe_port_start_command start;
+       struct afe_audioif_config_command config;
+       int ret = 0;
+
+       if (!afe_config) {
+               pr_err("%s: Error, no configuration data\n", __func__);
+               ret = -EINVAL;
+               return ret;
+       }
+
+       pr_debug("%s: %d %d\n", __func__, port_id, rate);
+
+       if ((port_id == RT_PROXY_DAI_001_RX) ||
+               (port_id == RT_PROXY_DAI_002_TX))
+               return 0;
+       if ((port_id == RT_PROXY_DAI_002_RX) ||
+               (port_id == RT_PROXY_DAI_001_TX))
+               port_id = VIRTUAL_ID_TO_PORTID(port_id);
+
+       ret = afe_q6_interface_prepare();
+       if (ret != 0)
+               return ret;
+
+       config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       config.hdr.pkt_size = afe_sizeof_cfg_cmd(port_id);
+       config.hdr.src_port = 0;
+       config.hdr.dest_port = 0;
+       config.hdr.token = 0;
+       switch (port_id) {
+       case SLIMBUS_0_RX:
+       case SLIMBUS_0_TX:
+       case SLIMBUS_1_RX:
+       case SLIMBUS_1_TX:
+       case SLIMBUS_2_RX:
+       case SLIMBUS_2_TX:
+       case SLIMBUS_3_RX:
+       case SLIMBUS_3_TX:
+       case SLIMBUS_4_RX:
+       case SLIMBUS_4_TX:
+               config.hdr.opcode = AFE_PORT_AUDIO_SLIM_SCH_CONFIG;
+       break;
+       case MI2S_TX:
+       case MI2S_RX:
+       case SECONDARY_I2S_RX:
+       case SECONDARY_I2S_TX:
+       case PRIMARY_I2S_RX:
+       case PRIMARY_I2S_TX:
+               /* AFE_PORT_CMD_I2S_CONFIG command is not supported
+                * in the LPASS EL 1.0. So we have to distiguish
+                * which AFE command, AFE_PORT_CMD_I2S_CONFIG or
+                * AFE_PORT_AUDIO_IF_CONFIG     to use. If the format
+                * is L-PCM, the AFE_PORT_AUDIO_IF_CONFIG is used
+                * to make the backward compatible.
+                */
+               pr_debug("%s: afe_config->mi2s.format = %d\n", __func__,
+                                afe_config->mi2s.format);
+               if (afe_config->mi2s.format == MSM_AFE_I2S_FORMAT_LPCM)
+                       config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
+               else
+                       config.hdr.opcode = AFE_PORT_CMD_I2S_CONFIG;
+       break;
+       default:
+               config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
+       break;
+       }
+
+       if (afe_validate_port(port_id) < 0) {
+
+               pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
+                               port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       config.port_id = port_id;
+       config.port = *afe_config;
+
+       atomic_set(&this_afe.state, 1);
+       atomic_set(&this_afe.status, 0);
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &config);
+       if (ret < 0) {
+               pr_err("%s: AFE enable for port %d failed\n", __func__,
+                               port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       ret = wait_event_timeout(this_afe.wait,
+                       (atomic_read(&this_afe.state) == 0),
+                               msecs_to_jiffies(TIMEOUT_MS));
+       if (!ret) {
+               pr_err("%s: wait_event timeout\n", __func__);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       if (atomic_read(&this_afe.status) != 0) {
+               pr_err("%s: config cmd failed\n", __func__);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       start.hdr.pkt_size = sizeof(start);
+       start.hdr.src_port = 0;
+       start.hdr.dest_port = 0;
+       start.hdr.token = 0;
+       start.hdr.opcode = AFE_PORT_CMD_START;
+       start.port_id = port_id;
+       start.gain = 0x2000;
+       start.sample_rate = rate;
+
+       atomic_set(&this_afe.state, 1);
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
+       if (ret < 0) {
+               pr_err("%s: AFE enable for port %d failed\n", __func__,
+                               port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       ret = wait_event_timeout(this_afe.wait,
+                       (atomic_read(&this_afe.state) == 0),
+                               msecs_to_jiffies(TIMEOUT_MS));
+       if (!ret) {
+               pr_err("%s: wait_event timeout\n", __func__);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       if (this_afe.task != current)
+               this_afe.task = current;
+
+       pr_debug("task_name = %s pid = %d\n",
+                       this_afe.task->comm, this_afe.task->pid);
+       return 0;
+fail_cmd:
+       return ret;
+}
+
+int afe_loopback(u16 enable, u16 dst_port, u16 src_port)
+{
+       struct afe_loopback_command lb_cmd;
+       int ret = 0;
+
+       ret = afe_q6_interface_prepare();
+       if (ret != 0)
+               return ret;
+
+       if ((afe_get_port_type(dst_port) == MSM_AFE_PORT_TYPE_RX) &&
+               (afe_get_port_type(src_port) == MSM_AFE_PORT_TYPE_RX))
+               return afe_loopback_cfg(enable, dst_port, src_port,
+                                       LB_MODE_EC_REF_VOICE_AUDIO);
+
+       lb_cmd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                                               APR_HDR_LEN(20), APR_PKT_VER);
+       lb_cmd.hdr.pkt_size = APR_PKT_SIZE(APR_HDR_SIZE,
+                                               sizeof(lb_cmd) - APR_HDR_SIZE);
+       lb_cmd.hdr.src_port = 0;
+       lb_cmd.hdr.dest_port = 0;
+       lb_cmd.hdr.token = 0;
+       lb_cmd.hdr.opcode = AFE_PORT_CMD_LOOPBACK;
+       lb_cmd.tx_port_id = src_port;
+       lb_cmd.rx_port_id = dst_port;
+       lb_cmd.mode = 0xFFFF;
+       lb_cmd.enable = (enable ? 1 : 0);
+       atomic_set(&this_afe.state, 1);
+
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lb_cmd);
+       if (ret < 0) {
+               pr_err("%s: AFE loopback failed\n", __func__);
+               ret = -EINVAL;
+               goto done;
+       }
+       ret = wait_event_timeout(this_afe.wait,
+               (atomic_read(&this_afe.state) == 0),
+                               msecs_to_jiffies(TIMEOUT_MS));
+       if (!ret) {
+               pr_err("%s: wait_event timeout\n", __func__);
+               ret = -EINVAL;
+       }
+done:
+       return ret;
+}
+
+int afe_loopback_cfg(u16 enable, u16 dst_port, u16 src_port, u16 mode)
+{
+       struct afe_port_cmd_set_param lp_cfg;
+       int ret = 0;
+
+       ret = afe_q6_interface_prepare();
+       if (ret != 0)
+               return ret;
+
+       pr_debug("%s: src_port %d, dst_port %d\n",
+                 __func__, src_port, dst_port);
+
+       lp_cfg.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       lp_cfg.hdr.pkt_size = sizeof(lp_cfg);
+       lp_cfg.hdr.src_port = 0;
+       lp_cfg.hdr.dest_port = 0;
+       lp_cfg.hdr.token = 0;
+       lp_cfg.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
+
+       lp_cfg.port_id = src_port;
+       lp_cfg.payload_size     = sizeof(struct afe_param_payload_base) +
+               sizeof(struct afe_param_loopback_cfg);
+       lp_cfg.payload_address  = 0;
+
+       lp_cfg.payload.base.module_id = AFE_MODULE_LOOPBACK;
+       lp_cfg.payload.base.param_id    = AFE_PARAM_ID_LOOPBACK_CONFIG;
+       lp_cfg.payload.base.param_size = sizeof(struct afe_param_loopback_cfg);
+       lp_cfg.payload.base.reserved    = 0;
+
+       lp_cfg.payload.param.loopback_cfg.loopback_cfg_minor_version =
+                       AFE_API_VERSION_LOOPBACK_CONFIG;
+       lp_cfg.payload.param.loopback_cfg.dst_port_id = dst_port;
+       lp_cfg.payload.param.loopback_cfg.routing_mode = mode;
+       lp_cfg.payload.param.loopback_cfg.enable = enable;
+       lp_cfg.payload.param.loopback_cfg.reserved = 0;
+
+       atomic_set(&this_afe.state, 1);
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &lp_cfg);
+       if (ret < 0) {
+               pr_err("%s: AFE loopback config failed for src_port %d, dst_port %d\n",
+                          __func__, src_port, dst_port);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       ret = wait_event_timeout(this_afe.wait,
+               (atomic_read(&this_afe.state) == 0),
+                       msecs_to_jiffies(TIMEOUT_MS));
+       if (ret < 0) {
+               pr_err("%s: wait_event timeout\n", __func__);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return ret;
+}
+
+int afe_loopback_gain(u16 port_id, u16 volume)
+{
+       struct afe_port_cmd_set_param set_param;
+       int ret = 0;
+
+       if (this_afe.apr == NULL) {
+               this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+                                       0xFFFFFFFF, &this_afe);
+               pr_debug("%s: Register AFE\n", __func__);
+               if (this_afe.apr == NULL) {
+                       pr_err("%s: Unable to register AFE\n", __func__);
+                       ret = -ENODEV;
+                       return ret;
+               }
+       }
+
+       if (afe_validate_port(port_id) < 0) {
+
+               pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
+                               port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       /* RX ports numbers are even .TX ports numbers are odd. */
+       if (port_id % 2 == 0) {
+               pr_err("%s: Failed : afe loopback gain only for TX ports."
+                       " port_id %d\n", __func__, port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       pr_debug("%s: %d %hX\n", __func__, port_id, volume);
+
+       set_param.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       set_param.hdr.pkt_size = sizeof(set_param);
+       set_param.hdr.src_port = 0;
+       set_param.hdr.dest_port = 0;
+       set_param.hdr.token = 0;
+       set_param.hdr.opcode = AFE_PORT_CMD_SET_PARAM;
+
+       set_param.port_id               = port_id;
+       set_param.payload_size  = sizeof(struct afe_param_payload_base) +
+                                 sizeof(struct afe_param_loopback_gain);
+       set_param.payload_address       = 0;
+
+       set_param.payload.base.module_id        = AFE_MODULE_ID_PORT_INFO;
+       set_param.payload.base.param_id = AFE_PARAM_ID_LOOPBACK_GAIN;
+       set_param.payload.base.param_size =
+               sizeof(struct afe_param_loopback_gain);
+       set_param.payload.base.reserved = 0;
+
+       set_param.payload.param.loopback_gain.gain              = volume;
+       set_param.payload.param.loopback_gain.reserved  = 0;
+
+       atomic_set(&this_afe.state, 1);
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_param);
+       if (ret < 0) {
+               pr_err("%s: AFE param set failed for port %d\n",
+                                       __func__, port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       ret = wait_event_timeout(this_afe.wait,
+               (atomic_read(&this_afe.state) == 0),
+                       msecs_to_jiffies(TIMEOUT_MS));
+       if (ret < 0) {
+               pr_err("%s: wait_event timeout\n", __func__);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return ret;
+}
+
+int afe_apply_gain(u16 port_id, u16 gain)
+{
+       struct afe_port_gain_command set_gain;
+       int ret = 0;
+
+       if (this_afe.apr == NULL) {
+               pr_err("%s: AFE is not opened\n", __func__);
+               ret = -EPERM;
+               goto fail_cmd;
+       }
+
+       if (afe_validate_port(port_id) < 0) {
+               pr_err("%s: Failed : Invalid Port id = %d\n", __func__,
+                               port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       /* RX ports numbers are even .TX ports numbers are odd. */
+       if (port_id % 2 == 0) {
+               pr_err("%s: Failed : afe apply gain only for TX ports."
+                       " port_id %d\n", __func__, port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       pr_debug("%s: %d %hX\n", __func__, port_id, gain);
+
+       set_gain.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       set_gain.hdr.pkt_size = sizeof(set_gain);
+       set_gain.hdr.src_port = 0;
+       set_gain.hdr.dest_port = 0;
+       set_gain.hdr.token = 0;
+       set_gain.hdr.opcode = AFE_PORT_CMD_APPLY_GAIN;
+
+       set_gain.port_id                = port_id;
+       set_gain.gain   = gain;
+
+       atomic_set(&this_afe.state, 1);
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &set_gain);
+       if (ret < 0) {
+               pr_err("%s: AFE Gain set failed for port %d\n",
+                                       __func__, port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       ret = wait_event_timeout(this_afe.wait,
+               (atomic_read(&this_afe.state) == 0),
+                       msecs_to_jiffies(TIMEOUT_MS));
+       if (ret < 0) {
+               pr_err("%s: wait_event timeout\n", __func__);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return ret;
+}
+
+int afe_pseudo_port_start_nowait(u16 port_id)
+{
+       int ret = 0;
+       struct afe_pseudoport_start_command start;
+
+       pr_debug("%s: port_id=%d\n", __func__, port_id);
+       if (this_afe.apr == NULL) {
+               pr_err("%s: AFE APR is not registered\n", __func__);
+               return -ENODEV;
+       }
+
+
+       start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       start.hdr.pkt_size = sizeof(start);
+       start.hdr.src_port = 0;
+       start.hdr.dest_port = 0;
+       start.hdr.token = 0;
+       start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
+       start.port_id = port_id;
+       start.timing = 1;
+
+       atomic_set(&this_afe.state, 1);
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
+       if (ret < 0) {
+               pr_err("%s: AFE enable for port %d failed %d\n",
+                      __func__, port_id, ret);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+int afe_start_pseudo_port(u16 port_id)
+{
+       int ret = 0;
+       struct afe_pseudoport_start_command start;
+
+       pr_debug("%s: port_id=%d\n", __func__, port_id);
+
+       ret = afe_q6_interface_prepare();
+       if (ret != 0)
+               return ret;
+
+       start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       start.hdr.pkt_size = sizeof(start);
+       start.hdr.src_port = 0;
+       start.hdr.dest_port = 0;
+       start.hdr.token = 0;
+       start.hdr.opcode = AFE_PSEUDOPORT_CMD_START;
+       start.port_id = port_id;
+       start.timing = 1;
+
+       atomic_set(&this_afe.state, 1);
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &start);
+       if (ret < 0) {
+               pr_err("%s: AFE enable for port %d failed %d\n",
+                      __func__, port_id, ret);
+               return -EINVAL;
+       }
+
+       ret = wait_event_timeout(this_afe.wait,
+                                (atomic_read(&this_afe.state) == 0),
+                                msecs_to_jiffies(TIMEOUT_MS));
+       if (!ret) {
+               pr_err("%s: wait_event timeout\n", __func__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int afe_pseudo_port_stop_nowait(u16 port_id)
+{
+       int ret = 0;
+       struct afe_pseudoport_stop_command stop;
+
+       pr_debug("%s: port_id=%d\n", __func__, port_id);
+
+       if (this_afe.apr == NULL) {
+               pr_err("%s: AFE is already closed\n", __func__);
+               return -EINVAL;
+       }
+
+       stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       stop.hdr.pkt_size = sizeof(stop);
+       stop.hdr.src_port = 0;
+       stop.hdr.dest_port = 0;
+       stop.hdr.token = 0;
+       stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
+       stop.port_id = port_id;
+       stop.reserved = 0;
+
+       atomic_set(&this_afe.state, 1);
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+       if (ret < 0) {
+               pr_err("%s: AFE close failed %d\n", __func__, ret);
+               return -EINVAL;
+       }
+
+       return 0;
+
+}
+
+int afe_stop_pseudo_port(u16 port_id)
+{
+       int ret = 0;
+       struct afe_pseudoport_stop_command stop;
+
+       pr_debug("%s: port_id=%d\n", __func__, port_id);
+
+       if (this_afe.apr == NULL) {
+               pr_err("%s: AFE is already closed\n", __func__);
+               return -EINVAL;
+       }
+
+       stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       stop.hdr.pkt_size = sizeof(stop);
+       stop.hdr.src_port = 0;
+       stop.hdr.dest_port = 0;
+       stop.hdr.token = 0;
+       stop.hdr.opcode = AFE_PSEUDOPORT_CMD_STOP;
+       stop.port_id = port_id;
+       stop.reserved = 0;
+
+       atomic_set(&this_afe.state, 1);
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+       if (ret < 0) {
+               pr_err("%s: AFE close failed %d\n", __func__, ret);
+               return -EINVAL;
+       }
+
+       ret = wait_event_timeout(this_afe.wait,
+                                (atomic_read(&this_afe.state) == 0),
+                                msecs_to_jiffies(TIMEOUT_MS));
+       if (!ret) {
+               pr_err("%s: wait_event timeout\n", __func__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int afe_cmd_memory_map(u32 dma_addr_p, u32 dma_buf_sz)
+{
+       int ret = 0;
+       struct afe_cmd_memory_map mregion;
+
+       pr_debug("%s:\n", __func__);
+
+       if (this_afe.apr == NULL) {
+               this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+                                       0xFFFFFFFF, &this_afe);
+               pr_debug("%s: Register AFE\n", __func__);
+               if (this_afe.apr == NULL) {
+                       pr_err("%s: Unable to register AFE\n", __func__);
+                       ret = -ENODEV;
+                       return ret;
+               }
+       }
+
+       mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       mregion.hdr.pkt_size = sizeof(mregion);
+       mregion.hdr.src_port = 0;
+       mregion.hdr.dest_port = 0;
+       mregion.hdr.token = 0;
+       mregion.hdr.opcode = AFE_SERVICE_CMD_MEMORY_MAP;
+       mregion.phy_addr = dma_addr_p;
+       mregion.mem_sz = dma_buf_sz;
+       mregion.mem_id = 0;
+       mregion.rsvd = 0;
+
+       atomic_set(&this_afe.state, 1);
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
+       if (ret < 0) {
+               pr_err("%s: AFE memory map cmd failed %d\n",
+                      __func__, ret);
+               ret = -EINVAL;
+               return ret;
+       }
+
+       ret = wait_event_timeout(this_afe.wait,
+                                (atomic_read(&this_afe.state) == 0),
+                                msecs_to_jiffies(TIMEOUT_MS));
+       if (!ret) {
+               pr_err("%s: wait_event timeout\n", __func__);
+               ret = -EINVAL;
+               return ret;
+       }
+
+       return 0;
+}
+
+int afe_cmd_memory_map_nowait(u32 dma_addr_p, u32 dma_buf_sz)
+{
+       int ret = 0;
+       struct afe_cmd_memory_map mregion;
+
+       pr_debug("%s:\n", __func__);
+
+       if (this_afe.apr == NULL) {
+               this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+                                       0xFFFFFFFF, &this_afe);
+               pr_debug("%s: Register AFE\n", __func__);
+               if (this_afe.apr == NULL) {
+                       pr_err("%s: Unable to register AFE\n", __func__);
+                       ret = -ENODEV;
+                       return ret;
+               }
+       }
+
+       mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       mregion.hdr.pkt_size = sizeof(mregion);
+       mregion.hdr.src_port = 0;
+       mregion.hdr.dest_port = 0;
+       mregion.hdr.token = 0;
+       mregion.hdr.opcode = AFE_SERVICE_CMD_MEMORY_MAP;
+       mregion.phy_addr = dma_addr_p;
+       mregion.mem_sz = dma_buf_sz;
+       mregion.mem_id = 0;
+       mregion.rsvd = 0;
+
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
+       if (ret < 0) {
+               pr_err("%s: AFE memory map cmd failed %d\n",
+                       __func__, ret);
+               ret = -EINVAL;
+       }
+       return 0;
+}
+
+int afe_cmd_memory_unmap(u32 dma_addr_p)
+{
+       int ret = 0;
+       struct afe_cmd_memory_unmap mregion;
+
+       pr_debug("%s:\n", __func__);
+
+       if (this_afe.apr == NULL) {
+               this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+                                       0xFFFFFFFF, &this_afe);
+               pr_debug("%s: Register AFE\n", __func__);
+               if (this_afe.apr == NULL) {
+                       pr_err("%s: Unable to register AFE\n", __func__);
+                       ret = -ENODEV;
+                       return ret;
+               }
+       }
+
+       mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       mregion.hdr.pkt_size = sizeof(mregion);
+       mregion.hdr.src_port = 0;
+       mregion.hdr.dest_port = 0;
+       mregion.hdr.token = 0;
+       mregion.hdr.opcode = AFE_SERVICE_CMD_MEMORY_UNMAP;
+       mregion.phy_addr = dma_addr_p;
+
+       atomic_set(&this_afe.state, 1);
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
+       if (ret < 0) {
+               pr_err("%s: AFE memory unmap cmd failed %d\n",
+                      __func__, ret);
+               ret = -EINVAL;
+               return ret;
+       }
+
+       ret = wait_event_timeout(this_afe.wait,
+                                (atomic_read(&this_afe.state) == 0),
+                                msecs_to_jiffies(TIMEOUT_MS));
+       if (!ret) {
+               pr_err("%s: wait_event timeout\n", __func__);
+               ret = -EINVAL;
+               return ret;
+       }
+       return 0;
+}
+
+int afe_cmd_memory_unmap_nowait(u32 dma_addr_p)
+{
+       int ret = 0;
+       struct afe_cmd_memory_unmap mregion;
+
+       pr_debug("%s:\n", __func__);
+
+       if (this_afe.apr == NULL) {
+               this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+                                       0xFFFFFFFF, &this_afe);
+               pr_debug("%s: Register AFE\n", __func__);
+               if (this_afe.apr == NULL) {
+                       pr_err("%s: Unable to register AFE\n", __func__);
+                       ret = -ENODEV;
+                       return ret;
+               }
+       }
+
+       mregion.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       mregion.hdr.pkt_size = sizeof(mregion);
+       mregion.hdr.src_port = 0;
+       mregion.hdr.dest_port = 0;
+       mregion.hdr.token = 0;
+       mregion.hdr.opcode = AFE_SERVICE_CMD_MEMORY_UNMAP;
+       mregion.phy_addr = dma_addr_p;
+
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &mregion);
+       if (ret < 0) {
+               pr_err("%s: AFE memory unmap cmd failed %d\n",
+                       __func__, ret);
+               ret = -EINVAL;
+       }
+       return 0;
+}
+
+int afe_register_get_events(u16 port_id,
+               void (*cb) (uint32_t opcode,
+               uint32_t token, uint32_t *payload, void *priv),
+               void *private_data)
+{
+       int ret = 0;
+       struct afe_cmd_reg_rtport rtproxy;
+
+       pr_debug("%s:\n", __func__);
+
+       if (this_afe.apr == NULL) {
+               this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+                                       0xFFFFFFFF, &this_afe);
+               pr_debug("%s: Register AFE\n", __func__);
+               if (this_afe.apr == NULL) {
+                       pr_err("%s: Unable to register AFE\n", __func__);
+                       ret = -ENODEV;
+                       return ret;
+               }
+       }
+       if ((port_id == RT_PROXY_DAI_002_RX) ||
+               (port_id == RT_PROXY_DAI_001_TX))
+               port_id = VIRTUAL_ID_TO_PORTID(port_id);
+       else
+               return -EINVAL;
+
+       if (port_id == RT_PROXY_PORT_001_TX) {
+               this_afe.tx_cb = cb;
+               this_afe.tx_private_data = private_data;
+       } else if (port_id == RT_PROXY_PORT_001_RX) {
+               this_afe.rx_cb = cb;
+               this_afe.rx_private_data = private_data;
+       }
+
+       rtproxy.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       rtproxy.hdr.pkt_size = sizeof(rtproxy);
+       rtproxy.hdr.src_port = 1;
+       rtproxy.hdr.dest_port = 1;
+       rtproxy.hdr.token = 0;
+       rtproxy.hdr.opcode = AFE_SERVICE_CMD_REG_RTPORT;
+       rtproxy.port_id = port_id;
+       rtproxy.rsvd = 0;
+
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
+       if (ret < 0) {
+               pr_err("%s: AFE  reg. rtproxy_event failed %d\n",
+                          __func__, ret);
+               ret = -EINVAL;
+               return ret;
+       }
+       return 0;
+}
+
+int afe_unregister_get_events(u16 port_id)
+{
+       int ret = 0;
+       struct afe_cmd_unreg_rtport rtproxy;
+
+       pr_debug("%s:\n", __func__);
+
+       if (this_afe.apr == NULL) {
+               this_afe.apr = apr_register("ADSP", "AFE", afe_callback,
+                                       0xFFFFFFFF, &this_afe);
+               pr_debug("%s: Register AFE\n", __func__);
+               if (this_afe.apr == NULL) {
+                       pr_err("%s: Unable to register AFE\n", __func__);
+                       ret = -ENODEV;
+                       return ret;
+               }
+       }
+       if ((port_id == RT_PROXY_DAI_002_RX) ||
+               (port_id == RT_PROXY_DAI_001_TX))
+               port_id = VIRTUAL_ID_TO_PORTID(port_id);
+       else
+               return -EINVAL;
+
+       rtproxy.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       rtproxy.hdr.pkt_size = sizeof(rtproxy);
+       rtproxy.hdr.src_port = 0;
+       rtproxy.hdr.dest_port = 0;
+       rtproxy.hdr.token = 0;
+       rtproxy.hdr.opcode = AFE_SERVICE_CMD_UNREG_RTPORT;
+       rtproxy.port_id = port_id;
+       rtproxy.rsvd = 0;
+
+       if (port_id == RT_PROXY_PORT_001_TX) {
+               this_afe.tx_cb = NULL;
+               this_afe.tx_private_data = NULL;
+       } else if (port_id == RT_PROXY_PORT_001_RX) {
+               this_afe.rx_cb = NULL;
+               this_afe.rx_private_data = NULL;
+       }
+
+       atomic_set(&this_afe.state, 1);
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &rtproxy);
+       if (ret < 0) {
+               pr_err("%s: AFE enable Unreg. rtproxy_event failed %d\n",
+                          __func__, ret);
+               ret = -EINVAL;
+               return ret;
+       }
+
+       ret = wait_event_timeout(this_afe.wait,
+                                (atomic_read(&this_afe.state) == 0),
+                                msecs_to_jiffies(TIMEOUT_MS));
+       if (!ret) {
+               pr_err("%s: wait_event timeout\n", __func__);
+               ret = -EINVAL;
+               return ret;
+       }
+       return 0;
+}
+
+int afe_rt_proxy_port_write(u32 buf_addr_p, int bytes)
+{
+       int ret = 0;
+       struct afe_cmd_rtport_wr afecmd_wr;
+
+       if (this_afe.apr == NULL) {
+               pr_err("%s:register to AFE is not done\n", __func__);
+               ret = -ENODEV;
+               return ret;
+       }
+       pr_debug("%s: buf_addr_p = 0x%08x bytes = %d\n", __func__,
+                                               buf_addr_p, bytes);
+
+       afecmd_wr.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       afecmd_wr.hdr.pkt_size = sizeof(afecmd_wr);
+       afecmd_wr.hdr.src_port = 0;
+       afecmd_wr.hdr.dest_port = 0;
+       afecmd_wr.hdr.token = 0;
+       afecmd_wr.hdr.opcode = AFE_SERVICE_CMD_RTPORT_WR;
+       afecmd_wr.buf_addr = (uint32_t)buf_addr_p;
+       afecmd_wr.port_id = RT_PROXY_PORT_001_TX;
+       afecmd_wr.bytes_avail = bytes;
+       afecmd_wr.rsvd = 0;
+
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_wr);
+       if (ret < 0) {
+               pr_err("%s: AFE rtproxy write to port 0x%x failed %d\n",
+                          __func__, afecmd_wr.port_id, ret);
+               ret = -EINVAL;
+               return ret;
+       }
+       return 0;
+
+}
+
+int afe_rt_proxy_port_read(u32 buf_addr_p, int bytes)
+{
+       int ret = 0;
+       struct afe_cmd_rtport_rd afecmd_rd;
+
+       if (this_afe.apr == NULL) {
+               pr_err("%s: register to AFE is not done\n", __func__);
+               ret = -ENODEV;
+               return ret;
+       }
+       pr_debug("%s: buf_addr_p = 0x%08x bytes = %d\n", __func__,
+                                               buf_addr_p, bytes);
+
+       afecmd_rd.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       afecmd_rd.hdr.pkt_size = sizeof(afecmd_rd);
+       afecmd_rd.hdr.src_port = 0;
+       afecmd_rd.hdr.dest_port = 0;
+       afecmd_rd.hdr.token = 0;
+       afecmd_rd.hdr.opcode = AFE_SERVICE_CMD_RTPORT_RD;
+       afecmd_rd.buf_addr = (uint32_t)buf_addr_p;
+       afecmd_rd.port_id = RT_PROXY_PORT_001_RX;
+       afecmd_rd.bytes_avail = bytes;
+       afecmd_rd.rsvd = 0;
+
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &afecmd_rd);
+       if (ret < 0) {
+               pr_err("%s: AFE rtproxy read  cmd to port 0x%x failed %d\n",
+                          __func__, afecmd_rd.port_id, ret);
+               ret = -EINVAL;
+               return ret;
+       }
+       return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static struct dentry *debugfs_afelb;
+static struct dentry *debugfs_afelb_gain;
+
+static int afe_debug_open(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       pr_info("debug intf %s\n", (char *) file->private_data);
+       return 0;
+}
+
+static int afe_get_parameters(char *buf, long int *param1, int num_of_par)
+{
+       char *token;
+       int base, cnt;
+
+       token = strsep(&buf, " ");
+
+       for (cnt = 0; cnt < num_of_par; cnt++) {
+               if (token != NULL) {
+                       if ((token[1] == 'x') || (token[1] == 'X'))
+                               base = 16;
+                       else
+                               base = 10;
+
+                       if (kstrtoul(token, base, &param1[cnt]) != 0)
+                               return -EINVAL;
+
+                       token = strsep(&buf, " ");
+               } else
+                       return -EINVAL;
+       }
+       return 0;
+}
+#define AFE_LOOPBACK_ON (1)
+#define AFE_LOOPBACK_OFF (0)
+static ssize_t afe_debug_write(struct file *filp,
+       const char __user *ubuf, size_t cnt, loff_t *ppos)
+{
+       char *lb_str = filp->private_data;
+       char lbuf[32];
+       int rc;
+       unsigned long param[5];
+
+       if (cnt > sizeof(lbuf) - 1)
+               return -EINVAL;
+
+       rc = copy_from_user(lbuf, ubuf, cnt);
+       if (rc)
+               return -EFAULT;
+
+       lbuf[cnt] = '\0';
+
+       if (!strcmp(lb_str, "afe_loopback")) {
+               rc = afe_get_parameters(lbuf, param, 3);
+               if (!rc) {
+                       pr_info("%s %lu %lu %lu\n", lb_str, param[0], param[1],
+                               param[2]);
+
+                       if ((param[0] != AFE_LOOPBACK_ON) && (param[0] !=
+                               AFE_LOOPBACK_OFF)) {
+                               pr_err("%s: Error, parameter 0 incorrect\n",
+                                       __func__);
+                               rc = -EINVAL;
+                               goto afe_error;
+                       }
+                       if ((afe_validate_port(param[1]) < 0) ||
+                           (afe_validate_port(param[2])) < 0) {
+                               pr_err("%s: Error, invalid afe port\n",
+                                       __func__);
+                       }
+                       if (this_afe.apr == NULL) {
+                               pr_err("%s: Error, AFE not opened\n", __func__);
+                               rc = -EINVAL;
+                       } else {
+                               rc = afe_loopback(param[0], param[1], param[2]);
+                       }
+               } else {
+                       pr_err("%s: Error, invalid parameters\n", __func__);
+                       rc = -EINVAL;
+               }
+
+       } else if (!strcmp(lb_str, "afe_loopback_gain")) {
+               rc = afe_get_parameters(lbuf, param, 2);
+               if (!rc) {
+                       pr_info("%s %lu %lu\n", lb_str, param[0], param[1]);
+
+                       if (afe_validate_port(param[0]) < 0) {
+                               pr_err("%s: Error, invalid afe port\n",
+                                       __func__);
+                               rc = -EINVAL;
+                               goto afe_error;
+                       }
+
+                       if (param[1] > 100) {
+                               pr_err("%s: Error, volume shoud be 0 to 100"
+                                       " percentage param = %lu\n",
+                                       __func__, param[1]);
+                               rc = -EINVAL;
+                               goto afe_error;
+                       }
+
+                       param[1] = (Q6AFE_MAX_VOLUME * param[1]) / 100;
+
+                       if (this_afe.apr == NULL) {
+                               pr_err("%s: Error, AFE not opened\n", __func__);
+                               rc = -EINVAL;
+                       } else {
+                               rc = afe_loopback_gain(param[0], param[1]);
+                       }
+               } else {
+                       pr_err("%s: Error, invalid parameters\n", __func__);
+                       rc = -EINVAL;
+               }
+       }
+
+afe_error:
+       if (rc == 0)
+               rc = cnt;
+       else
+               pr_err("%s: rc = %d\n", __func__, rc);
+
+       return rc;
+}
+
+static const struct file_operations afe_debug_fops = {
+       .open = afe_debug_open,
+       .write = afe_debug_write
+};
+#endif
+int afe_sidetone(u16 tx_port_id, u16 rx_port_id, u16 enable, uint16_t gain)
+{
+       struct afe_port_sidetone_command cmd_sidetone;
+       int ret = 0;
+
+       pr_info("%s: tx_port_id:%d rx_port_id:%d enable:%d gain:%d\n", __func__,
+                                       tx_port_id, rx_port_id, enable, gain);
+       cmd_sidetone.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       cmd_sidetone.hdr.pkt_size = sizeof(cmd_sidetone);
+       cmd_sidetone.hdr.src_port = 0;
+       cmd_sidetone.hdr.dest_port = 0;
+       cmd_sidetone.hdr.token = 0;
+       cmd_sidetone.hdr.opcode = AFE_PORT_CMD_SIDETONE_CTL;
+       cmd_sidetone.tx_port_id = tx_port_id;
+       cmd_sidetone.rx_port_id = rx_port_id;
+       cmd_sidetone.gain = gain;
+       cmd_sidetone.enable = enable;
+
+       atomic_set(&this_afe.state, 1);
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &cmd_sidetone);
+       if (ret < 0) {
+               pr_err("%s: AFE sidetone failed for tx_port:%d rx_port:%d\n",
+                                       __func__, tx_port_id, rx_port_id);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       ret = wait_event_timeout(this_afe.wait,
+               (atomic_read(&this_afe.state) == 0),
+                       msecs_to_jiffies(TIMEOUT_MS));
+       if (ret < 0) {
+               pr_err("%s: wait_event timeout\n", __func__);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return ret;
+}
+
+int afe_port_stop_nowait(int port_id)
+{
+       struct afe_port_stop_command stop;
+       int ret = 0;
+
+       if (this_afe.apr == NULL) {
+               pr_err("AFE is already closed\n");
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       pr_debug("%s: port_id=%d\n", __func__, port_id);
+       port_id = afe_convert_virtual_to_portid(port_id);
+
+       stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       stop.hdr.pkt_size = sizeof(stop);
+       stop.hdr.src_port = 0;
+       stop.hdr.dest_port = 0;
+       stop.hdr.token = 0;
+       stop.hdr.opcode = AFE_PORT_CMD_STOP;
+       stop.port_id = port_id;
+       stop.reserved = 0;
+
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+
+       if (ret == -ENETRESET) {
+               pr_info("%s: Need to reset, calling APR deregister", __func__);
+               return apr_deregister(this_afe.apr);
+       } else if (IS_ERR_VALUE(ret)) {
+               pr_err("%s: AFE close failed\n", __func__);
+               ret = -EINVAL;
+       }
+
+fail_cmd:
+       return ret;
+
+}
+
+int afe_close(int port_id)
+{
+       struct afe_port_stop_command stop;
+       int ret = 0;
+
+       if (this_afe.apr == NULL) {
+               pr_err("AFE is already closed\n");
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+       pr_debug("%s: port_id=%d\n", __func__, port_id);
+
+       if ((port_id == RT_PROXY_DAI_001_RX) ||
+               (port_id == RT_PROXY_DAI_002_TX)) {
+               pr_debug("%s: before decrementing pcm_afe_instance %d\n",
+                               __func__, pcm_afe_instance[port_id & 0x1]);
+               port_id = VIRTUAL_ID_TO_PORTID(port_id);
+               pcm_afe_instance[port_id & 0x1]--;
+               if (!(pcm_afe_instance[port_id & 0x1] == 0 &&
+                       proxy_afe_instance[port_id & 0x1] == 0))
+                       return 0;
+               else
+                       afe_close_done[port_id & 0x1] = true;
+       }
+
+       if ((port_id == RT_PROXY_DAI_002_RX) ||
+               (port_id == RT_PROXY_DAI_001_TX)) {
+               pr_debug("%s: before decrementing proxy_afe_instance %d\n",
+                               __func__, proxy_afe_instance[port_id & 0x1]);
+               port_id = VIRTUAL_ID_TO_PORTID(port_id);
+               proxy_afe_instance[port_id & 0x1]--;
+               if (!(pcm_afe_instance[port_id & 0x1] == 0 &&
+                       proxy_afe_instance[port_id & 0x1] == 0))
+                       return 0;
+               else
+                       afe_close_done[port_id & 0x1] = true;
+       }
+
+       port_id = afe_convert_virtual_to_portid(port_id);
+
+       stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD,
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       stop.hdr.pkt_size = sizeof(stop);
+       stop.hdr.src_port = 0;
+       stop.hdr.dest_port = 0;
+       stop.hdr.token = 0;
+       stop.hdr.opcode = AFE_PORT_CMD_STOP;
+       stop.port_id = port_id;
+       stop.reserved = 0;
+
+       atomic_set(&this_afe.state, 1);
+       ret = apr_send_pkt(this_afe.apr, (uint32_t *) &stop);
+
+       if (ret == -ENETRESET) {
+               pr_info("%s: Need to reset, calling APR deregister", __func__);
+               return apr_deregister(this_afe.apr);
+       }
+
+       if (ret < 0) {
+               pr_err("%s: AFE close failed\n", __func__);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+
+       ret = wait_event_timeout(this_afe.wait,
+                       (atomic_read(&this_afe.state) == 0),
+                                       msecs_to_jiffies(TIMEOUT_MS));
+       if (!ret) {
+               pr_err("%s: wait_event timeout\n", __func__);
+               ret = -EINVAL;
+               goto fail_cmd;
+       }
+fail_cmd:
+       return ret;
+}
+
+static int __init afe_init(void)
+{
+       init_waitqueue_head(&this_afe.wait);
+       atomic_set(&this_afe.state, 0);
+       atomic_set(&this_afe.status, 0);
+       this_afe.apr = NULL;
+#ifdef CONFIG_DEBUG_FS
+       debugfs_afelb = debugfs_create_file("afe_loopback",
+       0220, NULL, (void *) "afe_loopback",
+       &afe_debug_fops);
+
+       debugfs_afelb_gain = debugfs_create_file("afe_loopback_gain",
+       0220, NULL, (void *) "afe_loopback_gain",
+       &afe_debug_fops);
+
+
+#endif
+       return 0;
+}
+
+static void __exit afe_exit(void)
+{
+       int i;
+#ifdef CONFIG_DEBUG_FS
+       if (debugfs_afelb)
+               debugfs_remove(debugfs_afelb);
+       if (debugfs_afelb_gain)
+               debugfs_remove(debugfs_afelb_gain);
+#endif
+       for (i = 0; i < MAX_AUDPROC_TYPES; i++) {
+               if (afe_cal_addr[i].cal_paddr != 0)
+                       afe_cmd_memory_unmap_nowait(
+                               afe_cal_addr[i].cal_paddr);
+       }
+}
+
+device_initcall(afe_init);
+__exitcall(afe_exit);
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
new file mode 100644 (file)
index 0000000..7fc06ae
--- /dev/null
@@ -0,0 +1,3841 @@
+/*
+ * Copyright (c) 2010-2013, The Linux Foundation. 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/kernel.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/miscdevice.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+#include <linux/dma-mapping.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/msm_audio.h>
+#include <linux/debugfs.h>
+#include <linux/time.h>
+#include <linux/atomic.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/ioctls.h>
+
+#include <sound/qdsp6v2/audio_acdb.h>
+#include <sound/qdsp6v2/rtac.h>
+
+#include <sound/apr_audio.h>
+#include <sound/q6asm.h>
+
+
+#define TRUE        0x01
+#define FALSE       0x00
+#define READDONE_IDX_STATUS 0
+#define READDONE_IDX_BUFFER 1
+#define READDONE_IDX_SIZE 2
+#define READDONE_IDX_OFFSET 3
+#define READDONE_IDX_MSW_TS 4
+#define READDONE_IDX_LSW_TS 5
+#define READDONE_IDX_FLAGS 6
+#define READDONE_IDX_NUMFRAMES 7
+#define READDONE_IDX_ID 8
+#ifdef CONFIG_DEBUG_FS
+#define OUT_BUFFER_SIZE 56
+#define IN_BUFFER_SIZE 24
+#endif
+static DEFINE_MUTEX(session_lock);
+
+/* session id: 0 reserved */
+static struct audio_client *session[SESSION_MAX+1];
+static int32_t q6asm_mmapcallback(struct apr_client_data *data, void *priv);
+static int32_t q6asm_callback(struct apr_client_data *data, void *priv);
+static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+                       uint32_t pkt_size, uint32_t cmd_flg);
+static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+                       uint32_t pkt_size, uint32_t cmd_flg);
+static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
+                               uint32_t bufsz, uint32_t bufcnt);
+static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir,
+                               uint32_t bufsz, uint32_t bufcnt);
+
+static void q6asm_reset_buf_state(struct audio_client *ac);
+
+#ifdef CONFIG_DEBUG_FS
+static struct timeval out_cold_tv;
+static struct timeval out_warm_tv;
+static struct timeval out_cont_tv;
+static struct timeval in_cont_tv;
+static long out_enable_flag;
+static long in_enable_flag;
+static struct dentry *out_dentry;
+static struct dentry *in_dentry;
+static int in_cont_index;
+/*This var is used to keep track of first write done for cold output latency */
+static int out_cold_index;
+static char *out_buffer;
+static char *in_buffer;
+static int audio_output_latency_dbgfs_open(struct inode *inode,
+                                                       struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+static ssize_t audio_output_latency_dbgfs_read(struct file *file,
+                               char __user *buf, size_t count, loff_t *ppos)
+{
+       snprintf(out_buffer, OUT_BUFFER_SIZE, "%ld,%ld,%ld,%ld,%ld,%ld,",\
+               out_cold_tv.tv_sec, out_cold_tv.tv_usec, out_warm_tv.tv_sec,\
+               out_warm_tv.tv_usec, out_cont_tv.tv_sec, out_cont_tv.tv_usec);
+       return  simple_read_from_buffer(buf, OUT_BUFFER_SIZE, ppos,
+                                               out_buffer, OUT_BUFFER_SIZE);
+}
+static ssize_t audio_output_latency_dbgfs_write(struct file *file,
+                       const char __user *buf, size_t count, loff_t *ppos)
+{
+       char *temp;
+
+       if (count > 2*sizeof(char))
+               return -EINVAL;
+       else
+               temp  = kmalloc(2*sizeof(char), GFP_KERNEL);
+
+       out_cold_index = 0;
+
+       if (temp) {
+               if (copy_from_user(temp, buf, 2*sizeof(char))) {
+                       kfree(temp);
+                       return -EFAULT;
+               }
+               if (!kstrtol(temp, 10, &out_enable_flag)) {
+                       kfree(temp);
+                       return count;
+               }
+               kfree(temp);
+       }
+       return -EINVAL;
+}
+static const struct file_operations audio_output_latency_debug_fops = {
+       .open = audio_output_latency_dbgfs_open,
+       .read = audio_output_latency_dbgfs_read,
+       .write = audio_output_latency_dbgfs_write
+};
+
+static int audio_input_latency_dbgfs_open(struct inode *inode,
+                                                       struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+static ssize_t audio_input_latency_dbgfs_read(struct file *file,
+                               char __user *buf, size_t count, loff_t *ppos)
+{
+       snprintf(in_buffer, IN_BUFFER_SIZE, "%ld,%ld,",\
+                               in_cont_tv.tv_sec, in_cont_tv.tv_usec);
+       return  simple_read_from_buffer(buf, IN_BUFFER_SIZE, ppos,
+                                               in_buffer, IN_BUFFER_SIZE);
+}
+static ssize_t audio_input_latency_dbgfs_write(struct file *file,
+                       const char __user *buf, size_t count, loff_t *ppos)
+{
+       char *temp;
+
+       if (count > 2*sizeof(char))
+               return -EINVAL;
+       else
+               temp  = kmalloc(2*sizeof(char), GFP_KERNEL);
+       if (temp) {
+               if (copy_from_user(temp, buf, 2*sizeof(char))) {
+                       kfree(temp);
+                       return -EFAULT;
+               }
+               if (!kstrtol(temp, 10, &in_enable_flag)) {
+                       kfree(temp);
+                       return count;
+               }
+               kfree(temp);
+       }
+       return -EINVAL;
+}
+static const struct file_operations audio_input_latency_debug_fops = {
+       .open = audio_input_latency_dbgfs_open,
+       .read = audio_input_latency_dbgfs_read,
+       .write = audio_input_latency_dbgfs_write
+};
+#endif
+struct asm_mmap {
+       atomic_t ref_cnt;
+       atomic_t cmd_state;
+       wait_queue_head_t cmd_wait;
+       void *apr;
+};
+
+static struct asm_mmap this_mmap;
+
+static int q6asm_session_alloc(struct audio_client *ac)
+{
+       int n;
+       mutex_lock(&session_lock);
+       for (n = 1; n <= SESSION_MAX; n++) {
+               if (!session[n]) {
+                       session[n] = ac;
+                       mutex_unlock(&session_lock);
+                       return n;
+               }
+       }
+       mutex_unlock(&session_lock);
+       return -ENOMEM;
+}
+
+static void q6asm_session_free(struct audio_client *ac)
+{
+       pr_debug("%s: sessionid[%d]\n", __func__, ac->session);
+       rtac_remove_popp_from_adm_devices(ac->session);
+       mutex_lock(&session_lock);
+       session[ac->session] = 0;
+       mutex_unlock(&session_lock);
+       ac->session = 0;
+       ac->perf_mode = false;
+       return;
+}
+
+int q6asm_audio_client_buf_free(unsigned int dir,
+                       struct audio_client *ac)
+{
+       struct audio_port_data *port;
+       int cnt = 0;
+       int rc = 0;
+       pr_debug("%s: Session id %d\n", __func__, ac->session);
+       mutex_lock(&ac->cmd_lock);
+       if (ac->io_mode & SYNC_IO_MODE) {
+               port = &ac->port[dir];
+               if (!port->buf) {
+                       mutex_unlock(&ac->cmd_lock);
+                       return 0;
+               }
+               cnt = port->max_buf_cnt - 1;
+
+               if (cnt >= 0) {
+                       rc = q6asm_memory_unmap_regions(ac, dir,
+                                                       port->buf[0].size,
+                                                       port->max_buf_cnt);
+                       if (rc < 0)
+                               pr_err("%s CMD Memory_unmap_regions failed\n",
+                                                               __func__);
+               }
+
+               while (cnt >= 0) {
+                       if (port->buf[cnt].data) {
+                               pr_debug("%s:data[%p]phys[%p][%p] cnt[%d] mem_buffer[%p]\n",
+                                       __func__, (void *)port->buf[cnt].data,
+                                       (void *)port->buf[cnt].phys,
+                                       (void *)&port->buf[cnt].phys, cnt,
+                                       (void *)port->buf[cnt].mem_buffer);
+                               
+                       dma_free_writecombine(NULL, port->buf[cnt].size, port->buf[cnt].data, port->buf[cnt].phys);
+
+                               port->buf[cnt].data = NULL;
+                               port->buf[cnt].phys = 0;
+                               --(port->max_buf_cnt);
+                       }
+                       --cnt;
+               }
+               kfree(port->buf);
+               port->buf = NULL;
+       }
+       mutex_unlock(&ac->cmd_lock);
+       return 0;
+}
+
+int q6asm_audio_client_buf_free_contiguous(unsigned int dir,
+                       struct audio_client *ac)
+{
+       struct audio_port_data *port;
+       int cnt = 0;
+       int rc = 0;
+       pr_debug("%s: Session id %d\n", __func__, ac->session);
+       mutex_lock(&ac->cmd_lock);
+       port = &ac->port[dir];
+       if (!port->buf) {
+               mutex_unlock(&ac->cmd_lock);
+               return 0;
+       }
+       cnt = port->max_buf_cnt - 1;
+
+       if (cnt >= 0) {
+               rc = q6asm_memory_unmap(ac, port->buf[0].phys, dir);
+               if (rc < 0)
+                       pr_err("%s CMD Memory_unmap_regions failed\n",
+                                                       __func__);
+       }
+
+       if (port->buf[0].data) {
+               pr_debug("%s:data[%p]phys[%p][%p] mem_buffer[%p]\n",
+                       __func__,
+                       (void *)port->buf[0].data,
+                       (void *)port->buf[0].phys,
+                       (void *)&port->buf[0].phys,
+                       (void *)port->buf[0].mem_buffer);
+
+
+               dma_free_writecombine(NULL, port->max_buf_cnt * port->buf[0].size,
+                                   port->buf[0].data, port->buf[0].phys);
+       }
+
+       while (cnt >= 0) {
+               port->buf[cnt].data = NULL;
+               port->buf[cnt].phys = 0;
+               cnt--;
+       }
+       port->max_buf_cnt = 0;
+       kfree(port->buf);
+       port->buf = NULL;
+       mutex_unlock(&ac->cmd_lock);
+       return 0;
+}
+
+void q6asm_audio_client_free(struct audio_client *ac)
+{
+       int loopcnt;
+       struct audio_port_data *port;
+       if (!ac || !ac->session)
+               return;
+       pr_debug("%s: Session id %d\n", __func__, ac->session);
+       if (ac->io_mode & SYNC_IO_MODE) {
+               for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
+                       port = &ac->port[loopcnt];
+                       if (!port->buf)
+                               continue;
+                       pr_debug("%s:loopcnt = %d\n", __func__, loopcnt);
+                       q6asm_audio_client_buf_free(loopcnt, ac);
+               }
+       }
+
+       apr_deregister(ac->apr);
+       q6asm_session_free(ac);
+
+       pr_debug("%s: APR De-Register\n", __func__);
+       if (atomic_read(&this_mmap.ref_cnt) <= 0) {
+               pr_err("%s: APR Common Port Already Closed\n", __func__);
+               goto done;
+       }
+
+       atomic_dec(&this_mmap.ref_cnt);
+       if (atomic_read(&this_mmap.ref_cnt) == 0) {
+               apr_deregister(this_mmap.apr);
+               pr_debug("%s:APR De-Register common port\n", __func__);
+       }
+done:
+       kfree(ac);
+       return;
+}
+
+int q6asm_set_io_mode(struct audio_client *ac, uint32_t mode)
+{
+       if (ac == NULL) {
+               pr_err("%s APR handle NULL\n", __func__);
+               return -EINVAL;
+       }
+
+       if (mode == ASYNC_IO_MODE) {
+               ac->io_mode &= ~SYNC_IO_MODE;
+               ac->io_mode |= ASYNC_IO_MODE;
+       } else if (mode == SYNC_IO_MODE) {
+               ac->io_mode &= ~ASYNC_IO_MODE;
+               ac->io_mode |= SYNC_IO_MODE;
+       } else {
+               pr_err("%s:Not an valid IO Mode:%d\n", __func__, ac->io_mode);
+               return -EINVAL;
+       }
+
+       pr_debug("%s:Set Mode to %d\n", __func__, ac->io_mode);
+       return 0;
+}
+
+struct audio_client *q6asm_audio_client_alloc(app_cb cb, void *priv)
+{
+       struct audio_client *ac;
+       int n;
+       int lcnt = 0;
+
+       ac = kzalloc(sizeof(struct audio_client), GFP_KERNEL);
+       if (!ac)
+               return NULL;
+       n = q6asm_session_alloc(ac);
+       if (n <= 0)
+               goto fail_session;
+       ac->session = n;
+       ac->cb = cb;
+       ac->priv = priv;
+       ac->io_mode = SYNC_IO_MODE;
+       ac->perf_mode = false;
+       ac->apr = apr_register("ADSP", "ASM", \
+                               (apr_fn)q6asm_callback,\
+                               ((ac->session) << 8 | 0x0001),\
+                               ac);
+
+       if (ac->apr == NULL) {
+               pr_err("%s Registration with APR failed\n", __func__);
+                       goto fail;
+       }
+       rtac_set_asm_handle(n, ac->apr);
+
+       pr_debug("%s Registering the common port with APR\n", __func__);
+       if (atomic_read(&this_mmap.ref_cnt) == 0) {
+               this_mmap.apr = apr_register("ADSP", "ASM", \
+                                       (apr_fn)q6asm_mmapcallback,\
+                                       0x0FFFFFFFF, &this_mmap);
+               if (this_mmap.apr == NULL) {
+                       pr_debug("%s Unable to register APR ASM common port\n",
+                                                        __func__);
+                       goto fail;
+               }
+       }
+
+       atomic_inc(&this_mmap.ref_cnt);
+       init_waitqueue_head(&ac->cmd_wait);
+       init_waitqueue_head(&ac->time_wait);
+       atomic_set(&ac->time_flag, 1);
+       mutex_init(&ac->cmd_lock);
+       for (lcnt = 0; lcnt <= OUT; lcnt++) {
+               mutex_init(&ac->port[lcnt].lock);
+               spin_lock_init(&ac->port[lcnt].dsp_lock);
+       }
+       atomic_set(&ac->cmd_state, 0);
+       atomic_set(&ac->cmd_response, 0);
+
+       pr_debug("%s: session[%d]\n", __func__, ac->session);
+
+       return ac;
+fail:
+       q6asm_audio_client_free(ac);
+       return NULL;
+fail_session:
+       kfree(ac);
+       return NULL;
+}
+
+struct audio_client *q6asm_get_audio_client(int session_id)
+{
+       if ((session_id <= 0) || (session_id > SESSION_MAX)) {
+               pr_err("%s: invalid session: %d\n", __func__, session_id);
+               goto err;
+       }
+
+       if (!session[session_id]) {
+               pr_err("%s: session not active: %d\n", __func__, session_id);
+               goto err;
+       }
+
+       return session[session_id];
+err:
+       return NULL;
+}
+
+int q6asm_audio_client_buf_alloc(unsigned int dir,
+                       struct audio_client *ac,
+                       unsigned int bufsz,
+                       unsigned int bufcnt)
+{
+       int cnt = 0;
+       int rc = 0;
+       struct audio_buffer *buf;
+
+       if (!(ac) || ((dir != IN) && (dir != OUT)))
+               return -EINVAL;
+
+       pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n", __func__, ac->session,
+               bufsz, bufcnt);
+
+       if (ac->session <= 0 || ac->session > 8)
+               goto fail;
+
+       if (ac->io_mode & SYNC_IO_MODE) {
+               if (ac->port[dir].buf) {
+                       pr_debug("%s: buffer already allocated\n", __func__);
+                       return 0;
+               }
+               mutex_lock(&ac->cmd_lock);
+               buf = kzalloc(((sizeof(struct audio_buffer))*bufcnt),
+                               GFP_KERNEL);
+
+               if (!buf) {
+                       mutex_unlock(&ac->cmd_lock);
+                       goto fail;
+               }
+
+               ac->port[dir].buf = buf;
+
+               while (cnt < bufcnt) {
+                       if (bufsz > 0) {
+                               if (!buf[cnt].data) {
+                                       buf[cnt].size = bufsz; 
+                                       buf[cnt].data = dma_alloc_writecombine(NULL, bufsz,
+                                               &buf[cnt].phys, GFP_KERNEL);
+                                       if (WARN_ON(IS_ERR_OR_NULL(buf[0].data))) {
+                                               pr_err("%s: allocation failed\n", __func__);
+                                               goto fail;
+                                       }
+       
+
+                                       buf[cnt].used = 1;
+                                       buf[cnt].size = bufsz;
+                                       buf[cnt].actual_size = bufsz;
+                                       pr_debug("%s data[%p]phys[%p][%p]\n",
+                                               __func__,
+                                          (void *)buf[cnt].data,
+                                          (void *)buf[cnt].phys,
+                                          (void *)&buf[cnt].phys);
+                                       cnt++;
+                               }
+                       }
+               }
+               ac->port[dir].max_buf_cnt = cnt;
+
+               mutex_unlock(&ac->cmd_lock);
+               rc = q6asm_memory_map_regions(ac, dir, bufsz, cnt);
+               if (rc < 0) {
+                       pr_err("%s:CMD Memory_map_regions failed\n", __func__);
+                       goto fail;
+               }
+       }
+       return 0;
+fail:
+       q6asm_audio_client_buf_free(dir, ac);
+       return -EINVAL;
+}
+
+int q6asm_audio_client_buf_alloc_contiguous(unsigned int dir,
+                       struct audio_client *ac,
+                       unsigned int bufsz,
+                       unsigned int bufcnt)
+{
+       int cnt = 0;
+       int rc = 0;
+       struct audio_buffer *buf;
+       if (!(ac) || ((dir != IN) && (dir != OUT)))
+               return -EINVAL;
+
+       pr_debug("%s: session[%d]bufsz[%d]bufcnt[%d]\n",
+                       __func__, ac->session,
+                       bufsz, bufcnt);
+
+       if (ac->session <= 0 || ac->session > 8)
+               goto fail;
+
+       if (ac->port[dir].buf) {
+               pr_debug("%s: buffer already allocated\n", __func__);
+               return 0;
+       }
+       mutex_lock(&ac->cmd_lock);
+       buf = kzalloc(((sizeof(struct audio_buffer))*bufcnt),
+                       GFP_KERNEL);
+
+       if (!buf) {
+               mutex_unlock(&ac->cmd_lock);
+               goto fail;
+       }
+
+       ac->port[dir].buf = buf;
+
+
+       buf[0].size = bufsz * bufcnt; 
+       buf[0].data = dma_alloc_writecombine(NULL, bufsz *bufcnt,
+                       &buf[0].phys, GFP_KERNEL);
+       if (WARN_ON(IS_ERR_OR_NULL(buf[0].data))) {
+               pr_err("%s: allocation failed\n", __func__);
+               goto fail;
+       }
+       
+       if (!buf[0].data) {
+               pr_err("%s:invalid vaddr, iomap failed\n", __func__);
+               mutex_unlock(&ac->cmd_lock);
+               goto fail;
+       }
+
+       buf[0].used = dir ^ 1;
+       buf[0].size = bufsz;
+       buf[0].actual_size = bufsz;
+       cnt = 1;
+       while (cnt < bufcnt) {
+               if (bufsz > 0) {
+                       buf[cnt].data =  buf[0].data + (cnt * bufsz);
+                       buf[cnt].phys =  buf[0].phys + (cnt * bufsz);
+                       if (!buf[cnt].data) {
+                               pr_err("%s Buf alloc failed\n",
+                                                       __func__);
+                               mutex_unlock(&ac->cmd_lock);
+                               goto fail;
+                       }
+                       buf[cnt].used = dir ^ 1;
+                       buf[cnt].size = bufsz;
+                       buf[cnt].actual_size = bufsz;
+                       pr_debug("%s data[%p]phys[%p][%p]\n", __func__,
+                                  (void *)buf[cnt].data,
+                                  (void *)buf[cnt].phys,
+                                  (void *)&buf[cnt].phys);
+               }
+               cnt++;
+       }
+       ac->port[dir].max_buf_cnt = cnt;
+
+       pr_debug("%s ac->port[%d].max_buf_cnt[%d]\n", __func__, dir,
+                        ac->port[dir].max_buf_cnt);
+       mutex_unlock(&ac->cmd_lock);
+       rc = q6asm_memory_map(ac, buf[0].phys, dir, bufsz, cnt);
+       if (rc < 0) {
+               pr_err("%s:CMD Memory_map_regions failed\n", __func__);
+               goto fail;
+       }
+       return 0;
+fail:
+       q6asm_audio_client_buf_free_contiguous(dir, ac);
+       return -EINVAL;
+}
+
+static int32_t q6asm_mmapcallback(struct apr_client_data *data, void *priv)
+{
+       uint32_t token;
+       uint32_t *payload = data->payload;
+
+       if (data->opcode == RESET_EVENTS) {
+               pr_debug("%s: Reset event is received: %d %d apr[%p]\n",
+                               __func__,
+                               data->reset_event,
+                               data->reset_proc,
+                               this_mmap.apr);
+               apr_reset(this_mmap.apr);
+               this_mmap.apr = NULL;
+               atomic_set(&this_mmap.cmd_state, 0);
+               return 0;
+       }
+
+       pr_debug("%s:ptr0[0x%x]ptr1[0x%x]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]\n",
+                __func__, payload[0], payload[1], data->opcode, data->token,
+               data->payload_size, data->src_port, data->dest_port);
+
+       if (data->opcode == APR_BASIC_RSP_RESULT) {
+               token = data->token;
+               switch (payload[0]) {
+               case ASM_SESSION_CMD_MEMORY_MAP:
+               case ASM_SESSION_CMD_MEMORY_UNMAP:
+               case ASM_SESSION_CMD_MEMORY_MAP_REGIONS:
+               case ASM_SESSION_CMD_MEMORY_UNMAP_REGIONS:
+                       pr_debug("%s:command[0x%x]success [0x%x]\n",
+                                       __func__, payload[0], payload[1]);
+                       if (atomic_read(&this_mmap.cmd_state)) {
+                               atomic_set(&this_mmap.cmd_state, 0);
+                               wake_up(&this_mmap.cmd_wait);
+                       }
+                       break;
+               default:
+                       pr_debug("%s:command[0x%x] not expecting rsp\n",
+                                               __func__, payload[0]);
+                       break;
+               }
+       }
+       return 0;
+}
+
+static int32_t is_no_wait_cmd_rsp(uint32_t opcode, uint32_t *cmd_type)
+{
+       if (opcode == APR_BASIC_RSP_RESULT) {
+               if (cmd_type != NULL) {
+                       switch (cmd_type[0]) {
+                       case ASM_SESSION_CMD_RUN:
+                       case ASM_SESSION_CMD_PAUSE:
+                       case ASM_DATA_CMD_EOS:
+                               return 1;
+                       default:
+                               break;
+                       }
+               } else
+                       pr_err("%s: null pointer!", __func__);
+       } else if (opcode == ASM_DATA_CMDRSP_EOS)
+               return 1;
+
+       return 0;
+}
+
+static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
+{
+       int i = 0;
+       struct audio_client *ac = (struct audio_client *)priv;
+       uint32_t token;
+       unsigned long dsp_flags;
+       uint32_t *payload;
+       uint32_t wakeup_flag = 1;
+
+
+       if ((ac == NULL) || (data == NULL)) {
+               pr_err("ac or priv NULL\n");
+               return -EINVAL;
+       }
+       if (ac->session <= 0 || ac->session > 8) {
+               pr_err("%s:Session ID is invalid, session = %d\n", __func__,
+                       ac->session);
+               return -EINVAL;
+       }
+
+       payload = data->payload;
+       if ((atomic_read(&ac->nowait_cmd_cnt) > 0) &&
+               is_no_wait_cmd_rsp(data->opcode, payload)) {
+               pr_debug("%s: nowait_cmd_cnt %d\n",
+                               __func__,
+                               atomic_read(&ac->nowait_cmd_cnt));
+               atomic_dec(&ac->nowait_cmd_cnt);
+               wakeup_flag = 0;
+       }
+
+       if (data->opcode == RESET_EVENTS) {
+               pr_debug("q6asm_callback: Reset event is received: %d %d apr[%p]\n",
+                               data->reset_event, data->reset_proc, ac->apr);
+                       if (ac->cb)
+                               ac->cb(data->opcode, data->token,
+                                       (uint32_t *)data->payload, ac->priv);
+               apr_reset(ac->apr);
+               return 0;
+       }
+
+       pr_debug("%s: session[%d]opcode[0x%x] token[0x%x]payload_s[%d] src[%d] dest[%d]\n",
+                __func__,
+               ac->session, data->opcode,
+               data->token, data->payload_size, data->src_port,
+               data->dest_port);
+
+       if (data->opcode == APR_BASIC_RSP_RESULT) {
+               token = data->token;
+               pr_debug("%s payload[0]:%x", __func__, payload[0]);
+               switch (payload[0]) {
+               case ASM_STREAM_CMD_SET_PP_PARAMS:
+                       if (rtac_make_asm_callback(ac->session, payload,
+                                       data->payload_size))
+                               break;
+               case ASM_SESSION_CMD_PAUSE:
+               case ASM_DATA_CMD_EOS:
+               case ASM_STREAM_CMD_CLOSE:
+               case ASM_STREAM_CMD_FLUSH:
+               case ASM_SESSION_CMD_RUN:
+               case ASM_SESSION_CMD_REGISTER_FOR_TX_OVERFLOW_EVENTS:
+               case ASM_STREAM_CMD_FLUSH_READBUFS:
+               pr_debug("%s:Payload = [0x%x]\n", __func__, payload[0]);
+               if (token != ac->session) {
+                       pr_err("%s:Invalid session[%d] rxed expected[%d]",
+                                       __func__, token, ac->session);
+                       return -EINVAL;
+               }
+               case ASM_STREAM_CMD_OPEN_READ:
+               case ASM_STREAM_CMD_OPEN_READ_V2_1:
+               case ASM_STREAM_CMD_OPEN_WRITE:
+               case ASM_STREAM_CMD_OPEN_WRITE_V2_1:
+               case ASM_STREAM_CMD_OPEN_READWRITE:
+               case ASM_STREAM_CMD_OPEN_LOOPBACK:
+               case ASM_DATA_CMD_MEDIA_FORMAT_UPDATE:
+               case ASM_STREAM_CMD_SET_ENCDEC_PARAM:
+               case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED:
+               case ASM_STREAM_CMD_OPEN_READ_COMPRESSED:
+                       if (payload[0] == ASM_STREAM_CMD_CLOSE) {
+                               atomic_set(&ac->cmd_close_state, 0);
+                               wake_up(&ac->cmd_wait);
+                       } else if (atomic_read(&ac->cmd_state) &&
+                                       wakeup_flag) {
+                               atomic_set(&ac->cmd_state, 0);
+                               if (payload[1] == ADSP_EUNSUPPORTED) {
+                                       pr_debug("paload[1]:%d unsupported",
+                                                               payload[1]);
+                                       atomic_set(&ac->cmd_response, 1);
+                               }
+                               else
+                                       atomic_set(&ac->cmd_response, 0);
+                               wake_up(&ac->cmd_wait);
+                       }
+                       if (ac->cb)
+                               ac->cb(data->opcode, data->token,
+                                       (uint32_t *)data->payload, ac->priv);
+                       break;
+               default:
+                       pr_debug("%s:command[0x%x] not expecting rsp\n",
+                                                       __func__, payload[0]);
+                       break;
+               }
+               return 0;
+       }
+
+       switch (data->opcode) {
+       case ASM_DATA_EVENT_WRITE_DONE:{
+               struct audio_port_data *port = &ac->port[IN];
+               pr_debug("%s: Rxed opcode[0x%x] status[0x%x] token[%d]",
+                               __func__, payload[0], payload[1],
+                               data->token);
+               if (ac->io_mode & SYNC_IO_MODE) {
+                       if (port->buf == NULL) {
+                               pr_err("%s: Unexpected Write Done\n",
+                                                               __func__);
+                               return -EINVAL;
+                       }
+                       spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+                       if (port->buf[data->token].phys !=
+                               payload[0]) {
+                               pr_err("Buf expected[%p]rxed[%p]\n",\
+                                  (void *)port->buf[data->token].phys,\
+                                  (void *)payload[0]);
+                               spin_unlock_irqrestore(&port->dsp_lock,
+                                                               dsp_flags);
+                               return -EINVAL;
+                       }
+                       token = data->token;
+                       port->buf[token].used = 1;
+                       spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+#ifdef CONFIG_DEBUG_FS
+                       if (out_enable_flag) {
+                               /* For first Write done log the time and reset
+                                  out_cold_index*/
+                               if (out_cold_index != 1) {
+                                       do_gettimeofday(&out_cold_tv);
+                                       pr_debug("COLD: apr_send_pkt at %ld sec %ld microsec\n",
+                                       out_cold_tv.tv_sec,
+                                       out_cold_tv.tv_usec);
+                                       out_cold_index = 1;
+                               }
+                               pr_debug("out_enable_flag %ld",\
+                                       out_enable_flag);
+                       }
+#endif
+                       for (i = 0; i < port->max_buf_cnt; i++)
+                               pr_debug("%d ", port->buf[i].used);
+
+               }
+               break;
+       }
+       case ASM_STREAM_CMDRSP_GET_PP_PARAMS:
+               rtac_make_asm_callback(ac->session, payload,
+                       data->payload_size);
+               break;
+       case ASM_DATA_EVENT_READ_DONE:{
+
+               struct audio_port_data *port = &ac->port[OUT];
+#ifdef CONFIG_DEBUG_FS
+               if (in_enable_flag) {
+                       /* when in_cont_index == 7, DSP would be
+                        * writing into the 8th 512 byte buffer and this
+                        * timestamp is tapped here.Once done it then writes
+                        * to 9th 512 byte buffer.These two buffers(8th, 9th)
+                        * reach the test application in 5th iteration and that
+                        * timestamp is tapped at user level. The difference
+                        * of these two timestamps gives us the time between
+                        * the time at which dsp started filling the sample
+                        * required and when it reached the test application.
+                        * Hence continuous input latency
+                        */
+                       if (in_cont_index == 7) {
+                               do_gettimeofday(&in_cont_tv);
+                               pr_err("In_CONT:previous read buffer done at %ld sec %ld microsec\n",
+                               in_cont_tv.tv_sec, in_cont_tv.tv_usec);
+                       }
+               }
+#endif
+               pr_debug("%s:R-D: status=%d buff_add=%x act_size=%d offset=%d\n",
+                               __func__, payload[READDONE_IDX_STATUS],
+                               payload[READDONE_IDX_BUFFER],
+                               payload[READDONE_IDX_SIZE],
+                               payload[READDONE_IDX_OFFSET]);
+               pr_debug("%s:R-D:msw_ts=%d lsw_ts=%d flags=%d id=%d num=%d\n",
+                               __func__, payload[READDONE_IDX_MSW_TS],
+                               payload[READDONE_IDX_LSW_TS],
+                               payload[READDONE_IDX_FLAGS],
+                               payload[READDONE_IDX_ID],
+                               payload[READDONE_IDX_NUMFRAMES]);
+#ifdef CONFIG_DEBUG_FS
+               if (in_enable_flag)
+                       in_cont_index++;
+#endif
+               if (ac->io_mode & SYNC_IO_MODE) {
+                       if (port->buf == NULL) {
+                               pr_err("%s: Unexpected Write Done\n", __func__);
+                               return -EINVAL;
+                       }
+                       spin_lock_irqsave(&port->dsp_lock, dsp_flags);
+                       token = data->token;
+                       port->buf[token].used = 0;
+                       if (port->buf[token].phys !=
+                               payload[READDONE_IDX_BUFFER]) {
+                               pr_err("Buf expected[%p]rxed[%p]\n",\
+                                  (void *)port->buf[token].phys,\
+                                  (void *)payload[READDONE_IDX_BUFFER]);
+                               spin_unlock_irqrestore(&port->dsp_lock,
+                                                       dsp_flags);
+                               break;
+                       }
+                       port->buf[token].actual_size =
+                               payload[READDONE_IDX_SIZE];
+                       spin_unlock_irqrestore(&port->dsp_lock, dsp_flags);
+               }
+               break;
+       }
+       case ASM_DATA_EVENT_EOS:
+       case ASM_DATA_CMDRSP_EOS:
+               pr_debug("%s:EOS ACK received: rxed opcode[0x%x]\n",
+                                 __func__, data->opcode);
+               break;
+       case ASM_STREAM_CMDRSP_GET_ENCDEC_PARAM:
+               break;
+       case ASM_SESSION_EVENT_TX_OVERFLOW:
+               pr_err("ASM_SESSION_EVENT_TX_OVERFLOW\n");
+               break;
+       case ASM_SESSION_CMDRSP_GET_SESSION_TIME:
+               pr_debug("%s: ASM_SESSION_CMDRSP_GET_SESSION_TIME, payload[0] = %d, payload[1] = %d, payload[2] = %d\n",
+                                __func__,
+                                payload[0], payload[1], payload[2]);
+               ac->time_stamp = (uint64_t)(((uint64_t)payload[1] << 32) |
+                               payload[2]);
+               if (atomic_read(&ac->time_flag)) {
+                       atomic_set(&ac->time_flag, 0);
+                       wake_up(&ac->time_wait);
+               }
+               break;
+       case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY:
+       case ASM_DATA_EVENT_ENC_SR_CM_NOTIFY:
+               pr_debug("%s: ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY, payload[0] = %d, payload[1] = %d, payload[2] = %d, payload[3] = %d\n",
+                                __func__,
+                               payload[0], payload[1], payload[2],
+                               payload[3]);
+               break;
+       }
+       if (ac->cb)
+               ac->cb(data->opcode, data->token,
+                       data->payload, ac->priv);
+
+       return 0;
+}
+
+void *q6asm_is_cpu_buf_avail(int dir, struct audio_client *ac, uint32_t *size,
+                               uint32_t *index)
+{
+       void *data;
+       unsigned char idx;
+       struct audio_port_data *port;
+
+       if (!ac || ((dir != IN) && (dir != OUT)))
+               return NULL;
+
+       if (ac->io_mode & SYNC_IO_MODE) {
+               port = &ac->port[dir];
+
+               mutex_lock(&port->lock);
+               idx = port->cpu_buf;
+               if (port->buf == NULL) {
+                       pr_debug("%s:Buffer pointer null\n", __func__);
+                       mutex_unlock(&port->lock);
+                       return NULL;
+               }
+               /*  dir 0: used = 0 means buf in use
+                       dir 1: used = 1 means buf in use */
+               if (port->buf[idx].used == dir) {
+                       /* To make it more robust, we could loop and get the
+                       next avail buf, its risky though */
+                       pr_debug("%s:Next buf idx[0x%x] not available,dir[%d]\n",
+                        __func__, idx, dir);
+                       mutex_unlock(&port->lock);
+                       return NULL;
+               }
+               *size = port->buf[idx].actual_size;
+               *index = port->cpu_buf;
+               data = port->buf[idx].data;
+               pr_debug("%s:session[%d]index[%d] data[%p]size[%d]\n",
+                                               __func__,
+                                               ac->session,
+                                               port->cpu_buf,
+                                               data, *size);
+               /* By default increase the cpu_buf cnt
+               user accesses this function,increase cpu
+               buf(to avoid another api)*/
+               port->buf[idx].used = dir;
+               port->cpu_buf = ((port->cpu_buf + 1) & (port->max_buf_cnt - 1));
+               mutex_unlock(&port->lock);
+               return data;
+       }
+       return NULL;
+}
+
+void *q6asm_is_cpu_buf_avail_nolock(int dir, struct audio_client *ac,
+                                       uint32_t *size, uint32_t *index)
+{
+       void *data;
+       unsigned char idx;
+       struct audio_port_data *port;
+
+       if (!ac || ((dir != IN) && (dir != OUT)))
+               return NULL;
+
+       port = &ac->port[dir];
+
+       idx = port->cpu_buf;
+       if (port->buf == NULL) {
+               pr_debug("%s:Buffer pointer null\n", __func__);
+               return NULL;
+       }
+       /*
+        * dir 0: used = 0 means buf in use
+        * dir 1: used = 1 means buf in use
+        */
+       if (port->buf[idx].used == dir) {
+               /*
+                * To make it more robust, we could loop and get the
+                * next avail buf, its risky though
+                */
+               pr_debug("%s:Next buf idx[0x%x] not available, dir[%d]\n",
+                __func__, idx, dir);
+               return NULL;
+       }
+       *size = port->buf[idx].actual_size;
+       *index = port->cpu_buf;
+       data = port->buf[idx].data;
+       pr_debug("%s:session[%d]index[%d] data[%p]size[%d]\n",
+               __func__, ac->session, port->cpu_buf,
+               data, *size);
+       /*
+        * By default increase the cpu_buf cnt
+        * user accesses this function,increase cpu
+        * buf(to avoid another api)
+        */
+       port->buf[idx].used = dir;
+       port->cpu_buf = ((port->cpu_buf + 1) & (port->max_buf_cnt - 1));
+       return data;
+}
+
+int q6asm_is_dsp_buf_avail(int dir, struct audio_client *ac)
+{
+       int ret = -1;
+       struct audio_port_data *port;
+       uint32_t idx;
+
+       if (!ac || (dir != OUT))
+               return ret;
+
+       if (ac->io_mode & SYNC_IO_MODE) {
+               port = &ac->port[dir];
+
+               mutex_lock(&port->lock);
+               idx = port->dsp_buf;
+
+               if (port->buf[idx].used == (dir ^ 1)) {
+                       /* To make it more robust, we could loop and get the
+                       next avail buf, its risky though */
+                       pr_err("Next buf idx[0x%x] not available, dir[%d]\n",
+                                                               idx, dir);
+                       mutex_unlock(&port->lock);
+                       return ret;
+               }
+               pr_debug("%s: session[%d]dsp_buf=%d cpu_buf=%d\n", __func__,
+                       ac->session, port->dsp_buf, port->cpu_buf);
+               ret = ((port->dsp_buf != port->cpu_buf) ? 0 : -1);
+               mutex_unlock(&port->lock);
+       }
+       return ret;
+}
+
+static void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr,
+                       uint32_t pkt_size, uint32_t cmd_flg)
+{
+       pr_debug("%s:session=%d pkt size=%d cmd_flg=%d\n", __func__, pkt_size,
+               cmd_flg, ac->session);
+       mutex_lock(&ac->cmd_lock);
+       hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+                               APR_HDR_LEN(sizeof(struct apr_hdr)),\
+                               APR_PKT_VER);
+       hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
+       hdr->src_domain = APR_DOMAIN_APPS;
+       hdr->dest_svc = APR_SVC_ASM;
+       hdr->dest_domain = APR_DOMAIN_ADSP;
+       hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
+       hdr->dest_port = ((ac->session << 8) & 0xFF00) | 0x01;
+       if (cmd_flg) {
+               hdr->token = ac->session;
+               atomic_set(&ac->cmd_state, 1);
+       }
+       hdr->pkt_size  = pkt_size;
+       mutex_unlock(&ac->cmd_lock);
+       return;
+}
+
+static void q6asm_add_mmaphdr(struct apr_hdr *hdr, uint32_t pkt_size,
+                                                       uint32_t cmd_flg)
+{
+       pr_debug("%s:pkt size=%d cmd_flg=%d\n", __func__, pkt_size, cmd_flg);
+       hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+                               APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER);
+       hdr->src_port = 0;
+       hdr->dest_port = 0;
+       if (cmd_flg) {
+               hdr->token = 0;
+               atomic_set(&this_mmap.cmd_state, 1);
+       }
+       hdr->pkt_size  = pkt_size;
+       return;
+}
+
+int q6asm_open_read(struct audio_client *ac,
+               uint32_t format)
+{
+       int rc = 0x00;
+       struct asm_stream_cmd_open_read open;
+#ifdef CONFIG_DEBUG_FS
+       in_cont_index = 0;
+#endif
+       if ((ac == NULL) || (ac->apr == NULL)) {
+               pr_err("%s: APR handle NULL\n", __func__);
+               return -EINVAL;
+       }
+       pr_debug("%s:session[%d]", __func__, ac->session);
+
+       q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+       open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ;
+       /* Stream prio : High, provide meta info with encoded frames */
+       open.src_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+
+       open.pre_proc_top = get_asm_topology();
+       if (open.pre_proc_top == 0)
+               open.pre_proc_top = DEFAULT_POPP_TOPOLOGY;
+
+       switch (format) {
+       case FORMAT_LINEAR_PCM:
+               open.uMode = STREAM_PRIORITY_HIGH;
+               open.format = LINEAR_PCM;
+               break;
+       case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
+               open.uMode = STREAM_PRIORITY_HIGH;
+               open.format = MULTI_CHANNEL_PCM;
+               break;
+       case FORMAT_MPEG4_AAC:
+               open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+               open.format = MPEG4_AAC;
+               break;
+       case FORMAT_V13K:
+               open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+               open.format = V13K_FS;
+               break;
+       case FORMAT_EVRC:
+               open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+               open.format = EVRC_FS;
+               break;
+       case FORMAT_AMRNB:
+               open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+               open.format = AMRNB_FS;
+               break;
+       case FORMAT_AMRWB:
+               open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+               open.format = AMRWB_FS;
+               break;
+       default:
+               pr_err("Invalid format[%d]\n", format);
+               goto fail_cmd;
+       }
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+       if (rc < 0) {
+               pr_err("open failed op[0x%x]rc[%d]\n", \
+                                               open.hdr.opcode, rc);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s: timeout. waited for OPEN_WRITE rc[%d]\n", __func__,
+                       rc);
+               goto fail_cmd;
+       }
+
+       ac->io_mode |= TUN_READ_IO_MODE;
+
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_open_read_v2_1(struct audio_client *ac,
+               uint32_t format)
+{
+       int rc = 0x00;
+       struct asm_stream_cmd_open_read_v2_1 open;
+#ifdef CONFIG_DEBUG_FS
+       in_cont_index = 0;
+#endif
+       if ((ac == NULL) || (ac->apr == NULL)) {
+               pr_err("%s: APR handle NULL\n", __func__);
+               return -EINVAL;
+       }
+       pr_debug("%s:session[%d]", __func__, ac->session);
+
+       q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+       open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V2_1;
+       open.src_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+       open.pre_proc_top = get_asm_topology();
+       if (open.pre_proc_top == 0)
+               open.pre_proc_top = DEFAULT_POPP_TOPOLOGY;
+
+       switch (format) {
+       case FORMAT_LINEAR_PCM:
+               open.uMode = STREAM_PRIORITY_HIGH;
+               open.format = LINEAR_PCM;
+               break;
+       case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
+               open.uMode = STREAM_PRIORITY_HIGH;
+               open.format = MULTI_CHANNEL_PCM;
+               break;
+       case FORMAT_MPEG4_AAC:
+               open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+               open.format = MPEG4_AAC;
+               break;
+       case FORMAT_V13K:
+               open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+               open.format = V13K_FS;
+               break;
+       case FORMAT_EVRC:
+               open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+               open.format = EVRC_FS;
+               break;
+       case FORMAT_AMRNB:
+               open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+               open.format = AMRNB_FS;
+               break;
+       case FORMAT_AMRWB:
+               open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_HIGH;
+               open.format = AMRWB_FS;
+               break;
+       default:
+               pr_err("Invalid format[%d]\n", format);
+               goto fail_cmd;
+       }
+       open.uMode = ASM_OPEN_READ_PERF_MODE_BIT;
+       open.bits_per_sample = PCM_BITS_PER_SAMPLE;
+       open.reserved = 0;
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+       if (rc < 0) {
+               pr_err("open failed op[0x%x]rc[%d]\n", \
+                                               open.hdr.opcode, rc);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s: timeout. waited for OPEN_WRITE rc[%d]\n", __func__,
+                       rc);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+
+int q6asm_open_read_compressed(struct audio_client *ac,
+                        uint32_t frames_per_buffer, uint32_t meta_data_mode)
+{
+       int rc = 0x00;
+       struct asm_stream_cmd_open_read_compressed open;
+#ifdef CONFIG_DEBUG_FS
+       in_cont_index = 0;
+#endif
+       if ((ac == NULL) || (ac->apr == NULL)) {
+               pr_err("%s: APR handle NULL\n", __func__);
+               return -EINVAL;
+       }
+       pr_debug("%s:session[%d]", __func__, ac->session);
+
+       q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+       open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_COMPRESSED;
+       /* hardcoded as following*/
+       open.frame_per_buf = frames_per_buffer;
+       open.uMode = meta_data_mode;
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+       if (rc < 0) {
+               pr_err("open failed op[0x%x]rc[%d]\n", open.hdr.opcode, rc);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+               (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s: timeout. waited for OPEN_READ_COMPRESSED rc[%d]\n",
+                                __func__, rc);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format)
+{
+       int rc = 0x00;
+       struct asm_stream_cmd_open_write_compressed open;
+
+       if ((ac == NULL) || (ac->apr == NULL)) {
+               pr_err("%s: APR handle NULL\n", __func__);
+               return -EINVAL;
+       }
+       pr_debug("%s: session[%d] wr_format[0x%x]", __func__, ac->session,
+               format);
+
+       q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+
+       open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED;
+
+       switch (format) {
+       case FORMAT_AC3:
+               open.format = AC3_DECODER;
+               break;
+       case FORMAT_EAC3:
+               open.format = EAC3_DECODER;
+               break;
+       case FORMAT_MP3:
+               open.format = MP3;
+               break;
+       case FORMAT_DTS:
+               open.format = DTS;
+               break;
+       case FORMAT_DTS_LBR:
+               open.format = DTS_LBR;
+               break;
+       case FORMAT_AAC:
+               open.format = MPEG4_AAC;
+               break;
+       case FORMAT_ATRAC:
+               open.format = ATRAC;
+               break;
+       case FORMAT_WMA_V10PRO:
+               open.format = WMA_V10PRO;
+               break;
+       case FORMAT_MAT:
+               open.format = MAT;
+               break;
+       default:
+               pr_err("%s: Invalid format[%d]\n", __func__, format);
+               goto fail_cmd;
+       }
+       /*Below flag indicates the DSP that Compressed audio input
+       stream is not IEC 61937 or IEC 60958 packetizied*/
+       open.flags = 0x00000000;
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+       if (rc < 0) {
+               pr_err("%s: open failed op[0x%x]rc[%d]\n", \
+                                       __func__, open.hdr.opcode, rc);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s: timeout. waited for OPEN_WRITE rc[%d]\n", __func__,
+                       rc);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_open_write(struct audio_client *ac, uint32_t format)
+{
+       int rc = 0x00;
+       struct asm_stream_cmd_open_write open;
+
+       if ((ac == NULL) || (ac->apr == NULL)) {
+               pr_err("%s: APR handle NULL\n", __func__);
+               return -EINVAL;
+       }
+       pr_debug("%s: session[%d] wr_format[0x%x]", __func__, ac->session,
+               format);
+
+       q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+
+       if (ac->perf_mode) {
+               pr_debug("%s In Performance/lowlatency mode", __func__);
+               open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V2_1;
+               open.uMode = ASM_OPEN_WRITE_PERF_MODE_BIT;
+               /* source endpoint : matrix */
+               open.sink_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+               open.stream_handle = PCM_BITS_PER_SAMPLE;
+       } else {
+               open.hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE;
+               open.uMode = STREAM_PRIORITY_HIGH;
+               /* source endpoint : matrix */
+               open.sink_endpoint = ASM_END_POINT_DEVICE_MATRIX;
+               open.stream_handle = 0x00;
+       }
+       open.post_proc_top = get_asm_topology();
+       if (open.post_proc_top == 0)
+               open.post_proc_top = DEFAULT_POPP_TOPOLOGY;
+
+       switch (format) {
+       case FORMAT_LINEAR_PCM:
+               open.format = LINEAR_PCM;
+               break;
+       case FORMAT_MULTI_CHANNEL_LINEAR_PCM:
+               open.format = MULTI_CHANNEL_PCM;
+               break;
+       case FORMAT_MPEG4_AAC:
+               open.format = MPEG4_AAC;
+               break;
+       case FORMAT_MPEG4_MULTI_AAC:
+               open.format = MPEG4_MULTI_AAC;
+               break;
+       case FORMAT_WMA_V9:
+               open.format = WMA_V9;
+               break;
+       case FORMAT_WMA_V10PRO:
+               open.format = WMA_V10PRO;
+               break;
+       case FORMAT_MP3:
+               open.format = MP3;
+               break;
+       case FORMAT_DTS:
+               open.format = DTS;
+               break;
+       case FORMAT_DTS_LBR:
+               open.format = DTS_LBR;
+               break;
+       case FORMAT_AMRWB:
+               open.format = AMRWB_FS;
+               pr_debug("q6asm_open_write FORMAT_AMRWB");
+               break;
+       case FORMAT_AMR_WB_PLUS:
+               open.format = AMR_WB_PLUS;
+               pr_debug("q6asm_open_write FORMAT_AMR_WB_PLUS");
+               break;
+       default:
+               pr_err("%s: Invalid format[%d]\n", __func__, format);
+               goto fail_cmd;
+       }
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+       if (rc < 0) {
+               pr_err("%s: open failed op[0x%x]rc[%d]\n", \
+                                       __func__, open.hdr.opcode, rc);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s: timeout. waited for OPEN_WRITE rc[%d]\n", __func__,
+                       rc);
+               goto fail_cmd;
+       }
+       if (atomic_read(&ac->cmd_response)) {
+               pr_err("%s: format = %x not supported\n", __func__, format);
+               goto fail_cmd;
+       }
+
+       ac->io_mode |= TUN_WRITE_IO_MODE;
+
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_open_read_write(struct audio_client *ac,
+                       uint32_t rd_format,
+                       uint32_t wr_format)
+{
+       int rc = 0x00;
+       struct asm_stream_cmd_open_read_write open;
+
+       if ((ac == NULL) || (ac->apr == NULL)) {
+               pr_err("APR handle NULL\n");
+               return -EINVAL;
+       }
+       pr_debug("%s: session[%d]", __func__, ac->session);
+       pr_debug("wr_format[0x%x]rd_format[0x%x]",
+                               wr_format, rd_format);
+
+       q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+       open.hdr.opcode = ASM_STREAM_CMD_OPEN_READWRITE;
+
+       open.uMode = BUFFER_META_ENABLE | STREAM_PRIORITY_NORMAL;
+       /* source endpoint : matrix */
+       open.post_proc_top = get_asm_topology();
+       if (open.post_proc_top == 0)
+               open.post_proc_top = DEFAULT_POPP_TOPOLOGY;
+
+       switch (wr_format) {
+       case FORMAT_LINEAR_PCM:
+               open.write_format = LINEAR_PCM;
+               break;
+       case FORMAT_MPEG4_AAC:
+               open.write_format = MPEG4_AAC;
+               break;
+       case FORMAT_MPEG4_MULTI_AAC:
+               open.write_format = MPEG4_MULTI_AAC;
+               break;
+       case FORMAT_WMA_V9:
+               open.write_format = WMA_V9;
+               break;
+       case FORMAT_WMA_V10PRO:
+               open.write_format = WMA_V10PRO;
+               break;
+       case FORMAT_AMRNB:
+               open.write_format = AMRNB_FS;
+               break;
+       case FORMAT_AMRWB:
+               open.write_format = AMRWB_FS;
+               break;
+       case FORMAT_AMR_WB_PLUS:
+               open.write_format = AMR_WB_PLUS;
+               break;
+       case FORMAT_V13K:
+               open.write_format = V13K_FS;
+               break;
+       case FORMAT_EVRC:
+               open.write_format = EVRC_FS;
+               break;
+       case FORMAT_EVRCB:
+               open.write_format = EVRCB_FS;
+               break;
+       case FORMAT_EVRCWB:
+               open.write_format = EVRCWB_FS;
+               break;
+       case FORMAT_MP3:
+               open.write_format = MP3;
+               break;
+       default:
+               pr_err("Invalid format[%d]\n", wr_format);
+               goto fail_cmd;
+       }
+
+       switch (rd_format) {
+       case FORMAT_LINEAR_PCM:
+               open.read_format = LINEAR_PCM;
+               break;
+       case FORMAT_MPEG4_AAC:
+               open.read_format = MPEG4_AAC;
+               break;
+       case FORMAT_V13K:
+               open.read_format = V13K_FS;
+               break;
+       case FORMAT_EVRC:
+               open.read_format = EVRC_FS;
+               break;
+       case FORMAT_AMRNB:
+               open.read_format = AMRNB_FS;
+               break;
+       case FORMAT_AMRWB:
+               open.read_format = AMRWB_FS;
+               break;
+       default:
+               pr_err("Invalid format[%d]\n", rd_format);
+               goto fail_cmd;
+       }
+       pr_debug("%s:rdformat[0x%x]wrformat[0x%x]\n", __func__,
+                       open.read_format, open.write_format);
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+       if (rc < 0) {
+               pr_err("open failed op[0x%x]rc[%d]\n", \
+                                               open.hdr.opcode, rc);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("timeout. waited for OPEN_WRITE rc[%d]\n", rc);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_open_loopack(struct audio_client *ac)
+{
+       int rc = 0x00;
+       struct asm_stream_cmd_open_loopback open;
+
+       if ((ac == NULL) || (ac->apr == NULL)) {
+               pr_err("APR handle NULL\n");
+               return -EINVAL;
+       }
+       pr_debug("%s: session[%d]", __func__, ac->session);
+
+       q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE);
+       open.hdr.opcode = ASM_STREAM_CMD_OPEN_LOOPBACK;
+
+       open.mode_flags = 0;
+       open.src_endpointype = 0;
+       open.sink_endpointype = 0;
+       /* source endpoint : matrix */
+       open.postprocopo_id = get_asm_topology();
+       if (open.postprocopo_id == 0)
+               open.postprocopo_id = DEFAULT_POPP_TOPOLOGY;
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &open);
+       if (rc < 0) {
+               pr_err("open failed op[0x%x]rc[%d]\n", \
+                                               open.hdr.opcode, rc);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("timeout. waited for OPEN_WRITE rc[%d]\n", rc);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_run(struct audio_client *ac, uint32_t flags,
+               uint32_t msw_ts, uint32_t lsw_ts)
+{
+       struct asm_stream_cmd_run run;
+       int rc;
+       if (!ac || ac->apr == NULL) {
+               pr_err("APR handle NULL\n");
+               return -EINVAL;
+       }
+       pr_debug("%s session[%d]", __func__, ac->session);
+       q6asm_add_hdr(ac, &run.hdr, sizeof(run), TRUE);
+
+       run.hdr.opcode = ASM_SESSION_CMD_RUN;
+       run.flags    = flags;
+       run.msw_ts   = msw_ts;
+       run.lsw_ts   = lsw_ts;
+#ifdef CONFIG_DEBUG_FS
+       if (out_enable_flag) {
+               do_gettimeofday(&out_cold_tv);
+               pr_debug("COLD: apr_send_pkt at %ld sec %ld microsec\n",\
+                               out_cold_tv.tv_sec, out_cold_tv.tv_usec);
+       }
+#endif
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
+       if (rc < 0) {
+               pr_err("Commmand run failed[%d]", rc);
+               goto fail_cmd;
+       }
+
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("timeout. waited for run success rc[%d]", rc);
+               goto fail_cmd;
+       }
+
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_run_nowait(struct audio_client *ac, uint32_t flags,
+               uint32_t msw_ts, uint32_t lsw_ts)
+{
+       struct asm_stream_cmd_run run;
+       int rc;
+       if (!ac || ac->apr == NULL) {
+               pr_err("%s:APR handle NULL\n", __func__);
+               return -EINVAL;
+       }
+       pr_debug("session[%d]", ac->session);
+       q6asm_add_hdr_async(ac, &run.hdr, sizeof(run), TRUE);
+
+       run.hdr.opcode = ASM_SESSION_CMD_RUN;
+       run.flags    = flags;
+       run.msw_ts   = msw_ts;
+       run.lsw_ts   = lsw_ts;
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &run);
+       if (rc < 0) {
+               pr_err("%s:Commmand run failed[%d]", __func__, rc);
+               return -EINVAL;
+       }
+       atomic_inc(&ac->nowait_cmd_cnt);
+       return 0;
+}
+
+
+int q6asm_enc_cfg_blk_aac(struct audio_client *ac,
+                        uint32_t frames_per_buf,
+                       uint32_t sample_rate, uint32_t channels,
+                       uint32_t bit_rate, uint32_t mode, uint32_t format)
+{
+       struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+       int rc = 0;
+
+       pr_debug("%s:session[%d]frames[%d]SR[%d]ch[%d]bitrate[%d]mode[%d] format[%d]",
+                __func__, ac->session, frames_per_buf,
+               sample_rate, channels, bit_rate, mode, format);
+
+       q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+       enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+       enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+       enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+       enc_cfg.enc_blk.frames_per_buf = frames_per_buf;
+       enc_cfg.enc_blk.format_id = MPEG4_AAC;
+       enc_cfg.enc_blk.cfg_size  = sizeof(struct asm_aac_read_cfg);
+       enc_cfg.enc_blk.cfg.aac.bitrate = bit_rate;
+       enc_cfg.enc_blk.cfg.aac.enc_mode = mode;
+       enc_cfg.enc_blk.cfg.aac.format = format;
+       enc_cfg.enc_blk.cfg.aac.ch_cfg = channels;
+       enc_cfg.enc_blk.cfg.aac.sample_rate = sample_rate;
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+       if (rc < 0) {
+               pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("timeout. waited for FORMAT_UPDATE\n");
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_pcm(struct audio_client *ac,
+                       uint32_t rate, uint32_t channels)
+{
+       struct asm_stream_cmd_encdec_cfg_blk  enc_cfg;
+
+       int rc = 0;
+
+       pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
+                        ac->session, rate, channels);
+
+       q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+       enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+       enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+       enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+       enc_cfg.enc_blk.frames_per_buf = 1;
+       enc_cfg.enc_blk.format_id = LINEAR_PCM;
+       enc_cfg.enc_blk.cfg_size = sizeof(struct asm_pcm_cfg);
+       enc_cfg.enc_blk.cfg.pcm.ch_cfg = channels;
+       enc_cfg.enc_blk.cfg.pcm.bits_per_sample = 16;
+       enc_cfg.enc_blk.cfg.pcm.sample_rate = rate;
+       enc_cfg.enc_blk.cfg.pcm.is_signed = 1;
+       enc_cfg.enc_blk.cfg.pcm.interleaved = 1;
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+       if (rc < 0) {
+               pr_err("Comamnd open failed\n");
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("timeout opcode[0x%x] ", enc_cfg.hdr.opcode);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_pcm_native(struct audio_client *ac,
+                       uint32_t rate, uint32_t channels)
+{
+       struct asm_stream_cmd_encdec_cfg_blk  enc_cfg;
+
+       int rc = 0;
+
+       pr_debug("%s: Session %d, rate = %d, channels = %d, setting the rate and channels to 0 for native\n",
+                        __func__, ac->session, rate, channels);
+
+       q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+       enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+       enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+       enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+       enc_cfg.enc_blk.frames_per_buf = 1;
+       enc_cfg.enc_blk.format_id = LINEAR_PCM;
+       enc_cfg.enc_blk.cfg_size = sizeof(struct asm_pcm_cfg);
+       enc_cfg.enc_blk.cfg.pcm.ch_cfg = 0;/*channels;*/
+       enc_cfg.enc_blk.cfg.pcm.bits_per_sample = 16;
+       enc_cfg.enc_blk.cfg.pcm.sample_rate = 0;/*rate;*/
+       enc_cfg.enc_blk.cfg.pcm.is_signed = 1;
+       enc_cfg.enc_blk.cfg.pcm.interleaved = 1;
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+       if (rc < 0) {
+               pr_err("Comamnd open failed\n");
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("timeout opcode[0x%x] ", enc_cfg.hdr.opcode);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_multi_ch_pcm(struct audio_client *ac,
+                       uint32_t rate, uint32_t channels)
+{
+       struct asm_stream_cmd_encdec_cfg_blk  enc_cfg;
+
+       int rc = 0;
+
+       pr_debug("%s: Session %d, rate = %d, channels = %d\n", __func__,
+                        ac->session, rate, channels);
+
+       q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+       enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+       enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+       enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+       enc_cfg.enc_blk.frames_per_buf = 1;
+       enc_cfg.enc_blk.format_id = MULTI_CHANNEL_PCM;
+       enc_cfg.enc_blk.cfg_size =
+               sizeof(struct asm_multi_channel_pcm_fmt_blk);
+       enc_cfg.enc_blk.cfg.mpcm.num_channels = channels;
+       enc_cfg.enc_blk.cfg.mpcm.bits_per_sample = 16;
+       enc_cfg.enc_blk.cfg.mpcm.sample_rate = rate;
+       enc_cfg.enc_blk.cfg.mpcm.is_signed = 1;
+       enc_cfg.enc_blk.cfg.mpcm.is_interleaved = 1;
+       if (channels == 1) {
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[0] = PCM_CHANNEL_FL;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[1] = 0;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[2] = 0;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[3] = 0;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[4] = 0;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[5] = 0;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[6] = 0;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[7] = 0;
+       } else if (channels == 2) {
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[0] = PCM_CHANNEL_FL;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[1] = PCM_CHANNEL_FR;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[2] = 0;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[3] = 0;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[4] = 0;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[5] = 0;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[6] = 0;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[7] = 0;
+       } else if (channels == 4) {
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[0] = PCM_CHANNEL_FL;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[1] = PCM_CHANNEL_FR;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[2] = PCM_CHANNEL_RB;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[3] = PCM_CHANNEL_LB;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[4] = 0;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[5] = 0;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[6] = 0;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[7] = 0;
+       } else if (channels == 6) {
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[0] = PCM_CHANNEL_FL;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[1] = PCM_CHANNEL_FR;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[2] = PCM_CHANNEL_LFE;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[3] = PCM_CHANNEL_FC;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[4] = PCM_CHANNEL_LB;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[5] = PCM_CHANNEL_RB;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[6] = 0;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[7] = 0;
+       } else if (channels == 8) {
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[0] = PCM_CHANNEL_FL;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[1] = PCM_CHANNEL_FR;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[2] = PCM_CHANNEL_LFE;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[3] = PCM_CHANNEL_FC;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[4] = PCM_CHANNEL_LB;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[5] = PCM_CHANNEL_RB;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[6] = PCM_CHANNEL_FLC;
+               enc_cfg.enc_blk.cfg.mpcm.channel_mapping[7] = PCM_CHANNEL_FRC;
+       }
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+       if (rc < 0) {
+               pr_err("Comamnd open failed\n");
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("timeout opcode[0x%x] ", enc_cfg.hdr.opcode);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_enable_sbrps(struct audio_client *ac,
+                       uint32_t sbr_ps_enable)
+{
+       struct asm_stream_cmd_encdec_sbr  sbrps;
+
+       int rc = 0;
+
+       pr_debug("%s: Session %d\n", __func__, ac->session);
+
+       q6asm_add_hdr(ac, &sbrps.hdr, sizeof(sbrps), TRUE);
+
+       sbrps.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+       sbrps.param_id = ASM_ENABLE_SBR_PS;
+       sbrps.param_size = sizeof(struct asm_sbr_ps);
+       sbrps.sbr_ps.enable = sbr_ps_enable;
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &sbrps);
+       if (rc < 0) {
+               pr_err("Command opcode[0x%x]paramid[0x%x] failed\n",
+                               ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+                               ASM_ENABLE_SBR_PS);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("timeout opcode[0x%x] ", sbrps.hdr.opcode);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_cfg_dual_mono_aac(struct audio_client *ac,
+                       uint16_t sce_left, uint16_t sce_right)
+{
+       struct asm_stream_cmd_encdec_dualmono dual_mono;
+
+       int rc = 0;
+
+       pr_debug("%s: Session %d, sce_left = %d, sce_right = %d\n",
+                        __func__, ac->session, sce_left, sce_right);
+
+       q6asm_add_hdr(ac, &dual_mono.hdr, sizeof(dual_mono), TRUE);
+
+       dual_mono.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+       dual_mono.param_id = ASM_CONFIGURE_DUAL_MONO;
+       dual_mono.param_size = sizeof(struct asm_dual_mono);
+       dual_mono.channel_map.sce_left = sce_left;
+       dual_mono.channel_map.sce_right = sce_right;
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &dual_mono);
+       if (rc < 0) {
+               pr_err("%s:Command opcode[0x%x]paramid[0x%x] failed\n",
+                               __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+                               ASM_CONFIGURE_DUAL_MONO);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s:timeout opcode[0x%x]\n", __func__,
+                                               dual_mono.hdr.opcode);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_cfg_aac_sel_mix_coef(struct audio_client *ac, uint32_t mix_coeff)
+{
+       struct asm_aac_stereo_mix_coeff_selection_param aac_mix_coeff;
+       int rc = 0;
+       q6asm_add_hdr(ac, &aac_mix_coeff.hdr, sizeof(aac_mix_coeff), TRUE);
+       aac_mix_coeff.hdr.opcode =
+                ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+       aac_mix_coeff.param_id =
+               ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG;
+       aac_mix_coeff.param_size =
+                sizeof(struct asm_aac_stereo_mix_coeff_selection_param);
+       aac_mix_coeff.aac_stereo_mix_coeff_flag = mix_coeff;
+       pr_debug("%s, mix_coeff = %u", __func__, mix_coeff);
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &aac_mix_coeff);
+       if (rc < 0) {
+               pr_err("%s:Command opcode[0x%x]paramid[0x%x] failed\n",
+                       __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+                       ASM_PARAM_ID_AAC_STEREO_MIX_COEFF_SELECTION_FLAG);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s:timeout opcode[0x%x]\n", __func__,
+                                               aac_mix_coeff.hdr.opcode);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_set_encdec_chan_map(struct audio_client *ac,
+                       uint32_t num_channels)
+{
+       struct asm_stream_cmd_encdec_channelmap chan_map;
+       u8 *channel_mapping;
+
+       int rc = 0;
+
+       pr_debug("%s: Session %d, num_channels = %d\n",
+                        __func__, ac->session, num_channels);
+
+       q6asm_add_hdr(ac, &chan_map.hdr, sizeof(chan_map), TRUE);
+
+       chan_map.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+       chan_map.param_id = ASM_ENCDEC_DEC_CHAN_MAP;
+       chan_map.param_size = sizeof(struct asm_dec_chan_map);
+       chan_map.chan_map.num_channels = num_channels;
+
+       channel_mapping =
+               chan_map.chan_map.channel_mapping;
+
+       memset(channel_mapping, PCM_CHANNEL_NULL, MAX_CHAN_MAP_CHANNELS);
+       if (num_channels == 1)  {
+               channel_mapping[0] = PCM_CHANNEL_FL;
+       } else if (num_channels == 2) {
+               channel_mapping[0] = PCM_CHANNEL_FL;
+               channel_mapping[1] = PCM_CHANNEL_FR;
+       } else if (num_channels == 4) {
+               channel_mapping[0] = PCM_CHANNEL_FL;
+               channel_mapping[1] = PCM_CHANNEL_FR;
+               channel_mapping[1] = PCM_CHANNEL_LB;
+               channel_mapping[1] = PCM_CHANNEL_RB;
+       } else if (num_channels == 6) {
+               channel_mapping[0] = PCM_CHANNEL_FC;
+               channel_mapping[1] = PCM_CHANNEL_FL;
+               channel_mapping[2] = PCM_CHANNEL_FR;
+               channel_mapping[3] = PCM_CHANNEL_LB;
+               channel_mapping[4] = PCM_CHANNEL_RB;
+               channel_mapping[5] = PCM_CHANNEL_LFE;
+       } else if (num_channels == 8) {
+               channel_mapping[0] = PCM_CHANNEL_FC;
+               channel_mapping[1] = PCM_CHANNEL_FL;
+               channel_mapping[2] = PCM_CHANNEL_FR;
+               channel_mapping[3] = PCM_CHANNEL_LB;
+               channel_mapping[4] = PCM_CHANNEL_RB;
+               channel_mapping[5] = PCM_CHANNEL_LFE;
+               channel_mapping[6] = PCM_CHANNEL_FLC;
+               channel_mapping[7] = PCM_CHANNEL_FRC;
+       } else {
+               pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
+                               num_channels);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &chan_map);
+       if (rc < 0) {
+               pr_err("%s:Command opcode[0x%x]paramid[0x%x] failed\n",
+                               __func__, ASM_STREAM_CMD_SET_ENCDEC_PARAM,
+                               ASM_ENCDEC_DEC_CHAN_MAP);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s:timeout opcode[0x%x]\n", __func__,
+                                               chan_map.hdr.opcode);
+               rc = -ETIMEDOUT;
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return rc;
+}
+
+int q6asm_enc_cfg_blk_qcelp(struct audio_client *ac, uint32_t frames_per_buf,
+               uint16_t min_rate, uint16_t max_rate,
+               uint16_t reduced_rate_level, uint16_t rate_modulation_cmd)
+{
+       struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+       int rc = 0;
+
+       pr_debug("%s:session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] reduced_rate_level[0x%4x]rate_modulation_cmd[0x%4x]",
+                __func__,
+               ac->session, frames_per_buf, min_rate, max_rate,
+               reduced_rate_level, rate_modulation_cmd);
+
+       q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+       enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+
+       enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+       enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+
+       enc_cfg.enc_blk.frames_per_buf = frames_per_buf;
+       enc_cfg.enc_blk.format_id = V13K_FS;
+       enc_cfg.enc_blk.cfg_size  = sizeof(struct asm_qcelp13_read_cfg);
+       enc_cfg.enc_blk.cfg.qcelp13.min_rate = min_rate;
+       enc_cfg.enc_blk.cfg.qcelp13.max_rate = max_rate;
+       enc_cfg.enc_blk.cfg.qcelp13.reduced_rate_level = reduced_rate_level;
+       enc_cfg.enc_blk.cfg.qcelp13.rate_modulation_cmd = rate_modulation_cmd;
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+       if (rc < 0) {
+               pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("timeout. waited for FORMAT_UPDATE\n");
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_evrc(struct audio_client *ac, uint32_t frames_per_buf,
+               uint16_t min_rate, uint16_t max_rate,
+               uint16_t rate_modulation_cmd)
+{
+       struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+       int rc = 0;
+
+       pr_debug("%s:session[%d]frames[%d]min_rate[0x%4x]max_rate[0x%4x] rate_modulation_cmd[0x%4x]",
+                __func__, ac->session,
+               frames_per_buf, min_rate, max_rate, rate_modulation_cmd);
+
+       q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+       enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+
+       enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+       enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+
+       enc_cfg.enc_blk.frames_per_buf = frames_per_buf;
+       enc_cfg.enc_blk.format_id = EVRC_FS;
+       enc_cfg.enc_blk.cfg_size  = sizeof(struct asm_evrc_read_cfg);
+       enc_cfg.enc_blk.cfg.evrc.min_rate = min_rate;
+       enc_cfg.enc_blk.cfg.evrc.max_rate = max_rate;
+       enc_cfg.enc_blk.cfg.evrc.rate_modulation_cmd = rate_modulation_cmd;
+       enc_cfg.enc_blk.cfg.evrc.reserved = 0;
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+       if (rc < 0) {
+               pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("timeout. waited for FORMAT_UPDATE\n");
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_amrnb(struct audio_client *ac, uint32_t frames_per_buf,
+                       uint16_t band_mode, uint16_t dtx_enable)
+{
+       struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+       int rc = 0;
+
+       pr_debug("%s:session[%d]frames[%d]band_mode[0x%4x]dtx_enable[0x%4x]",
+               __func__, ac->session, frames_per_buf, band_mode, dtx_enable);
+
+       q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+       enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+
+       enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+       enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+
+       enc_cfg.enc_blk.frames_per_buf = frames_per_buf;
+       enc_cfg.enc_blk.format_id = AMRNB_FS;
+       enc_cfg.enc_blk.cfg_size  = sizeof(struct asm_amrnb_read_cfg);
+       enc_cfg.enc_blk.cfg.amrnb.mode = band_mode;
+       enc_cfg.enc_blk.cfg.amrnb.dtx_mode = dtx_enable;
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+       if (rc < 0) {
+               pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("timeout. waited for FORMAT_UPDATE\n");
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_enc_cfg_blk_amrwb(struct audio_client *ac, uint32_t frames_per_buf,
+                       uint16_t band_mode, uint16_t dtx_enable)
+{
+       struct asm_stream_cmd_encdec_cfg_blk enc_cfg;
+       int rc = 0;
+
+       pr_debug("%s:session[%d]frames[%d]band_mode[0x%4x]dtx_enable[0x%4x]",
+               __func__, ac->session, frames_per_buf, band_mode, dtx_enable);
+
+       q6asm_add_hdr(ac, &enc_cfg.hdr, sizeof(enc_cfg), TRUE);
+
+       enc_cfg.hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM;
+
+       enc_cfg.param_id = ASM_ENCDEC_CFG_BLK_ID;
+       enc_cfg.param_size = sizeof(struct asm_encode_cfg_blk);
+
+       enc_cfg.enc_blk.frames_per_buf = frames_per_buf;
+       enc_cfg.enc_blk.format_id = AMRWB_FS;
+       enc_cfg.enc_blk.cfg_size  = sizeof(struct asm_amrwb_read_cfg);
+       enc_cfg.enc_blk.cfg.amrwb.mode = band_mode;
+       enc_cfg.enc_blk.cfg.amrwb.dtx_mode = dtx_enable;
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &enc_cfg);
+       if (rc < 0) {
+               pr_err("Comamnd %d failed\n", ASM_STREAM_CMD_SET_ENCDEC_PARAM);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("timeout. waited for FORMAT_UPDATE\n");
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_media_format_block_pcm(struct audio_client *ac,
+                               uint32_t rate, uint32_t channels)
+{
+       struct asm_stream_media_format_update fmt;
+       int rc = 0;
+
+       pr_debug("%s:session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
+               channels);
+
+       q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+       fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+       fmt.format = LINEAR_PCM;
+       fmt.cfg_size = sizeof(struct asm_pcm_cfg);
+       fmt.write_cfg.pcm_cfg.ch_cfg = channels;
+       fmt.write_cfg.pcm_cfg.bits_per_sample = 16;
+       fmt.write_cfg.pcm_cfg.sample_rate = rate;
+       fmt.write_cfg.pcm_cfg.is_signed = 1;
+       fmt.write_cfg.pcm_cfg.interleaved = 1;
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+       if (rc < 0) {
+               pr_err("%s:Comamnd open failed\n", __func__);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac,
+                               uint32_t rate, uint32_t channels)
+{
+       struct asm_stream_media_format_update fmt;
+       u8 *channel_mapping;
+       int rc = 0;
+
+       pr_debug("%s:session[%d]rate[%d]ch[%d]\n", __func__, ac->session, rate,
+               channels);
+
+       q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+       fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+       fmt.format = MULTI_CHANNEL_PCM;
+       fmt.cfg_size = sizeof(struct asm_multi_channel_pcm_fmt_blk);
+       fmt.write_cfg.multi_ch_pcm_cfg.num_channels = channels;
+       fmt.write_cfg.multi_ch_pcm_cfg.bits_per_sample = 16;
+       fmt.write_cfg.multi_ch_pcm_cfg.sample_rate = rate;
+       fmt.write_cfg.multi_ch_pcm_cfg.is_signed = 1;
+       fmt.write_cfg.multi_ch_pcm_cfg.is_interleaved = 1;
+       channel_mapping =
+               fmt.write_cfg.multi_ch_pcm_cfg.channel_mapping;
+
+       memset(channel_mapping, 0, PCM_FORMAT_MAX_NUM_CHANNEL);
+
+       if (channels == 1)  {
+               channel_mapping[0] = PCM_CHANNEL_FL;
+       } else if (channels == 2) {
+               channel_mapping[0] = PCM_CHANNEL_FL;
+               channel_mapping[1] = PCM_CHANNEL_FR;
+       } else if (channels == 4) {
+               channel_mapping[0] = PCM_CHANNEL_FL;
+               channel_mapping[1] = PCM_CHANNEL_FR;
+               channel_mapping[1] = PCM_CHANNEL_LB;
+               channel_mapping[1] = PCM_CHANNEL_RB;
+       } else if (channels == 6) {
+               channel_mapping[0] = PCM_CHANNEL_FL;
+               channel_mapping[1] = PCM_CHANNEL_FR;
+               channel_mapping[2] = PCM_CHANNEL_FC;
+               channel_mapping[3] = PCM_CHANNEL_LFE;
+               channel_mapping[4] = PCM_CHANNEL_LB;
+               channel_mapping[5] = PCM_CHANNEL_RB;
+       } else if (channels == 8) {
+               channel_mapping[0] = PCM_CHANNEL_FC;
+               channel_mapping[1] = PCM_CHANNEL_FL;
+               channel_mapping[2] = PCM_CHANNEL_FR;
+               channel_mapping[3] = PCM_CHANNEL_LB;
+               channel_mapping[4] = PCM_CHANNEL_RB;
+               channel_mapping[5] = PCM_CHANNEL_LFE;
+               channel_mapping[6] = PCM_CHANNEL_FLC;
+               channel_mapping[7] = PCM_CHANNEL_FRC;
+       } else {
+               pr_err("%s: ERROR.unsupported num_ch = %u\n", __func__,
+                               channels);
+               return -EINVAL;
+       }
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+       if (rc < 0) {
+               pr_err("%s:Comamnd open failed\n", __func__);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_media_format_block_aac(struct audio_client *ac,
+                               struct asm_aac_cfg *cfg)
+{
+       struct asm_stream_media_format_update fmt;
+       int rc = 0;
+
+       pr_debug("%s:session[%d]rate[%d]ch[%d]\n", __func__, ac->session,
+               cfg->sample_rate, cfg->ch_cfg);
+
+       q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+       fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+       fmt.format = MPEG4_AAC;
+       fmt.cfg_size = sizeof(struct asm_aac_cfg);
+       fmt.write_cfg.aac_cfg.format = cfg->format;
+       fmt.write_cfg.aac_cfg.aot = cfg->aot;
+       fmt.write_cfg.aac_cfg.ep_config = cfg->ep_config;
+       fmt.write_cfg.aac_cfg.section_data_resilience =
+                                       cfg->section_data_resilience;
+       fmt.write_cfg.aac_cfg.scalefactor_data_resilience =
+                                       cfg->scalefactor_data_resilience;
+       fmt.write_cfg.aac_cfg.spectral_data_resilience =
+                                       cfg->spectral_data_resilience;
+       fmt.write_cfg.aac_cfg.ch_cfg = cfg->ch_cfg;
+       fmt.write_cfg.aac_cfg.sample_rate = cfg->sample_rate;
+       pr_info("%s:format=%x cfg_size=%d aac-cfg=%x aot=%d ch=%d sr=%d\n",
+                       __func__, fmt.format, fmt.cfg_size,
+                       fmt.write_cfg.aac_cfg.format,
+                       fmt.write_cfg.aac_cfg.aot,
+                       fmt.write_cfg.aac_cfg.ch_cfg,
+                       fmt.write_cfg.aac_cfg.sample_rate);
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+       if (rc < 0) {
+               pr_err("%s:Comamnd open failed\n", __func__);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_media_format_block_amrwbplus(struct audio_client *ac,
+                                       struct asm_amrwbplus_cfg *cfg)
+{
+       struct asm_stream_media_format_update fmt;
+       int rc = 0;
+       pr_debug("q6asm_media_format_block_amrwbplus");
+
+       pr_debug("%s:session[%d]band-mode[%d]frame-fmt[%d]ch[%d]\n",
+               __func__,
+               ac->session,
+               cfg->amr_band_mode,
+               cfg->amr_frame_fmt,
+               cfg->num_channels);
+
+       q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+       fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+       fmt.format = AMR_WB_PLUS;
+       fmt.cfg_size = cfg->size_bytes;
+
+       fmt.write_cfg.amrwbplus_cfg.size_bytes    = cfg->size_bytes;
+       fmt.write_cfg.amrwbplus_cfg.version       = cfg->version;
+       fmt.write_cfg.amrwbplus_cfg.num_channels  = cfg->num_channels;
+       fmt.write_cfg.amrwbplus_cfg.amr_band_mode = cfg->amr_band_mode;
+       fmt.write_cfg.amrwbplus_cfg.amr_dtx_mode  = cfg->amr_dtx_mode;
+       fmt.write_cfg.amrwbplus_cfg.amr_frame_fmt = cfg->amr_frame_fmt;
+       fmt.write_cfg.amrwbplus_cfg.amr_lsf_idx   = cfg->amr_lsf_idx;
+
+       pr_debug("%s: num_channels=%x amr_band_mode=%d amr_frame_fmt=%d\n",
+                       __func__,
+                       cfg->num_channels,
+                       cfg->amr_band_mode,
+                       cfg->amr_frame_fmt);
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+       if (rc < 0) {
+               pr_err("%s:Comamnd media format update failed..\n", __func__);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                               (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+int q6asm_media_format_block_multi_aac(struct audio_client *ac,
+                               struct asm_aac_cfg *cfg)
+{
+       struct asm_stream_media_format_update fmt;
+       int rc = 0;
+
+       pr_debug("%s:session[%d]rate[%d]ch[%d]\n", __func__, ac->session,
+               cfg->sample_rate, cfg->ch_cfg);
+
+       q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+       fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+       fmt.format = MPEG4_MULTI_AAC;
+       fmt.cfg_size = sizeof(struct asm_aac_cfg);
+       fmt.write_cfg.aac_cfg.format = cfg->format;
+       fmt.write_cfg.aac_cfg.aot = cfg->aot;
+       fmt.write_cfg.aac_cfg.ep_config = cfg->ep_config;
+       fmt.write_cfg.aac_cfg.section_data_resilience =
+                                       cfg->section_data_resilience;
+       fmt.write_cfg.aac_cfg.scalefactor_data_resilience =
+                                       cfg->scalefactor_data_resilience;
+       fmt.write_cfg.aac_cfg.spectral_data_resilience =
+                                       cfg->spectral_data_resilience;
+       fmt.write_cfg.aac_cfg.ch_cfg = cfg->ch_cfg;
+       fmt.write_cfg.aac_cfg.sample_rate = cfg->sample_rate;
+       pr_info("%s:format=%x cfg_size=%d aac-cfg=%x aot=%d ch=%d sr=%d\n",
+                       __func__, fmt.format, fmt.cfg_size,
+                       fmt.write_cfg.aac_cfg.format,
+                       fmt.write_cfg.aac_cfg.aot,
+                       fmt.write_cfg.aac_cfg.ch_cfg,
+                       fmt.write_cfg.aac_cfg.sample_rate);
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+       if (rc < 0) {
+               pr_err("%s:Comamnd open failed\n", __func__);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+
+
+int q6asm_media_format_block(struct audio_client *ac, uint32_t format)
+{
+
+       struct asm_stream_media_format_update fmt;
+       int rc = 0;
+
+       pr_debug("%s:session[%d] format[0x%x]\n", __func__,
+                       ac->session, format);
+
+       q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+       fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+       switch (format) {
+       case FORMAT_V13K:
+               fmt.format = V13K_FS;
+               break;
+       case FORMAT_EVRC:
+               fmt.format = EVRC_FS;
+               break;
+       case FORMAT_AMRWB:
+               fmt.format = AMRWB_FS;
+               break;
+       case FORMAT_AMR_WB_PLUS:
+               fmt.format = AMR_WB_PLUS;
+               break;
+       case FORMAT_AMRNB:
+               fmt.format = AMRNB_FS;
+               break;
+       case FORMAT_MP3:
+               fmt.format = MP3;
+               break;
+       case FORMAT_DTS:
+               fmt.format = DTS;
+               break;
+       case FORMAT_DTS_LBR:
+               fmt.format = DTS_LBR;
+               break;
+       default:
+               pr_err("Invalid format[%d]\n", format);
+               goto fail_cmd;
+       }
+       fmt.cfg_size = 0;
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+       if (rc < 0) {
+               pr_err("%s:Comamnd open failed\n", __func__);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+               (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_media_format_block_wma(struct audio_client *ac,
+                               void *cfg)
+{
+       struct asm_stream_media_format_update fmt;
+       struct asm_wma_cfg *wma_cfg = (struct asm_wma_cfg *)cfg;
+       int rc = 0;
+
+       pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d], balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x]\n",
+               ac->session, wma_cfg->format_tag, wma_cfg->sample_rate,
+               wma_cfg->ch_cfg, wma_cfg->avg_bytes_per_sec,
+               wma_cfg->block_align, wma_cfg->valid_bits_per_sample,
+               wma_cfg->ch_mask, wma_cfg->encode_opt);
+
+       q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+       fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+       fmt.format = WMA_V9;
+       fmt.cfg_size = sizeof(struct asm_wma_cfg);
+       fmt.write_cfg.wma_cfg.format_tag = wma_cfg->format_tag;
+       fmt.write_cfg.wma_cfg.ch_cfg = wma_cfg->ch_cfg;
+       fmt.write_cfg.wma_cfg.sample_rate = wma_cfg->sample_rate;
+       fmt.write_cfg.wma_cfg.avg_bytes_per_sec = wma_cfg->avg_bytes_per_sec;
+       fmt.write_cfg.wma_cfg.block_align = wma_cfg->block_align;
+       fmt.write_cfg.wma_cfg.valid_bits_per_sample =
+                       wma_cfg->valid_bits_per_sample;
+       fmt.write_cfg.wma_cfg.ch_mask = wma_cfg->ch_mask;
+       fmt.write_cfg.wma_cfg.encode_opt = wma_cfg->encode_opt;
+       fmt.write_cfg.wma_cfg.adv_encode_opt = 0;
+       fmt.write_cfg.wma_cfg.adv_encode_opt2 = 0;
+       fmt.write_cfg.wma_cfg.drc_peak_ref = 0;
+       fmt.write_cfg.wma_cfg.drc_peak_target = 0;
+       fmt.write_cfg.wma_cfg.drc_ave_ref = 0;
+       fmt.write_cfg.wma_cfg.drc_ave_target = 0;
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+       if (rc < 0) {
+               pr_err("%s:Comamnd open failed\n", __func__);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_media_format_block_wmapro(struct audio_client *ac,
+                               void *cfg)
+{
+       struct asm_stream_media_format_update fmt;
+       struct asm_wmapro_cfg *wmapro_cfg = (struct asm_wmapro_cfg *)cfg;
+       int rc = 0;
+
+       pr_debug("session[%d]format_tag[0x%4x] rate[%d] ch[0x%4x] bps[%d], balign[0x%4x], bit_sample[0x%4x], ch_msk[%d], enc_opt[0x%4x], adv_enc_opt[0x%4x], adv_enc_opt2[0x%8x]\n",
+               ac->session, wmapro_cfg->format_tag, wmapro_cfg->sample_rate,
+               wmapro_cfg->ch_cfg,  wmapro_cfg->avg_bytes_per_sec,
+               wmapro_cfg->block_align, wmapro_cfg->valid_bits_per_sample,
+               wmapro_cfg->ch_mask, wmapro_cfg->encode_opt,
+               wmapro_cfg->adv_encode_opt, wmapro_cfg->adv_encode_opt2);
+
+       q6asm_add_hdr(ac, &fmt.hdr, sizeof(fmt), TRUE);
+
+       fmt.hdr.opcode = ASM_DATA_CMD_MEDIA_FORMAT_UPDATE;
+
+       fmt.format = WMA_V10PRO;
+       fmt.cfg_size = sizeof(struct asm_wmapro_cfg);
+       fmt.write_cfg.wmapro_cfg.format_tag = wmapro_cfg->format_tag;
+       fmt.write_cfg.wmapro_cfg.ch_cfg = wmapro_cfg->ch_cfg;
+       fmt.write_cfg.wmapro_cfg.sample_rate = wmapro_cfg->sample_rate;
+       fmt.write_cfg.wmapro_cfg.avg_bytes_per_sec =
+                               wmapro_cfg->avg_bytes_per_sec;
+       fmt.write_cfg.wmapro_cfg.block_align = wmapro_cfg->block_align;
+       fmt.write_cfg.wmapro_cfg.valid_bits_per_sample =
+                               wmapro_cfg->valid_bits_per_sample;
+       fmt.write_cfg.wmapro_cfg.ch_mask = wmapro_cfg->ch_mask;
+       fmt.write_cfg.wmapro_cfg.encode_opt = wmapro_cfg->encode_opt;
+       fmt.write_cfg.wmapro_cfg.adv_encode_opt = wmapro_cfg->adv_encode_opt;
+       fmt.write_cfg.wmapro_cfg.adv_encode_opt2 = wmapro_cfg->adv_encode_opt2;
+       fmt.write_cfg.wmapro_cfg.drc_peak_ref = 0;
+       fmt.write_cfg.wmapro_cfg.drc_peak_target = 0;
+       fmt.write_cfg.wmapro_cfg.drc_ave_ref = 0;
+       fmt.write_cfg.wmapro_cfg.drc_ave_target = 0;
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &fmt);
+       if (rc < 0) {
+               pr_err("%s:Comamnd open failed\n", __func__);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s:timeout. waited for FORMAT_UPDATE\n", __func__);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_memory_map(struct audio_client *ac, uint32_t buf_add, int dir,
+                                       uint32_t bufsz, uint32_t bufcnt)
+{
+       struct asm_stream_cmd_memory_map mem_map;
+       int rc = 0;
+
+       if (!ac || ac->apr == NULL || this_mmap.apr == NULL) {
+               pr_err("APR handle NULL\n");
+               return -EINVAL;
+       }
+
+       pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+       mem_map.hdr.opcode = ASM_SESSION_CMD_MEMORY_MAP;
+
+       mem_map.buf_add = buf_add;
+       mem_map.buf_size = bufsz * bufcnt;
+       mem_map.mempool_id = 0; /* EBI */
+       mem_map.reserved = 0;
+
+       q6asm_add_mmaphdr(&mem_map.hdr,
+                       sizeof(struct asm_stream_cmd_memory_map), TRUE);
+
+       pr_debug("buf add[%x]  buf_add_parameter[%x]\n",
+                                       mem_map.buf_add, buf_add);
+
+       rc = apr_send_pkt(this_mmap.apr, (uint32_t *) &mem_map);
+       if (rc < 0) {
+               pr_err("mem_map op[0x%x]rc[%d]\n",
+                               mem_map.hdr.opcode, rc);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+
+       rc = wait_event_timeout(this_mmap.cmd_wait,
+               (atomic_read(&this_mmap.cmd_state) == 0), 5 * HZ);
+       if (!rc) {
+               pr_err("timeout. waited for memory_map\n");
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       rc = 0;
+fail_cmd:
+       return rc;
+}
+
+int q6asm_memory_unmap(struct audio_client *ac, uint32_t buf_add, int dir)
+{
+       struct asm_stream_cmd_memory_unmap mem_unmap;
+       int rc = 0;
+
+       if (!ac || ac->apr == NULL || this_mmap.apr == NULL) {
+               pr_err("APR handle NULL\n");
+               return -EINVAL;
+       }
+       pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+       q6asm_add_mmaphdr(&mem_unmap.hdr,
+                       sizeof(struct asm_stream_cmd_memory_unmap), TRUE);
+       mem_unmap.hdr.opcode = ASM_SESSION_CMD_MEMORY_UNMAP;
+       mem_unmap.buf_add = buf_add;
+
+       rc = apr_send_pkt(this_mmap.apr, (uint32_t *) &mem_unmap);
+       if (rc < 0) {
+               pr_err("mem_unmap op[0x%x]rc[%d]\n",
+                                       mem_unmap.hdr.opcode, rc);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+
+       rc = wait_event_timeout(this_mmap.cmd_wait,
+                       (atomic_read(&this_mmap.cmd_state) == 0), 5 * HZ);
+       if (!rc) {
+               pr_err("timeout. waited for memory_map\n");
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       rc = 0;
+fail_cmd:
+       return rc;
+}
+
+int q6asm_set_lrgain(struct audio_client *ac, int left_gain, int right_gain)
+{
+       void *vol_cmd = NULL;
+       void *payload = NULL;
+       struct asm_pp_params_command *cmd = NULL;
+       struct asm_lrchannel_gain_params *lrgain = NULL;
+       int sz = 0;
+       int rc  = 0;
+
+       sz = sizeof(struct asm_pp_params_command) +
+               + sizeof(struct asm_lrchannel_gain_params);
+       vol_cmd = kzalloc(sz, GFP_KERNEL);
+       if (vol_cmd == NULL) {
+               pr_err("%s[%d]: Mem alloc failed\n", __func__, ac->session);
+               rc = -EINVAL;
+               return rc;
+       }
+       cmd = (struct asm_pp_params_command *)vol_cmd;
+       q6asm_add_hdr_async(ac, &cmd->hdr, sz, TRUE);
+       cmd->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS;
+       cmd->payload = NULL;
+       cmd->payload_size = sizeof(struct  asm_pp_param_data_hdr) +
+                               sizeof(struct asm_lrchannel_gain_params);
+       cmd->params.module_id = VOLUME_CONTROL_MODULE_ID;
+       cmd->params.param_id = L_R_CHANNEL_GAIN_PARAM_ID;
+       cmd->params.param_size = sizeof(struct asm_lrchannel_gain_params);
+       cmd->params.reserved = 0;
+
+       payload = (u8 *)(vol_cmd + sizeof(struct asm_pp_params_command));
+       lrgain = (struct asm_lrchannel_gain_params *)payload;
+
+       lrgain->left_gain = left_gain;
+       lrgain->right_gain = right_gain;
+       rc = apr_send_pkt(ac->apr, (uint32_t *) vol_cmd);
+       if (rc < 0) {
+               pr_err("%s: Volume Command failed\n", __func__);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s: timeout in sending volume command to apr\n",
+                       __func__);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       rc = 0;
+fail_cmd:
+       kfree(vol_cmd);
+       return rc;
+}
+
+static int q6asm_memory_map_regions(struct audio_client *ac, int dir,
+                               uint32_t bufsz, uint32_t bufcnt)
+{
+       struct   asm_stream_cmd_memory_map_regions *mmap_regions = NULL;
+       struct asm_memory_map_regions *mregions = NULL;
+       struct audio_port_data *port = NULL;
+       struct audio_buffer *ab = NULL;
+       void    *mmap_region_cmd = NULL;
+       void    *payload = NULL;
+       int     rc = 0;
+       int     i = 0;
+       int     cmd_size = 0;
+
+       if (!ac || ac->apr == NULL || this_mmap.apr == NULL) {
+               pr_err("APR handle NULL\n");
+               return -EINVAL;
+       }
+       pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+       cmd_size = sizeof(struct asm_stream_cmd_memory_map_regions)
+                       + sizeof(struct asm_memory_map_regions) * bufcnt;
+
+       mmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+       if (mmap_region_cmd == NULL) {
+               pr_err("%s: Mem alloc failed\n", __func__);
+               rc = -EINVAL;
+               return rc;
+       }
+       mmap_regions = (struct asm_stream_cmd_memory_map_regions *)
+                                                       mmap_region_cmd;
+       q6asm_add_mmaphdr(&mmap_regions->hdr, cmd_size, TRUE);
+       mmap_regions->hdr.opcode = ASM_SESSION_CMD_MEMORY_MAP_REGIONS;
+       mmap_regions->mempool_id = 0;
+       mmap_regions->nregions = bufcnt & 0x00ff;
+       pr_debug("map_regions->nregions = %d\n", mmap_regions->nregions);
+       payload = ((u8 *) mmap_region_cmd +
+               sizeof(struct asm_stream_cmd_memory_map_regions));
+       mregions = (struct asm_memory_map_regions *)payload;
+
+       port = &ac->port[dir];
+       for (i = 0; i < bufcnt; i++) {
+               ab = &port->buf[i];
+               mregions->phys = ab->phys;
+               mregions->buf_size = ab->size;
+               ++mregions;
+       }
+
+       rc = apr_send_pkt(this_mmap.apr, (uint32_t *) mmap_region_cmd);
+       if (rc < 0) {
+               pr_err("mmap_regions op[0x%x]rc[%d]\n",
+                                       mmap_regions->hdr.opcode, rc);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+
+       rc = wait_event_timeout(this_mmap.cmd_wait,
+                       (atomic_read(&this_mmap.cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("timeout. waited for memory_map\n");
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       rc = 0;
+fail_cmd:
+       kfree(mmap_region_cmd);
+       return rc;
+}
+
+static int q6asm_memory_unmap_regions(struct audio_client *ac, int dir,
+                               uint32_t bufsz, uint32_t bufcnt)
+{
+       struct asm_stream_cmd_memory_unmap_regions *unmap_regions = NULL;
+       struct asm_memory_unmap_regions *mregions = NULL;
+       struct audio_port_data *port = NULL;
+       struct audio_buffer *ab = NULL;
+       void    *unmap_region_cmd = NULL;
+       void    *payload = NULL;
+       int     rc = 0;
+       int     i = 0;
+       int     cmd_size = 0;
+
+       if (!ac || ac->apr == NULL || this_mmap.apr == NULL) {
+               pr_err("APR handle NULL\n");
+               return -EINVAL;
+       }
+       pr_debug("%s: Session[%d]\n", __func__, ac->session);
+
+       cmd_size = sizeof(struct asm_stream_cmd_memory_unmap_regions) +
+                       sizeof(struct asm_memory_unmap_regions) * bufcnt;
+
+       unmap_region_cmd = kzalloc(cmd_size, GFP_KERNEL);
+       if (unmap_region_cmd == NULL) {
+               pr_err("%s: Mem alloc failed\n", __func__);
+               rc = -EINVAL;
+               return rc;
+       }
+       unmap_regions = (struct asm_stream_cmd_memory_unmap_regions *)
+                                                       unmap_region_cmd;
+       q6asm_add_mmaphdr(&unmap_regions->hdr, cmd_size, TRUE);
+       unmap_regions->hdr.opcode = ASM_SESSION_CMD_MEMORY_UNMAP_REGIONS;
+       unmap_regions->nregions = bufcnt & 0x00ff;
+       pr_debug("unmap_regions->nregions = %d\n", unmap_regions->nregions);
+       payload = ((u8 *) unmap_region_cmd +
+                       sizeof(struct asm_stream_cmd_memory_unmap_regions));
+       mregions = (struct asm_memory_unmap_regions *)payload;
+       port = &ac->port[dir];
+       for (i = 0; i < bufcnt; i++) {
+               ab = &port->buf[i];
+               mregions->phys = ab->phys;
+               ++mregions;
+       }
+
+       rc = apr_send_pkt(this_mmap.apr, (uint32_t *) unmap_region_cmd);
+       if (rc < 0) {
+               pr_err("mmap_regions op[0x%x]rc[%d]\n",
+                                       unmap_regions->hdr.opcode, rc);
+               goto fail_cmd;
+       }
+
+       rc = wait_event_timeout(this_mmap.cmd_wait,
+                       (atomic_read(&this_mmap.cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("timeout. waited for memory_unmap\n");
+               goto fail_cmd;
+       }
+       rc = 0;
+
+fail_cmd:
+       kfree(unmap_region_cmd);
+       return rc;
+}
+
+int q6asm_set_mute(struct audio_client *ac, int muteflag)
+{
+       void *vol_cmd = NULL;
+       void *payload = NULL;
+       struct asm_pp_params_command *cmd = NULL;
+       struct asm_mute_params *mute = NULL;
+       int sz = 0;
+       int rc  = 0;
+
+       sz = sizeof(struct asm_pp_params_command) +
+               + sizeof(struct asm_mute_params);
+       vol_cmd = kzalloc(sz, GFP_KERNEL);
+       if (vol_cmd == NULL) {
+               pr_err("%s[%d]: Mem alloc failed\n", __func__, ac->session);
+               rc = -EINVAL;
+               return rc;
+       }
+       cmd = (struct asm_pp_params_command *)vol_cmd;
+       q6asm_add_hdr_async(ac, &cmd->hdr, sz, TRUE);
+       cmd->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS;
+       cmd->payload = NULL;
+       cmd->payload_size = sizeof(struct  asm_pp_param_data_hdr) +
+                               sizeof(struct asm_mute_params);
+       cmd->params.module_id = VOLUME_CONTROL_MODULE_ID;
+       cmd->params.param_id = MUTE_CONFIG_PARAM_ID;
+       cmd->params.param_size = sizeof(struct asm_mute_params);
+       cmd->params.reserved = 0;
+
+       payload = (u8 *)(vol_cmd + sizeof(struct asm_pp_params_command));
+       mute = (struct asm_mute_params *)payload;
+
+       mute->muteflag = muteflag;
+       rc = apr_send_pkt(ac->apr, (uint32_t *) vol_cmd);
+       if (rc < 0) {
+               pr_err("%s: Mute Command failed\n", __func__);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s: timeout in sending mute command to apr\n",
+                       __func__);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       rc = 0;
+fail_cmd:
+       kfree(vol_cmd);
+       return rc;
+}
+
+int q6asm_set_volume(struct audio_client *ac, int volume)
+{
+       void *vol_cmd = NULL;
+       void *payload = NULL;
+       struct asm_pp_params_command *cmd = NULL;
+       struct asm_master_gain_params *mgain = NULL;
+       int sz = 0;
+       int rc  = 0;
+
+       sz = sizeof(struct asm_pp_params_command) +
+               + sizeof(struct asm_master_gain_params);
+       vol_cmd = kzalloc(sz, GFP_KERNEL);
+       if (vol_cmd == NULL) {
+               pr_err("%s[%d]: Mem alloc failed\n", __func__, ac->session);
+               rc = -EINVAL;
+               return rc;
+       }
+       cmd = (struct asm_pp_params_command *)vol_cmd;
+       q6asm_add_hdr_async(ac, &cmd->hdr, sz, TRUE);
+       cmd->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS;
+       cmd->payload = NULL;
+       cmd->payload_size = sizeof(struct  asm_pp_param_data_hdr) +
+                               sizeof(struct asm_master_gain_params);
+       cmd->params.module_id = VOLUME_CONTROL_MODULE_ID;
+       cmd->params.param_id = MASTER_GAIN_PARAM_ID;
+       cmd->params.param_size = sizeof(struct asm_master_gain_params);
+       cmd->params.reserved = 0;
+
+       payload = (u8 *)(vol_cmd + sizeof(struct asm_pp_params_command));
+       mgain = (struct asm_master_gain_params *)payload;
+
+       mgain->master_gain = volume;
+       mgain->padding = 0x00;
+       rc = apr_send_pkt(ac->apr, (uint32_t *) vol_cmd);
+       if (rc < 0) {
+               pr_err("%s: Volume Command failed\n", __func__);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s: timeout in sending volume command to apr\n",
+                       __func__);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       rc = 0;
+fail_cmd:
+       kfree(vol_cmd);
+       return rc;
+}
+
+int q6asm_set_softpause(struct audio_client *ac,
+                       struct asm_softpause_params *pause_param)
+{
+       void *vol_cmd = NULL;
+       void *payload = NULL;
+       struct asm_pp_params_command *cmd = NULL;
+       struct asm_softpause_params *params = NULL;
+       int sz = 0;
+       int rc  = 0;
+
+       sz = sizeof(struct asm_pp_params_command) +
+               + sizeof(struct asm_softpause_params);
+       vol_cmd = kzalloc(sz, GFP_KERNEL);
+       if (vol_cmd == NULL) {
+               pr_err("%s[%d]: Mem alloc failed\n", __func__, ac->session);
+               rc = -EINVAL;
+               return rc;
+       }
+       cmd = (struct asm_pp_params_command *)vol_cmd;
+       q6asm_add_hdr_async(ac, &cmd->hdr, sz, TRUE);
+       cmd->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS;
+       cmd->payload = NULL;
+       cmd->payload_size = sizeof(struct  asm_pp_param_data_hdr) +
+                               sizeof(struct asm_softpause_params);
+       cmd->params.module_id = VOLUME_CONTROL_MODULE_ID;
+       cmd->params.param_id = SOFT_PAUSE_PARAM_ID;
+       cmd->params.param_size = sizeof(struct asm_softpause_params);
+       cmd->params.reserved = 0;
+
+       payload = (u8 *)(vol_cmd + sizeof(struct asm_pp_params_command));
+       params = (struct asm_softpause_params *)payload;
+
+       params->enable = pause_param->enable;
+       params->period = pause_param->period;
+       params->step = pause_param->step;
+       params->rampingcurve = pause_param->rampingcurve;
+       pr_debug("%s: soft Pause Command: enable = %d, period = %d, step = %d, curve = %d\n",
+                        __func__, params->enable,
+                        params->period, params->step, params->rampingcurve);
+       rc = apr_send_pkt(ac->apr, (uint32_t *) vol_cmd);
+       if (rc < 0) {
+               pr_err("%s: Volume Command(soft_pause) failed\n", __func__);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s: timeout in sending volume command(soft_pause) to apr\n",
+                                                __func__);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       rc = 0;
+fail_cmd:
+       kfree(vol_cmd);
+       return rc;
+}
+
+int q6asm_set_softvolume(struct audio_client *ac,
+                       struct asm_softvolume_params *softvol_param)
+{
+       void *vol_cmd = NULL;
+       void *payload = NULL;
+       struct asm_pp_params_command *cmd = NULL;
+       struct asm_softvolume_params *params = NULL;
+       int sz = 0;
+       int rc  = 0;
+
+       sz = sizeof(struct asm_pp_params_command) +
+               + sizeof(struct asm_softvolume_params);
+       vol_cmd = kzalloc(sz, GFP_KERNEL);
+       if (vol_cmd == NULL) {
+               pr_err("%s[%d]: Mem alloc failed\n", __func__, ac->session);
+               rc = -EINVAL;
+               return rc;
+       }
+       cmd = (struct asm_pp_params_command *)vol_cmd;
+       q6asm_add_hdr_async(ac, &cmd->hdr, sz, TRUE);
+       cmd->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS;
+       cmd->payload = NULL;
+       cmd->payload_size = sizeof(struct  asm_pp_param_data_hdr) +
+                               sizeof(struct asm_softvolume_params);
+       cmd->params.module_id = VOLUME_CONTROL_MODULE_ID;
+       cmd->params.param_id = SOFT_VOLUME_PARAM_ID;
+       cmd->params.param_size = sizeof(struct asm_softvolume_params);
+       cmd->params.reserved = 0;
+
+       payload = (u8 *)(vol_cmd + sizeof(struct asm_pp_params_command));
+       params = (struct asm_softvolume_params *)payload;
+
+       params->period = softvol_param->period;
+       params->step = softvol_param->step;
+       params->rampingcurve = softvol_param->rampingcurve;
+       pr_debug("%s: soft Volume:opcode = %d,payload_sz =%d,module_id =%d, param_id = %d, param_sz = %d\n",
+                        __func__,
+                       cmd->hdr.opcode, cmd->payload_size,
+                       cmd->params.module_id, cmd->params.param_id,
+                       cmd->params.param_size);
+       pr_debug("%s: soft Volume Command: period = %d, step = %d, curve = %d\n",
+                        __func__, params->period,
+                        params->step, params->rampingcurve);
+       rc = apr_send_pkt(ac->apr, (uint32_t *) vol_cmd);
+       if (rc < 0) {
+               pr_err("%s: Volume Command(soft_volume) failed\n", __func__);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s: timeout in sending volume command(soft_volume) to apr\n",
+                                                        __func__);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       rc = 0;
+fail_cmd:
+       kfree(vol_cmd);
+       return rc;
+}
+
+int q6asm_equalizer(struct audio_client *ac, void *eq)
+{
+       void *eq_cmd = NULL;
+       void *payload = NULL;
+       struct asm_pp_params_command *cmd = NULL;
+       struct asm_equalizer_params *equalizer = NULL;
+       struct msm_audio_eq_stream_config *eq_params = NULL;
+       int i  = 0;
+       int sz = 0;
+       int rc  = 0;
+
+       sz = sizeof(struct asm_pp_params_command) +
+               + sizeof(struct asm_equalizer_params);
+       eq_cmd = kzalloc(sz, GFP_KERNEL);
+       if (eq_cmd == NULL) {
+               pr_err("%s[%d]: Mem alloc failed\n", __func__, ac->session);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       eq_params = (struct msm_audio_eq_stream_config *) eq;
+       cmd = (struct asm_pp_params_command *)eq_cmd;
+       q6asm_add_hdr(ac, &cmd->hdr, sz, TRUE);
+       cmd->hdr.opcode = ASM_STREAM_CMD_SET_PP_PARAMS;
+       cmd->payload = NULL;
+       cmd->payload_size = sizeof(struct  asm_pp_param_data_hdr) +
+                               sizeof(struct asm_equalizer_params);
+       cmd->params.module_id = EQUALIZER_MODULE_ID;
+       cmd->params.param_id = EQUALIZER_PARAM_ID;
+       cmd->params.param_size = sizeof(struct asm_equalizer_params);
+       cmd->params.reserved = 0;
+       payload = (u8 *)(eq_cmd + sizeof(struct asm_pp_params_command));
+       equalizer = (struct asm_equalizer_params *)payload;
+
+       equalizer->enable = eq_params->enable;
+       equalizer->num_bands = eq_params->num_bands;
+       pr_debug("%s: enable:%d numbands:%d\n", __func__, eq_params->enable,
+                                                       eq_params->num_bands);
+       for (i = 0; i < eq_params->num_bands; i++) {
+               equalizer->eq_bands[i].band_idx =
+                                       eq_params->eq_bands[i].band_idx;
+               equalizer->eq_bands[i].filter_type =
+                                       eq_params->eq_bands[i].filter_type;
+               equalizer->eq_bands[i].center_freq_hz =
+                                       eq_params->eq_bands[i].center_freq_hz;
+               equalizer->eq_bands[i].filter_gain =
+                                       eq_params->eq_bands[i].filter_gain;
+               equalizer->eq_bands[i].q_factor =
+                                       eq_params->eq_bands[i].q_factor;
+               pr_debug("%s: filter_type:%u bandnum:%d\n", __func__,
+                               eq_params->eq_bands[i].filter_type, i);
+               pr_debug("%s: center_freq_hz:%u bandnum:%d\n", __func__,
+                               eq_params->eq_bands[i].center_freq_hz, i);
+               pr_debug("%s: filter_gain:%d bandnum:%d\n", __func__,
+                               eq_params->eq_bands[i].filter_gain, i);
+               pr_debug("%s: q_factor:%d bandnum:%d\n", __func__,
+                               eq_params->eq_bands[i].q_factor, i);
+       }
+       rc = apr_send_pkt(ac->apr, (uint32_t *) eq_cmd);
+       if (rc < 0) {
+               pr_err("%s: Equalizer Command failed\n", __func__);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+
+       rc = wait_event_timeout(ac->cmd_wait,
+                       (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s: timeout in sending equalizer command to apr\n",
+                       __func__);
+               rc = -EINVAL;
+               goto fail_cmd;
+       }
+       rc = 0;
+fail_cmd:
+       kfree(eq_cmd);
+       return rc;
+}
+
+int q6asm_read(struct audio_client *ac)
+{
+       struct asm_stream_cmd_read read;
+       struct audio_buffer        *ab;
+       int dsp_buf;
+       struct audio_port_data     *port;
+       int rc;
+       if (!ac || ac->apr == NULL) {
+               pr_err("APR handle NULL\n");
+               return -EINVAL;
+       }
+       if (ac->io_mode & SYNC_IO_MODE) {
+               port = &ac->port[OUT];
+
+               q6asm_add_hdr(ac, &read.hdr, sizeof(read), FALSE);
+
+               mutex_lock(&port->lock);
+
+               dsp_buf = port->dsp_buf;
+               ab = &port->buf[dsp_buf];
+
+               pr_debug("%s:session[%d]dsp-buf[%d][%p]cpu_buf[%d][%p]\n",
+                                       __func__,
+                                       ac->session,
+                                       dsp_buf,
+                                       (void *)port->buf[dsp_buf].data,
+                                       port->cpu_buf,
+                                       (void *)port->buf[port->cpu_buf].phys);
+
+               read.hdr.opcode = ASM_DATA_CMD_READ;
+               read.buf_add = ab->phys;
+               read.buf_size = ab->size;
+               read.uid = port->dsp_buf;
+               read.hdr.token = port->dsp_buf;
+
+               port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
+               mutex_unlock(&port->lock);
+               pr_debug("%s:buf add[0x%x] token[%d] uid[%d]\n", __func__,
+                                               read.buf_add,
+                                               read.hdr.token,
+                                               read.uid);
+               rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+               if (rc < 0) {
+                       pr_err("read op[0x%x]rc[%d]\n", read.hdr.opcode, rc);
+                       goto fail_cmd;
+               }
+               return 0;
+       }
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_read_nolock(struct audio_client *ac)
+{
+       struct asm_stream_cmd_read read;
+       struct audio_buffer        *ab;
+       int dsp_buf;
+       struct audio_port_data     *port;
+       int rc;
+       if (!ac || ac->apr == NULL) {
+               pr_err("APR handle NULL\n");
+               return -EINVAL;
+       }
+       if (ac->io_mode & SYNC_IO_MODE) {
+               port = &ac->port[OUT];
+
+               q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
+
+
+               dsp_buf = port->dsp_buf;
+               ab = &port->buf[dsp_buf];
+
+               pr_debug("%s:session[%d]dsp-buf[%d][%p]cpu_buf[%d][%p]\n",
+                                       __func__,
+                                       ac->session,
+                                       dsp_buf,
+                                       (void *)port->buf[dsp_buf].data,
+                                       port->cpu_buf,
+                                       (void *)port->buf[port->cpu_buf].phys);
+
+               read.hdr.opcode = ASM_DATA_CMD_READ;
+               read.buf_add = ab->phys;
+               read.buf_size = ab->size;
+               read.uid = port->dsp_buf;
+               read.hdr.token = port->dsp_buf;
+
+               port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
+               pr_info("%s:buf add[0x%x] token[%d] uid[%d]\n", __func__,
+                                       read.buf_add,
+                                       read.hdr.token,
+                                       read.uid);
+               rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+               if (rc < 0) {
+                       pr_err("read op[0x%x]rc[%d]\n", read.hdr.opcode, rc);
+                       goto fail_cmd;
+               }
+               return 0;
+       }
+fail_cmd:
+       return -EINVAL;
+}
+
+
+static void q6asm_add_hdr_async(struct audio_client *ac, struct apr_hdr *hdr,
+                       uint32_t pkt_size, uint32_t cmd_flg)
+{
+       pr_debug("session=%d pkt size=%d cmd_flg=%d\n", pkt_size, cmd_flg,
+               ac->session);
+       hdr->hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \
+                               APR_HDR_LEN(sizeof(struct apr_hdr)),\
+                               APR_PKT_VER);
+       hdr->src_svc = ((struct apr_svc *)ac->apr)->id;
+       hdr->src_domain = APR_DOMAIN_APPS;
+       hdr->dest_svc = APR_SVC_ASM;
+       hdr->dest_domain = APR_DOMAIN_ADSP;
+       hdr->src_port = ((ac->session << 8) & 0xFF00) | 0x01;
+       hdr->dest_port = ((ac->session << 8) & 0xFF00) | 0x01;
+       if (cmd_flg) {
+               hdr->token = ac->session;
+               atomic_set(&ac->cmd_state, 1);
+       }
+       hdr->pkt_size  = pkt_size;
+       return;
+}
+
+int q6asm_async_write(struct audio_client *ac,
+                                         struct audio_aio_write_param *param)
+{
+       int rc = 0;
+       struct asm_stream_cmd_write write;
+
+       if (!ac || ac->apr == NULL) {
+               pr_err("%s: APR handle NULL\n", __func__);
+               return -EINVAL;
+       }
+
+       q6asm_add_hdr_async(ac, &write.hdr, sizeof(write), FALSE);
+
+       /* Pass physical address as token for AIO scheme */
+       write.hdr.token = param->uid;
+       write.hdr.opcode = ASM_DATA_CMD_WRITE;
+       write.buf_add = param->paddr;
+       write.avail_bytes = param->len;
+       write.uid = param->uid;
+       write.msw_ts = param->msw_ts;
+       write.lsw_ts = param->lsw_ts;
+       /* Use 0xFF00 for disabling timestamps */
+       if (param->flags == 0xFF00)
+               write.uflags = (0x00000000 | (param->flags & 0x800000FF));
+       else
+               write.uflags = (0x80000000 | param->flags);
+
+       pr_debug("%s: session[%d] bufadd[0x%x]len[0x%x]", __func__, ac->session,
+               write.buf_add, write.avail_bytes);
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
+       if (rc < 0) {
+               pr_debug("[%s] write op[0x%x]rc[%d]\n", __func__,
+                       write.hdr.opcode, rc);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_async_read(struct audio_client *ac,
+                                         struct audio_aio_read_param *param)
+{
+       int rc = 0;
+       struct asm_stream_cmd_read read;
+
+       if (!ac || ac->apr == NULL) {
+               pr_err("%s: APR handle NULL\n", __func__);
+               return -EINVAL;
+       }
+
+       q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
+
+       /* Pass physical address as token for AIO scheme */
+       read.hdr.token = param->paddr;
+       read.hdr.opcode = ASM_DATA_CMD_READ;
+       read.buf_add = param->paddr;
+       read.buf_size = param->len;
+       read.uid = param->uid;
+
+       pr_debug("%s: session[%d] bufadd[0x%x]len[0x%x]", __func__, ac->session,
+               read.buf_add, read.buf_size);
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+       if (rc < 0) {
+               pr_debug("[%s] read op[0x%x]rc[%d]\n", __func__,
+                       read.hdr.opcode, rc);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_async_read_compressed(struct audio_client *ac,
+                                         struct audio_aio_read_param *param)
+{
+       int rc = 0;
+       struct asm_stream_cmd_read read;
+
+       if (!ac || ac->apr == NULL) {
+               pr_err("%s: APR handle NULL\n", __func__);
+               return -EINVAL;
+       }
+
+       q6asm_add_hdr_async(ac, &read.hdr, sizeof(read), FALSE);
+
+       /* Pass physical address as token for AIO scheme */
+       read.hdr.token = param->paddr;
+       read.hdr.opcode = ASM_DATA_CMD_READ_COMPRESSED;
+       read.buf_add = param->paddr;
+       read.buf_size = param->len;
+       read.uid = param->uid;
+
+       pr_debug("%s: session[%d] bufadd[0x%x]len[0x%x]", __func__, ac->session,
+               read.buf_add, read.buf_size);
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &read);
+       if (rc < 0) {
+               pr_debug("[%s] read op[0x%x]rc[%d]\n", __func__,
+                       read.hdr.opcode, rc);
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_write(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+               uint32_t lsw_ts, uint32_t flags)
+{
+       int rc = 0;
+       struct asm_stream_cmd_write write;
+       struct audio_port_data *port;
+       struct audio_buffer    *ab;
+       int dsp_buf = 0;
+
+       if (!ac || ac->apr == NULL) {
+               pr_err("APR handle NULL\n");
+               return -EINVAL;
+       }
+       pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
+       if (ac->io_mode & SYNC_IO_MODE) {
+               port = &ac->port[IN];
+
+               q6asm_add_hdr(ac, &write.hdr, sizeof(write),
+                               FALSE);
+               mutex_lock(&port->lock);
+
+               dsp_buf = port->dsp_buf;
+               ab = &port->buf[dsp_buf];
+
+               write.hdr.token = port->dsp_buf;
+               write.hdr.opcode = ASM_DATA_CMD_WRITE;
+               write.buf_add = ab->phys;
+               write.avail_bytes = len;
+               write.uid = port->dsp_buf;
+               write.msw_ts = msw_ts;
+               write.lsw_ts = lsw_ts;
+               /* Use 0xFF00 for disabling timestamps */
+               if (flags == 0xFF00)
+                       write.uflags = (0x00000000 | (flags & 0x800000FF));
+               else
+                       write.uflags = (0x80000000 | flags);
+               port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
+
+               pr_debug("%s:ab->phys[0x%x]bufadd[0x%x]token[0x%x]buf_id[0x%x]"
+                                                       , __func__,
+                                                       ab->phys,
+                                                       write.buf_add,
+                                                       write.hdr.token,
+                                                       write.uid);
+               mutex_unlock(&port->lock);
+#ifdef CONFIG_DEBUG_FS
+               if (out_enable_flag) {
+                       char zero_pattern[2] = {0x00, 0x00};
+                       /* If First two byte is non zero and last two byte
+                       is zero then it is warm output pattern */
+                       if ((strncmp(((char *)ab->data), zero_pattern, 2)) &&
+                       (!strncmp(((char *)ab->data + 2), zero_pattern, 2))) {
+                               do_gettimeofday(&out_warm_tv);
+                               pr_debug("WARM:apr_send_pkt at %ld sec %ld microsec\n",
+                                out_warm_tv.tv_sec,\
+                               out_warm_tv.tv_usec);
+                               pr_debug("Warm Pattern Matched");
+                       }
+                       /* If First two byte is zero and last two byte is
+                       non zero then it is cont ouput pattern */
+                       else if ((!strncmp(((char *)ab->data), zero_pattern, 2))
+                       && (strncmp(((char *)ab->data + 2), zero_pattern, 2))) {
+                               do_gettimeofday(&out_cont_tv);
+                               pr_debug("CONT:apr_send_pkt at %ld sec %ld microsec\n",
+                               out_cont_tv.tv_sec,\
+                               out_cont_tv.tv_usec);
+                               pr_debug("Cont Pattern Matched");
+                       }
+               }
+#endif
+               rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
+               if (rc < 0) {
+                       pr_err("write op[0x%x]rc[%d]\n", write.hdr.opcode, rc);
+                       goto fail_cmd;
+               }
+               pr_debug("%s: WRITE SUCCESS\n", __func__);
+               return 0;
+       }
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_write_nolock(struct audio_client *ac, uint32_t len, uint32_t msw_ts,
+                       uint32_t lsw_ts, uint32_t flags)
+{
+       int rc = 0;
+       struct asm_stream_cmd_write write;
+       struct audio_port_data *port;
+       struct audio_buffer    *ab;
+       int dsp_buf = 0;
+
+       if (!ac || ac->apr == NULL) {
+               pr_err("APR handle NULL\n");
+               return -EINVAL;
+       }
+       pr_debug("%s: session[%d] len=%d", __func__, ac->session, len);
+       if (ac->io_mode & SYNC_IO_MODE) {
+               port = &ac->port[IN];
+
+               q6asm_add_hdr_async(ac, &write.hdr, sizeof(write),
+                                       FALSE);
+
+               dsp_buf = port->dsp_buf;
+               ab = &port->buf[dsp_buf];
+
+               write.hdr.token = port->dsp_buf;
+               write.hdr.opcode = ASM_DATA_CMD_WRITE;
+               write.buf_add = ab->phys;
+               write.avail_bytes = len;
+               write.uid = port->dsp_buf;
+               write.msw_ts = msw_ts;
+               write.lsw_ts = lsw_ts;
+               /* Use 0xFF00 for disabling timestamps */
+               if (flags == 0xFF00)
+                       write.uflags = (0x00000000 | (flags & 0x800000FF));
+               else
+                       write.uflags = (0x80000000 | flags);
+               port->dsp_buf = (port->dsp_buf + 1) & (port->max_buf_cnt - 1);
+
+               pr_debug("%s:ab->phys[0x%x]bufadd[0x%x]token[0x%x]buf_id[0x%x]"
+                                                       , __func__,
+                                                       ab->phys,
+                                                       write.buf_add,
+                                                       write.hdr.token,
+                                                       write.uid);
+
+               rc = apr_send_pkt(ac->apr, (uint32_t *) &write);
+               if (rc < 0) {
+                       pr_err("write op[0x%x]rc[%d]\n", write.hdr.opcode, rc);
+                       goto fail_cmd;
+               }
+               pr_debug("%s: WRITE SUCCESS\n", __func__);
+               return 0;
+       }
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_get_session_time(struct audio_client *ac, uint64_t *tstamp)
+{
+       struct apr_hdr hdr;
+       int rc;
+
+       if (!ac || ac->apr == NULL || tstamp == NULL) {
+               pr_err("APR handle or tstamp NULL\n");
+               return -EINVAL;
+       }
+       q6asm_add_hdr(ac, &hdr, sizeof(hdr), FALSE);
+       hdr.opcode = ASM_SESSION_CMD_GET_SESSION_TIME;
+       atomic_set(&ac->time_flag, 1);
+
+       pr_debug("%s: session[%d]opcode[0x%x]\n", __func__,
+                                               ac->session,
+                                               hdr.opcode);
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
+       if (rc < 0) {
+               pr_err("Commmand 0x%x failed\n", hdr.opcode);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->time_wait,
+                       (atomic_read(&ac->time_flag) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("%s: timeout in getting session time from DSP\n",
+                       __func__);
+               goto fail_cmd;
+       }
+
+       *tstamp = ac->time_stamp;
+       return 0;
+
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_cmd(struct audio_client *ac, int cmd)
+{
+       struct apr_hdr hdr;
+       int rc;
+       atomic_t *state;
+       int cnt = 0;
+
+       if (!ac || ac->apr == NULL) {
+               pr_err("APR handle NULL\n");
+               return -EINVAL;
+       }
+       q6asm_add_hdr(ac, &hdr, sizeof(hdr), TRUE);
+       switch (cmd) {
+       case CMD_PAUSE:
+               pr_debug("%s:CMD_PAUSE\n", __func__);
+               hdr.opcode = ASM_SESSION_CMD_PAUSE;
+               state = &ac->cmd_state;
+               break;
+       case CMD_FLUSH:
+               pr_debug("%s:CMD_FLUSH\n", __func__);
+               hdr.opcode = ASM_STREAM_CMD_FLUSH;
+               state = &ac->cmd_state;
+               break;
+       case CMD_OUT_FLUSH:
+               pr_debug("%s:CMD_OUT_FLUSH\n", __func__);
+               hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS;
+               state = &ac->cmd_state;
+               break;
+       case CMD_EOS:
+               pr_debug("%s:CMD_EOS\n", __func__);
+               hdr.opcode = ASM_DATA_CMD_EOS;
+               atomic_set(&ac->cmd_state, 0);
+               state = &ac->cmd_state;
+               break;
+       case CMD_CLOSE:
+               pr_debug("%s:CMD_CLOSE\n", __func__);
+               hdr.opcode = ASM_STREAM_CMD_CLOSE;
+               atomic_set(&ac->cmd_close_state, 1);
+               state = &ac->cmd_close_state;
+               break;
+       default:
+               pr_err("Invalid format[%d]\n", cmd);
+               goto fail_cmd;
+       }
+       pr_debug("%s:session[%d]opcode[0x%x] ", __func__,
+                                               ac->session,
+                                               hdr.opcode);
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
+       if (rc < 0) {
+               pr_err("Commmand 0x%x failed\n", hdr.opcode);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait, (atomic_read(state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("timeout. waited for response opcode[0x%x]\n",
+                                                       hdr.opcode);
+               goto fail_cmd;
+       }
+       if (cmd == CMD_FLUSH)
+               q6asm_reset_buf_state(ac);
+       if (cmd == CMD_CLOSE) {
+               /* check if DSP return all buffers */
+               if (ac->port[IN].buf) {
+                       for (cnt = 0; cnt < ac->port[IN].max_buf_cnt;
+                                                               cnt++) {
+                               if (ac->port[IN].buf[cnt].used == IN) {
+                                       pr_debug("Write Buf[%d] not returned\n",
+                                                                       cnt);
+                               }
+                       }
+               }
+               if (ac->port[OUT].buf) {
+                       for (cnt = 0; cnt < ac->port[OUT].max_buf_cnt; cnt++) {
+                               if (ac->port[OUT].buf[cnt].used == OUT) {
+                                       pr_debug("Read Buf[%d] not returned\n",
+                                                                       cnt);
+                               }
+                       }
+               }
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_cmd_nowait(struct audio_client *ac, int cmd)
+{
+       struct apr_hdr hdr;
+       int rc;
+
+       if (!ac || ac->apr == NULL) {
+               pr_err("%s:APR handle NULL\n", __func__);
+               return -EINVAL;
+       }
+       q6asm_add_hdr_async(ac, &hdr, sizeof(hdr), TRUE);
+       switch (cmd) {
+       case CMD_PAUSE:
+               pr_debug("%s:CMD_PAUSE\n", __func__);
+               hdr.opcode = ASM_SESSION_CMD_PAUSE;
+               break;
+       case CMD_EOS:
+               pr_debug("%s:CMD_EOS\n", __func__);
+               hdr.opcode = ASM_DATA_CMD_EOS;
+               break;
+       default:
+               pr_err("%s:Invalid format[%d]\n", __func__, cmd);
+               goto fail_cmd;
+       }
+       pr_debug("%s:session[%d]opcode[0x%x] ", __func__,
+                                               ac->session,
+                                               hdr.opcode);
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &hdr);
+       if (rc < 0) {
+               pr_err("%s:Commmand 0x%x failed\n", __func__, hdr.opcode);
+               goto fail_cmd;
+       }
+       atomic_inc(&ac->nowait_cmd_cnt);
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+static void q6asm_reset_buf_state(struct audio_client *ac)
+{
+       int cnt = 0;
+       int loopcnt = 0;
+       int used;
+       struct audio_port_data *port = NULL;
+
+       if (ac->io_mode & SYNC_IO_MODE) {
+               used = (ac->io_mode & TUN_WRITE_IO_MODE ? 1 : 0);
+               mutex_lock(&ac->cmd_lock);
+               for (loopcnt = 0; loopcnt <= OUT; loopcnt++) {
+                       port = &ac->port[loopcnt];
+                       cnt = port->max_buf_cnt - 1;
+                       port->dsp_buf = 0;
+                       port->cpu_buf = 0;
+                       while (cnt >= 0) {
+                               if (!port->buf)
+                                       continue;
+                               port->buf[cnt].used = used;
+                               cnt--;
+                       }
+               }
+               mutex_unlock(&ac->cmd_lock);
+       }
+}
+
+int q6asm_reg_tx_overflow(struct audio_client *ac, uint16_t enable)
+{
+       struct asm_stream_cmd_reg_tx_overflow_event tx_overflow;
+       int rc;
+
+       if (!ac || ac->apr == NULL) {
+               pr_err("APR handle NULL\n");
+               return -EINVAL;
+       }
+       pr_debug("%s:session[%d]enable[%d]\n", __func__,
+                                               ac->session, enable);
+       q6asm_add_hdr(ac, &tx_overflow.hdr, sizeof(tx_overflow), TRUE);
+
+       tx_overflow.hdr.opcode = \
+                       ASM_SESSION_CMD_REGISTER_FOR_TX_OVERFLOW_EVENTS;
+       /* tx overflow event: enable */
+       tx_overflow.enable = enable;
+
+       rc = apr_send_pkt(ac->apr, (uint32_t *) &tx_overflow);
+       if (rc < 0) {
+               pr_err("tx overflow op[0x%x]rc[%d]\n", \
+                                               tx_overflow.hdr.opcode, rc);
+               goto fail_cmd;
+       }
+       rc = wait_event_timeout(ac->cmd_wait,
+                               (atomic_read(&ac->cmd_state) == 0), 5*HZ);
+       if (!rc) {
+               pr_err("timeout. waited for tx overflow\n");
+               goto fail_cmd;
+       }
+       return 0;
+fail_cmd:
+       return -EINVAL;
+}
+
+int q6asm_get_apr_service_id(int session_id)
+{
+       pr_debug("%s\n", __func__);
+
+       if (session_id < 0 || session_id > SESSION_MAX) {
+               pr_err("%s: invalid session_id = %d\n", __func__, session_id);
+               return -EINVAL;
+       }
+
+       return ((struct apr_svc *)session[session_id]->apr)->id;
+}
+
+
+static int __init q6asm_init(void)
+{
+       pr_debug("%s\n", __func__);
+       init_waitqueue_head(&this_mmap.cmd_wait);
+       memset(session, 0, sizeof(session));
+#ifdef CONFIG_DEBUG_FS
+       out_buffer = kmalloc(OUT_BUFFER_SIZE, GFP_KERNEL);
+       out_dentry = debugfs_create_file("audio_out_latency_measurement_node",\
+                               0664,\
+                               NULL, NULL, &audio_output_latency_debug_fops);
+       if (IS_ERR(out_dentry))
+               pr_err("debugfs_create_file failed\n");
+       in_buffer = kmalloc(IN_BUFFER_SIZE, GFP_KERNEL);
+       in_dentry = debugfs_create_file("audio_in_latency_measurement_node",\
+                               0664,\
+                               NULL, NULL, &audio_input_latency_debug_fops);
+       if (IS_ERR(in_dentry))
+               pr_err("debugfs_create_file failed\n");
+#endif
+       return 0;
+}
+
+device_initcall(q6asm_init);