1 /*
2  * Copyright 2021-23, NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/drivers/counter.h>
8 #include <zephyr/irq.h>
9 #include <fsl_rtc.h>
10 #include "fsl_power.h"
11 #include <zephyr/logging/log.h>
12 
13 LOG_MODULE_REGISTER(mcux_rtc, CONFIG_COUNTER_LOG_LEVEL);
14 
15 struct mcux_lpc_rtc_data {
16 	counter_alarm_callback_t alarm_callback;
17 	counter_top_callback_t top_callback;
18 	void *alarm_user_data;
19 	void *top_user_data;
20 	uint32_t value;
21 };
22 
23 struct mcux_lpc_rtc_config {
24 	struct counter_config_info info;
25 	RTC_Type *base;
26 	const struct device *rtc_dev;
27 	void (*irq_config_func)(const struct device *dev);
28 	/* Device defined as wake-up source */
29 	bool wakeup_source;
30 };
31 
32 #if CONFIG_COUNTER_MCUX_LPC_RTC_HIGHRES
33 static int mcux_lpc_rtc_highres_start(const struct device *dev);
34 #endif
35 
mcux_lpc_rtc_isr(const struct device * dev)36 static void mcux_lpc_rtc_isr(const struct device *dev)
37 {
38 	const struct counter_config_info *info = dev->config;
39 	const struct mcux_lpc_rtc_config *config =
40 		CONTAINER_OF(info, struct mcux_lpc_rtc_config, info);
41 	struct mcux_lpc_rtc_data *data = dev->data;
42 	counter_alarm_callback_t cb;
43 	uint32_t current = RTC_GetSecondsTimerCount(config->base);
44 
45 	LOG_DBG("Current time is %d ticks", current);
46 
47 	if ((RTC_GetStatusFlags(config->base) & RTC_CTRL_ALARM1HZ_MASK) &&
48 	    (data->alarm_callback)) {
49 		cb = data->alarm_callback;
50 		data->alarm_callback = NULL;
51 		cb(dev, 0, current, data->alarm_user_data);
52 	}
53 
54 	if (data->top_callback) {
55 		data->top_callback(dev, data->top_user_data);
56 	}
57 
58 	/*
59 	 * Clear any conditions to ack the IRQ
60 	 *
61 	 * callback may have already reset the alarm flag if a new
62 	 * alarm value was programmed to the TAR
63 	 */
64 	if (RTC_GetStatusFlags(config->base) & RTC_CTRL_ALARM1HZ_MASK) {
65 		RTC_ClearStatusFlags(config->base, kRTC_AlarmFlag);
66 	}
67 
68 	/* Check if the Wake counter interrupt was set */
69 	if (RTC_GetStatusFlags(config->base) & RTC_CTRL_WAKE1KHZ_MASK) {
70 		RTC_ClearStatusFlags(config->base, kRTC_WakeupFlag);
71 #if CONFIG_COUNTER_MCUX_LPC_RTC_HIGHRES
72 		if (config->base->CTRL & RTC_CTRL_RTC1KHZ_EN_MASK) {
73 			mcux_lpc_rtc_highres_start(dev);
74 		}
75 #endif
76 	}
77 }
78 
79 #if CONFIG_COUNTER_MCUX_LPC_RTC_1HZ
80 
81 #define DT_DRV_COMPAT nxp_lpc_rtc
82 
mcux_lpc_rtc_start(const struct device * dev)83 static int mcux_lpc_rtc_start(const struct device *dev)
84 {
85 	const struct counter_config_info *info = dev->config;
86 	const struct mcux_lpc_rtc_config *config =
87 		CONTAINER_OF(info, struct mcux_lpc_rtc_config, info);
88 
89 	RTC_EnableTimer(config->base, true);
90 
91 	return 0;
92 }
93 
mcux_lpc_rtc_stop(const struct device * dev)94 static int mcux_lpc_rtc_stop(const struct device *dev)
95 {
96 	const struct counter_config_info *info = dev->config;
97 	const struct mcux_lpc_rtc_config *config =
98 		CONTAINER_OF(info, struct mcux_lpc_rtc_config, info);
99 
100 	RTC_EnableTimer(config->base, false);
101 
102 	/* clear out any set alarms */
103 	RTC_SetSecondsTimerMatch(config->base, 0);
104 
105 	return 0;
106 }
107 
mcux_lpc_rtc_read(const struct device * dev)108 static uint32_t mcux_lpc_rtc_read(const struct device *dev)
109 {
110 	const struct counter_config_info *info = dev->config;
111 	const struct mcux_lpc_rtc_config *config =
112 		CONTAINER_OF(info, struct mcux_lpc_rtc_config, info);
113 
114 	uint32_t ticks = RTC_GetSecondsTimerCount(config->base);
115 
116 	return ticks;
117 }
118 
mcux_lpc_rtc_get_value(const struct device * dev,uint32_t * ticks)119 static int mcux_lpc_rtc_get_value(const struct device *dev, uint32_t *ticks)
120 {
121 	*ticks = mcux_lpc_rtc_read(dev);
122 	return 0;
123 }
124 
mcux_lpc_rtc_set_alarm(const struct device * dev,uint8_t chan_id,const struct counter_alarm_cfg * alarm_cfg)125 static int mcux_lpc_rtc_set_alarm(const struct device *dev, uint8_t chan_id,
126 			      const struct counter_alarm_cfg *alarm_cfg)
127 {
128 	const struct counter_config_info *info = dev->config;
129 	const struct mcux_lpc_rtc_config *config =
130 		CONTAINER_OF(info, struct mcux_lpc_rtc_config, info);
131 	struct mcux_lpc_rtc_data *data = dev->data;
132 
133 	uint32_t ticks = alarm_cfg->ticks;
134 	uint32_t current = mcux_lpc_rtc_read(dev);
135 
136 	LOG_DBG("Current time is %d ticks", current);
137 
138 	if (chan_id != 0U) {
139 		LOG_ERR("Invalid channel id");
140 		return -EINVAL;
141 	}
142 
143 	if (data->alarm_callback != NULL) {
144 		return -EBUSY;
145 	}
146 
147 	if ((alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) == 0) {
148 		ticks += current;
149 	}
150 
151 	if (ticks < current) {
152 		LOG_ERR("Alarm cannot be earlier than current time");
153 		return -EINVAL;
154 	}
155 
156 	data->alarm_callback = alarm_cfg->callback;
157 	data->alarm_user_data = alarm_cfg->user_data;
158 
159 	RTC_SetSecondsTimerMatch(config->base, ticks);
160 	LOG_DBG("Alarm set to %d ticks", ticks);
161 
162 	return 0;
163 }
164 
mcux_lpc_rtc_cancel_alarm(const struct device * dev,uint8_t chan_id)165 static int mcux_lpc_rtc_cancel_alarm(const struct device *dev, uint8_t chan_id)
166 {
167 	struct mcux_lpc_rtc_data *data = dev->data;
168 
169 	if (chan_id != 0U) {
170 		LOG_ERR("Invalid channel id");
171 		return -EINVAL;
172 	}
173 
174 	data->alarm_callback = NULL;
175 
176 	return 0;
177 }
178 
mcux_lpc_rtc_set_top_value(const struct device * dev,const struct counter_top_cfg * cfg)179 static int mcux_lpc_rtc_set_top_value(const struct device *dev,
180 				  const struct counter_top_cfg *cfg)
181 {
182 	return -ENOTSUP;
183 }
184 
mcux_lpc_rtc_get_pending_int(const struct device * dev)185 static uint32_t mcux_lpc_rtc_get_pending_int(const struct device *dev)
186 {
187 	const struct counter_config_info *info = dev->config;
188 	const struct mcux_lpc_rtc_config *config =
189 		CONTAINER_OF(info, struct mcux_lpc_rtc_config, info);
190 
191 	return RTC_GetStatusFlags(config->base) & RTC_CTRL_ALARM1HZ_MASK;
192 }
193 
mcux_lpc_rtc_get_top_value(const struct device * dev)194 static uint32_t mcux_lpc_rtc_get_top_value(const struct device *dev)
195 {
196 	const struct counter_config_info *info = dev->config;
197 
198 	return info->max_top_value;
199 }
200 
mcux_lpc_rtc_init(const struct device * dev)201 static int mcux_lpc_rtc_init(const struct device *dev)
202 {
203 	const struct counter_config_info *info = dev->config;
204 	const struct mcux_lpc_rtc_config *config =
205 		CONTAINER_OF(info, struct mcux_lpc_rtc_config, info);
206 
207 	RTC_Init(config->base);
208 
209 	/* Issue a software reset to set the registers to init state */
210 	RTC_Reset(config->base);
211 
212 	config->irq_config_func(dev);
213 
214 	if (config->wakeup_source) {
215 		/* Enable the bit to wakeup from Deep Power Down mode */
216 		RTC_EnableAlarmTimerInterruptFromDPD(config->base, true);
217 	}
218 
219 	return 0;
220 }
221 
222 static const struct counter_driver_api mcux_rtc_driver_api = {
223 	.start = mcux_lpc_rtc_start,
224 	.stop = mcux_lpc_rtc_stop,
225 	.get_value = mcux_lpc_rtc_get_value,
226 	.set_alarm = mcux_lpc_rtc_set_alarm,
227 	.cancel_alarm = mcux_lpc_rtc_cancel_alarm,
228 	.set_top_value = mcux_lpc_rtc_set_top_value,
229 	.get_pending_int = mcux_lpc_rtc_get_pending_int,
230 	.get_top_value = mcux_lpc_rtc_get_top_value,
231 };
232 
233 #define COUNTER_LPC_RTC_DEVICE(id)						\
234 	static void mcux_lpc_rtc_irq_config_##id(const struct device *dev);	\
235 	static const struct mcux_lpc_rtc_config mcux_lpc_rtc_config_##id = {	\
236 		.base = (RTC_Type *)DT_INST_REG_ADDR(id),			\
237 		.irq_config_func = mcux_lpc_rtc_irq_config_##id,		\
238 		.rtc_dev = DEVICE_DT_GET_OR_NULL(DT_INST_CHILD(id, rtc_highres)),	\
239 		.info = {						\
240 			.max_top_value = UINT32_MAX,			\
241 			.freq = 1,					\
242 			.flags = COUNTER_CONFIG_INFO_COUNT_UP,		\
243 			.channels = 1,					\
244 		},							\
245 		.wakeup_source = DT_INST_PROP(id, wakeup_source)	\
246 	};								\
247 	static struct mcux_lpc_rtc_data mcux_lpc_rtc_data_##id;		\
248 	DEVICE_DT_INST_DEFINE(id, &mcux_lpc_rtc_init, NULL,		\
249 				&mcux_lpc_rtc_data_##id, &mcux_lpc_rtc_config_##id.info,	\
250 				POST_KERNEL, CONFIG_COUNTER_INIT_PRIORITY,		\
251 				&mcux_rtc_driver_api);					\
252 	static void mcux_lpc_rtc_irq_config_##id(const struct device *dev)	\
253 	{									\
254 		IRQ_CONNECT(DT_INST_IRQN(id),					\
255 			DT_INST_IRQ(id, priority),				\
256 			mcux_lpc_rtc_isr, DEVICE_DT_INST_GET(id), 0);		\
257 		irq_enable(DT_INST_IRQN(id));					\
258 		if (DT_INST_PROP(id, wakeup_source)) {				\
259 			EnableDeepSleepIRQ(DT_INST_IRQN(id));			\
260 		}								\
261 	}
262 
DT_INST_FOREACH_STATUS_OKAY(COUNTER_LPC_RTC_DEVICE)263 DT_INST_FOREACH_STATUS_OKAY(COUNTER_LPC_RTC_DEVICE)
264 #endif
265 
266 #if CONFIG_COUNTER_MCUX_LPC_RTC_HIGHRES
267 
268 #undef DT_DRV_COMPAT
269 #define DT_DRV_COMPAT nxp_lpc_rtc_highres
270 
271 static int mcux_lpc_rtc_highres_start(const struct device *dev)
272 {
273 	const struct counter_config_info *info = dev->config;
274 	const struct mcux_lpc_rtc_config *config =
275 		CONTAINER_OF(info, struct mcux_lpc_rtc_config, info);
276 	struct mcux_lpc_rtc_data *data = dev->data;
277 
278 	if (config->rtc_dev) {
279 		/* We have another RTC driver enabled, check if RTC is enabled */
280 		if ((config->base->CTRL & RTC_CTRL_RTC_EN_MASK) == 0) {
281 			/* RTC is not enabled and we do not turn it on as it will effect
282 			 * the RTC counter value thereby affecting the RTC counter drivers
283 			 */
284 			LOG_ERR("RTC Wake counter cannot be started as RTC is not enabled.");
285 			return -EINVAL;
286 		}
287 	} else {
288 		if ((config->base->CTRL & RTC_CTRL_RTC_EN_MASK) == 0) {
289 			RTC_EnableTimer(config->base, true);
290 		}
291 	}
292 
293 	if (data->value == 0) {
294 		/* Start from the max value */
295 		RTC_SetWakeupCount(config->base, counter_get_top_value(dev));
296 	} else {
297 		RTC_SetWakeupCount(config->base, data->value);
298 	}
299 
300 	return 0;
301 }
302 
mcux_lpc_rtc_highres_stop(const struct device * dev)303 static int mcux_lpc_rtc_highres_stop(const struct device *dev)
304 {
305 	const struct counter_config_info *info = dev->config;
306 	const struct mcux_lpc_rtc_config *config =
307 		CONTAINER_OF(info, struct mcux_lpc_rtc_config, info);
308 
309 	config->base->CTRL &= ~RTC_CTRL_RTC1KHZ_EN_MASK;
310 
311 	if (config->rtc_dev == NULL) {
312 		/* Disable RTC as no other driver is using it */
313 		RTC_EnableTimer(config->base, false);
314 	}
315 
316 	return 0;
317 }
318 
mcux_lpc_rtc_highres_read(const struct device * dev)319 static uint32_t mcux_lpc_rtc_highres_read(const struct device *dev)
320 {
321 	const struct counter_config_info *info = dev->config;
322 	const struct mcux_lpc_rtc_config *config =
323 		CONTAINER_OF(info, struct mcux_lpc_rtc_config, info);
324 
325 	uint32_t ticks = RTC_GetWakeupCount(config->base);
326 
327 	return ticks;
328 }
329 
mcux_lpc_rtc_highres_set_alarm(const struct device * dev,uint8_t chan_id,const struct counter_alarm_cfg * alarm_cfg)330 static int mcux_lpc_rtc_highres_set_alarm(const struct device *dev, uint8_t chan_id,
331 					  const struct counter_alarm_cfg *alarm_cfg)
332 {
333 	return -ENOTSUP;
334 }
335 
mcux_lpc_rtc_highres_cancel_alarm(const struct device * dev,uint8_t chan_id)336 static int mcux_lpc_rtc_highres_cancel_alarm(const struct device *dev, uint8_t chan_id)
337 {
338 	return -ENOTSUP;
339 }
340 
341 
mcux_lpc_rtc_highres_get_value(const struct device * dev,uint32_t * ticks)342 static int mcux_lpc_rtc_highres_get_value(const struct device *dev, uint32_t *ticks)
343 {
344 	*ticks = mcux_lpc_rtc_highres_read(dev);
345 	return 0;
346 }
347 
mcux_lpc_rtc_highres_set_top_value(const struct device * dev,const struct counter_top_cfg * cfg)348 static int mcux_lpc_rtc_highres_set_top_value(const struct device *dev,
349 				  const struct counter_top_cfg *cfg)
350 {
351 	const struct counter_config_info *info = dev->config;
352 	const struct mcux_lpc_rtc_config *config =
353 		CONTAINER_OF(info, struct mcux_lpc_rtc_config, info);
354 	struct mcux_lpc_rtc_data *data = dev->data;
355 
356 	if (cfg->flags & COUNTER_TOP_CFG_DONT_RESET) {
357 		return -ENOTSUP;
358 	}
359 
360 	data->value = cfg->ticks;
361 	data->top_callback = cfg->callback;
362 	data->top_user_data = cfg->user_data;
363 
364 	if (config->base->CTRL & RTC_CTRL_RTC1KHZ_EN_MASK) {
365 		return mcux_lpc_rtc_highres_start(dev);
366 	}
367 
368 	return 0;
369 }
370 
mcux_lpc_rtc_highres_get_pending_int(const struct device * dev)371 static uint32_t mcux_lpc_rtc_highres_get_pending_int(const struct device *dev)
372 {
373 	const struct counter_config_info *info = dev->config;
374 	const struct mcux_lpc_rtc_config *config =
375 		CONTAINER_OF(info, struct mcux_lpc_rtc_config, info);
376 
377 	return RTC_GetStatusFlags(config->base) & RTC_CTRL_WAKE1KHZ_MASK;
378 }
379 
mcux_lpc_rtc_highres_get_top_value(const struct device * dev)380 static uint32_t mcux_lpc_rtc_highres_get_top_value(const struct device *dev)
381 {
382 	struct mcux_lpc_rtc_data *data = dev->data;
383 	const struct counter_config_info *info = dev->config;
384 
385 	if (data->value == 0) {
386 		return info->max_top_value;
387 	} else {
388 		return data->value;
389 	}
390 }
391 
mcux_lpc_rtc_highres_init(const struct device * dev)392 static int mcux_lpc_rtc_highres_init(const struct device *dev)
393 {
394 	const struct counter_config_info *info = dev->config;
395 	const struct mcux_lpc_rtc_config *config =
396 		CONTAINER_OF(info, struct mcux_lpc_rtc_config, info);
397 
398 	/* Initialize the RTC if this is only driver using it */
399 	if (config->rtc_dev == NULL) {
400 		RTC_Init(config->base);
401 
402 		/* Issue a software reset to set the registers to init state */
403 		RTC_Reset(config->base);
404 
405 		config->irq_config_func(dev);
406 	}
407 
408 	if (config->wakeup_source) {
409 		/* Enable the bit to wakeup from Deep Power Down mode */
410 		RTC_EnableWakeUpTimerInterruptFromDPD(config->base, true);
411 	}
412 
413 	return 0;
414 }
415 
416 static const struct counter_driver_api mcux_rtc_highres_driver_api = {
417 	.start = mcux_lpc_rtc_highres_start,
418 	.stop = mcux_lpc_rtc_highres_stop,
419 	.get_value = mcux_lpc_rtc_highres_get_value,
420 	.set_alarm = mcux_lpc_rtc_highres_set_alarm,
421 	.cancel_alarm = mcux_lpc_rtc_highres_cancel_alarm,
422 	.set_top_value = mcux_lpc_rtc_highres_set_top_value,
423 	.get_pending_int = mcux_lpc_rtc_highres_get_pending_int,
424 	.get_top_value = mcux_lpc_rtc_highres_get_top_value,
425 };
426 
427 #define COUNTER_LPC_RTC_HIGHRES_IRQ_INIT(n)							\
428 	do {											\
429 		IRQ_CONNECT(DT_IRQN(DT_INST_PARENT(n)),						\
430 			DT_IRQ(DT_INST_PARENT(n), priority),					\
431 			mcux_lpc_rtc_isr,							\
432 			DEVICE_DT_INST_GET(n), 0);						\
433 		irq_enable(DT_IRQN(DT_INST_PARENT(n)));						\
434 		if (DT_INST_PROP(n, wakeup_source)) {						\
435 			EnableDeepSleepIRQ(DT_IRQN(DT_INST_PARENT(n)));				\
436 		}										\
437 	} while (false)
438 
439 #define COUNTER_LPC_RTC_HIGHRES_DEVICE(id)							\
440 	static void mcux_lpc_rtc_highres_irq_config_##id(const struct device *dev);		\
441 	static const struct mcux_lpc_rtc_config mcux_lpc_rtc_highres_config_##id = {		\
442 		.base = (RTC_Type *)DT_REG_ADDR(DT_INST_PARENT(id)),				\
443 		.rtc_dev = DEVICE_DT_GET_OR_NULL(DT_INST_PARENT(id)),				\
444 		.irq_config_func = mcux_lpc_rtc_highres_irq_config_##id,			\
445 		.info = {									\
446 			.max_top_value = UINT16_MAX,						\
447 			.freq = 1000,								\
448 			.channels = 0,								\
449 		},										\
450 		.wakeup_source = DT_INST_PROP(id, wakeup_source)				\
451 	};											\
452 	static struct mcux_lpc_rtc_data mcux_lpc_rtc_highres_data_##id;				\
453 	DEVICE_DT_INST_DEFINE(id, &mcux_lpc_rtc_highres_init, NULL,				\
454 				&mcux_lpc_rtc_highres_data_##id,				\
455 				&mcux_lpc_rtc_highres_config_##id.info,				\
456 				POST_KERNEL, CONFIG_COUNTER_INIT_PRIORITY,			\
457 				&mcux_rtc_highres_driver_api);					\
458 	static void mcux_lpc_rtc_highres_irq_config_##id(const struct device *dev)		\
459 	{											\
460 		COND_CODE_1(IS_ENABLED(DT_HAS_COMPAT_STATUS_OKAY(nxp_lpc_rtc)),			\
461 			 (), (COUNTER_LPC_RTC_HIGHRES_IRQ_INIT(id));)				\
462 	}
463 
464 DT_INST_FOREACH_STATUS_OKAY(COUNTER_LPC_RTC_HIGHRES_DEVICE)
465 
466 #endif
467