summary refs log tree commit diff
path: root/sound/soc
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2010-02-25 19:44:00 +0100
committerTakashi Iwai <tiwai@suse.de>2010-02-25 19:44:00 +0100
commita0b62329bb290c10d7278809af910ed115768991 (patch)
treee80a293adced8e97010b6e210a502c929e1a0c1f /sound/soc
parentd62abe563fa4718e7f85f3e871655434db92366d (diff)
parentb4e82b5b785670b68136765059d1afc65c0ae023 (diff)
downloadlinux-a0b62329bb290c10d7278809af910ed115768991.tar.gz
Merge branch 'for-2.6.34' of git://opensource.wolfsonmicro.com/linux-2.6-asoc into topic/asoc
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/imx/imx-pcm-fiq.c40
1 files changed, 30 insertions, 10 deletions
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c
index 5532579ece4d..d9cb9849b033 100644
--- a/sound/soc/imx/imx-pcm-fiq.c
+++ b/sound/soc/imx/imx-pcm-fiq.c
@@ -35,22 +35,25 @@
 struct imx_pcm_runtime_data {
 	int period;
 	int periods;
-	unsigned long dma_addr;
-	int dma;
 	unsigned long offset;
+	unsigned long last_offset;
 	unsigned long size;
-	unsigned long period_cnt;
-	void *buf;
 	struct timer_list timer;
-	int period_time;
+	int poll_time;
 };
 
+static inline void imx_ssi_set_next_poll(struct imx_pcm_runtime_data *iprtd)
+{
+	iprtd->timer.expires = jiffies + iprtd->poll_time;
+}
+
 static void imx_ssi_timer_callback(unsigned long data)
 {
 	struct snd_pcm_substream *substream = (void *)data;
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct imx_pcm_runtime_data *iprtd = runtime->private_data;
 	struct pt_regs regs;
+	unsigned long delta;
 
 	get_fiq_regs(&regs);
 
@@ -59,9 +62,25 @@ static void imx_ssi_timer_callback(unsigned long data)
 	else
 		iprtd->offset = regs.ARM_r9 & 0xffff;
 
-	iprtd->timer.expires = jiffies + iprtd->period_time;
+	/* How much data have we transferred since the last period report? */
+	if (iprtd->offset >= iprtd->last_offset)
+		delta = iprtd->offset - iprtd->last_offset;
+	else
+		delta = runtime->buffer_size + iprtd->offset
+			- iprtd->last_offset;
+
+	/* If we've transferred at least a period then report it and
+	 * reset our poll time */
+	if (delta >= runtime->period_size) {
+		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);
-	snd_pcm_period_elapsed(substream);
+
 }
 
 static struct fiq_handler fh = {
@@ -76,9 +95,10 @@ static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
 
 	iprtd->size = params_buffer_bytes(params);
 	iprtd->periods = params_periods(params);
-	iprtd->period = params_period_bytes(params);
+	iprtd->period = params_period_bytes(params) ;
 	iprtd->offset = 0;
-	iprtd->period_time = HZ / (params_rate(params) / params_period_size(params));
+	iprtd->last_offset = 0;
+	iprtd->poll_time = HZ / (params_rate(params) / params_period_size(params));
 
 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 
@@ -114,7 +134,7 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		iprtd->timer.expires = jiffies + iprtd->period_time;
+		imx_ssi_set_next_poll(iprtd);
 		add_timer(&iprtd->timer);
 		if (++fiq_enable == 1)
 			enable_fiq(imx_pcm_fiq);