]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/kernel-video.git/commitdiff
ASoC: davinci-mcasp: Add hw_rule for buffer_size when using AFIFO
authorAngela Stegmaier <angelabaker@ti.com>
Fri, 12 Jul 2013 20:17:34 +0000 (15:17 -0500)
committerMisael Lopez Cruz <misael.lopez@ti.com>
Mon, 22 Jul 2013 20:04:18 +0000 (15:04 -0500)
The AFIFO threshold imposes a limiation on the buffer size.
When the AFIFO is used, the buffer size (in samples) needs to be
an integer multiple of the AFIFO threshold value (wnumevt, rnumevt).

This patch adds a hw_rule to the McASP driver for version 4
of the McASP to account for the limitation on the buffer size.

Change-Id: I3bd320130b10a55d3d84defd99572526ad6469fb
Signed-off-by: Angela Stegmaier <angelabaker@ti.com>
sound/soc/davinci/davinci-mcasp.c

index da38efba7213b3b63053a2c3ff27d5aea1704141..ef30dbdd7aeeafc2b5f79c04e80b448a22fca423 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/of_device.h>
+#include <linux/lcm.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -1042,14 +1043,92 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
        return ret;
 }
 
+static int davinci_mcasp_hwrule_buffersize(struct snd_pcm_hw_params *params,
+                                               struct snd_pcm_hw_rule *rule,
+                                               int stream)
+{
+       struct snd_interval *buffer_size = hw_param_interval(params,
+                                       SNDRV_PCM_HW_PARAM_BUFFER_SIZE);
+       int channels = params_channels(params);
+       int periods = params_periods(params);
+       struct davinci_audio_dev *dev = rule->private;
+       int i;
+       u8 slots = dev->tdm_slots;
+       u8 max_active_serializers = (channels + slots - 1) / slots;
+       u8 num_ser = 0;
+       u8 num_evt = 0;
+       unsigned long step = 1;
+
+       if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+               for (i = 0; i < dev->num_serializer; i++) {
+                       if (dev->serial_dir[i] == TX_MODE &&
+                                       num_ser < max_active_serializers)
+                               num_ser++;
+               }
+               num_evt = dev->txnumevt * num_ser;
+       } else {
+               for (i = 0; i < dev->num_serializer; i++) {
+                       if (dev->serial_dir[i] == RX_MODE &&
+                                       num_ser < max_active_serializers)
+                               num_ser++;
+               }
+               num_evt = dev->rxnumevt * num_ser;
+       }
+
+       /*
+        * The buffersize (in samples), must be a multiple of num_evt.  The
+        * buffersize (in frames) is the product of the period_size and the
+        * number of periods. Therefore, the buffersize should be a multiple
+        * of the number of periods. The below finds the least common
+        * multiple of num_evt and channels (since the number of samples
+        * per frame is equal to the number of channels). It also makes sure
+        * that the resulting step value (LCM / channels) is a multiple of the
+        * number of periods.
+        */
+       step = lcm((lcm(num_evt, channels) / channels), periods);
+
+       return snd_interval_step(buffer_size, 0, step);
+}
+
+static int davinci_mcasp_hwrule_txbuffersize(struct snd_pcm_hw_params *params,
+                                                 struct snd_pcm_hw_rule *rule)
+{
+       return davinci_mcasp_hwrule_buffersize(params, rule,
+                                               SNDRV_PCM_STREAM_PLAYBACK);
+}
+
+static int davinci_mcasp_hwrule_rxbuffersize(struct snd_pcm_hw_params *params,
+                                                 struct snd_pcm_hw_rule *rule)
+{
+       return davinci_mcasp_hwrule_buffersize(params, rule,
+                                               SNDRV_PCM_STREAM_CAPTURE);
+}
+
 static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
                                 struct snd_soc_dai *dai)
 {
        struct davinci_audio_dev *dev = snd_soc_dai_get_drvdata(dai);
 
-       if (dev->version == MCASP_VERSION_4)
+
+       if (dev->version == MCASP_VERSION_4) {
                snd_soc_dai_set_dma_data(dai, substream,
                                         dev->dma_params[substream->stream]);
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+                       if (dev->txnumevt)
+                               snd_pcm_hw_rule_add(substream->runtime, 0,
+                                       SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                       davinci_mcasp_hwrule_txbuffersize,
+                                       dev,
+                                       SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
+               } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+                       if (dev->rxnumevt)
+                               snd_pcm_hw_rule_add(substream->runtime, 0,
+                                       SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
+                                       davinci_mcasp_hwrule_rxbuffersize,
+                                       dev,
+                                       SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
+               }
+       }
        else
                snd_soc_dai_set_dma_data(dai, substream, dev->dma_params);