ASoC: msm: Add compressed TX support

There is use case that the HDMI input goes through MI2S
TX interface to ADSP. Add compressed TX support for
this use case.

Change-Id: I510e3e63b68ea1887e4c99ebf1c6f76112abbed5
Signed-off-by: Subhash Chandra Bose Naripeddy <snariped@codeaurora.org>
This commit is contained in:
Subhash Chandra Bose Naripeddy 2012-06-12 11:29:18 -07:00 committed by Stephen Boyd
parent 311882694b
commit 1cd3eb87ac
9 changed files with 403 additions and 68 deletions

View file

@ -1145,6 +1145,13 @@ struct asm_stream_cmd_open_read {
#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
struct asm_stream_cmd_open_write {
struct apr_hdr hdr;
@ -1185,6 +1192,17 @@ struct adm_cmd_connect_afe_port {
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

View file

@ -122,6 +122,16 @@ struct snd_compr_codec_caps {
struct snd_codec_desc descriptor[MAX_NUM_CODEC_DESCRIPTORS];
};
/**
* struct snd_compr_audio_info: compressed input audio information
* @frame_size: legth of the encoded frame with valid data
* @reserved: reserved for furture use
*/
struct snd_compr_audio_info {
uint32_t frame_size;
uint32_t reserved[15];
};
/**
* compress path ioctl definitions
* SNDRV_COMPRESS_GET_CAPS: Query capability of DSP

View file

@ -180,6 +180,8 @@ int q6asm_audio_client_buf_free_contiguous(unsigned int dir,
int q6asm_open_read(struct audio_client *ac, uint32_t format);
int q6asm_open_read_compressed(struct audio_client *ac, uint32_t format);
int q6asm_open_write(struct audio_client *ac, uint32_t format);
int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format);

View file

@ -850,7 +850,7 @@ static int msm_mi2s_free_gpios(void)
static void msm_mi2s_shutdown(struct snd_pcm_substream *substream)
{
if (mi2s_bit_clk) {
clk_disable(mi2s_bit_clk);
clk_disable_unprepare(mi2s_bit_clk);
clk_put(mi2s_bit_clk);
mi2s_bit_clk = NULL;
}
@ -892,7 +892,7 @@ static int msm_mi2s_startup(struct snd_pcm_substream *substream)
if (IS_ERR(mi2s_bit_clk))
return PTR_ERR(mi2s_bit_clk);
clk_set_rate(mi2s_bit_clk, 0);
ret = clk_enable(mi2s_bit_clk);
ret = clk_prepare_enable(mi2s_bit_clk);
if (IS_ERR_VALUE(ret)) {
pr_err("Unable to enable mi2s_bit_clk\n");
clk_put(mi2s_bit_clk);

View file

@ -34,6 +34,13 @@
#include "msm-compr-q6.h"
#include "msm-pcm-routing.h"
#define COMPRE_CAPTURE_NUM_PERIODS 16
/* Allocate the worst case frame size for compressed audio */
#define COMPRE_CAPTURE_HEADER_SIZE (sizeof(struct snd_compr_audio_info))
#define COMPRE_CAPTURE_MAX_FRAME_SIZE (6144)
#define COMPRE_CAPTURE_PERIOD_SIZE (COMPRE_CAPTURE_MAX_FRAME_SIZE + \
COMPRE_CAPTURE_HEADER_SIZE)
struct snd_msm {
struct msm_audio *prtd;
unsigned volume;
@ -42,6 +49,27 @@ static struct snd_msm compressed_audio = {NULL, 0x2000} ;
static struct audio_locks the_locks;
static struct snd_pcm_hardware msm_compr_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 = 8,
.buffer_bytes_max =
COMPRE_CAPTURE_PERIOD_SIZE * COMPRE_CAPTURE_NUM_PERIODS ,
.period_bytes_min = COMPRE_CAPTURE_PERIOD_SIZE,
.period_bytes_max = COMPRE_CAPTURE_PERIOD_SIZE,
.periods_min = COMPRE_CAPTURE_NUM_PERIODS,
.periods_max = COMPRE_CAPTURE_NUM_PERIODS,
.fifo_size = 0,
};
static struct snd_pcm_hardware msm_compr_hardware_playback = {
.info = (SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@ -81,7 +109,9 @@ static void compr_event_handler(uint32_t opcode,
struct snd_pcm_substream *substream = prtd->substream;
struct snd_pcm_runtime *runtime = substream->runtime;
struct audio_aio_write_param param;
struct audio_aio_read_param read_param;
struct audio_buffer *buf = NULL;
uint32_t *ptrmem = (uint32_t *)payload;
int i = 0;
pr_debug("%s opcode =%08x\n", __func__, opcode);
@ -138,9 +168,53 @@ static void compr_event_handler(uint32_t opcode,
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("buf = %p, data = 0x%X, *data = %p,\n"
"prtd->pcm_irq_pos = %d\n",
prtd->audio_client->port[OUT].buf,
*(uint32_t *)prtd->audio_client->port[OUT].buf->data,
prtd->audio_client->port[OUT].buf->data,
prtd->pcm_irq_pos);
memcpy(prtd->audio_client->port[OUT].buf->data +
prtd->pcm_irq_pos, (ptrmem + 2),
COMPRE_CAPTURE_HEADER_SIZE);
pr_debug("buf = %p, updated data = 0x%X, *data = %p\n",
prtd->audio_client->port[OUT].buf,
*(uint32_t *)(prtd->audio_client->port[OUT].buf->data +
prtd->pcm_irq_pos),
prtd->audio_client->port[OUT].buf->data);
if (!atomic_read(&prtd->start))
break;
pr_debug("frame size=%d, buffer = 0x%X\n", ptrmem[2],
ptrmem[1]);
if (ptrmem[2] > COMPRE_CAPTURE_MAX_FRAME_SIZE) {
pr_err("Frame length exceeded the max length");
break;
}
buf = prtd->audio_client->port[OUT].buf;
pr_debug("pcm_irq_pos=%d, buf[0].phys = 0x%X\n",
prtd->pcm_irq_pos, (uint32_t)buf[0].phys);
read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE ;
read_param.paddr = (unsigned long)(buf[0].phys) +
prtd->pcm_irq_pos + COMPRE_CAPTURE_HEADER_SIZE;
prtd->pcm_irq_pos += prtd->pcm_count;
if (atomic_read(&prtd->start))
snd_pcm_period_elapsed(substream);
q6asm_async_read(prtd->audio_client, &read_param);
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 (!atomic_read(&prtd->pending_buffer))
break;
pr_debug("%s:writing %d bytes"
@ -286,6 +360,44 @@ static int msm_compr_playback_prepare(struct snd_pcm_substream *substream)
return 0;
}
static int msm_compr_capture_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct compr_audio *compr = runtime->private_data;
struct msm_audio *prtd = &compr->prtd;
struct audio_buffer *buf = prtd->audio_client->port[OUT].buf;
struct audio_aio_read_param read_param;
int ret = 0;
int i;
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 ret;
read_param.len = prtd->pcm_count - COMPRE_CAPTURE_HEADER_SIZE;
pr_debug("%s: Samp_rate = %d, Channel = %d, pcm_size = %d,\n"
"pcm_count = %d, periods = %d\n",
__func__, prtd->samp_rate, prtd->channel_mode,
prtd->pcm_size, prtd->pcm_count, runtime->periods);
for (i = 0; i < runtime->periods; i++) {
read_param.uid = i;
read_param.paddr = ((unsigned long)(buf[i].phys) +
COMPRE_CAPTURE_HEADER_SIZE);
q6asm_async_read(prtd->audio_client, &read_param);
}
prtd->periods = runtime->periods;
prtd->enabled = 1;
return ret;
}
static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd)
{
int ret = 0;
@ -298,8 +410,15 @@ static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd)
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
prtd->pcm_irq_pos = 0;
if (compr->info.codec_param.codec.id ==
SND_AUDIOCODEC_AC3_PASS_THROUGH) {
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (compr->info.codec_param.codec.id ==
SND_AUDIOCODEC_AC3_PASS_THROUGH) {
msm_pcm_routing_reg_psthr_stream(
soc_prtd->dai_link->be_id,
prtd->session_id, substream->stream,
1);
}
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
msm_pcm_routing_reg_psthr_stream(
soc_prtd->dai_link->be_id,
prtd->session_id, substream->stream, 1);
@ -312,11 +431,19 @@ static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd)
break;
case SNDRV_PCM_TRIGGER_STOP:
pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
if (compr->info.codec_param.codec.id ==
SND_AUDIOCODEC_AC3_PASS_THROUGH) {
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
if (compr->info.codec_param.codec.id ==
SND_AUDIOCODEC_AC3_PASS_THROUGH) {
msm_pcm_routing_reg_psthr_stream(
soc_prtd->dai_link->be_id,
prtd->session_id, substream->stream,
0);
}
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
msm_pcm_routing_reg_psthr_stream(
soc_prtd->dai_link->be_id,
prtd->session_id, substream->stream, 0);
prtd->session_id, substream->stream,
0);
}
atomic_set(&prtd->start, 0);
break;
@ -370,10 +497,6 @@ static int msm_compr_open(struct snd_pcm_substream *substream)
.rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
};
/* Capture path */
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
return -EINVAL;
pr_debug("%s\n", __func__);
compr = kzalloc(sizeof(struct compr_audio), GFP_KERNEL);
if (compr == NULL) {
@ -389,13 +512,18 @@ static int msm_compr_open(struct snd_pcm_substream *substream)
kfree(prtd);
return -ENOMEM;
}
runtime->hw = msm_compr_hardware_playback;
pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
prtd->session_id = prtd->audio_client->session;
prtd->cmd_ack = 1;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
runtime->hw = msm_compr_hardware_playback;
prtd->cmd_ack = 1;
} else {
runtime->hw = msm_compr_hardware_capture;
}
ret = snd_pcm_hw_constraint_list(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
@ -410,7 +538,8 @@ static int msm_compr_open(struct snd_pcm_substream *substream)
prtd->dsp_cnt = 0;
atomic_set(&prtd->pending_buffer, 1);
compr->codec = FORMAT_MP3;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
compr->codec = FORMAT_MP3;
populate_codec_list(compr, runtime);
runtime->private_data = compr;
compressed_audio.prtd = &compr->prtd;
@ -473,6 +602,27 @@ static int msm_compr_playback_close(struct snd_pcm_substream *substream)
return 0;
}
static int msm_compr_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 compr_audio *compr = runtime->private_data;
struct msm_audio *prtd = &compr->prtd;
int dir = OUT;
pr_debug("%s\n", __func__);
atomic_set(&prtd->pending_buffer, 0);
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_CAPTURE);
q6asm_audio_client_free(prtd->audio_client);
kfree(prtd);
return 0;
}
static int msm_compr_close(struct snd_pcm_substream *substream)
{
int ret = 0;
@ -480,7 +630,7 @@ static int msm_compr_close(struct snd_pcm_substream *substream)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
ret = msm_compr_playback_close(substream);
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
ret = EINVAL;
ret = msm_compr_capture_close(substream);
return ret;
}
static int msm_compr_prepare(struct snd_pcm_substream *substream)
@ -490,7 +640,7 @@ static int msm_compr_prepare(struct snd_pcm_substream *substream)
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
ret = msm_compr_playback_prepare(substream);
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
ret = EINVAL;
ret = msm_compr_capture_prepare(substream);
return ret;
}
@ -504,7 +654,10 @@ static snd_pcm_uframes_t msm_compr_pointer(struct snd_pcm_substream *substream)
if (prtd->pcm_irq_pos >= prtd->pcm_size)
prtd->pcm_irq_pos = 0;
pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
pr_debug("%s: pcm_irq_pos = %d, pcm_size = %d, sample_bits = %d,\n"
"frame_bits = %d\n", __func__, prtd->pcm_irq_pos,
prtd->pcm_size, runtime->sample_bits,
runtime->frame_bits);
return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
}
@ -546,28 +699,44 @@ static int msm_compr_hw_params(struct snd_pcm_substream *substream,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dir = IN;
else
return -EINVAL;
dir = OUT;
switch (compr->info.codec_param.codec.id) {
case SND_AUDIOCODEC_AC3_PASS_THROUGH:
ret = q6asm_open_write_compressed(prtd->audio_client,
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
switch (compr->info.codec_param.codec.id) {
case SND_AUDIOCODEC_AC3_PASS_THROUGH:
ret = q6asm_open_write_compressed(prtd->audio_client,
compr->codec);
if (ret < 0) {
pr_err("%s: Session out open failed\n",
__func__);
return -ENOMEM;
}
break;
default:
ret = q6asm_open_write(prtd->audio_client,
compr->codec);
if (ret < 0) {
pr_err("%s: Session out open failed\n",
__func__);
return -ENOMEM;
}
msm_pcm_routing_reg_phy_stream(
soc_prtd->dai_link->be_id,
prtd->session_id, substream->stream);
break;
}
} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
ret = q6asm_open_read_compressed(prtd->audio_client,
compr->codec);
if (ret < 0) {
pr_err("%s: compressed Session out open failed\n",
__func__);
__func__);
return -ENOMEM;
}
break;
default:
ret = q6asm_open_write(prtd->audio_client, compr->codec);
if (ret < 0) {
pr_err("%s: Session out open failed\n", __func__);
return -ENOMEM;
}
msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
prtd->session_id, substream->stream);
break;
}
ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
if (ret < 0) {
@ -586,13 +755,17 @@ static int msm_compr_hw_params(struct snd_pcm_substream *substream,
}
buf = prtd->audio_client->port[dir].buf;
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;
pr_debug("%s: buf[%p]dma_buf->area[%p]dma_buf->addr[%p]\n"
"dma_buf->bytes[%d]\n", __func__,
(void *)buf, (void *)dma_buf->area,
(void *)dma_buf->addr, dma_buf->bytes);
if (!dma_buf->area)
return -ENOMEM;

View file

@ -176,6 +176,17 @@ static struct snd_soc_dai_driver msm_fe_dais[] = {
.rate_min = 8000,
.rate_max = 48000,
},
.capture = {
.stream_name = "MultiMedia4 Capture",
.aif_name = "MM_UL4",
.rates = (SNDRV_PCM_RATE_8000_48000|
SNDRV_PCM_RATE_KNOT),
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 8,
.rate_min = 8000,
.rate_max = 48000,
},
.ops = &msm_fe_Multimedia_dai_ops,
.name = "MultiMedia4",
},

View file

@ -40,9 +40,14 @@ struct msm_dai_q6_dai_data {
union afe_port_config port_config;
};
struct msm_dai_q6_mi2s_dai_config {
u16 pdata_mi2s_lines;
struct msm_dai_q6_dai_data mi2s_dai_data;
};
struct msm_dai_q6_mi2s_dai_data {
struct msm_dai_q6_dai_data tx_dai;
struct msm_dai_q6_dai_data rx_dai;
struct msm_dai_q6_mi2s_dai_config tx_dai;
struct msm_dai_q6_mi2s_dai_config rx_dai;
struct snd_pcm_hw_constraint_list rate_constraint;
struct snd_pcm_hw_constraint_list bitwidth_constraint;
};
@ -86,8 +91,8 @@ static int msm_dai_q6_mi2s_format_get(struct snd_kcontrol *kcontrol,
static const char *mi2s_format[] = {
"LPCM",
"Compr",
"60958-LPCM",
"60958-Compr"};
"LPCM-60958",
"Compr-60958"};
static const struct soc_enum mi2s_config_enum[] = {
SOC_ENUM_SINGLE_EXT(4, mi2s_format),
@ -143,21 +148,63 @@ static int msm_dai_q6_mi2s_hw_params(struct snd_pcm_substream *substream,
{
struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
dev_get_drvdata(dai->dev);
struct msm_dai_q6_dai_data *dai_data =
struct msm_dai_q6_mi2s_dai_config *mi2s_dai_config =
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
&mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
struct msm_dai_q6_dai_data *dai_data = &mi2s_dai_config->mi2s_dai_data;
dai_data->channels = params_channels(params);
switch (dai_data->channels) {
case 2:
dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
case 8:
case 7:
if (mi2s_dai_config->pdata_mi2s_lines < AFE_I2S_8CHS)
goto error_invalid_data;
dai_data->port_config.mi2s.line = AFE_I2S_8CHS;
break;
case 6:
case 5:
if (mi2s_dai_config->pdata_mi2s_lines < AFE_I2S_6CHS)
goto error_invalid_data;
dai_data->port_config.mi2s.line = AFE_I2S_6CHS;
break;
case 4:
case 3:
if (mi2s_dai_config->pdata_mi2s_lines < AFE_I2S_QUAD01)
goto error_invalid_data;
if (mi2s_dai_config->pdata_mi2s_lines == AFE_I2S_QUAD23)
dai_data->port_config.mi2s.line =
mi2s_dai_config->pdata_mi2s_lines;
else
dai_data->port_config.mi2s.line = AFE_I2S_QUAD01;
break;
case 2:
case 1:
dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
if (mi2s_dai_config->pdata_mi2s_lines < AFE_I2S_SD0)
goto error_invalid_data;
switch (mi2s_dai_config->pdata_mi2s_lines) {
case AFE_I2S_SD0:
case AFE_I2S_SD1:
case AFE_I2S_SD2:
case AFE_I2S_SD3:
dai_data->port_config.mi2s.line =
mi2s_dai_config->pdata_mi2s_lines;
break;
case AFE_I2S_QUAD01:
case AFE_I2S_6CHS:
case AFE_I2S_8CHS:
dai_data->port_config.mi2s.line = AFE_I2S_SD0;
break;
case AFE_I2S_QUAD23:
dai_data->port_config.mi2s.line = AFE_I2S_SD2;
break;
}
if (dai_data->channels == 2)
dai_data->port_config.mi2s.channel = MSM_AFE_STEREO;
else
dai_data->port_config.mi2s.channel = MSM_AFE_MONO;
break;
default:
pr_warn("greater than stereo has not been validated");
break;
goto error_invalid_data;
}
dai_data->rate = params_rate(params);
dai_data->port_config.mi2s.bitwidth = 16;
@ -166,7 +213,14 @@ static int msm_dai_q6_mi2s_hw_params(struct snd_pcm_substream *substream,
mi2s_dai_data->rate_constraint.list = &dai_data->rate;
mi2s_dai_data->bitwidth_constraint.list = &dai_data->bitwidth;
}
pr_debug("%s: dai_data->channels = %d, line = %d\n", __func__,
dai_data->channels, dai_data->port_config.mi2s.line);
return 0;
error_invalid_data:
pr_err("%s: dai_data->channels = %d, line = %d\n", __func__,
dai_data->channels, dai_data->port_config.mi2s.line);
return -EINVAL;
}
static int msm_dai_q6_mi2s_get_lineconfig(u16 sd_lines, u16 *config_ptr,
@ -276,7 +330,9 @@ static int msm_dai_q6_mi2s_platform_data_validation(
}
if (ch_cnt) {
dai_data->rx_dai.port_config.mi2s.line = sdline_config;
dai_data->rx_dai.mi2s_dai_data.port_config.mi2s.line =
sdline_config;
dai_data->rx_dai.pdata_mi2s_lines = sdline_config;
dai_driver->playback.channels_min = 1;
dai_driver->playback.channels_max = ch_cnt << 1;
} else {
@ -292,7 +348,9 @@ static int msm_dai_q6_mi2s_platform_data_validation(
}
if (ch_cnt) {
dai_data->tx_dai.port_config.mi2s.line = sdline_config;
dai_data->tx_dai.mi2s_dai_data.port_config.mi2s.line =
sdline_config;
dai_data->tx_dai.pdata_mi2s_lines = sdline_config;
dai_driver->capture.channels_min = 1;
dai_driver->capture.channels_max = ch_cnt << 1;
} else {
@ -301,8 +359,8 @@ static int msm_dai_q6_mi2s_platform_data_validation(
}
dev_info(&pdev->dev, "%s: playback sdline %x capture sdline %x\n",
__func__, dai_data->rx_dai.port_config.mi2s.line,
dai_data->tx_dai.port_config.mi2s.line);
__func__, dai_data->rx_dai.pdata_mi2s_lines,
dai_data->tx_dai.pdata_mi2s_lines);
dev_info(&pdev->dev, "%s: playback ch_max %d capture ch_mx %d\n",
__func__, dai_driver->playback.channels_max,
dai_driver->capture.channels_max);
@ -315,8 +373,10 @@ static int msm_dai_q6_mi2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
struct msm_dai_q6_mi2s_dai_data *mi2s_dai_data =
dev_get_drvdata(dai->dev);
if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask) ||
test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
if (test_bit(STATUS_PORT_STARTED,
mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask) ||
test_bit(STATUS_PORT_STARTED,
mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask)) {
dev_err(dai->dev, "%s: err chg i2s mode while dai running",
__func__);
return -EPERM;
@ -324,12 +384,12 @@ static int msm_dai_q6_mi2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBS_CFS:
mi2s_dai_data->rx_dai.port_config.mi2s.ws = 1;
mi2s_dai_data->tx_dai.port_config.mi2s.ws = 1;
mi2s_dai_data->rx_dai.mi2s_dai_data.port_config.mi2s.ws = 1;
mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.mi2s.ws = 1;
break;
case SND_SOC_DAIFMT_CBM_CFM:
mi2s_dai_data->rx_dai.port_config.mi2s.ws = 0;
mi2s_dai_data->tx_dai.port_config.mi2s.ws = 0;
mi2s_dai_data->rx_dai.mi2s_dai_data.port_config.mi2s.ws = 0;
mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.mi2s.ws = 0;
break;
default:
return -EINVAL;
@ -345,7 +405,8 @@ static int msm_dai_q6_mi2s_prepare(struct snd_pcm_substream *substream,
dev_get_drvdata(dai->dev);
struct msm_dai_q6_dai_data *dai_data =
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
&mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
&mi2s_dai_data->rx_dai.mi2s_dai_data :
&mi2s_dai_data->tx_dai.mi2s_dai_data);
int rc = 0;
if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
@ -364,7 +425,8 @@ static int msm_dai_q6_mi2s_trigger(struct snd_pcm_substream *substream, int cmd,
dev_get_drvdata(dai->dev);
struct msm_dai_q6_dai_data *dai_data =
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
&mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
&mi2s_dai_data->rx_dai.mi2s_dai_data :
&mi2s_dai_data->tx_dai.mi2s_dai_data);
u16 port_id = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
MI2S_RX : MI2S_TX);
int rc = 0;
@ -406,7 +468,8 @@ static void msm_dai_q6_mi2s_shutdown(struct snd_pcm_substream *substream,
dev_get_drvdata(dai->dev);
struct msm_dai_q6_dai_data *dai_data =
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
&mi2s_dai_data->rx_dai : &mi2s_dai_data->tx_dai);
&mi2s_dai_data->rx_dai.mi2s_dai_data :
&mi2s_dai_data->tx_dai.mi2s_dai_data);
u16 port_id = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
MI2S_RX : MI2S_TX);
int rc = 0;
@ -418,8 +481,10 @@ static void msm_dai_q6_mi2s_shutdown(struct snd_pcm_substream *substream,
clear_bit(STATUS_PORT_STARTED, dai_data->status_mask);
}
if (!test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask) &&
!test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
if (!test_bit(STATUS_PORT_STARTED,
mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask) &&
!test_bit(STATUS_PORT_STARTED,
mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask)) {
mi2s_dai_data->rate_constraint.list = NULL;
mi2s_dai_data->bitwidth_constraint.list = NULL;
}
@ -1268,9 +1333,9 @@ static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
struct snd_kcontrol *kcontrol = NULL;
int rc = 0;
if (mi2s_dai_data->rx_dai.port_config.mi2s.line) {
if (mi2s_dai_data->rx_dai.mi2s_dai_data.port_config.mi2s.line) {
kcontrol = snd_ctl_new1(&mi2s_config_controls[0],
&mi2s_dai_data->rx_dai);
&mi2s_dai_data->rx_dai.mi2s_dai_data);
rc = snd_ctl_add(dai->card->snd_card, kcontrol);
if (IS_ERR_VALUE(rc)) {
@ -1279,10 +1344,10 @@ static int msm_dai_q6_dai_mi2s_probe(struct snd_soc_dai *dai)
}
}
if (mi2s_dai_data->tx_dai.port_config.mi2s.line) {
if (mi2s_dai_data->tx_dai.mi2s_dai_data.port_config.mi2s.line) {
rc = snd_ctl_add(dai->card->snd_card,
snd_ctl_new1(&mi2s_config_controls[2],
&mi2s_dai_data->tx_dai));
snd_ctl_new1(&mi2s_config_controls[2],
&mi2s_dai_data->tx_dai.mi2s_dai_data));
if (IS_ERR_VALUE(rc)) {
if (kcontrol)
@ -1302,19 +1367,21 @@ static int msm_dai_q6_dai_mi2s_remove(struct snd_soc_dai *dai)
int rc;
/* If AFE port is still up, close it */
if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->rx_dai.status_mask)) {
if (test_bit(STATUS_PORT_STARTED,
mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask)) {
rc = afe_close(MI2S_RX); /* can block */
if (IS_ERR_VALUE(rc))
dev_err(dai->dev, "fail to close MI2S_RX port\n");
clear_bit(STATUS_PORT_STARTED,
mi2s_dai_data->rx_dai.status_mask);
mi2s_dai_data->rx_dai.mi2s_dai_data.status_mask);
}
if (test_bit(STATUS_PORT_STARTED, mi2s_dai_data->tx_dai.status_mask)) {
if (test_bit(STATUS_PORT_STARTED,
mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask)) {
rc = afe_close(MI2S_TX); /* can block */
if (IS_ERR_VALUE(rc))
dev_err(dai->dev, "fail to close MI2S_TX port\n");
clear_bit(STATUS_PORT_STARTED,
mi2s_dai_data->tx_dai.status_mask);
mi2s_dai_data->tx_dai.mi2s_dai_data.status_mask);
}
kfree(mi2s_dai_data);
snd_soc_unregister_dai(dai->dev);
@ -1966,6 +2033,8 @@ static __devinit int msm_dai_q6_mi2s_dev_probe(struct platform_device *pdev)
return 0;
err_pdata:
dev_err(&pdev->dev, "fail to msm_dai_q6_mi2s_dev_probe\n");
kfree(dai_data);
rtn:
return rc;

View file

@ -1352,6 +1352,13 @@ static const struct snd_kcontrol_new mmul2_mixer_controls[] = {
msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new mmul4_mixer_controls[] = {
SOC_SINGLE_EXT("MI2S_TX", MSM_BACKEND_DAI_MI2S_TX,
MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer,
msm_routing_put_audio_mixer),
};
static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = {
SOC_SINGLE_EXT("CSVoice", MSM_BACKEND_DAI_PRI_I2S_RX,
MSM_FRONTEND_DAI_CS_VOICE, 1, 0, msm_routing_get_voice_mixer,
@ -1983,6 +1990,7 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
SND_SOC_DAPM_AIF_IN("VOIP_DL", "VoIP Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, 0, 0, 0),
SND_SOC_DAPM_AIF_IN("VoLTE_DL", "VoLTE Playback", 0, 0, 0, 0),
@ -2080,6 +2088,8 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = {
mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0,
mmul2_mixer_controls, ARRAY_SIZE(mmul2_mixer_controls)),
SND_SOC_DAPM_MIXER("MultiMedia4 Mixer", SND_SOC_NOPM, 0, 0,
mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)),
SND_SOC_DAPM_MIXER("AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
auxpcm_rx_mixer_controls, ARRAY_SIZE(auxpcm_rx_mixer_controls)),
SND_SOC_DAPM_MIXER("SEC_AUX_PCM_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
@ -2247,6 +2257,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MultiMedia1 Mixer", "PRI_TX", "PRI_I2S_TX"},
{"MultiMedia1 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia2 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia4 Mixer", "MI2S_TX", "MI2S_TX"},
{"MultiMedia1 Mixer", "SLIM_0_TX", "SLIMBUS_0_TX"},
{"MultiMedia1 Mixer", "AUX_PCM_UL_TX", "AUX_PCM_TX"},
{"MultiMedia1 Mixer", "SEC_AUX_PCM_UL_TX", "SEC_AUX_PCM_TX"},
@ -2276,6 +2287,7 @@ static const struct snd_soc_dapm_route intercon[] = {
{"MM_UL1", NULL, "MultiMedia1 Mixer"},
{"MultiMedia2 Mixer", "INTERNAL_FM_TX", "INT_FM_TX"},
{"MM_UL2", NULL, "MultiMedia2 Mixer"},
{"MM_UL4", NULL, "MultiMedia4 Mixer"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia1", "MM_DL1"},
{"AUX_PCM_RX Audio Mixer", "MultiMedia2", "MM_DL2"},

View file

@ -737,6 +737,9 @@ int q6asm_audio_client_buf_alloc_contiguous(unsigned int dir,
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) {
@ -857,6 +860,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv)
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 (atomic_read(&ac->cmd_state)) {
atomic_set(&ac->cmd_state, 0);
wake_up(&ac->cmd_wait);
@ -1260,6 +1264,42 @@ fail_cmd:
return -EINVAL;
}
int q6asm_open_read_compressed(struct audio_client *ac, uint32_t format)
{
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 = 1;
open.uMode = 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_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;