ASoC: pcm_dmaengine: Extract snd_dmaengine_pcm_refine_runtime_hwparams

When set the runtime hardware parameters, we may need to query
the capability of DMA to complete the parameters.

This patch is to Extract this operation from
dmaengine_pcm_set_runtime_hwparams function to a separate function
snd_dmaengine_pcm_refine_runtime_hwparams, that other components
which need this feature can call this function.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Reviewed-by: Nicolin Chen <nicoleotsuka@gmail.com>
Link: https://lore.kernel.org/r/d728f65194e9978cbec4132b522d4fed420d704a.1569493933.git.shengjiu.wang@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Shengjiu Wang 2019-09-27 09:46:11 +08:00 committed by Mark Brown
parent 109539c986
commit e957204e73
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
3 changed files with 94 additions and 55 deletions

View File

@ -83,6 +83,11 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
const struct snd_dmaengine_dai_dma_data *dma_data,
struct dma_slave_config *config);
int snd_dmaengine_pcm_refine_runtime_hwparams(
struct snd_pcm_substream *substream,
struct snd_dmaengine_dai_dma_data *dma_data,
struct snd_pcm_hardware *hw,
struct dma_chan *chan);
/*
* Try to request the DMA channel using compat_request_channel or

View File

@ -369,4 +369,87 @@ int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream)
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan);
/**
* snd_dmaengine_pcm_refine_runtime_hwparams - Refine runtime hw params
* @substream: PCM substream
* @dma_data: DAI DMA data
* @hw: PCM hw params
* @chan: DMA channel to use for data transfers
*
* Returns 0 on success, a negative error code otherwise.
*
* This function will query DMA capability, then refine the pcm hardware
* parameters.
*/
int snd_dmaengine_pcm_refine_runtime_hwparams(
struct snd_pcm_substream *substream,
struct snd_dmaengine_dai_dma_data *dma_data,
struct snd_pcm_hardware *hw,
struct dma_chan *chan)
{
struct dma_slave_caps dma_caps;
u32 addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
snd_pcm_format_t i;
int ret = 0;
if (!hw || !chan || !dma_data)
return -EINVAL;
ret = dma_get_slave_caps(chan, &dma_caps);
if (ret == 0) {
if (dma_caps.cmd_pause && dma_caps.cmd_resume)
hw->info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME;
if (dma_caps.residue_granularity <= DMA_RESIDUE_GRANULARITY_SEGMENT)
hw->info |= SNDRV_PCM_INFO_BATCH;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
addr_widths = dma_caps.dst_addr_widths;
else
addr_widths = dma_caps.src_addr_widths;
}
/*
* If SND_DMAENGINE_PCM_DAI_FLAG_PACK is set keep
* hw.formats set to 0, meaning no restrictions are in place.
* In this case it's the responsibility of the DAI driver to
* provide the supported format information.
*/
if (!(dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK))
/*
* Prepare formats mask for valid/allowed sample types. If the
* dma does not have support for the given physical word size,
* it needs to be masked out so user space can not use the
* format which produces corrupted audio.
* In case the dma driver does not implement the slave_caps the
* default assumption is that it supports 1, 2 and 4 bytes
* widths.
*/
for (i = SNDRV_PCM_FORMAT_FIRST; i <= SNDRV_PCM_FORMAT_LAST; i++) {
int bits = snd_pcm_format_physical_width(i);
/*
* Enable only samples with DMA supported physical
* widths
*/
switch (bits) {
case 8:
case 16:
case 24:
case 32:
case 64:
if (addr_widths & (1 << (bits / 8)))
hw->formats |= pcm_format_to_bits(i);
break;
default:
/* Unsupported types */
break;
}
}
return ret;
}
EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_refine_runtime_hwparams);
MODULE_LICENSE("GPL");

View File

@ -118,12 +118,7 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea
struct device *dma_dev = dmaengine_dma_dev(pcm, substream);
struct dma_chan *chan = pcm->chan[substream->stream];
struct snd_dmaengine_dai_dma_data *dma_data;
struct dma_slave_caps dma_caps;
struct snd_pcm_hardware hw;
u32 addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
snd_pcm_format_t i;
int ret;
if (pcm->config && pcm->config->pcm_hardware)
@ -145,56 +140,12 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea
if (pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE)
hw.info |= SNDRV_PCM_INFO_BATCH;
ret = dma_get_slave_caps(chan, &dma_caps);
if (ret == 0) {
if (dma_caps.cmd_pause && dma_caps.cmd_resume)
hw.info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME;
if (dma_caps.residue_granularity <= DMA_RESIDUE_GRANULARITY_SEGMENT)
hw.info |= SNDRV_PCM_INFO_BATCH;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
addr_widths = dma_caps.dst_addr_widths;
else
addr_widths = dma_caps.src_addr_widths;
}
/*
* If SND_DMAENGINE_PCM_DAI_FLAG_PACK is set keep
* hw.formats set to 0, meaning no restrictions are in place.
* In this case it's the responsibility of the DAI driver to
* provide the supported format information.
*/
if (!(dma_data->flags & SND_DMAENGINE_PCM_DAI_FLAG_PACK))
/*
* Prepare formats mask for valid/allowed sample types. If the
* dma does not have support for the given physical word size,
* it needs to be masked out so user space can not use the
* format which produces corrupted audio.
* In case the dma driver does not implement the slave_caps the
* default assumption is that it supports 1, 2 and 4 bytes
* widths.
*/
for (i = SNDRV_PCM_FORMAT_FIRST; i <= SNDRV_PCM_FORMAT_LAST; i++) {
int bits = snd_pcm_format_physical_width(i);
/*
* Enable only samples with DMA supported physical
* widths
*/
switch (bits) {
case 8:
case 16:
case 24:
case 32:
case 64:
if (addr_widths & (1 << (bits / 8)))
hw.formats |= pcm_format_to_bits(i);
break;
default:
/* Unsupported types */
break;
}
}
ret = snd_dmaengine_pcm_refine_runtime_hwparams(substream,
dma_data,
&hw,
chan);
if (ret)
return ret;
return snd_soc_set_runtime_hwparams(substream, &hw);
}