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 { unsigned long offset; unsigned long last_offset; unsigned long size; - struct timer_list timer; - int poll_time; + struct hrtimer hrt; + int poll_time_ns; + struct snd_pcm_substream *substream; + atomic_t running; }; -static inline void imx_ssi_set_next_poll(struct imx_pcm_runtime_data *iprtd) +static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) { - iprtd->timer.expires = jiffies + iprtd->poll_time; -} - -static void imx_ssi_timer_callback(unsigned long data) -{ - struct snd_pcm_substream *substream = (void *)data; + struct imx_pcm_runtime_data *iprtd = + container_of(hrt, struct imx_pcm_runtime_data, hrt); + struct snd_pcm_substream *substream = iprtd->substream; struct snd_pcm_runtime *runtime = substream->runtime; - struct imx_pcm_runtime_data *iprtd = runtime->private_data; struct pt_regs regs; unsigned long delta; + if (!atomic_read(&iprtd->running)) + return HRTIMER_NORESTART; + get_fiq_regs(®s); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) @@ -72,16 +73,14 @@ static void imx_ssi_timer_callback(unsigned long data) /* If we've transferred at least a period then report it and * reset our poll time */ - if (delta >= runtime->period_size) { + if (delta >= iprtd->period) { snd_pcm_period_elapsed(substream); iprtd->last_offset = iprtd->offset; - - imx_ssi_set_next_poll(iprtd); } - /* Restart the timer; if we didn't report we'll run on the next tick */ - add_timer(&iprtd->timer); + hrtimer_forward_now(hrt, ns_to_ktime(iprtd->poll_time_ns)); + return HRTIMER_RESTART; } static struct fiq_handler fh = { @@ -99,8 +98,8 @@ static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, iprtd->period = params_period_bytes(params) ; iprtd->offset = 0; iprtd->last_offset = 0; - iprtd->poll_time = HZ / (params_rate(params) / params_period_size(params)); - + iprtd->poll_time_ns = 1000000000 / params_rate(params) * + params_period_size(params); snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); return 0; @@ -135,8 +134,9 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - imx_ssi_set_next_poll(iprtd); - add_timer(&iprtd->timer); + atomic_set(&iprtd->running, 1); + hrtimer_start(&iprtd->hrt, ns_to_ktime(iprtd->poll_time_ns), + HRTIMER_MODE_REL); if (++fiq_enable == 1) enable_fiq(imx_pcm_fiq); @@ -145,11 +145,11 @@ static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - del_timer(&iprtd->timer); + atomic_set(&iprtd->running, 0); + if (--fiq_enable == 0) disable_fiq(imx_pcm_fiq); - break; default: return -EINVAL; @@ -180,7 +180,7 @@ static struct snd_pcm_hardware snd_imx_hardware = { .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, .period_bytes_min = 128, .period_bytes_max = 16 * 1024, - .periods_min = 2, + .periods_min = 4, .periods_max = 255, .fifo_size = 0, }; @@ -194,9 +194,11 @@ static int snd_imx_open(struct snd_pcm_substream *substream) iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL); runtime->private_data = iprtd; - init_timer(&iprtd->timer); - iprtd->timer.data = (unsigned long)substream; - iprtd->timer.function = imx_ssi_timer_callback; + iprtd->substream = substream; + + atomic_set(&iprtd->running, 0); + hrtimer_init(&iprtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + iprtd->hrt.function = snd_hrtimer_callback; ret = snd_pcm_hw_constraint_integer(substream->runtime, SNDRV_PCM_HW_PARAM_PERIODS); @@ -212,7 +214,8 @@ static int snd_imx_close(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct imx_pcm_runtime_data *iprtd = runtime->private_data; - del_timer_sync(&iprtd->timer); + hrtimer_cancel(&iprtd->hrt); + kfree(iprtd); return 0; |