mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 20:07:46 +09:00
ASoC: rockchip: multi_dais_pcm: obtain the vad data
This patch recaculate the hw pointer to make the vad data available and submit the residue dma buffer requests in single xfer mode for the first round, and then cyclic xfer mode for normal. Change-Id: I27c1d6e32cfcac74ae53bb151da859cd4325517b Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
This commit is contained in:
@@ -34,6 +34,10 @@ struct dmaengine_mpcm_runtime_data {
|
||||
unsigned int pos;
|
||||
unsigned int master_chan;
|
||||
bool start_flag;
|
||||
#ifdef CONFIG_SND_SOC_ROCKCHIP_VAD
|
||||
unsigned int vpos;
|
||||
unsigned int vresidue_bytes;
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline struct dmaengine_mpcm_runtime_data *substream_to_prtd(
|
||||
@@ -198,6 +202,119 @@ static void mpcm_dmaengine_terminate_all(struct dmaengine_mpcm_runtime_data *prt
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SND_SOC_ROCKCHIP_VAD
|
||||
static void dmaengine_mpcm_single_dma_complete(void *arg)
|
||||
{
|
||||
struct snd_pcm_substream *substream = arg;
|
||||
struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream);
|
||||
unsigned int pos, size;
|
||||
void *buf;
|
||||
|
||||
if (snd_pcm_vad_attached(substream) &&
|
||||
substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
|
||||
buf = substream->runtime->dma_area + prtd->vpos;
|
||||
pos = prtd->vpos + snd_pcm_lib_period_bytes(substream);
|
||||
|
||||
if (pos <= snd_pcm_lib_buffer_bytes(substream))
|
||||
size = substream->runtime->period_size;
|
||||
else
|
||||
size = bytes_to_frames(substream->runtime,
|
||||
prtd->vresidue_bytes);
|
||||
snd_pcm_vad_preprocess(substream, buf, size);
|
||||
}
|
||||
|
||||
prtd->vpos += snd_pcm_lib_period_bytes(substream);
|
||||
if (prtd->vpos >= snd_pcm_lib_buffer_bytes(substream))
|
||||
prtd->vpos = 0;
|
||||
snd_pcm_period_elapsed(substream);
|
||||
}
|
||||
|
||||
static int __mpcm_prepare_single_and_submit(struct snd_pcm_substream *substream,
|
||||
dma_addr_t buf_start, int size)
|
||||
{
|
||||
struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
enum dma_transfer_direction direction;
|
||||
unsigned long flags = DMA_CTRL_ACK;
|
||||
unsigned int *maps = prtd->channel_maps;
|
||||
int offset, i;
|
||||
bool callback = false;
|
||||
|
||||
direction = snd_pcm_substream_to_dma_direction(substream);
|
||||
|
||||
if (!substream->runtime->no_period_wakeup)
|
||||
flags |= DMA_PREP_INTERRUPT;
|
||||
|
||||
offset = 0;
|
||||
for (i = 0; i < prtd->num_chans; i++) {
|
||||
if (!prtd->chans[i])
|
||||
continue;
|
||||
desc = dmaengine_prep_slave_single(prtd->chans[i],
|
||||
buf_start + offset,
|
||||
size,
|
||||
direction, flags);
|
||||
|
||||
if (!desc)
|
||||
return -ENOMEM;
|
||||
if (!callback) {
|
||||
desc->callback = dmaengine_mpcm_single_dma_complete;
|
||||
desc->callback_param = substream;
|
||||
callback = true;
|
||||
}
|
||||
dmaengine_submit(desc);
|
||||
offset += samples_to_bytes(runtime, maps[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dmaengine_mpcm_prepare_single_and_submit(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream);
|
||||
enum dma_transfer_direction direction;
|
||||
unsigned long flags = DMA_CTRL_ACK;
|
||||
snd_pcm_uframes_t avail;
|
||||
dma_addr_t buf_start, buf_end;
|
||||
int offset, i, count, ret;
|
||||
int buffer_bytes, period_bytes, residue_bytes;
|
||||
|
||||
direction = snd_pcm_substream_to_dma_direction(substream);
|
||||
|
||||
if (!substream->runtime->no_period_wakeup)
|
||||
flags |= DMA_PREP_INTERRUPT;
|
||||
|
||||
period_bytes = snd_pcm_lib_period_bytes(substream);
|
||||
buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
|
||||
avail = snd_pcm_vad_avail(substream);
|
||||
offset = frames_to_bytes(substream->runtime, avail);
|
||||
prtd->vpos = offset;
|
||||
buf_start = substream->runtime->dma_addr + offset;
|
||||
buf_end = substream->runtime->dma_addr + snd_pcm_lib_buffer_bytes(substream);
|
||||
count = (buf_end - buf_start) / period_bytes;
|
||||
residue_bytes = (buf_end - buf_start) % period_bytes;
|
||||
prtd->vresidue_bytes = residue_bytes;
|
||||
pr_debug("%s: offset: %d, buffer_bytes: %d\n", __func__, offset, buffer_bytes);
|
||||
pr_debug("%s: count: %d, residue_bytes: %d\n", __func__, count, residue_bytes);
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = __mpcm_prepare_single_and_submit(substream, buf_start,
|
||||
period_bytes);
|
||||
if (ret)
|
||||
return ret;
|
||||
buf_start += period_bytes;
|
||||
}
|
||||
|
||||
if (residue_bytes) {
|
||||
ret = __mpcm_prepare_single_and_submit(substream, buf_start,
|
||||
residue_bytes);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int snd_dmaengine_mpcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct dmaengine_mpcm_runtime_data *prtd = substream_to_prtd(substream);
|
||||
@@ -206,6 +323,14 @@ static int snd_dmaengine_mpcm_trigger(struct snd_pcm_substream *substream, int c
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
#ifdef CONFIG_SND_SOC_ROCKCHIP_VAD
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE &&
|
||||
snd_pcm_vad_attached(substream) &&
|
||||
snd_pcm_vad_avail(substream)) {
|
||||
dmaengine_mpcm_prepare_single_and_submit(substream);
|
||||
mpcm_dma_async_issue_pending(prtd);
|
||||
}
|
||||
#endif
|
||||
ret = dmaengine_mpcm_prepare_and_submit(substream);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -452,6 +577,10 @@ static snd_pcm_uframes_t dmaengine_mpcm_pointer(struct snd_pcm_substream *substr
|
||||
pos = buf_size - state.residue;
|
||||
|
||||
frames = bytes_to_frames(substream->runtime, pos);
|
||||
#ifdef CONFIG_SND_SOC_ROCKCHIP_VAD
|
||||
if (prtd->vpos)
|
||||
frames = bytes_to_frames(substream->runtime, prtd->vpos);
|
||||
#endif
|
||||
if (!prtd->start_flag && frames >= MAX_FIFO_SIZE)
|
||||
prtd->start_flag = true;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user