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