ASoC: generic-dmaengine-pcm: Check DMA residue granularity
authorLars-Peter Clausen <lars@metafoo.de>
Sat, 11 Jan 2014 13:02:19 +0000 (14:02 +0100)
committerMark Brown <broonie@linaro.org>
Tue, 14 Jan 2014 21:28:39 +0000 (21:28 +0000)
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>
sound/soc/soc-generic-dmaengine-pcm.c

index 4e2bed8..560a778 100644 (file)
@@ -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;