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 d9cb9849b03..6b518e07eea 100644 --- a/sound/soc/imx/imx-pcm-fiq.c +++ b/sound/soc/imx/imx-pcm-fiq.c @@ -19,6 +19,7 @@  #include <linux/interrupt.h>  #include <linux/module.h>  #include <linux/platform_device.h> +#include <linux/slab.h>  #include <sound/core.h>  #include <sound/initval.h> @@ -38,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) @@ -71,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 = { @@ -98,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; @@ -134,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); @@ -144,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; @@ -179,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,  }; @@ -193,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); @@ -211,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;  |