diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2010-04-08 05:31:26 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-04-08 10:21:05 -0400 |
commit | 43a3cec01354573517f1348383e0ab6e6067076b (patch) | |
tree | 6ff27b48e5839c4d4f7292a1e10c6238790df730 /sound | |
parent | 671999cb5d8817611f865f3877f5a5b81372f61e (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.c | 45 |
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 | ||
45 | static inline void imx_ssi_set_next_poll(struct imx_pcm_runtime_data *iprtd) | 46 | static 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; | |
50 | static 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 | ||
86 | static struct fiq_handler fh = { | 81 | static 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; |