Merge branch 'fix/asoc' into for-linus
authorTakashi Iwai <tiwai@suse.de>
Fri, 16 Apr 2010 08:03:36 +0000 (10:03 +0200)
committerTakashi Iwai <tiwai@suse.de>
Fri, 16 Apr 2010 08:03:36 +0000 (10:03 +0200)
1  2 
sound/soc/codecs/wm2000.c
sound/soc/imx/imx-pcm-dma-mx2.c
sound/soc/imx/imx-pcm-fiq.c
sound/soc/imx/imx-ssi.c

@@@ -23,7 -23,6 +23,6 @@@
  
  #include <linux/module.h>
  #include <linux/moduleparam.h>
- #include <linux/version.h>
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/firmware.h>
@@@ -32,7 -31,6 +31,7 @@@
  #include <linux/i2c.h>
  #include <linux/platform_device.h>
  #include <linux/debugfs.h>
 +#include <linux/slab.h>
  #include <sound/core.h>
  #include <sound/pcm.h>
  #include <sound/pcm_params.h>
@@@ -19,7 -19,6 +19,7 @@@
  #include <linux/interrupt.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
 +#include <linux/slab.h>
  
  #include <sound/core.h>
  #include <sound/initval.h>
@@@ -71,7 -70,12 +71,12 @@@ static void imx_ssi_dma_callback(int ch
  
  static void snd_imx_dma_err_callback(int channel, void *data, int err)
  {
-       pr_err("DMA error callback called\n");
+       struct snd_pcm_substream *substream = data;
+       struct snd_soc_pcm_runtime *rtd = substream->private_data;
+       struct imx_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct imx_pcm_runtime_data *iprtd = runtime->private_data;
+       int ret;
  
        pr_err("DMA timeout on channel %d -%s%s%s%s\n",
                 channel,
                 err & IMX_DMA_ERR_REQUEST ?  " request" : "",
                 err & IMX_DMA_ERR_TRANSFER ? " transfer" : "",
                 err & IMX_DMA_ERR_BUFFER ?   " buffer" : "");
+       imx_dma_disable(iprtd->dma);
+       ret = imx_dma_setup_sg(iprtd->dma, iprtd->sg_list, iprtd->sg_count,
+                       IMX_DMA_LENGTH_LOOP, dma_params->dma_addr,
+                       substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+                       DMA_MODE_WRITE : DMA_MODE_READ);
+       if (!ret)
+               imx_dma_enable(iprtd->dma);
  }
  
  static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream)
@@@ -19,7 -19,6 +19,7 @@@
  #include <linux/interrupt.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
 +#include <linux/slab.h>
  
  #include <sound/core.h>
  #include <sound/initval.h>
@@@ -39,23 -38,24 +39,24 @@@ struct imx_pcm_runtime_data 
        unsigned long offset;
        unsigned long last_offset;
        unsigned long size;
-       struct timer_list timer;
-       int poll_time;
+       struct hrtimer hrt;
+       int poll_time_ns;
+       struct snd_pcm_substream *substream;
+       atomic_t running;
  };
  
- static inline void imx_ssi_set_next_poll(struct imx_pcm_runtime_data *iprtd)
+ static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
  {
-       iprtd->timer.expires = jiffies + iprtd->poll_time;
- }
- static void imx_ssi_timer_callback(unsigned long data)
- {
-       struct snd_pcm_substream *substream = (void *)data;
+       struct imx_pcm_runtime_data *iprtd =
+               container_of(hrt, struct imx_pcm_runtime_data, hrt);
+       struct snd_pcm_substream *substream = iprtd->substream;
        struct snd_pcm_runtime *runtime = substream->runtime;
-       struct imx_pcm_runtime_data *iprtd = runtime->private_data;
        struct pt_regs regs;
        unsigned long delta;
  
+       if (!atomic_read(&iprtd->running))
+               return HRTIMER_NORESTART;
        get_fiq_regs(&regs);
  
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
  
        /* If we've transferred at least a period then report it and
         * reset our poll time */
-       if (delta >= runtime->period_size) {
+       if (delta >= iprtd->period) {
                snd_pcm_period_elapsed(substream);
                iprtd->last_offset = iprtd->offset;
-               imx_ssi_set_next_poll(iprtd);
        }
  
-       /* Restart the timer; if we didn't report we'll run on the next tick */
-       add_timer(&iprtd->timer);
+       hrtimer_forward_now(hrt, ns_to_ktime(iprtd->poll_time_ns));
  
+       return HRTIMER_RESTART;
  }
  
  static struct fiq_handler fh = {
@@@ -99,8 -97,8 +98,8 @@@ static int snd_imx_pcm_hw_params(struc
        iprtd->period = params_period_bytes(params) ;
        iprtd->offset = 0;
        iprtd->last_offset = 0;
-       iprtd->poll_time = HZ / (params_rate(params) / params_period_size(params));
+       iprtd->poll_time_ns = 1000000000 / params_rate(params) *
+                               params_period_size(params);
        snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
  
        return 0;
@@@ -135,8 -133,9 +134,9 @@@ static int snd_imx_pcm_trigger(struct s
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               imx_ssi_set_next_poll(iprtd);
-               add_timer(&iprtd->timer);
+               atomic_set(&iprtd->running, 1);
+               hrtimer_start(&iprtd->hrt, ns_to_ktime(iprtd->poll_time_ns),
+                     HRTIMER_MODE_REL);
                if (++fiq_enable == 1)
                        enable_fiq(imx_pcm_fiq);
  
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               del_timer(&iprtd->timer);
+               atomic_set(&iprtd->running, 0);
                if (--fiq_enable == 0)
                        disable_fiq(imx_pcm_fiq);
  
                break;
        default:
                return -EINVAL;
@@@ -180,7 -179,7 +180,7 @@@ static struct snd_pcm_hardware snd_imx_
        .buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
        .period_bytes_min = 128,
        .period_bytes_max = 16 * 1024,
-       .periods_min = 2,
+       .periods_min = 4,
        .periods_max = 255,
        .fifo_size = 0,
  };
@@@ -194,9 -193,11 +194,11 @@@ static int snd_imx_open(struct snd_pcm_
        iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
        runtime->private_data = iprtd;
  
-       init_timer(&iprtd->timer);
-       iprtd->timer.data = (unsigned long)substream;
-       iprtd->timer.function = imx_ssi_timer_callback;
+       iprtd->substream = substream;
+       atomic_set(&iprtd->running, 0);
+       hrtimer_init(&iprtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+       iprtd->hrt.function = snd_hrtimer_callback;
  
        ret = snd_pcm_hw_constraint_integer(substream->runtime,
                        SNDRV_PCM_HW_PARAM_PERIODS);
@@@ -212,7 -213,8 +214,8 @@@ static int snd_imx_close(struct snd_pcm
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct imx_pcm_runtime_data *iprtd = runtime->private_data;
  
-       del_timer_sync(&iprtd->timer);
+       hrtimer_cancel(&iprtd->hrt);
        kfree(iprtd);
  
        return 0;
diff --combined sound/soc/imx/imx-ssi.c
@@@ -39,7 -39,6 +39,7 @@@
  #include <linux/interrupt.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
 +#include <linux/slab.h>
  
  #include <sound/core.h>
  #include <sound/initval.h>
@@@ -656,7 -655,8 +656,8 @@@ static int imx_ssi_probe(struct platfor
        dai->private_data = ssi;
  
        if ((cpu_is_mx27() || cpu_is_mx21()) &&
-                       !(ssi->flags & IMX_SSI_USE_AC97)) {
+                       !(ssi->flags & IMX_SSI_USE_AC97) &&
+                       (ssi->flags & IMX_SSI_DMA)) {
                ssi->flags |= IMX_SSI_DMA;
                platform = imx_ssi_dma_mx2_init(pdev, ssi);
        } else