summaryrefslogtreecommitdiffstats
path: root/sound/soc/soc-generic-dmaengine-pcm.c
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2014-01-11 14:02:19 +0100
committerMark Brown <broonie@linaro.org>2014-01-14 21:28:39 +0000
commit478028e088d6a94666d8a776be2cd2291faf3bbd (patch)
tree8bebc11e20820e4a61b1ccbe8dd7ab9881571a15 /sound/soc/soc-generic-dmaengine-pcm.c
parent93b943edfc5e439f7b843535e0bb0f7d2371f67f (diff)
downloadlinux-478028e088d6a94666d8a776be2cd2291faf3bbd.tar.gz
linux-478028e088d6a94666d8a776be2cd2291faf3bbd.tar.bz2
linux-478028e088d6a94666d8a776be2cd2291faf3bbd.zip
ASoC: generic-dmaengine-pcm: Check DMA residue granularity
The dmaengine framework now exposes the granularity with which it is able to report the transfer residue for a certain DMA channel. Check the granularity in the generic dmaengine PCM driver and a) Set the SNDRV_PCM_INFO_BATCH if the granularity is per period or worse. b) Fallback to the (race condition prone) period counting if the driver does not support any residue reporting. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'sound/soc/soc-generic-dmaengine-pcm.c')
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
index 4e2bed89a4a4..560a7787d8a7 100644
--- a/sound/soc/soc-generic-dmaengine-pcm.c
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -144,6 +144,8 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea
if (ret == 0) {
if (dma_caps.cmd_pause)
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;
}
return snd_soc_set_runtime_hwparams(substream, &hw);
@@ -187,6 +189,21 @@ static struct dma_chan *dmaengine_pcm_compat_request_channel(
dma_data->filter_data);
}
+static bool dmaengine_pcm_can_report_residue(struct dma_chan *chan)
+{
+ struct dma_slave_caps dma_caps;
+ int ret;
+
+ ret = dma_get_slave_caps(chan, &dma_caps);
+ if (ret != 0)
+ return true;
+
+ if (dma_caps.residue_granularity == DMA_RESIDUE_GRANULARITY_DESCRIPTOR)
+ return false;
+
+ return true;
+}
+
static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
@@ -239,6 +256,16 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
max_buffer_size);
if (ret)
goto err_free;
+
+ /*
+ * This will only return false if we know for sure that at least
+ * one channel does not support residue reporting. If the DMA
+ * driver does not implement the slave_caps API we rely having
+ * the NO_RESIDUE flag set manually in case residue reporting is
+ * not supported.
+ */
+ if (!dmaengine_pcm_can_report_residue(pcm->chan[i]))
+ pcm->flags |= SND_DMAENGINE_PCM_FLAG_NO_RESIDUE;
}
return 0;