diff options
Diffstat (limited to 'sound/core/pcm_dmaengine.c')
| -rw-r--r-- | sound/core/pcm_dmaengine.c | 83 | 
1 files changed, 83 insertions, 0 deletions
diff --git a/sound/core/pcm_dmaengine.c b/sound/core/pcm_dmaengine.c index 89a05926ac73..5749a8a49784 100644 --- a/sound/core/pcm_dmaengine.c +++ b/sound/core/pcm_dmaengine.c @@ -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");  | 

