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