1 /*
2  * Copyright 2024 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_irtc
8 
9 #include <zephyr/devicetree.h>
10 #include <zephyr/drivers/rtc.h>
11 #include <zephyr/irq.h>
12 #include "rtc_utils.h"
13 
14 struct nxp_irtc_config {
15 	RTC_Type *base;
16 	void (*irq_config_func)(const struct device *dev);
17 	bool is_output_clock_enabled;
18 	uint8_t clock_src;
19 	uint8_t alarm_match_flag;
20 };
21 
22 struct nxp_irtc_data {
23 	bool is_dst_enabled;
24 #ifdef CONFIG_RTC_ALARM
25 	rtc_alarm_callback alarm_callback;
26 	void *alarm_user_data;
27 	uint16_t alarm_mask;
28 #endif /* CONFIG_RTC_ALARM */
29 };
30 
31 /* The IRTC Offset is 2112 instead of 1900 [2112 - 1900] -> [212] */
32 #define RTC_NXP_IRTC_YEAR_OFFSET 212
33 
34 #define RTC_NXP_GET_REG_FIELD(_reg, _name, _field)				\
35 	((_reg->_name & RTC_##_name##_##_field##_MASK) >>			\
36 	 RTC_##_name##_##_field##_SHIFT)
37 
38 /*
39  * The runtime where this is accessed is unknown so we force a lock on the registers then force an
40  * unlock to guarantee 2 seconds of write time
41  */
nxp_irtc_unlock_registers(RTC_Type * reg)42 static void nxp_irtc_unlock_registers(RTC_Type *reg)
43 {
44 	/* Lock the regsiters */
45 	while ((reg->STATUS & (uint16_t)RTC_STATUS_WRITE_PROT_EN_MASK) == 0) {
46 		*(uint8_t *)(&reg->STATUS) |= RTC_STATUS_WE(0x2);
47 	}
48 	/* Unlock the registers */
49 	while ((reg->STATUS & (int16_t)RTC_STATUS_WRITE_PROT_EN_MASK) != 0) {
50 		/*
51 		 * The casting is required for writing only a single Byte to the STATUS Register,
52 		 * the pattern here unlocks all RTC registers for writing. When unlocked if a 0x20
53 		 * if written to the STATUS register the RTC registers will lock again and the next
54 		 * write will lead to a fault.
55 		 */
56 		*(volatile uint8_t *)(&reg->STATUS) = 0x00;
57 		*(volatile uint8_t *)(&reg->STATUS) = 0x40;
58 		*(volatile uint8_t *)(&reg->STATUS) = 0xC0;
59 		*(volatile uint8_t *)(&reg->STATUS) = 0x80;
60 	}
61 }
62 
nxp_irtc_set_time(const struct device * dev,const struct rtc_time * timeptr)63 static int nxp_irtc_set_time(const struct device *dev, const struct rtc_time *timeptr)
64 {
65 	const struct nxp_irtc_config *config = dev->config;
66 	struct nxp_irtc_data *data = dev->data;
67 	RTC_Type *irtc_reg = config->base;
68 
69 	if (!timeptr || !rtc_utils_validate_rtc_time(timeptr, 0)) {
70 		return -EINVAL;
71 	}
72 
73 	int calc_year = timeptr->tm_year - RTC_NXP_IRTC_YEAR_OFFSET;
74 	/* The IRTC Month Index starts at 1 instead of 0 */
75 	int calc_month = timeptr->tm_mon + 1;
76 
77 	uint32_t key = irq_lock();
78 
79 	nxp_irtc_unlock_registers(irtc_reg);
80 	irtc_reg->SECONDS = RTC_SECONDS_SEC_CNT(timeptr->tm_sec);
81 
82 	irtc_reg->HOURMIN = RTC_HOURMIN_MIN_CNT(timeptr->tm_min) |
83 		RTC_HOURMIN_HOUR_CNT(timeptr->tm_hour);
84 
85 	/* 1 is valid for rtc_time.tm_wday property but is out of bounds for IRTC registers */
86 	irtc_reg->DAYS = RTC_DAYS_DAY_CNT(timeptr->tm_mday) |
87 		      (timeptr->tm_wday == -1 ? 0 : RTC_DAYS_DOW(timeptr->tm_wday));
88 
89 	irtc_reg->YEARMON = RTC_YEARMON_MON_CNT(calc_month) | RTC_YEARMON_YROFST(calc_year);
90 
91 	if (timeptr->tm_isdst != -1) {
92 		irtc_reg->CTRL |= RTC_CTRL_DST_EN(timeptr->tm_isdst);
93 		data->is_dst_enabled = true;
94 	}
95 
96 	irq_unlock(key);
97 
98 	return 0;
99 }
100 
nxp_irtc_get_time(const struct device * dev,struct rtc_time * timeptr)101 static int nxp_irtc_get_time(const struct device *dev, struct rtc_time *timeptr)
102 {
103 	const struct nxp_irtc_config *config = dev->config;
104 	struct nxp_irtc_data *data = dev->data;
105 	RTC_Type *irtc_reg = config->base;
106 
107 	__ASSERT(timeptr != 0, "timeptr has not been set");
108 
109 	timeptr->tm_sec = RTC_NXP_GET_REG_FIELD(irtc_reg, SECONDS, SEC_CNT);
110 	timeptr->tm_min = RTC_NXP_GET_REG_FIELD(irtc_reg, HOURMIN, MIN_CNT);
111 	timeptr->tm_hour = RTC_NXP_GET_REG_FIELD(irtc_reg, HOURMIN, HOUR_CNT);
112 	timeptr->tm_wday = RTC_NXP_GET_REG_FIELD(irtc_reg, DAYS, DOW);
113 	timeptr->tm_mday = RTC_NXP_GET_REG_FIELD(irtc_reg, DAYS, DAY_CNT);
114 	timeptr->tm_mon = RTC_NXP_GET_REG_FIELD(irtc_reg, YEARMON, MON_CNT) - 1;
115 	timeptr->tm_year = (int8_t)RTC_NXP_GET_REG_FIELD(irtc_reg, YEARMON, YROFST) +
116 		RTC_NXP_IRTC_YEAR_OFFSET;
117 	if (data->is_dst_enabled) {
118 		timeptr->tm_isdst =
119 			((irtc_reg->CTRL & RTC_CTRL_DST_EN_MASK) >> RTC_CTRL_DST_EN_SHIFT);
120 	}
121 
122 	/* There is no nano second support for IRTC */
123 	timeptr->tm_nsec = 0;
124 	/* There is no day of the year support for IRTC */
125 	timeptr->tm_yday = -1;
126 
127 	return 0;
128 }
129 
130 #if defined(CONFIG_RTC_ALARM)
nxp_irtc_alarm_get_supported_fields(const struct device * dev,uint16_t id,uint16_t * mask)131 static int nxp_irtc_alarm_get_supported_fields(const struct device *dev, uint16_t id,
132 					       uint16_t *mask)
133 {
134 	ARG_UNUSED(dev);
135 
136 	if (id != 0) {
137 		return -EINVAL;
138 	}
139 
140 	*mask = (RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE |
141 		 RTC_ALARM_TIME_MASK_HOUR | RTC_ALARM_TIME_MASK_MONTHDAY |
142 		 RTC_ALARM_TIME_MASK_MONTH | RTC_ALARM_TIME_MASK_YEAR);
143 
144 	return 0;
145 }
146 
nxp_irtc_alarm_set_time(const struct device * dev,uint16_t id,uint16_t mask,const struct rtc_time * timeptr)147 static int nxp_irtc_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask,
148 				   const struct rtc_time *timeptr)
149 {
150 	const struct nxp_irtc_config *config = dev->config;
151 	struct nxp_irtc_data *data = dev->data;
152 	RTC_Type *irtc_reg = config->base;
153 
154 	if (id != 0 || (mask && (timeptr == 0)) ||
155 	    (timeptr && !rtc_utils_validate_rtc_time(timeptr, mask))) {
156 		return -EINVAL;
157 	}
158 
159 	uint32_t key = irq_lock();
160 
161 	nxp_irtc_unlock_registers(irtc_reg);
162 
163 	if (mask & RTC_ALARM_TIME_MASK_SECOND) {
164 		irtc_reg->ALM_SECONDS = RTC_ALM_SECONDS_ALM_SEC(timeptr->tm_sec);
165 	}
166 
167 	if (mask & RTC_ALARM_TIME_MASK_MINUTE) {
168 		irtc_reg->ALM_HOURMIN = RTC_ALM_HOURMIN_ALM_MIN(timeptr->tm_min);
169 	}
170 
171 	if (mask & RTC_ALARM_TIME_MASK_HOUR) {
172 		irtc_reg->ALM_HOURMIN |= RTC_ALM_HOURMIN_ALM_HOUR(timeptr->tm_hour);
173 	}
174 
175 	if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) {
176 		irtc_reg->ALM_DAYS = RTC_ALM_DAYS_ALM_DAY(timeptr->tm_mday);
177 	}
178 
179 	if (mask & RTC_ALARM_TIME_MASK_MONTH) {
180 		irtc_reg->ALM_YEARMON = RTC_ALM_YEARMON_ALM_MON(timeptr->tm_mon + 1);
181 	}
182 
183 	if (mask & RTC_ALARM_TIME_MASK_YEAR) {
184 		irtc_reg->ALM_YEARMON |=
185 			RTC_ALM_YEARMON_ALM_YEAR(timeptr->tm_year - RTC_NXP_IRTC_YEAR_OFFSET);
186 	}
187 
188 	/* Clearing out the ALARM Flag Field then setting the correct value */
189 	irtc_reg->CTRL &= ~(0xC);
190 	switch (mask) {
191 	case 0x0F:
192 		irtc_reg->CTRL |= RTC_CTRL_ALM_MATCH(0x4);
193 		break;
194 	case 0x1F:
195 		irtc_reg->CTRL |= RTC_CTRL_ALM_MATCH(0x8);
196 		break;
197 	case 0x3F:
198 		irtc_reg->CTRL |= RTC_CTRL_ALM_MATCH(0xC);
199 		break;
200 	default:
201 		irtc_reg->CTRL |= RTC_CTRL_ALM_MATCH(0x0);
202 	}
203 
204 	/* Enabling Alarm Interrupts */
205 	irtc_reg->IER |= RTC_ISR_ALM_IS_MASK;
206 	data->alarm_mask = mask;
207 
208 	irq_unlock(key);
209 
210 	return 0;
211 }
212 
nxp_irtc_alarm_get_time(const struct device * dev,uint16_t id,uint16_t * mask,struct rtc_time * timeptr)213 static int nxp_irtc_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask,
214 				   struct rtc_time *timeptr)
215 {
216 	const struct nxp_irtc_config *config = dev->config;
217 	struct nxp_irtc_data *data = dev->data;
218 	RTC_Type *irtc_reg = config->base;
219 	uint16_t curr_alarm_mask = data->alarm_mask;
220 	uint16_t return_mask = 0;
221 
222 	if (id != 0 || !timeptr) {
223 		return -EINVAL;
224 	}
225 
226 	if (curr_alarm_mask & RTC_ALARM_TIME_MASK_SECOND) {
227 		timeptr->tm_sec = RTC_NXP_GET_REG_FIELD(irtc_reg, ALM_SECONDS, ALM_SEC);
228 		return_mask |= RTC_ALARM_TIME_MASK_SECOND;
229 	}
230 
231 	if (curr_alarm_mask & RTC_ALARM_TIME_MASK_MINUTE) {
232 		timeptr->tm_min = RTC_NXP_GET_REG_FIELD(irtc_reg, HOURMIN, MIN_CNT);
233 		return_mask |= RTC_ALARM_TIME_MASK_MINUTE;
234 	}
235 
236 	if (curr_alarm_mask & RTC_ALARM_TIME_MASK_HOUR) {
237 		timeptr->tm_hour = RTC_NXP_GET_REG_FIELD(irtc_reg, HOURMIN, HOUR_CNT);
238 		return_mask |= RTC_ALARM_TIME_MASK_HOUR;
239 	}
240 
241 	if (curr_alarm_mask & RTC_ALARM_TIME_MASK_MONTHDAY) {
242 		timeptr->tm_mday = RTC_NXP_GET_REG_FIELD(irtc_reg, DAYS, DAY_CNT);
243 		return_mask |= RTC_ALARM_TIME_MASK_MONTHDAY;
244 	}
245 
246 	if (curr_alarm_mask & RTC_ALARM_TIME_MASK_MONTH) {
247 		timeptr->tm_mon = RTC_NXP_GET_REG_FIELD(irtc_reg, YEARMON, MON_CNT) - 1;
248 		return_mask |= RTC_ALARM_TIME_MASK_MONTH;
249 	}
250 
251 	if (curr_alarm_mask & RTC_ALARM_TIME_MASK_YEAR) {
252 		timeptr->tm_year = (int8_t)RTC_NXP_GET_REG_FIELD(irtc_reg, YEARMON, YROFST) +
253 			RTC_NXP_IRTC_YEAR_OFFSET;
254 		return_mask |= RTC_ALARM_TIME_MASK_YEAR;
255 	}
256 
257 	*mask = return_mask;
258 
259 	return 0;
260 }
261 
nxp_irtc_alarm_is_pending(const struct device * dev,uint16_t id)262 static int nxp_irtc_alarm_is_pending(const struct device *dev, uint16_t id)
263 {
264 	struct nxp_irtc_data *data = dev->data;
265 	RTC_Type *irtc_reg = config->base;
266 
267 	if (id != 0) {
268 		return -EINVAL;
269 	}
270 
271 	return RTC_ISR_ALM_IS(0x4);
272 }
273 
nxp_irtc_alarm_set_callback(const struct device * dev,uint16_t id,rtc_alarm_callback callback,void * user_data)274 static int nxp_irtc_alarm_set_callback(const struct device *dev, uint16_t id,
275 				       rtc_alarm_callback callback, void *user_data)
276 {
277 	struct nxp_irtc_data *data = dev->data;
278 
279 	if (id != 0) {
280 		return -EINVAL;
281 	}
282 
283 	uint32_t key = irq_lock();
284 
285 	data->alarm_callback = callback;
286 	data->alarm_user_data = user_data;
287 
288 	irq_unlock(key);
289 
290 	return 0;
291 }
292 
293 #endif /* CONFIG_RTC_ALARM */
294 #if defined(CONFIG_RTC_UPDATE)
295 
nxp_irtc_update_set_callback(const struct device * dev,rtc_update_callback callback,void * user_data)296 static int nxp_irtc_update_set_callback(const struct device *dev, rtc_update_callback callback,
297 					void *user_data)
298 {
299 	ARG_UNUSED(dev);
300 	ARG_UNUSED(calibration);
301 	ARG_UNUSED(user_data);
302 	return -ENOTSUP;
303 }
304 
305 #endif /* CONFIG_RTC_UPDATE */
306 #if defined(CONFIG_RTC_CALIBRATION)
307 
nxp_irtc_set_calibration(const struct device * dev,int32_t calibration)308 static int nxp_irtc_set_calibration(const struct device *dev, int32_t calibration)
309 {
310 	ARG_UNUSED(dev);
311 	ARG_UNUSED(calibration);
312 	return -ENOTSUP;
313 }
314 
nxp_irtc_get_calibration(const struct device * dev,int32_t * calibration)315 static int nxp_irtc_get_calibration(const struct device *dev, int32_t *calibration)
316 {
317 	ARG_UNUSED(dev);
318 	ARG_UNUSED(calibration);
319 	return -ENOTSUP;
320 }
321 
322 #endif /* CONFIG_RTC_CALIBRATION */
323 
nxp_irtc_init(const struct device * dev)324 static int nxp_irtc_init(const struct device *dev)
325 {
326 	const struct nxp_irtc_config *config = dev->config;
327 	RTC_Type *irtc_reg = config->base;
328 
329 	nxp_irtc_unlock_registers(irtc_reg);
330 
331 	/* set the control register bits */
332 	irtc_reg->CTRL = RTC_CTRL_CLK_SEL(config->clock_src) |
333 			       RTC_CTRL_CLKO_DIS(!config->is_output_clock_enabled);
334 
335 	config->irq_config_func(dev);
336 
337 	return 0;
338 }
339 
nxp_irtc_isr(const struct device * dev)340 static void nxp_irtc_isr(const struct device *dev)
341 {
342 #ifdef CONFIG_RTC_ALARM
343 	const struct nxp_irtc_config *config = dev->config;
344 	RTC_Type *irtc_reg = config->base;
345 	struct nxp_irtc_data *data = dev->data;
346 	uint32_t key = irq_lock();
347 
348 	nxp_irtc_unlock_registers(irtc_reg);
349 	/* Clearing ISR Register since w1c */
350 	irtc_reg->ISR = irtc_reg->ISR;
351 
352 	if (data->alarm_callback) {
353 		data->alarm_callback(dev, 0, data->alarm_user_data);
354 	}
355 	irq_unlock(key);
356 #endif /* CONFIG_RTC_ALARM */
357 }
358 
359 static DEVICE_API(rtc, rtc_nxp_irtc_driver_api) = {
360 	.set_time = nxp_irtc_set_time,
361 	.get_time = nxp_irtc_get_time,
362 #if defined(CONFIG_RTC_ALARM)
363 	.alarm_get_supported_fields = nxp_irtc_alarm_get_supported_fields,
364 	.alarm_set_time = nxp_irtc_alarm_set_time,
365 	.alarm_get_time = nxp_irtc_alarm_get_time,
366 	.alarm_is_pending = nxp_irtc_alarm_is_pending,
367 	.alarm_set_callback = nxp_irtc_alarm_set_callback,
368 #endif /* CONFIG_RTC_ALARM */
369 #if defined(CONFIG_RTC_UPDATE)
370 	.update_set_callback = nxp_irtc_update_set_callback,
371 #endif /* CONFIG_RTC_UPDATE */
372 #if defined(CONFIG_RTC_CALIBRATION)
373 	.set_calibration = nxp_irtc_set_calibration,
374 	.get_calibration = nxp_irtc_get_calibration,
375 #endif /* CONFIG_RTC_CALIBRATION */
376 };
377 
378 #define RTC_NXP_IRTC_DEVICE_INIT(n)                                                                \
379 	static void nxp_irtc_config_func_##n(const struct device *dev)                             \
380 	{                                                                                          \
381 		IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), nxp_irtc_isr,               \
382 			    DEVICE_DT_INST_GET(n), 0);                                             \
383 		irq_enable(DT_INST_IRQN(n));                                                       \
384 	}                                                                                          \
385 	static const struct nxp_irtc_config nxp_irtc_config_##n = {                                \
386 		.base = (RTC_Type *)DT_INST_REG_ADDR(n),                                           \
387 		.clock_src = DT_INST_PROP(n, clock_src),					   \
388 		.is_output_clock_enabled = DT_INST_PROP(n, output_clk_en),	                   \
389 		.irq_config_func = nxp_irtc_config_func_##n,                                       \
390 	};                                                                                         \
391                                                                                                    \
392 	static struct nxp_irtc_data nxp_irtc_data_##n;                                             \
393                                                                                                    \
394 	DEVICE_DT_INST_DEFINE(n, nxp_irtc_init, NULL, &nxp_irtc_data_##n, &nxp_irtc_config_##n,    \
395 			      PRE_KERNEL_1, CONFIG_RTC_INIT_PRIORITY, &rtc_nxp_irtc_driver_api);
396 
397 DT_INST_FOREACH_STATUS_OKAY(RTC_NXP_IRTC_DEVICE_INIT)
398