summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShengjiu Wang <shengjiu.wang@nxp.com>2017-11-20 16:23:21 +0800
committerShengjiu Wang <shengjiu.wang@nxp.com>2017-11-21 11:45:57 +0800
commit5ce2c85f3e61c1129da2d14230c32ccd20946278 (patch)
treeeb005a51ff0e7418f13c10bf1bf074aab577c2c0
parentdc863d108120f5ad1ad65dfe02b752cbcc52783c (diff)
MLK-16885-2: ASoC: imx-pcm-dma-v2: query the caps of dma
query the caps of dma, then update the hw parameters according the caps. for EDMA can't support 24bit sample, but we didn't add any constraint, that cause issues. Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com> (cherry picked from commit 4948f8320687a2c40d60ef51ea7d18d4d90882a2)
-rw-r--r--sound/soc/fsl/imx-pcm-dma-v2.c70
1 files changed, 63 insertions, 7 deletions
diff --git a/sound/soc/fsl/imx-pcm-dma-v2.c b/sound/soc/fsl/imx-pcm-dma-v2.c
index 4479247f0adf..8aa3cd8b2c2f 100644
--- a/sound/soc/fsl/imx-pcm-dma-v2.c
+++ b/sound/soc/fsl/imx-pcm-dma-v2.c
@@ -22,13 +22,11 @@
#include "imx-pcm.h"
-static const struct snd_pcm_hardware imx_pcm_hardware = {
+static struct snd_pcm_hardware imx_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_RESUME,
+ SNDRV_PCM_INFO_MMAP_VALID,
.buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
.period_bytes_min = 128,
.period_bytes_max = 65532, /* Limited by SDMA engine */
@@ -100,9 +98,13 @@ static int imx_pcm_open(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_dmaengine_dai_dma_data *dma_data;
+ struct dma_slave_caps dma_caps;
+ struct dma_chan *chan;
+ u32 addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
int ret;
-
- snd_soc_set_runtime_hwparams(substream, &imx_pcm_hardware);
+ int i;
dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
@@ -123,12 +125,66 @@ static int imx_pcm_open(struct snd_pcm_substream *substream)
return ret;
}
+ chan = snd_dmaengine_pcm_get_chan(substream);
+
+ ret = dma_get_slave_caps(chan, &dma_caps);
+ if (ret == 0) {
+ if (dma_caps.cmd_pause)
+ imx_pcm_hardware.info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME;
+ if (dma_caps.residue_granularity <= DMA_RESIDUE_GRANULARITY_SEGMENT)
+ imx_pcm_hardware.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 = 0; 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)))
+ imx_pcm_hardware.formats |= (1LL << i);
+ break;
+ default:
+ /* Unsupported types */
+ break;
+ }
+ }
+
+ snd_soc_set_runtime_hwparams(substream, &imx_pcm_hardware);
+
ret = snd_pcm_hw_constraint_integer(substream->runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0)
return ret;
-
return 0;
}