|
@@ -39,23 +39,24 @@ struct imx_pcm_runtime_data {
|
|
unsigned long offset;
|
|
unsigned long offset;
|
|
unsigned long last_offset;
|
|
unsigned long last_offset;
|
|
unsigned long size;
|
|
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 snd_pcm_runtime *runtime = substream->runtime;
|
|
- struct imx_pcm_runtime_data *iprtd = runtime->private_data;
|
|
|
|
struct pt_regs regs;
|
|
struct pt_regs regs;
|
|
unsigned long delta;
|
|
unsigned long delta;
|
|
|
|
|
|
|
|
+ if (!atomic_read(&iprtd->running))
|
|
|
|
+ return HRTIMER_NORESTART;
|
|
|
|
+
|
|
get_fiq_regs(®s);
|
|
get_fiq_regs(®s);
|
|
|
|
|
|
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
|
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
|
|
/* If we've transferred at least a period then report it and
|
|
* reset our poll time */
|
|
* reset our poll time */
|
|
- if (delta >= runtime->period_size) {
|
|
|
|
|
|
+ if (delta >= iprtd->period) {
|
|
snd_pcm_period_elapsed(substream);
|
|
snd_pcm_period_elapsed(substream);
|
|
iprtd->last_offset = iprtd->offset;
|
|
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 = {
|
|
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->period = params_period_bytes(params) ;
|
|
iprtd->offset = 0;
|
|
iprtd->offset = 0;
|
|
iprtd->last_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);
|
|
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
|
|
|
|
|
|
return 0;
|
|
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_START:
|
|
case SNDRV_PCM_TRIGGER_RESUME:
|
|
case SNDRV_PCM_TRIGGER_RESUME:
|
|
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
|
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)
|
|
if (++fiq_enable == 1)
|
|
enable_fiq(imx_pcm_fiq);
|
|
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_STOP:
|
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
|
- del_timer(&iprtd->timer);
|
|
|
|
|
|
+ atomic_set(&iprtd->running, 0);
|
|
|
|
+
|
|
if (--fiq_enable == 0)
|
|
if (--fiq_enable == 0)
|
|
disable_fiq(imx_pcm_fiq);
|
|
disable_fiq(imx_pcm_fiq);
|
|
|
|
|
|
-
|
|
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
@@ -180,7 +180,7 @@ static struct snd_pcm_hardware snd_imx_hardware = {
|
|
.buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
|
|
.buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
|
|
.period_bytes_min = 128,
|
|
.period_bytes_min = 128,
|
|
.period_bytes_max = 16 * 1024,
|
|
.period_bytes_max = 16 * 1024,
|
|
- .periods_min = 2,
|
|
|
|
|
|
+ .periods_min = 4,
|
|
.periods_max = 255,
|
|
.periods_max = 255,
|
|
.fifo_size = 0,
|
|
.fifo_size = 0,
|
|
};
|
|
};
|
|
@@ -194,9 +194,11 @@ static int snd_imx_open(struct snd_pcm_substream *substream)
|
|
iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
|
|
iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
|
|
runtime->private_data = iprtd;
|
|
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,
|
|
ret = snd_pcm_hw_constraint_integer(substream->runtime,
|
|
SNDRV_PCM_HW_PARAM_PERIODS);
|
|
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 snd_pcm_runtime *runtime = substream->runtime;
|
|
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
|
|
struct imx_pcm_runtime_data *iprtd = runtime->private_data;
|
|
|
|
|
|
- del_timer_sync(&iprtd->timer);
|
|
|
|
|
|
+ hrtimer_cancel(&iprtd->hrt);
|
|
|
|
+
|
|
kfree(iprtd);
|
|
kfree(iprtd);
|
|
|
|
|
|
return 0;
|
|
return 0;
|