diff options
Diffstat (limited to 'sound/soc/fsl/fsl_esai_mix.c')
-rw-r--r-- | sound/soc/fsl/fsl_esai_mix.c | 78 |
1 files changed, 57 insertions, 21 deletions
diff --git a/sound/soc/fsl/fsl_esai_mix.c b/sound/soc/fsl/fsl_esai_mix.c index f7dab64f108a..9b603f9a6e6f 100644 --- a/sound/soc/fsl/fsl_esai_mix.c +++ b/sound/soc/fsl/fsl_esai_mix.c @@ -71,6 +71,53 @@ int fsl_esai_mix_close(struct snd_pcm_substream *substream, return 0; } +static int fsl_esai_mix_pointer(struct fsl_esai_mix *mix) +{ + struct dma_tx_state state; + enum dma_status status; + unsigned int buf_size; + unsigned int pos = 0; + + status = dmaengine_tx_status(mix->chan, mix->cookie, &state); + if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) { + buf_size = mix->buffer_bytes; + if (state.residue > 0 && state.residue <= buf_size) + pos = buf_size - state.residue; + } + + return pos; +} + +static int fsl_esai_tx_avail(struct fsl_esai_mix *mix) +{ + int avail; + + mix->buffer_read_offset = fsl_esai_mix_pointer(mix); + + avail = mix->buffer_bytes - mix->buffer_write_offset + mix->buffer_read_offset; + if (avail < 0) + avail += mix->buffer_bytes; + else if (avail > mix->buffer_bytes) + avail -= mix->buffer_bytes; + + return avail; +} + +static int fsl_esai_rx_avail(struct fsl_esai_mix *mix) +{ + int avail; + + mix->buffer_write_offset = fsl_esai_mix_pointer(mix); + + avail = mix->buffer_bytes - mix->buffer_read_offset + mix->buffer_write_offset; + if (avail < 0) + avail += mix->buffer_bytes; + else if (avail > mix->buffer_bytes) + avail = avail - mix->buffer_bytes; + + return avail; +} + static void fsl_esai_mix_buffer_from_fe_tx(struct snd_pcm_substream *substream, bool elapse) { bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; @@ -115,9 +162,9 @@ static void fsl_esai_mix_buffer_from_fe_tx(struct snd_pcm_substream *substream, } spin_unlock_irqrestore(&rtd->card->dpcm_lock, flags); - avail = mix->buffer_bytes - mix->buffer_write_offset + mix->buffer_read_offset; - if (avail >= mix->buffer_bytes) - avail = avail - mix->buffer_bytes; + avail = fsl_esai_tx_avail(mix); + if (avail >= mix->buffer_bytes && elapse) + dev_err(rtd->cpu_dai->dev, "mix underrun\n"); while (avail >= mix->period_bytes) { size = mix->period_bytes; @@ -166,7 +213,7 @@ static void fsl_esai_mix_buffer_from_fe_tx(struct snd_pcm_substream *substream, } mix->buffer_write_offset += size; - if (mix->buffer_write_offset > mix->buffer_bytes) + if (mix->buffer_write_offset >= mix->buffer_bytes) mix->buffer_write_offset -= mix->buffer_bytes; avail -= mix->period_bytes; @@ -216,9 +263,9 @@ static void fsl_esai_split_buffer_from_be_rx(struct snd_pcm_substream *substream } spin_unlock_irqrestore(&rtd->card->dpcm_lock, flags); - avail = mix->buffer_bytes - mix->buffer_read_offset + mix->buffer_write_offset; - if (avail >= mix->buffer_bytes) - avail = avail - mix->buffer_bytes; + avail = fsl_esai_rx_avail(mix); + if (avail >= mix->buffer_bytes && elapse) + dev_err(rtd->cpu_dai->dev, "mix overrun\n"); while (avail >= mix->period_bytes) { size = mix->period_bytes; @@ -261,7 +308,7 @@ static void fsl_esai_split_buffer_from_be_rx(struct snd_pcm_substream *substream } mix->buffer_read_offset += size; - if (mix->buffer_read_offset > mix->buffer_bytes) + if (mix->buffer_read_offset >= mix->buffer_bytes) mix->buffer_read_offset -= mix->buffer_bytes; avail -= mix->period_bytes; @@ -296,16 +343,6 @@ static void fsl_esai_mix_dma_complete(void *arg) mix->substream = substream; - if (tx) { - mix->buffer_read_offset = mix->buffer_read_offset + mix->period_bytes; - if (mix->buffer_read_offset > mix->buffer_bytes) - mix->buffer_read_offset -= mix->buffer_bytes; - } else { - mix->buffer_write_offset = mix->buffer_write_offset + mix->period_bytes; - if (mix->buffer_write_offset > mix->buffer_bytes) - mix->buffer_write_offset -= mix->buffer_bytes; - } - queue_work(mix->mix_wq, &mix->work); } @@ -329,11 +366,11 @@ static int fsl_esai_mix_prepare_and_submit(struct snd_pcm_substream *substream, desc->callback = fsl_esai_mix_dma_complete; desc->callback_param = substream; - dmaengine_submit(desc); + mix->cookie = dmaengine_submit(desc); /* Mix the tx buffer */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - mix->buffer_read_offset = mix->buffer_bytes; + mix->buffer_read_offset = 0; mix->buffer_write_offset = 0; fsl_esai_mix_buffer_from_fe_tx(substream, false); } else { @@ -413,7 +450,6 @@ int fsl_esai_mix_probe(struct device *dev, struct fsl_esai_mix *mix_rx, struct f mix_rx->channels = 4; mix_rx->buffer_bytes = 2048 * mix_rx->client_cnt * 4; mix_rx->period_bytes = 2048 * mix_rx->client_cnt; - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, IMX_SSI_DMABUF_SIZE * mix_rx->client_cnt, |