ASoC: msm: Add support for 4 channel recording
Enable 4 channel recording in kernel
Signed-off-by: Mingming Yin <mingming@codeaurora.org>
Change-Id: I91c76e21a4080c0542a63555f0258010ed061fc0
diff --git a/include/sound/apr_audio.h b/include/sound/apr_audio.h
index f71d743..782ee8d 100644
--- a/include/sound/apr_audio.h
+++ b/include/sound/apr_audio.h
@@ -992,6 +992,7 @@
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;
};
diff --git a/include/sound/q6asm.h b/include/sound/q6asm.h
index c3d4bd5..aec4171 100644
--- a/include/sound/q6asm.h
+++ b/include/sound/q6asm.h
@@ -238,6 +238,9 @@
int q6asm_enc_cfg_blk_pcm(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);
diff --git a/sound/soc/msm/msm-dai-fe.c b/sound/soc/msm/msm-dai-fe.c
index 14d9adf..4c9cef9 100644
--- a/sound/soc/msm/msm-dai-fe.c
+++ b/sound/soc/msm/msm-dai-fe.c
@@ -62,7 +62,7 @@
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
.rate_min = 8000,
.rate_max = 48000,
},
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index b0cfd34..a53dd44 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -1007,7 +1007,7 @@
SNDRV_PCM_RATE_16000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
.rate_min = 8000,
.rate_max = 48000,
},
diff --git a/sound/soc/msm/msm-pcm-q6.c b/sound/soc/msm/msm-pcm-q6.c
index dd194d6..4686386 100644
--- a/sound/soc/msm/msm-pcm-q6.c
+++ b/sound/soc/msm/msm-pcm-q6.c
@@ -55,7 +55,7 @@
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
- .channels_max = 2,
+ .channels_max = 4,
.buffer_bytes_max = CAPTURE_NUM_PERIODS * CAPTURE_PERIOD_SIZE,
.period_bytes_min = CAPTURE_PERIOD_SIZE,
.period_bytes_max = CAPTURE_PERIOD_SIZE,
@@ -248,8 +248,14 @@
pr_debug("Samp_rate = %d\n", prtd->samp_rate);
pr_debug("Channel = %d\n", prtd->channel_mode);
- ret = q6asm_enc_cfg_blk_pcm(prtd->audio_client, prtd->samp_rate,
- 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__);
@@ -331,13 +337,6 @@
/* Capture path */
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
runtime->hw = msm_pcm_hardware_capture;
- ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM);
- if (ret < 0) {
- pr_err("%s: pcm in 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);
@@ -622,12 +621,28 @@
struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
struct audio_buffer *buf;
int dir, ret;
+ int format = FORMAT_LINEAR_PCM;
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);
+ kfree(prtd);
+ return -ENOMEM;
+ }
+ }
+
ret = q6asm_audio_client_buf_alloc_contiguous(dir,
prtd->audio_client,
runtime->hw.period_bytes_min,
diff --git a/sound/soc/msm/msm-pcm-routing.c b/sound/soc/msm/msm-pcm-routing.c
index c58bdf5..18f95f6 100644
--- a/sound/soc/msm/msm-pcm-routing.c
+++ b/sound/soc/msm/msm-pcm-routing.c
@@ -1842,8 +1842,9 @@
if (fe_dai_map[i][session_type] != INVALID_SESSION) {
channels = bedai->channel;
- if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) &&
- (channels > 2))
+ if ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK ||
+ substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ && (channels > 2))
adm_multi_ch_copp_open(bedai->port_id,
path_type,
bedai->sample_rate,
diff --git a/sound/soc/msm/qdsp6/q6adm.c b/sound/soc/msm/qdsp6/q6adm.c
index bc5c007..3745b17 100644
--- a/sound/soc/msm/qdsp6/q6adm.c
+++ b/sound/soc/msm/qdsp6/q6adm.c
@@ -489,6 +489,11 @@
} 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;
diff --git a/sound/soc/msm/qdsp6/q6asm.c b/sound/soc/msm/qdsp6/q6asm.c
index c7ebd2c..f3a2383 100644
--- a/sound/soc/msm/qdsp6/q6asm.c
+++ b/sound/soc/msm/qdsp6/q6asm.c
@@ -1228,6 +1228,10 @@
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;
@@ -1664,6 +1668,56 @@
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;
+ 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;
+
+ 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)
{