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