1 /*
2 * Copyright (c) 2024 Renesas Electronics Corporation
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #define DT_DRV_COMPAT renesas_rz_gtm_counter
7
8 #include <zephyr/device.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/counter.h>
11 #include <r_gtm.h>
12
13 #define RZ_GTM_TOP_VALUE UINT32_MAX
14
15 #define counter_rz_gtm_clear_pending(irq) NVIC_ClearPendingIRQ(irq)
16 #define counter_rz_gtm_set_pending(irq) NVIC_SetPendingIRQ(irq)
17 #define counter_rz_gtm_is_pending(irq) NVIC_GetPendingIRQ(irq)
18
19 struct counter_rz_gtm_config {
20 struct counter_config_info config_info;
21 const timer_api_t *fsp_api;
22 uint8_t irqn;
23 };
24
25 struct counter_rz_gtm_data {
26 timer_cfg_t *fsp_cfg;
27 gtm_instance_ctrl_t *fsp_ctrl;
28 /* top callback function */
29 counter_top_callback_t top_cb;
30 /* alarm callback function */
31 counter_alarm_callback_t alarm_cb;
32 void *user_data;
33 uint32_t clk_freq;
34 struct k_spinlock lock;
35 uint32_t guard_period;
36 uint32_t top_val;
37 bool is_started;
38 bool is_periodic;
39 };
40
counter_rz_gtm_get_value(const struct device * dev,uint32_t * ticks)41 static int counter_rz_gtm_get_value(const struct device *dev, uint32_t *ticks)
42 {
43 const struct counter_rz_gtm_config *cfg = dev->config;
44 struct counter_rz_gtm_data *data = dev->data;
45 timer_status_t timer_status;
46 fsp_err_t err;
47
48 err = cfg->fsp_api->statusGet(data->fsp_ctrl, &timer_status);
49 if (err != FSP_SUCCESS) {
50 return err;
51 }
52 uint32_t value = (uint32_t)timer_status.counter;
53 *ticks = value;
54
55 return 0;
56 }
57
counter_rz_gtm_irq_handler(timer_callback_args_t * p_args)58 static void counter_rz_gtm_irq_handler(timer_callback_args_t *p_args)
59 {
60 const struct device *dev = p_args->p_context;
61 struct counter_rz_gtm_data *data = dev->data;
62 counter_alarm_callback_t alarm_callback = data->alarm_cb;
63 k_spinlock_key_t key;
64
65 key = k_spin_lock(&data->lock);
66
67 if (alarm_callback) {
68 uint32_t now;
69
70 counter_rz_gtm_get_value(dev, &now);
71 data->alarm_cb = NULL;
72 alarm_callback(dev, 0, now, data->user_data);
73 } else if (data->top_cb) {
74 data->top_cb(dev, data->user_data);
75 }
76
77 k_spin_unlock(&data->lock, key);
78 }
79
counter_rz_gtm_init(const struct device * dev)80 static int counter_rz_gtm_init(const struct device *dev)
81 {
82 struct counter_rz_gtm_data *data = dev->data;
83 const struct counter_rz_gtm_config *cfg = dev->config;
84 int err;
85
86 data->top_val = data->fsp_cfg->period_counts;
87
88 err = cfg->fsp_api->open(data->fsp_ctrl, data->fsp_cfg);
89 if (err != FSP_SUCCESS) {
90 return err;
91 }
92 return err;
93 }
94
counter_rz_gtm_start_freerun(const struct device * dev)95 static void counter_rz_gtm_start_freerun(const struct device *dev)
96 {
97 /* enable counter in free running mode */
98 const struct counter_rz_gtm_config *cfg = dev->config;
99 struct counter_rz_gtm_data *data = dev->data;
100
101 gtm_extended_cfg_t *fsp_cfg_extend = (gtm_extended_cfg_t *)data->fsp_cfg->p_extend;
102
103 fsp_cfg_extend->gtm_mode = GTM_TIMER_MODE_FREERUN;
104 cfg->fsp_api->close(data->fsp_ctrl);
105 cfg->fsp_api->open(data->fsp_ctrl, data->fsp_cfg);
106 cfg->fsp_api->start(data->fsp_ctrl);
107 }
108
counter_rz_gtm_start_interval(const struct device * dev)109 static void counter_rz_gtm_start_interval(const struct device *dev)
110 {
111 /* start timer in interval mode */
112 const struct counter_rz_gtm_config *cfg = dev->config;
113 struct counter_rz_gtm_data *data = dev->data;
114
115 gtm_extended_cfg_t *fsp_cfg_extend = (gtm_extended_cfg_t *)data->fsp_cfg->p_extend;
116
117 fsp_cfg_extend->gtm_mode = GTM_TIMER_MODE_INTERVAL;
118 cfg->fsp_api->close(data->fsp_ctrl);
119 cfg->fsp_api->open(data->fsp_ctrl, data->fsp_cfg);
120 cfg->fsp_api->start(data->fsp_ctrl);
121 }
122
counter_rz_gtm_start(const struct device * dev)123 static int counter_rz_gtm_start(const struct device *dev)
124 {
125 const struct counter_rz_gtm_config *cfg = dev->config;
126 struct counter_rz_gtm_data *data = dev->data;
127 k_spinlock_key_t key;
128
129 key = k_spin_lock(&data->lock);
130
131 if (data->is_started) {
132 k_spin_unlock(&data->lock, key);
133 return -EALREADY;
134 }
135
136 if (data->is_periodic) {
137 data->fsp_cfg->period_counts = data->top_val;
138 counter_rz_gtm_start_interval(dev);
139 } else {
140 counter_rz_gtm_start_freerun(dev);
141 }
142
143 counter_rz_gtm_clear_pending(cfg->irqn);
144 data->is_started = true;
145 if (data->top_cb) {
146 irq_enable(cfg->irqn);
147 }
148
149 k_spin_unlock(&data->lock, key);
150
151 return 0;
152 }
153
counter_rz_gtm_stop(const struct device * dev)154 static int counter_rz_gtm_stop(const struct device *dev)
155 {
156 const struct counter_rz_gtm_config *cfg = dev->config;
157 struct counter_rz_gtm_data *data = dev->data;
158 k_spinlock_key_t key;
159
160 key = k_spin_lock(&data->lock);
161
162 if (!data->is_started) {
163 k_spin_unlock(&data->lock, key);
164 return 0;
165 }
166
167 fsp_err_t err = FSP_SUCCESS;
168
169 /* Stop timer */
170 err = cfg->fsp_api->stop(data->fsp_ctrl);
171
172 /* dis irq */
173 irq_disable(cfg->irqn);
174 counter_rz_gtm_clear_pending(cfg->irqn);
175
176 data->top_cb = NULL;
177 data->alarm_cb = NULL;
178 data->user_data = NULL;
179
180 data->is_started = false;
181
182 k_spin_unlock(&data->lock, key);
183
184 return err;
185 }
186
counter_rz_gtm_set_alarm(const struct device * dev,uint8_t chan,const struct counter_alarm_cfg * alarm_cfg)187 static int counter_rz_gtm_set_alarm(const struct device *dev, uint8_t chan,
188 const struct counter_alarm_cfg *alarm_cfg)
189 {
190 const struct counter_rz_gtm_config *cfg = dev->config;
191 struct counter_rz_gtm_data *data = dev->data;
192
193 bool absolute = alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE;
194 uint32_t val = alarm_cfg->ticks;
195 k_spinlock_key_t key;
196 bool irq_on_late;
197 uint32_t max_rel_val;
198 uint32_t now, diff;
199 int err = 0;
200
201 if (!alarm_cfg) {
202 return -EINVAL;
203 }
204 /* Alarm callback is mandatory */
205 if (!alarm_cfg->callback) {
206 return -EINVAL;
207 }
208
209 key = k_spin_lock(&data->lock);
210
211 if (!data->is_started) {
212 k_spin_unlock(&data->lock, key);
213 return -EINVAL;
214 }
215
216 /** Alarm_cb need equal NULL before */
217 if (data->alarm_cb) {
218 k_spin_unlock(&data->lock, key);
219 return -EBUSY;
220 }
221
222 /** Timer is currently in interval mode*/
223 if (data->is_periodic) {
224 /** return error because val exceeded the limit set alarm */
225 if (val > data->fsp_cfg->period_counts) {
226 k_spin_unlock(&data->lock, key);
227 return -EINVAL;
228 }
229
230 /* restore free running mode */
231 irq_disable(cfg->irqn);
232 data->top_cb = NULL;
233 data->alarm_cb = alarm_cfg->callback;
234 data->user_data = NULL;
235 data->top_val = RZ_GTM_TOP_VALUE;
236 data->is_periodic = false;
237
238 if (data->is_started) {
239 data->fsp_cfg->period_counts = data->top_val;
240 counter_rz_gtm_start_freerun(dev);
241 }
242 }
243
244 counter_rz_gtm_get_value(dev, &now);
245 data->alarm_cb = alarm_cfg->callback;
246 data->user_data = alarm_cfg->user_data;
247
248 if (absolute) {
249 max_rel_val = RZ_GTM_TOP_VALUE - data->guard_period;
250 irq_on_late = alarm_cfg->flags & COUNTER_ALARM_CFG_EXPIRE_WHEN_LATE;
251 } else {
252 /* If relative value is smaller than half of the counter range
253 * it is assumed that there is a risk of setting value too late
254 * and late detection algorithm must be applied. When late
255 * setting is detected, interrupt shall be triggered for
256 * immediate expiration of the timer. Detection is performed
257 * by limiting relative distance between CC and counter.
258 *
259 * Note that half of counter range is an arbitrary value.
260 */
261 irq_on_late = val < (RZ_GTM_TOP_VALUE / 2U);
262 /* limit max to detect short relative being set too late. */
263 max_rel_val = irq_on_late ? RZ_GTM_TOP_VALUE / 2U : RZ_GTM_TOP_VALUE;
264 val = (now + val) & RZ_GTM_TOP_VALUE;
265 }
266
267 /** Set new period */
268 data->fsp_cfg->period_counts = val;
269 err = cfg->fsp_api->periodSet(data->fsp_ctrl, data->fsp_cfg->period_counts);
270 if (err != FSP_SUCCESS) {
271 k_spin_unlock(&data->lock, key);
272 return err;
273 }
274
275 uint32_t read_counter_again = 0;
276
277 counter_rz_gtm_get_value(dev, &read_counter_again);
278 diff = ((val - 1U) - read_counter_again) & RZ_GTM_TOP_VALUE;
279 if (diff > max_rel_val) {
280 if (absolute) {
281 err = -ETIME;
282 }
283
284 /* Interrupt is triggered always for relative alarm and
285 * for absolute depending on the flag.
286 */
287 if (irq_on_late) {
288 irq_enable(cfg->irqn);
289 counter_rz_gtm_set_pending(cfg->irqn);
290 } else {
291 data->alarm_cb = NULL;
292 }
293 } else {
294 if (diff == 0) {
295 /* RELOAD value could be set just in time for interrupt
296 * trigger or too late. In any case time is interrupt
297 * should be triggered. No need to enable interrupt
298 * on TIMER just make sure interrupt is pending.
299 */
300 irq_enable(cfg->irqn);
301 counter_rz_gtm_set_pending(cfg->irqn);
302 } else {
303 counter_rz_gtm_clear_pending(cfg->irqn);
304 irq_enable(cfg->irqn);
305 }
306 }
307
308 k_spin_unlock(&data->lock, key);
309
310 return err;
311 }
312
counter_rz_gtm_cancel_alarm(const struct device * dev,uint8_t chan)313 static int counter_rz_gtm_cancel_alarm(const struct device *dev, uint8_t chan)
314 {
315 const struct counter_rz_gtm_config *cfg = dev->config;
316 struct counter_rz_gtm_data *data = dev->data;
317 k_spinlock_key_t key;
318
319 ARG_UNUSED(chan);
320
321 key = k_spin_lock(&data->lock);
322
323 if (!data->is_started) {
324 k_spin_unlock(&data->lock, key);
325 return -EINVAL;
326 }
327
328 if (!data->alarm_cb) {
329 k_spin_unlock(&data->lock, key);
330 return 0;
331 }
332
333 irq_disable(cfg->irqn);
334 counter_rz_gtm_clear_pending(cfg->irqn);
335 data->alarm_cb = NULL;
336 data->user_data = NULL;
337
338 k_spin_unlock(&data->lock, key);
339
340 return 0;
341 }
342
counter_rz_gtm_set_top_value(const struct device * dev,const struct counter_top_cfg * top_cfg)343 static int counter_rz_gtm_set_top_value(const struct device *dev,
344 const struct counter_top_cfg *top_cfg)
345 {
346 const struct counter_rz_gtm_config *cfg = dev->config;
347 struct counter_rz_gtm_data *data = dev->data;
348 k_spinlock_key_t key;
349 uint32_t cur_tick;
350 int ret = 0;
351
352 if (!top_cfg) {
353 return -EINVAL;
354 }
355
356 /** -EBUSY if any alarm is active */
357 if (data->alarm_cb) {
358 return -EBUSY;
359 }
360
361 key = k_spin_lock(&data->lock);
362
363 if (!data->is_periodic && top_cfg->ticks == RZ_GTM_TOP_VALUE) {
364 goto exit_unlock;
365 }
366
367 if (top_cfg->ticks == RZ_GTM_TOP_VALUE) {
368 /* restore free running mode */
369 irq_disable(cfg->irqn);
370 counter_rz_gtm_clear_pending(cfg->irqn);
371 data->top_cb = NULL;
372 data->user_data = NULL;
373 data->top_val = RZ_GTM_TOP_VALUE;
374 data->is_periodic = false;
375
376 if (data->is_started) {
377 counter_rz_gtm_start_freerun(dev);
378 counter_rz_gtm_clear_pending(cfg->irqn);
379 }
380 goto exit_unlock;
381 }
382
383 data->top_cb = top_cfg->callback;
384 data->user_data = top_cfg->user_data;
385 data->top_val = top_cfg->ticks;
386
387 if (!data->is_started) {
388 data->is_periodic = true;
389 goto exit_unlock;
390 }
391
392 if (!data->is_periodic) {
393 /* switch to interval mode first time, restart timer */
394 ret = cfg->fsp_api->stop(data->fsp_ctrl);
395 irq_disable(cfg->irqn);
396 data->is_periodic = true;
397 data->fsp_cfg->period_counts = data->top_val;
398 counter_rz_gtm_start_interval(dev);
399
400 if (data->top_cb) {
401 counter_rz_gtm_clear_pending(cfg->irqn);
402 irq_enable(cfg->irqn);
403 }
404 goto exit_unlock;
405 }
406
407 if (!data->top_cb) {
408 /* new top cfg is without callback - stop IRQs */
409 irq_disable(cfg->irqn);
410 counter_rz_gtm_clear_pending(cfg->irqn);
411 }
412 /* timer already in interval mode - only change top value */
413 data->fsp_cfg->period_counts = data->top_val;
414 cfg->fsp_api->periodSet(&data->fsp_ctrl, data->fsp_cfg->period_counts);
415
416 /* check if counter reset is required */
417 if (top_cfg->flags & COUNTER_TOP_CFG_DONT_RESET) {
418 /* Don't reset counter */
419 counter_rz_gtm_get_value(dev, &cur_tick);
420
421 if (cur_tick >= data->top_val) {
422 ret = -ETIME;
423 if (top_cfg->flags & COUNTER_TOP_CFG_RESET_WHEN_LATE) {
424 /* Reset counter if current is late */
425 cfg->fsp_api->stop(data->fsp_ctrl);
426 cfg->fsp_api->start(data->fsp_ctrl);
427 }
428 }
429 } else {
430 /* reset counter */
431 cfg->fsp_api->stop(data->fsp_ctrl);
432 cfg->fsp_api->start(data->fsp_ctrl);
433 }
434
435 exit_unlock:
436 k_spin_unlock(&data->lock, key);
437 return ret;
438 }
439
counter_rz_gtm_get_pending_int(const struct device * dev)440 static uint32_t counter_rz_gtm_get_pending_int(const struct device *dev)
441 {
442 const struct counter_rz_gtm_config *cfg = dev->config;
443
444 /* There is no register to check TIMER peripheral to check for interrupt
445 * pending, check directly in NVIC.
446 */
447 return counter_rz_gtm_is_pending(cfg->irqn);
448 }
449
counter_rz_gtm_get_top_value(const struct device * dev)450 static uint32_t counter_rz_gtm_get_top_value(const struct device *dev)
451 {
452 struct counter_rz_gtm_data *data = dev->data;
453 const struct counter_rz_gtm_config *cfg = dev->config;
454 uint32_t top_val = RZ_GTM_TOP_VALUE;
455
456 if (data->is_periodic) {
457 timer_info_t info;
458
459 cfg->fsp_api->infoGet(data->fsp_ctrl, &info);
460 top_val = info.period_counts;
461 }
462
463 return top_val;
464 }
counter_rz_gtm_get_guard_period(const struct device * dev,uint32_t flags)465 static uint32_t counter_rz_gtm_get_guard_period(const struct device *dev, uint32_t flags)
466 {
467 struct counter_rz_gtm_data *data = dev->data;
468
469 ARG_UNUSED(flags);
470 return data->guard_period;
471 }
472
counter_rz_gtm_set_guard_period(const struct device * dev,uint32_t guard,uint32_t flags)473 static int counter_rz_gtm_set_guard_period(const struct device *dev, uint32_t guard, uint32_t flags)
474 {
475 struct counter_rz_gtm_data *data = dev->data;
476
477 ARG_UNUSED(flags);
478 __ASSERT_NO_MSG(guard < counter_rz_gtm_get_top_value(dev));
479
480 data->guard_period = guard;
481
482 return 0;
483 }
484
counter_rz_gtm_get_freq(const struct device * dev)485 static uint32_t counter_rz_gtm_get_freq(const struct device *dev)
486 {
487 struct counter_rz_gtm_data *data = dev->data;
488 const struct counter_rz_gtm_config *cfg = dev->config;
489 timer_info_t info;
490
491 cfg->fsp_api->infoGet(data->fsp_ctrl, &info);
492
493 return info.clock_frequency;
494 }
495
496 static DEVICE_API(counter, counter_rz_gtm_driver_api) = {
497 .start = counter_rz_gtm_start,
498 .stop = counter_rz_gtm_stop,
499 .get_value = counter_rz_gtm_get_value,
500 .set_alarm = counter_rz_gtm_set_alarm,
501 .cancel_alarm = counter_rz_gtm_cancel_alarm,
502 .set_top_value = counter_rz_gtm_set_top_value,
503 .get_pending_int = counter_rz_gtm_get_pending_int,
504 .get_top_value = counter_rz_gtm_get_top_value,
505 .get_guard_period = counter_rz_gtm_get_guard_period,
506 .set_guard_period = counter_rz_gtm_set_guard_period,
507 .get_freq = counter_rz_gtm_get_freq,
508 };
509
510 extern void gtm_int_isr(void);
511
512 #define GTM(idx) DT_INST_PARENT(idx)
513
514 #define COUNTER_RZG_GTM_INIT(inst) \
515 static gtm_instance_ctrl_t g_timer##inst##_ctrl; \
516 static gtm_extended_cfg_t g_timer##inst##_extend = { \
517 .generate_interrupt_when_starts = GTM_GIWS_TYPE_DISABLED, \
518 .gtm_mode = GTM_TIMER_MODE_FREERUN, \
519 }; \
520 static timer_cfg_t g_timer##inst##_cfg = { \
521 .mode = TIMER_MODE_PERIODIC, \
522 .period_counts = (uint32_t)RZ_GTM_TOP_VALUE, \
523 .channel = DT_PROP(GTM(inst), channel), \
524 .p_callback = counter_rz_gtm_irq_handler, \
525 .p_context = DEVICE_DT_GET(DT_DRV_INST(inst)), \
526 .p_extend = &g_timer##inst##_extend, \
527 .cycle_end_ipl = DT_IRQ_BY_NAME(GTM(inst), overflow, priority), \
528 .cycle_end_irq = DT_IRQ_BY_NAME(GTM(inst), overflow, irq), \
529 }; \
530 static const struct counter_rz_gtm_config counter_rz_gtm_config_##inst = { \
531 .config_info = \
532 { \
533 .max_top_value = RZ_GTM_TOP_VALUE, \
534 .flags = COUNTER_CONFIG_INFO_COUNT_UP, \
535 .channels = 1, \
536 }, \
537 .fsp_api = &g_timer_on_gtm, \
538 .irqn = DT_IRQ_BY_NAME(GTM(inst), overflow, irq), \
539 }; \
540 static struct counter_rz_gtm_data counter_rz_gtm_data_##inst = { \
541 .fsp_cfg = &g_timer##inst##_cfg, .fsp_ctrl = &g_timer##inst##_ctrl}; \
542 static int counter_rz_gtm_init_##inst(const struct device *dev) \
543 { \
544 IRQ_CONNECT(DT_IRQ_BY_NAME(GTM(inst), overflow, irq), \
545 DT_IRQ_BY_NAME(GTM(inst), overflow, priority), gtm_int_isr, \
546 DEVICE_DT_INST_GET(inst), 0); \
547 return counter_rz_gtm_init(dev); \
548 } \
549 DEVICE_DT_INST_DEFINE(inst, counter_rz_gtm_init_##inst, NULL, &counter_rz_gtm_data_##inst, \
550 &counter_rz_gtm_config_##inst, PRE_KERNEL_1, \
551 CONFIG_COUNTER_INIT_PRIORITY, &counter_rz_gtm_driver_api);
552
553 DT_INST_FOREACH_STATUS_OKAY(COUNTER_RZG_GTM_INIT)
554