1 /*
2 * Copyright (c) 2018 blik GmbH
3 * Copyright (c) 2018,2024 NXP
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT nxp_kinetis_rtc
9
10 #include <zephyr/drivers/counter.h>
11 #include <zephyr/irq.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/sys_clock.h>
14 #include <fsl_rtc.h>
15 #include <zephyr/logging/log.h>
16
17 LOG_MODULE_REGISTER(mcux_rtc, CONFIG_COUNTER_LOG_LEVEL);
18
19 struct mcux_rtc_data {
20 counter_alarm_callback_t alarm_callback;
21 counter_top_callback_t top_callback;
22 void *alarm_user_data;
23 void *top_user_data;
24 };
25
26 struct mcux_rtc_config {
27 struct counter_config_info info;
28 RTC_Type *base;
29 void (*irq_config_func)(const struct device *dev);
30 };
31
mcux_rtc_start(const struct device * dev)32 static int mcux_rtc_start(const struct device *dev)
33 {
34 const struct counter_config_info *info = dev->config;
35 const struct mcux_rtc_config *config =
36 CONTAINER_OF(info, struct mcux_rtc_config, info);
37
38 RTC_StartTimer(config->base);
39 RTC_EnableInterrupts(config->base,
40 kRTC_AlarmInterruptEnable |
41 kRTC_TimeOverflowInterruptEnable |
42 kRTC_TimeInvalidInterruptEnable);
43
44 return 0;
45 }
46
mcux_rtc_stop(const struct device * dev)47 static int mcux_rtc_stop(const struct device *dev)
48 {
49 const struct counter_config_info *info = dev->config;
50 const struct mcux_rtc_config *config =
51 CONTAINER_OF(info, struct mcux_rtc_config, info);
52
53 RTC_DisableInterrupts(config->base,
54 kRTC_AlarmInterruptEnable |
55 kRTC_TimeOverflowInterruptEnable |
56 kRTC_TimeInvalidInterruptEnable);
57 RTC_StopTimer(config->base);
58
59 /* clear out any set alarms */
60 config->base->TAR = 0;
61
62 return 0;
63 }
64
mcux_rtc_read(const struct device * dev)65 static uint32_t mcux_rtc_read(const struct device *dev)
66 {
67 const struct counter_config_info *info = dev->config;
68 const struct mcux_rtc_config *config =
69 CONTAINER_OF(info, struct mcux_rtc_config, info);
70
71 uint32_t ticks = config->base->TSR;
72
73 /*
74 * Read TSR seconds twice in case it glitches during an update.
75 * This can happen when a read occurs at the time the register is
76 * incrementing.
77 */
78 if (config->base->TSR == ticks) {
79 return ticks;
80 }
81
82 ticks = config->base->TSR;
83
84 return ticks;
85 }
86
mcux_rtc_get_value(const struct device * dev,uint32_t * ticks)87 static int mcux_rtc_get_value(const struct device *dev, uint32_t *ticks)
88 {
89 *ticks = mcux_rtc_read(dev);
90 return 0;
91 }
92
mcux_rtc_set_alarm(const struct device * dev,uint8_t chan_id,const struct counter_alarm_cfg * alarm_cfg)93 static int mcux_rtc_set_alarm(const struct device *dev, uint8_t chan_id,
94 const struct counter_alarm_cfg *alarm_cfg)
95 {
96 const struct counter_config_info *info = dev->config;
97 const struct mcux_rtc_config *config =
98 CONTAINER_OF(info, struct mcux_rtc_config, info);
99 struct mcux_rtc_data *data = dev->data;
100
101 uint32_t ticks = alarm_cfg->ticks;
102 uint32_t current = mcux_rtc_read(dev);
103
104 LOG_DBG("Current time is %d ticks", current);
105
106 if (chan_id != 0U) {
107 LOG_ERR("Invalid channel id");
108 return -EINVAL;
109 }
110
111 if (data->alarm_callback != NULL) {
112 return -EBUSY;
113 }
114
115 if ((alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE) == 0) {
116 ticks += current;
117 }
118
119 if (ticks < current) {
120 LOG_ERR("Alarm cannot be earlier than current time");
121 return -EINVAL;
122 }
123
124 data->alarm_callback = alarm_cfg->callback;
125 data->alarm_user_data = alarm_cfg->user_data;
126
127 config->base->TAR = ticks;
128 LOG_DBG("Alarm set to %d ticks", ticks);
129
130 return 0;
131 }
132
mcux_rtc_cancel_alarm(const struct device * dev,uint8_t chan_id)133 static int mcux_rtc_cancel_alarm(const struct device *dev, uint8_t chan_id)
134 {
135 struct mcux_rtc_data *data = dev->data;
136
137 if (chan_id != 0U) {
138 LOG_ERR("Invalid channel id");
139 return -EINVAL;
140 }
141
142 data->alarm_callback = NULL;
143
144 return 0;
145 }
146
mcux_rtc_set_top_value(const struct device * dev,const struct counter_top_cfg * cfg)147 static int mcux_rtc_set_top_value(const struct device *dev,
148 const struct counter_top_cfg *cfg)
149 {
150 const struct counter_config_info *info = dev->config;
151 const struct mcux_rtc_config *config =
152 CONTAINER_OF(info, struct mcux_rtc_config, info);
153 struct mcux_rtc_data *data = dev->data;
154
155 if (cfg->ticks != info->max_top_value) {
156 LOG_ERR("Wrap can only be set to 0x%x.", info->max_top_value);
157 return -ENOTSUP;
158 }
159
160 if (!(cfg->flags & COUNTER_TOP_CFG_DONT_RESET)) {
161 RTC_StopTimer(config->base);
162 config->base->TSR = 0;
163 RTC_StartTimer(config->base);
164 }
165
166 data->top_callback = cfg->callback;
167 data->top_user_data = cfg->user_data;
168
169 return 0;
170 }
171
mcux_rtc_get_pending_int(const struct device * dev)172 static uint32_t mcux_rtc_get_pending_int(const struct device *dev)
173 {
174 const struct counter_config_info *info = dev->config;
175 const struct mcux_rtc_config *config =
176 CONTAINER_OF(info, struct mcux_rtc_config, info);
177
178 return RTC_GetStatusFlags(config->base) & RTC_SR_TAF_MASK;
179 }
180
mcux_rtc_get_top_value(const struct device * dev)181 static uint32_t mcux_rtc_get_top_value(const struct device *dev)
182 {
183 const struct counter_config_info *info = dev->config;
184
185 return info->max_top_value;
186 }
187
mcux_rtc_isr(const struct device * dev)188 static void mcux_rtc_isr(const struct device *dev)
189 {
190 const struct counter_config_info *info = dev->config;
191 const struct mcux_rtc_config *config =
192 CONTAINER_OF(info, struct mcux_rtc_config, info);
193 struct mcux_rtc_data *data = dev->data;
194 counter_alarm_callback_t cb;
195 uint32_t current = mcux_rtc_read(dev);
196
197
198 LOG_DBG("Current time is %d ticks", current);
199
200 if ((RTC_GetStatusFlags(config->base) & RTC_SR_TAF_MASK) &&
201 (data->alarm_callback)) {
202 cb = data->alarm_callback;
203 data->alarm_callback = NULL;
204 cb(dev, 0, current, data->alarm_user_data);
205 }
206
207 if ((RTC_GetStatusFlags(config->base) & RTC_SR_TOF_MASK) &&
208 (data->top_callback)) {
209 data->top_callback(dev, data->top_user_data);
210 }
211
212 /*
213 * Clear any conditions to ack the IRQ
214 *
215 * callback may have already reset the alarm flag if a new
216 * alarm value was programmed to the TAR
217 */
218 RTC_StopTimer(config->base);
219 if (RTC_GetStatusFlags(config->base) & RTC_SR_TAF_MASK) {
220 RTC_ClearStatusFlags(config->base, kRTC_AlarmFlag);
221 } else if (RTC_GetStatusFlags(config->base) & RTC_SR_TIF_MASK) {
222 RTC_ClearStatusFlags(config->base, kRTC_TimeInvalidFlag);
223 } else if (RTC_GetStatusFlags(config->base) & RTC_SR_TOF_MASK) {
224 RTC_ClearStatusFlags(config->base, kRTC_TimeOverflowFlag);
225 }
226 RTC_StartTimer(config->base);
227 }
228
mcux_rtc_init(const struct device * dev)229 static int mcux_rtc_init(const struct device *dev)
230 {
231 const struct counter_config_info *info = dev->config;
232 const struct mcux_rtc_config *config =
233 CONTAINER_OF(info, struct mcux_rtc_config, info);
234 rtc_config_t rtc_config;
235
236 RTC_GetDefaultConfig(&rtc_config);
237 RTC_Init(config->base, &rtc_config);
238
239 #if !(defined(FSL_FEATURE_RTC_HAS_NO_CR_OSCE) && FSL_FEATURE_RTC_HAS_NO_CR_OSCE)
240 /* Enable 32kHz oscillator and wait for 1ms to settle */
241 RTC_SetClockSource(config->base);
242 k_busy_wait(USEC_PER_MSEC);
243 #endif /* !FSL_FEATURE_RTC_HAS_NO_CR_OSCE */
244
245 config->irq_config_func(dev);
246
247 return 0;
248 }
249
250 static const struct counter_driver_api mcux_rtc_driver_api = {
251 .start = mcux_rtc_start,
252 .stop = mcux_rtc_stop,
253 .get_value = mcux_rtc_get_value,
254 .set_alarm = mcux_rtc_set_alarm,
255 .cancel_alarm = mcux_rtc_cancel_alarm,
256 .set_top_value = mcux_rtc_set_top_value,
257 .get_pending_int = mcux_rtc_get_pending_int,
258 .get_top_value = mcux_rtc_get_top_value,
259 };
260
261 static struct mcux_rtc_data mcux_rtc_data_0;
262
263 static void mcux_rtc_irq_config_0(const struct device *dev);
264
265 static struct mcux_rtc_config mcux_rtc_config_0 = {
266 .base = (RTC_Type *)DT_INST_REG_ADDR(0),
267 .irq_config_func = mcux_rtc_irq_config_0,
268 .info = {
269 .max_top_value = UINT32_MAX,
270 .freq = DT_INST_PROP(0, clock_frequency) /
271 DT_INST_PROP(0, prescaler),
272 .flags = COUNTER_CONFIG_INFO_COUNT_UP,
273 .channels = 1,
274 },
275 };
276
277 DEVICE_DT_INST_DEFINE(0, &mcux_rtc_init, NULL,
278 &mcux_rtc_data_0, &mcux_rtc_config_0.info,
279 POST_KERNEL, CONFIG_COUNTER_INIT_PRIORITY,
280 &mcux_rtc_driver_api);
281
mcux_rtc_irq_config_0(const struct device * dev)282 static void mcux_rtc_irq_config_0(const struct device *dev)
283 {
284 IRQ_CONNECT(DT_INST_IRQN(0),
285 DT_INST_IRQ(0, priority),
286 mcux_rtc_isr, DEVICE_DT_INST_GET(0), 0);
287 irq_enable(DT_INST_IRQN(0));
288 }
289