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