aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/imx/imx-pcm-fiq.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/imx/imx-pcm-fiq.c')
-rw-r--r--sound/soc/imx/imx-pcm-fiq.c55
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
46static inline void imx_ssi_set_next_poll(struct imx_pcm_runtime_data *iprtd) 48static 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;
51static 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(&regs); 60 get_fiq_regs(&regs);
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
87static struct fiq_handler fh = { 86static 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;