1 // SPDX-License-Identifier: GPL-2.0-only
3 * PCM timer handling on ctxfi
6 #include <linux/slab.h>
7 #include <linux/math64.h>
8 #include <linux/moduleparam.h>
9 #include <sound/core.h>
10 #include <sound/pcm.h>
12 #include "cthardware.h"
15 static bool use_system_timer
;
16 MODULE_PARM_DESC(use_system_timer
, "Force to use system-timer");
17 module_param(use_system_timer
, bool, 0444);
20 void (*init
)(struct ct_timer_instance
*);
21 void (*prepare
)(struct ct_timer_instance
*);
22 void (*start
)(struct ct_timer_instance
*);
23 void (*stop
)(struct ct_timer_instance
*);
24 void (*free_instance
)(struct ct_timer_instance
*);
25 void (*interrupt
)(struct ct_timer
*);
26 void (*free_global
)(struct ct_timer
*);
29 /* timer instance -- assigned to each PCM stream */
30 struct ct_timer_instance
{
32 struct ct_timer
*timer_base
;
33 struct ct_atc_pcm
*apcm
;
34 struct snd_pcm_substream
*substream
;
35 struct timer_list timer
;
36 struct list_head instance_list
;
37 struct list_head running_list
;
38 unsigned int position
;
39 unsigned int frag_count
;
40 unsigned int running
:1;
41 unsigned int need_update
:1;
44 /* timer instance manager */
46 spinlock_t lock
; /* global timer lock (for xfitimer) */
47 spinlock_t list_lock
; /* lock for instance list */
49 const struct ct_timer_ops
*ops
;
50 struct list_head instance_head
;
51 struct list_head running_head
;
52 unsigned int wc
; /* current wallclock */
53 unsigned int irq_handling
:1; /* in IRQ handling */
54 unsigned int reprogram
:1; /* need to reprogram the internval */
55 unsigned int running
:1; /* global timer running */
60 * system-timer-based updates
63 static void ct_systimer_callback(struct timer_list
*t
)
65 struct ct_timer_instance
*ti
= from_timer(ti
, t
, timer
);
66 struct snd_pcm_substream
*substream
= ti
->substream
;
67 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
68 struct ct_atc_pcm
*apcm
= ti
->apcm
;
69 unsigned int period_size
= runtime
->period_size
;
70 unsigned int buffer_size
= runtime
->buffer_size
;
72 unsigned int position
, dist
, interval
;
74 position
= substream
->ops
->pointer(substream
);
75 dist
= (position
+ buffer_size
- ti
->position
) % buffer_size
;
76 if (dist
>= period_size
||
77 position
/ period_size
!= ti
->position
/ period_size
) {
78 apcm
->interrupt(apcm
);
79 ti
->position
= position
;
81 /* Add extra HZ*5/1000 to avoid overrun issue when recording
82 * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */
83 interval
= ((period_size
- (position
% period_size
))
84 * HZ
+ (runtime
->rate
- 1)) / runtime
->rate
+ HZ
* 5 / 1000;
85 spin_lock_irqsave(&ti
->lock
, flags
);
87 mod_timer(&ti
->timer
, jiffies
+ interval
);
88 spin_unlock_irqrestore(&ti
->lock
, flags
);
91 static void ct_systimer_init(struct ct_timer_instance
*ti
)
93 timer_setup(&ti
->timer
, ct_systimer_callback
, 0);
96 static void ct_systimer_start(struct ct_timer_instance
*ti
)
98 struct snd_pcm_runtime
*runtime
= ti
->substream
->runtime
;
101 spin_lock_irqsave(&ti
->lock
, flags
);
103 mod_timer(&ti
->timer
,
104 jiffies
+ (runtime
->period_size
* HZ
+
105 (runtime
->rate
- 1)) / runtime
->rate
);
106 spin_unlock_irqrestore(&ti
->lock
, flags
);
109 static void ct_systimer_stop(struct ct_timer_instance
*ti
)
113 spin_lock_irqsave(&ti
->lock
, flags
);
115 del_timer(&ti
->timer
);
116 spin_unlock_irqrestore(&ti
->lock
, flags
);
119 static void ct_systimer_prepare(struct ct_timer_instance
*ti
)
121 ct_systimer_stop(ti
);
122 try_to_del_timer_sync(&ti
->timer
);
125 #define ct_systimer_free ct_systimer_prepare
127 static const struct ct_timer_ops ct_systimer_ops
= {
128 .init
= ct_systimer_init
,
129 .free_instance
= ct_systimer_free
,
130 .prepare
= ct_systimer_prepare
,
131 .start
= ct_systimer_start
,
132 .stop
= ct_systimer_stop
,
137 * Handling multiple streams using a global emu20k1 timer irq
140 #define CT_TIMER_FREQ 48000
142 #define MAX_TICKS ((1 << 13) - 1)
144 static void ct_xfitimer_irq_rearm(struct ct_timer
*atimer
, int ticks
)
146 struct hw
*hw
= atimer
->atc
->hw
;
147 if (ticks
> MAX_TICKS
)
149 hw
->set_timer_tick(hw
, ticks
);
150 if (!atimer
->running
)
151 hw
->set_timer_irq(hw
, 1);
155 static void ct_xfitimer_irq_stop(struct ct_timer
*atimer
)
157 if (atimer
->running
) {
158 struct hw
*hw
= atimer
->atc
->hw
;
159 hw
->set_timer_irq(hw
, 0);
160 hw
->set_timer_tick(hw
, 0);
165 static inline unsigned int ct_xfitimer_get_wc(struct ct_timer
*atimer
)
167 struct hw
*hw
= atimer
->atc
->hw
;
168 return hw
->get_wc(hw
);
172 * reprogram the timer interval;
173 * checks the running instance list and determines the next timer interval.
174 * also updates the each stream position, returns the number of streams
175 * to call snd_pcm_period_elapsed() appropriately
177 * call this inside the lock and irq disabled
179 static int ct_xfitimer_reprogram(struct ct_timer
*atimer
, int can_update
)
181 struct ct_timer_instance
*ti
;
182 unsigned int min_intr
= (unsigned int)-1;
184 unsigned int wc
, diff
;
186 if (list_empty(&atimer
->running_head
)) {
187 ct_xfitimer_irq_stop(atimer
);
188 atimer
->reprogram
= 0; /* clear flag */
192 wc
= ct_xfitimer_get_wc(atimer
);
193 diff
= wc
- atimer
->wc
;
195 list_for_each_entry(ti
, &atimer
->running_head
, running_list
) {
196 if (ti
->frag_count
> diff
)
197 ti
->frag_count
-= diff
;
200 unsigned int period_size
, rate
;
202 period_size
= ti
->substream
->runtime
->period_size
;
203 rate
= ti
->substream
->runtime
->rate
;
204 pos
= ti
->substream
->ops
->pointer(ti
->substream
);
205 if (pos
/ period_size
!= ti
->position
/ period_size
) {
211 pos
= period_size
- pos
;
212 ti
->frag_count
= div_u64((u64
)pos
* CT_TIMER_FREQ
+
215 if (ti
->need_update
&& !can_update
)
216 min_intr
= 0; /* pending to the next irq */
217 if (ti
->frag_count
< min_intr
)
218 min_intr
= ti
->frag_count
;
221 if (min_intr
< MIN_TICKS
)
222 min_intr
= MIN_TICKS
;
223 ct_xfitimer_irq_rearm(atimer
, min_intr
);
224 atimer
->reprogram
= 0; /* clear flag */
228 /* look through the instance list and call period_elapsed if needed */
229 static void ct_xfitimer_check_period(struct ct_timer
*atimer
)
231 struct ct_timer_instance
*ti
;
234 spin_lock_irqsave(&atimer
->list_lock
, flags
);
235 list_for_each_entry(ti
, &atimer
->instance_head
, instance_list
) {
236 if (ti
->running
&& ti
->need_update
) {
238 ti
->apcm
->interrupt(ti
->apcm
);
241 spin_unlock_irqrestore(&atimer
->list_lock
, flags
);
244 /* Handle timer-interrupt */
245 static void ct_xfitimer_callback(struct ct_timer
*atimer
)
250 spin_lock_irqsave(&atimer
->lock
, flags
);
251 atimer
->irq_handling
= 1;
253 update
= ct_xfitimer_reprogram(atimer
, 1);
254 spin_unlock(&atimer
->lock
);
256 ct_xfitimer_check_period(atimer
);
257 spin_lock(&atimer
->lock
);
258 } while (atimer
->reprogram
);
259 atimer
->irq_handling
= 0;
260 spin_unlock_irqrestore(&atimer
->lock
, flags
);
263 static void ct_xfitimer_prepare(struct ct_timer_instance
*ti
)
265 ti
->frag_count
= ti
->substream
->runtime
->period_size
;
271 /* start/stop the timer */
272 static void ct_xfitimer_update(struct ct_timer
*atimer
)
276 spin_lock_irqsave(&atimer
->lock
, flags
);
277 if (atimer
->irq_handling
) {
278 /* reached from IRQ handler; let it handle later */
279 atimer
->reprogram
= 1;
280 spin_unlock_irqrestore(&atimer
->lock
, flags
);
284 ct_xfitimer_irq_stop(atimer
);
285 ct_xfitimer_reprogram(atimer
, 0);
286 spin_unlock_irqrestore(&atimer
->lock
, flags
);
289 static void ct_xfitimer_start(struct ct_timer_instance
*ti
)
291 struct ct_timer
*atimer
= ti
->timer_base
;
294 spin_lock_irqsave(&atimer
->lock
, flags
);
295 if (list_empty(&ti
->running_list
))
296 atimer
->wc
= ct_xfitimer_get_wc(atimer
);
299 list_add(&ti
->running_list
, &atimer
->running_head
);
300 spin_unlock_irqrestore(&atimer
->lock
, flags
);
301 ct_xfitimer_update(atimer
);
304 static void ct_xfitimer_stop(struct ct_timer_instance
*ti
)
306 struct ct_timer
*atimer
= ti
->timer_base
;
309 spin_lock_irqsave(&atimer
->lock
, flags
);
310 list_del_init(&ti
->running_list
);
312 spin_unlock_irqrestore(&atimer
->lock
, flags
);
313 ct_xfitimer_update(atimer
);
316 static void ct_xfitimer_free_global(struct ct_timer
*atimer
)
318 ct_xfitimer_irq_stop(atimer
);
321 static const struct ct_timer_ops ct_xfitimer_ops
= {
322 .prepare
= ct_xfitimer_prepare
,
323 .start
= ct_xfitimer_start
,
324 .stop
= ct_xfitimer_stop
,
325 .interrupt
= ct_xfitimer_callback
,
326 .free_global
= ct_xfitimer_free_global
,
333 struct ct_timer_instance
*
334 ct_timer_instance_new(struct ct_timer
*atimer
, struct ct_atc_pcm
*apcm
)
336 struct ct_timer_instance
*ti
;
338 ti
= kzalloc(sizeof(*ti
), GFP_KERNEL
);
341 spin_lock_init(&ti
->lock
);
342 INIT_LIST_HEAD(&ti
->instance_list
);
343 INIT_LIST_HEAD(&ti
->running_list
);
344 ti
->timer_base
= atimer
;
346 ti
->substream
= apcm
->substream
;
347 if (atimer
->ops
->init
)
348 atimer
->ops
->init(ti
);
350 spin_lock_irq(&atimer
->list_lock
);
351 list_add(&ti
->instance_list
, &atimer
->instance_head
);
352 spin_unlock_irq(&atimer
->list_lock
);
357 void ct_timer_prepare(struct ct_timer_instance
*ti
)
359 if (ti
->timer_base
->ops
->prepare
)
360 ti
->timer_base
->ops
->prepare(ti
);
365 void ct_timer_start(struct ct_timer_instance
*ti
)
367 struct ct_timer
*atimer
= ti
->timer_base
;
368 atimer
->ops
->start(ti
);
371 void ct_timer_stop(struct ct_timer_instance
*ti
)
373 struct ct_timer
*atimer
= ti
->timer_base
;
374 atimer
->ops
->stop(ti
);
377 void ct_timer_instance_free(struct ct_timer_instance
*ti
)
379 struct ct_timer
*atimer
= ti
->timer_base
;
381 atimer
->ops
->stop(ti
); /* to be sure */
382 if (atimer
->ops
->free_instance
)
383 atimer
->ops
->free_instance(ti
);
385 spin_lock_irq(&atimer
->list_lock
);
386 list_del(&ti
->instance_list
);
387 spin_unlock_irq(&atimer
->list_lock
);
396 static void ct_timer_interrupt(void *data
, unsigned int status
)
398 struct ct_timer
*timer
= data
;
400 /* Interval timer interrupt */
401 if ((status
& IT_INT
) && timer
->ops
->interrupt
)
402 timer
->ops
->interrupt(timer
);
405 struct ct_timer
*ct_timer_new(struct ct_atc
*atc
)
407 struct ct_timer
*atimer
;
410 atimer
= kzalloc(sizeof(*atimer
), GFP_KERNEL
);
413 spin_lock_init(&atimer
->lock
);
414 spin_lock_init(&atimer
->list_lock
);
415 INIT_LIST_HEAD(&atimer
->instance_head
);
416 INIT_LIST_HEAD(&atimer
->running_head
);
419 if (!use_system_timer
&& hw
->set_timer_irq
) {
420 dev_info(atc
->card
->dev
, "Use xfi-native timer\n");
421 atimer
->ops
= &ct_xfitimer_ops
;
422 hw
->irq_callback_data
= atimer
;
423 hw
->irq_callback
= ct_timer_interrupt
;
425 dev_info(atc
->card
->dev
, "Use system timer\n");
426 atimer
->ops
= &ct_systimer_ops
;
431 void ct_timer_free(struct ct_timer
*atimer
)
433 struct hw
*hw
= atimer
->atc
->hw
;
434 hw
->irq_callback
= NULL
;
435 if (atimer
->ops
->free_global
)
436 atimer
->ops
->free_global(atimer
);