Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial
[linux-2.6.git] / sound / soc / ep93xx / ep93xx-pcm.c
index d009c17..8dfd3ad 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/slab.h>
+#include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
 
 #include <sound/core.h>
@@ -53,43 +54,34 @@ static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
 
 struct ep93xx_runtime_data
 {
-       struct ep93xx_dma_m2p_client    cl;
-       struct ep93xx_pcm_dma_params    *params;
        int                             pointer_bytes;
-       struct tasklet_struct           period_tasklet;
        int                             periods;
-       struct ep93xx_dma_buffer        buf[32];
+       int                             period_bytes;
+       struct dma_chan                 *dma_chan;
+       struct ep93xx_dma_data          dma_data;
 };
 
-static void ep93xx_pcm_period_elapsed(unsigned long data)
+static void ep93xx_pcm_dma_callback(void *data)
 {
-       struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
-       snd_pcm_period_elapsed(substream);
-}
+       struct snd_pcm_substream *substream = data;
+       struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
 
-static void ep93xx_pcm_buffer_started(void *cookie,
-                                     struct ep93xx_dma_buffer *buf)
-{
+       rtd->pointer_bytes += rtd->period_bytes;
+       rtd->pointer_bytes %= rtd->period_bytes * rtd->periods;
+
+       snd_pcm_period_elapsed(substream);
 }
 
-static void ep93xx_pcm_buffer_finished(void *cookie, 
-                                      struct ep93xx_dma_buffer *buf, 
-                                      int bytes, int error)
+static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
 {
-       struct snd_pcm_substream *substream = cookie;
-       struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
-
-       if (buf == rtd->buf + rtd->periods - 1)
-               rtd->pointer_bytes = 0;
-       else
-               rtd->pointer_bytes += buf->size;
+       struct ep93xx_dma_data *data = filter_param;
 
-       if (!error) {
-               ep93xx_dma_m2p_submit_recursive(&rtd->cl, buf);
-               tasklet_schedule(&rtd->period_tasklet);
-       } else {
-               snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+       if (data->direction == ep93xx_dma_chan_direction(chan)) {
+               chan->private = data;
+               return true;
        }
+
+       return false;
 }
 
 static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
@@ -98,30 +90,38 @@ static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
        struct snd_soc_dai *cpu_dai = soc_rtd->cpu_dai;
        struct ep93xx_pcm_dma_params *dma_params;
        struct ep93xx_runtime_data *rtd;    
+       dma_cap_mask_t mask;
        int ret;
 
-       dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
+       ret = snd_pcm_hw_constraint_integer(substream->runtime,
+                                           SNDRV_PCM_HW_PARAM_PERIODS);
+       if (ret < 0)
+               return ret;
+
        snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
 
        rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
        if (!rtd) 
                return -ENOMEM;
 
-       memset(&rtd->period_tasklet, 0, sizeof(rtd->period_tasklet));
-       rtd->period_tasklet.func = ep93xx_pcm_period_elapsed;
-       rtd->period_tasklet.data = (unsigned long)substream;
-
-       rtd->cl.name = dma_params->name;
-       rtd->cl.flags = dma_params->dma_port | EP93XX_DMA_M2P_IGNORE_ERROR |
-               ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
-                EP93XX_DMA_M2P_TX : EP93XX_DMA_M2P_RX);
-       rtd->cl.cookie = substream;
-       rtd->cl.buffer_started = ep93xx_pcm_buffer_started;
-       rtd->cl.buffer_finished = ep93xx_pcm_buffer_finished;
-       ret = ep93xx_dma_m2p_client_register(&rtd->cl);
-       if (ret < 0) {
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+       dma_cap_set(DMA_CYCLIC, mask);
+
+       dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
+       rtd->dma_data.port = dma_params->dma_port;
+       rtd->dma_data.name = dma_params->name;
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               rtd->dma_data.direction = DMA_TO_DEVICE;
+       else
+               rtd->dma_data.direction = DMA_FROM_DEVICE;
+
+       rtd->dma_chan = dma_request_channel(mask, ep93xx_pcm_dma_filter,
+                                           &rtd->dma_data);
+       if (!rtd->dma_chan) {
                kfree(rtd);
-               return ret;
+               return -EINVAL;
        }
        
        substream->runtime->private_data = rtd;
@@ -132,31 +132,52 @@ static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
 {
        struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
 
-       ep93xx_dma_m2p_client_unregister(&rtd->cl);
+       dma_release_channel(rtd->dma_chan);
        kfree(rtd);
        return 0;
 }
 
+static int ep93xx_pcm_dma_submit(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct ep93xx_runtime_data *rtd = runtime->private_data;
+       struct dma_chan *chan = rtd->dma_chan;
+       struct dma_device *dma_dev = chan->device;
+       struct dma_async_tx_descriptor *desc;
+
+       rtd->pointer_bytes = 0;
+       desc = dma_dev->device_prep_dma_cyclic(chan, runtime->dma_addr,
+                                              rtd->period_bytes * rtd->periods,
+                                              rtd->period_bytes,
+                                              rtd->dma_data.direction);
+       if (!desc)
+               return -EINVAL;
+
+       desc->callback = ep93xx_pcm_dma_callback;
+       desc->callback_param = substream;
+
+       dmaengine_submit(desc);
+       return 0;
+}
+
+static void ep93xx_pcm_dma_flush(struct snd_pcm_substream *substream)
+{
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct ep93xx_runtime_data *rtd = runtime->private_data;
+
+       dmaengine_terminate_all(rtd->dma_chan);
+}
+
 static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct ep93xx_runtime_data *rtd = runtime->private_data;
-       size_t totsize = params_buffer_bytes(params);
-       size_t period = params_period_bytes(params);
-       int i;
 
        snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
-       runtime->dma_bytes = totsize;
-
-       rtd->periods = (totsize + period - 1) / period;
-       for (i = 0; i < rtd->periods; i++) {
-               rtd->buf[i].bus_addr = runtime->dma_addr + (i * period);
-               rtd->buf[i].size = period;
-               if ((i + 1) * period > totsize)
-                       rtd->buf[i].size = totsize - (i * period);
-       }
 
+       rtd->periods = params_periods(params);
+       rtd->period_bytes = params_period_bytes(params);
        return 0;
 }
 
@@ -168,24 +189,20 @@ static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream)
 
 static int ep93xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 {
-       struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
        int ret;
-       int i;
 
        ret = 0;
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               rtd->pointer_bytes = 0;
-               for (i = 0; i < rtd->periods; i++)
-                       ep93xx_dma_m2p_submit(&rtd->cl, rtd->buf + i);
+               ret = ep93xx_pcm_dma_submit(substream);
                break;
 
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               ep93xx_dma_m2p_flush(&rtd->cl);
+               ep93xx_pcm_dma_flush(substream);
                break;
 
        default:
@@ -266,9 +283,11 @@ static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 
 static u64 ep93xx_pcm_dmamask = 0xffffffff;
 
-static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
-                         struct snd_pcm *pcm)
+static int ep93xx_pcm_new(struct snd_soc_pcm_runtime *rtd)
 {
+       struct snd_card *card = rtd->card->snd_card;
+       struct snd_soc_dai *dai = rtd->cpu_dai;
+       struct snd_pcm *pcm = rtd->pcm;
        int ret = 0;
 
        if (!card->dev->dma_mask)