diff options
Diffstat (limited to 'sound/soc/imx/imx-pcm-fiq.c')
-rw-r--r-- | sound/soc/imx/imx-pcm-fiq.c | 56 |
1 files changed, 30 insertions, 26 deletions
diff --git a/sound/soc/imx/imx-pcm-fiq.c b/sound/soc/imx/imx-pcm-fiq.c index d9cb9849b033..6b518e07eea9 100644 --- a/sound/soc/imx/imx-pcm-fiq.c +++ b/sound/soc/imx/imx-pcm-fiq.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/slab.h> | ||
22 | 23 | ||
23 | #include <sound/core.h> | 24 | #include <sound/core.h> |
24 | #include <sound/initval.h> | 25 | #include <sound/initval.h> |
@@ -38,23 +39,24 @@ struct imx_pcm_runtime_data { | |||
38 | unsigned long offset; | 39 | unsigned long offset; |
39 | unsigned long last_offset; | 40 | unsigned long last_offset; |
40 | unsigned long size; | 41 | unsigned long size; |
41 | struct timer_list timer; | 42 | struct hrtimer hrt; |
42 | int poll_time; | 43 | int poll_time_ns; |
44 | struct snd_pcm_substream *substream; | ||
45 | atomic_t running; | ||
43 | }; | 46 | }; |
44 | 47 | ||
45 | static inline void imx_ssi_set_next_poll(struct imx_pcm_runtime_data *iprtd) | 48 | static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) |
46 | { | 49 | { |
47 | iprtd->timer.expires = jiffies + iprtd->poll_time; | 50 | struct imx_pcm_runtime_data *iprtd = |
48 | } | 51 | container_of(hrt, struct imx_pcm_runtime_data, hrt); |
49 | 52 | 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; | 53 | struct snd_pcm_runtime *runtime = substream->runtime; |
54 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | ||
55 | struct pt_regs regs; | 54 | struct pt_regs regs; |
56 | unsigned long delta; | 55 | unsigned long delta; |
57 | 56 | ||
57 | if (!atomic_read(&iprtd->running)) | ||
58 | return HRTIMER_NORESTART; | ||
59 | |||
58 | get_fiq_regs(®s); | 60 | get_fiq_regs(®s); |
59 | 61 | ||
60 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 62 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
@@ -71,16 +73,14 @@ static void imx_ssi_timer_callback(unsigned long data) | |||
71 | 73 | ||
72 | /* If we've transferred at least a period then report it and | 74 | /* If we've transferred at least a period then report it and |
73 | * reset our poll time */ | 75 | * reset our poll time */ |
74 | if (delta >= runtime->period_size) { | 76 | if (delta >= iprtd->period) { |
75 | snd_pcm_period_elapsed(substream); | 77 | snd_pcm_period_elapsed(substream); |
76 | iprtd->last_offset = iprtd->offset; | 78 | iprtd->last_offset = iprtd->offset; |
77 | |||
78 | imx_ssi_set_next_poll(iprtd); | ||
79 | } | 79 | } |
80 | 80 | ||
81 | /* Restart the timer; if we didn't report we'll run on the next tick */ | 81 | hrtimer_forward_now(hrt, ns_to_ktime(iprtd->poll_time_ns)); |
82 | add_timer(&iprtd->timer); | ||
83 | 82 | ||
83 | return HRTIMER_RESTART; | ||
84 | } | 84 | } |
85 | 85 | ||
86 | static struct fiq_handler fh = { | 86 | static struct fiq_handler fh = { |
@@ -98,8 +98,8 @@ static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, | |||
98 | iprtd->period = params_period_bytes(params) ; | 98 | iprtd->period = params_period_bytes(params) ; |
99 | iprtd->offset = 0; | 99 | iprtd->offset = 0; |
100 | iprtd->last_offset = 0; | 100 | iprtd->last_offset = 0; |
101 | iprtd->poll_time = HZ / (params_rate(params) / params_period_size(params)); | 101 | iprtd->poll_time_ns = 1000000000 / params_rate(params) * |
102 | 102 | params_period_size(params); | |
103 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | 103 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); |
104 | 104 | ||
105 | return 0; | 105 | return 0; |
@@ -134,8 +134,9 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
134 | case SNDRV_PCM_TRIGGER_START: | 134 | case SNDRV_PCM_TRIGGER_START: |
135 | case SNDRV_PCM_TRIGGER_RESUME: | 135 | case SNDRV_PCM_TRIGGER_RESUME: |
136 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 136 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
137 | imx_ssi_set_next_poll(iprtd); | 137 | atomic_set(&iprtd->running, 1); |
138 | add_timer(&iprtd->timer); | 138 | hrtimer_start(&iprtd->hrt, ns_to_ktime(iprtd->poll_time_ns), |
139 | HRTIMER_MODE_REL); | ||
139 | if (++fiq_enable == 1) | 140 | if (++fiq_enable == 1) |
140 | enable_fiq(imx_pcm_fiq); | 141 | enable_fiq(imx_pcm_fiq); |
141 | 142 | ||
@@ -144,11 +145,11 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
144 | case SNDRV_PCM_TRIGGER_STOP: | 145 | case SNDRV_PCM_TRIGGER_STOP: |
145 | case SNDRV_PCM_TRIGGER_SUSPEND: | 146 | case SNDRV_PCM_TRIGGER_SUSPEND: |
146 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 147 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
147 | del_timer(&iprtd->timer); | 148 | atomic_set(&iprtd->running, 0); |
149 | |||
148 | if (--fiq_enable == 0) | 150 | if (--fiq_enable == 0) |
149 | disable_fiq(imx_pcm_fiq); | 151 | disable_fiq(imx_pcm_fiq); |
150 | 152 | ||
151 | |||
152 | break; | 153 | break; |
153 | default: | 154 | default: |
154 | return -EINVAL; | 155 | return -EINVAL; |
@@ -179,7 +180,7 @@ static struct snd_pcm_hardware snd_imx_hardware = { | |||
179 | .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, | 180 | .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, |
180 | .period_bytes_min = 128, | 181 | .period_bytes_min = 128, |
181 | .period_bytes_max = 16 * 1024, | 182 | .period_bytes_max = 16 * 1024, |
182 | .periods_min = 2, | 183 | .periods_min = 4, |
183 | .periods_max = 255, | 184 | .periods_max = 255, |
184 | .fifo_size = 0, | 185 | .fifo_size = 0, |
185 | }; | 186 | }; |
@@ -193,9 +194,11 @@ static int snd_imx_open(struct snd_pcm_substream *substream) | |||
193 | iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); | 194 | iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); |
194 | runtime->private_data = iprtd; | 195 | runtime->private_data = iprtd; |
195 | 196 | ||
196 | init_timer(&iprtd->timer); | 197 | iprtd->substream = substream; |
197 | iprtd->timer.data = (unsigned long)substream; | 198 | |
198 | iprtd->timer.function = imx_ssi_timer_callback; | 199 | atomic_set(&iprtd->running, 0); |
200 | hrtimer_init(&iprtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
201 | iprtd->hrt.function = snd_hrtimer_callback; | ||
199 | 202 | ||
200 | ret = snd_pcm_hw_constraint_integer(substream->runtime, | 203 | ret = snd_pcm_hw_constraint_integer(substream->runtime, |
201 | SNDRV_PCM_HW_PARAM_PERIODS); | 204 | SNDRV_PCM_HW_PARAM_PERIODS); |
@@ -211,7 +214,8 @@ static int snd_imx_close(struct snd_pcm_substream *substream) | |||
211 | struct snd_pcm_runtime *runtime = substream->runtime; | 214 | struct snd_pcm_runtime *runtime = substream->runtime; |
212 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; | 215 | struct imx_pcm_runtime_data *iprtd = runtime->private_data; |
213 | 216 | ||
214 | del_timer_sync(&iprtd->timer); | 217 | hrtimer_cancel(&iprtd->hrt); |
218 | |||
215 | kfree(iprtd); | 219 | kfree(iprtd); |
216 | 220 | ||
217 | return 0; | 221 | return 0; |