aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2010-04-08 05:31:26 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-04-08 10:21:05 -0400
commit43a3cec01354573517f1348383e0ab6e6067076b (patch)
tree6ff27b48e5839c4d4f7292a1e10c6238790df730 /sound
parent671999cb5d8817611f865f3877f5a5b81372f61e (diff)
ASoC: imx-ssi: Use a hrtimer in FIQ mode
Using a regular timer results in poll times < 1 jiffie with small buffers, so we loaded the timer with the actual jiffie value. We can be more accurate using a hrtimer. Also, we have to call snd_pcm_period_elapsed after playing period_bytes and not runtime->period_size (which is in samples and not in bytes). Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/imx/imx-pcm-fiq.c45
1 files changed, 21 insertions, 24 deletions
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c
index d9cb9849b033..64df813b9af8 100644
--- a/sound/soc/imx/imx-pcm-fiq.c
+++ b/sound/soc/imx/imx-pcm-fiq.c
@@ -38,20 +38,17 @@ struct imx_pcm_runtime_data {
38 unsigned long offset; 38 unsigned long offset;
39 unsigned long last_offset; 39 unsigned long last_offset;
40 unsigned long size; 40 unsigned long size;
41 struct timer_list timer; 41 struct hrtimer hrt;
42 int poll_time; 42 int poll_time_ns;
43 struct snd_pcm_substream *substream;
43}; 44};
44 45
45static inline void imx_ssi_set_next_poll(struct imx_pcm_runtime_data *iprtd) 46static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt)
46{ 47{
47 iprtd->timer.expires = jiffies + iprtd->poll_time; 48 struct imx_pcm_runtime_data *iprtd =
48} 49 container_of(hrt, struct imx_pcm_runtime_data, hrt);
49 50 struct snd_pcm_substream *substream = iprtd->substream;
50static void imx_ssi_timer_callback(unsigned long data)
51{
52 struct snd_pcm_substream *substream = (void *)data;
53 struct snd_pcm_runtime *runtime = substream->runtime; 51 struct snd_pcm_runtime *runtime = substream->runtime;
54 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
55 struct pt_regs regs; 52 struct pt_regs regs;
56 unsigned long delta; 53 unsigned long delta;
57 54
@@ -71,16 +68,14 @@ static void imx_ssi_timer_callback(unsigned long data)
71 68
72 /* If we've transferred at least a period then report it and 69 /* If we've transferred at least a period then report it and
73 * reset our poll time */ 70 * reset our poll time */
74 if (delta >= runtime->period_size) { 71 if (delta >= iprtd->period) {
75 snd_pcm_period_elapsed(substream); 72 snd_pcm_period_elapsed(substream);
76 iprtd->last_offset = iprtd->offset; 73 iprtd->last_offset = iprtd->offset;
77
78 imx_ssi_set_next_poll(iprtd);
79 } 74 }
80 75
81 /* Restart the timer; if we didn't report we'll run on the next tick */ 76 hrtimer_forward_now(hrt, ns_to_ktime(iprtd->poll_time_ns));
82 add_timer(&iprtd->timer);
83 77
78 return HRTIMER_RESTART;
84} 79}
85 80
86static struct fiq_handler fh = { 81static struct fiq_handler fh = {
@@ -98,8 +93,8 @@ static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
98 iprtd->period = params_period_bytes(params) ; 93 iprtd->period = params_period_bytes(params) ;
99 iprtd->offset = 0; 94 iprtd->offset = 0;
100 iprtd->last_offset = 0; 95 iprtd->last_offset = 0;
101 iprtd->poll_time = HZ / (params_rate(params) / params_period_size(params)); 96 iprtd->poll_time_ns = 1000000000 / params_rate(params) *
102 97 params_period_size(params);
103 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); 98 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
104 99
105 return 0; 100 return 0;
@@ -134,8 +129,8 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
134 case SNDRV_PCM_TRIGGER_START: 129 case SNDRV_PCM_TRIGGER_START:
135 case SNDRV_PCM_TRIGGER_RESUME: 130 case SNDRV_PCM_TRIGGER_RESUME:
136 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 131 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
137 imx_ssi_set_next_poll(iprtd); 132 hrtimer_start(&iprtd->hrt, ns_to_ktime(iprtd->poll_time_ns),
138 add_timer(&iprtd->timer); 133 HRTIMER_MODE_REL);
139 if (++fiq_enable == 1) 134 if (++fiq_enable == 1)
140 enable_fiq(imx_pcm_fiq); 135 enable_fiq(imx_pcm_fiq);
141 136
@@ -144,7 +139,7 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
144 case SNDRV_PCM_TRIGGER_STOP: 139 case SNDRV_PCM_TRIGGER_STOP:
145 case SNDRV_PCM_TRIGGER_SUSPEND: 140 case SNDRV_PCM_TRIGGER_SUSPEND:
146 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 141 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
147 del_timer(&iprtd->timer); 142 hrtimer_cancel(&iprtd->hrt);
148 if (--fiq_enable == 0) 143 if (--fiq_enable == 0)
149 disable_fiq(imx_pcm_fiq); 144 disable_fiq(imx_pcm_fiq);
150 145
@@ -193,9 +188,10 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
193 iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); 188 iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
194 runtime->private_data = iprtd; 189 runtime->private_data = iprtd;
195 190
196 init_timer(&iprtd->timer); 191 iprtd->substream = substream;
197 iprtd->timer.data = (unsigned long)substream; 192
198 iprtd->timer.function = imx_ssi_timer_callback; 193 hrtimer_init(&iprtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
194 iprtd->hrt.function = snd_hrtimer_callback;
199 195
200 ret = snd_pcm_hw_constraint_integer(substream->runtime, 196 ret = snd_pcm_hw_constraint_integer(substream->runtime,
201 SNDRV_PCM_HW_PARAM_PERIODS); 197 SNDRV_PCM_HW_PARAM_PERIODS);
@@ -211,7 +207,8 @@ static int snd_imx_close(struct snd_pcm_substream *substream)
211 struct snd_pcm_runtime *runtime = substream->runtime; 207 struct snd_pcm_runtime *runtime = substream->runtime;
212 struct imx_pcm_runtime_data *iprtd = runtime->private_data; 208 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
213 209
214 del_timer_sync(&iprtd->timer); 210 hrtimer_cancel(&iprtd->hrt);
211
215 kfree(iprtd); 212 kfree(iprtd);
216 213
217 return 0; 214 return 0;