1 /*
2  * Copyright (c) 2023 Bjarki Arge Andreasen
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT atmel_sam_rtc
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/device.h>
11 #include <zephyr/irq.h>
12 #include <zephyr/drivers/rtc.h>
13 #include <zephyr/sys/util.h>
14 
15 #include <string.h>
16 #include <soc.h>
17 #include "rtc_utils.h"
18 
19 #define RTC_SAM_REG_GET_FIELD(value, field) \
20 	((RTC_##field##_Msk & value) >> RTC_##field##_Pos)
21 
22 #define RTC_SAM_WPMR_DISABLE 0x52544300
23 #define RTC_SAM_WPMR_ENABLE 0x52544301
24 
25 #define RTC_SAM_CALIBRATE_PPB_MAX (1950000)
26 #define RTC_SAM_CALIBRATE_PPB_MIN (-1950000)
27 #define RTC_SAM_CALIBRATE_PPB_QUANTA (1500)
28 #define RTC_SAM_CALIBRATE_PPB_LOW_SCALE (30500)
29 
30 #define RTC_SAM_TIME_MASK                                                                          \
31 	(RTC_ALARM_TIME_MASK_SECOND | RTC_ALARM_TIME_MASK_MINUTE | RTC_ALARM_TIME_MASK_HOUR |      \
32 	 RTC_ALARM_TIME_MASK_MONTH | RTC_ALARM_TIME_MASK_MONTHDAY | RTC_ALARM_TIME_MASK_YEAR |     \
33 	 RTC_ALARM_TIME_MASK_WEEKDAY)
34 
35 typedef void (*rtc_sam_irq_init_fn_ptr)(void);
36 
37 struct rtc_sam_config {
38 	Rtc *regs;
39 	uint16_t irq_num;
40 	rtc_sam_irq_init_fn_ptr irq_init_fn_ptr;
41 };
42 
43 struct rtc_sam_data {
44 #ifdef CONFIG_RTC_ALARM
45 	rtc_alarm_callback alarm_callback;
46 	void *alarm_user_data;
47 #endif /* CONFIG_RTC_ALARM */
48 #ifdef CONFIG_RTC_UPDATE
49 	rtc_update_callback update_callback;
50 	void *update_user_data;
51 #endif /* CONFIG_RTC_UPDATE */
52 	struct k_spinlock lock;
53 	struct k_sem cr_sec_evt_sem;
54 	struct k_sem cr_upd_ack_sem;
55 };
56 
rtc_sam_disable_wp(void)57 static void rtc_sam_disable_wp(void)
58 {
59 #ifdef REG_RTC_WPMR
60 	REG_RTC_WPMR = RTC_SAM_WPMR_DISABLE;
61 #endif
62 }
63 
rtc_sam_enable_wp(void)64 static void rtc_sam_enable_wp(void)
65 {
66 #ifdef REG_RTC_WPMR
67 	REG_RTC_WPMR = RTC_SAM_WPMR_ENABLE;
68 #endif
69 }
70 
rtc_sam_timr_from_tm(const struct rtc_time * timeptr)71 static uint32_t rtc_sam_timr_from_tm(const struct rtc_time *timeptr)
72 {
73 	uint32_t timr;
74 
75 	timr = RTC_TIMR_SEC(bin2bcd(timeptr->tm_sec));
76 	timr |= RTC_TIMR_MIN(bin2bcd(timeptr->tm_min));
77 	timr |= RTC_TIMR_HOUR(bin2bcd(timeptr->tm_hour));
78 
79 	return timr;
80 }
81 
rtc_sam_calr_from_tm(const struct rtc_time * timeptr)82 static uint32_t rtc_sam_calr_from_tm(const struct rtc_time *timeptr)
83 {
84 	uint32_t calr;
85 	uint8_t centuries;
86 	uint8_t years;
87 
88 	calr = RTC_CALR_DATE(bin2bcd(timeptr->tm_mday));
89 	calr |= RTC_CALR_MONTH(bin2bcd(timeptr->tm_mon + 1));
90 	centuries = (uint8_t)((timeptr->tm_year / 100) + 19);
91 	years = (uint8_t)((timeptr->tm_year % 100));
92 	calr |= RTC_CALR_CENT(bin2bcd(centuries));
93 	calr |= RTC_CALR_YEAR(bin2bcd(years));
94 	calr |= RTC_CALR_DAY(bin2bcd(timeptr->tm_wday + 1));
95 	return calr;
96 }
97 
rtc_sam_set_time(const struct device * dev,const struct rtc_time * timeptr)98 static int rtc_sam_set_time(const struct device *dev, const struct rtc_time *timeptr)
99 {
100 	struct rtc_sam_data *data = dev->data;
101 	const struct rtc_sam_config *config = dev->config;
102 	Rtc *regs = config->regs;
103 
104 	if (rtc_utils_validate_rtc_time(timeptr, RTC_SAM_TIME_MASK) == false) {
105 		return -EINVAL;
106 	}
107 
108 	k_spinlock_key_t key = k_spin_lock(&data->lock);
109 
110 	k_sem_reset(&data->cr_sec_evt_sem);
111 	k_sem_take(&data->cr_sec_evt_sem, K_MSEC(1100));
112 	k_sem_reset(&data->cr_upd_ack_sem);
113 
114 	/* Enable update acknowledge interrupt */
115 	regs->RTC_IER = RTC_IER_ACKEN;
116 
117 	rtc_sam_disable_wp();
118 
119 	/* Request update */
120 	regs->RTC_CR = (RTC_CR_UPDTIM | RTC_CR_UPDCAL);
121 
122 	/* Await update acknowledge */
123 	if (k_sem_take(&data->cr_upd_ack_sem, K_MSEC(1100)) < 0) {
124 		regs->RTC_CR = 0;
125 
126 		rtc_sam_enable_wp();
127 
128 		/* Disable update acknowledge interrupt */
129 		regs->RTC_IDR = RTC_IDR_ACKDIS;
130 
131 		k_spin_unlock(&data->lock, key);
132 		return -EAGAIN;
133 	}
134 
135 	regs->RTC_TIMR = rtc_sam_timr_from_tm(timeptr);
136 	regs->RTC_CALR = rtc_sam_calr_from_tm(timeptr);
137 	regs->RTC_CR = 0;
138 	rtc_sam_enable_wp();
139 	regs->RTC_IDR = RTC_IDR_ACKDIS;
140 	k_spin_unlock(&data->lock, key);
141 	return 0;
142 }
143 
rtc_sam_get_time(const struct device * dev,struct rtc_time * timeptr)144 static int rtc_sam_get_time(const struct device *dev, struct rtc_time *timeptr)
145 {
146 	const struct rtc_sam_config *config = dev->config;
147 	Rtc *regs = config->regs;
148 
149 	uint32_t timr0;
150 	uint32_t calr0;
151 	uint32_t timr1;
152 	uint32_t calr1;
153 
154 	/* Validate time and date */
155 	if (regs->RTC_VER & (RTC_VER_NVTIM | RTC_VER_NVCAL)) {
156 		return -ENODATA;
157 	}
158 
159 	/* Read until synchronized (registers updated async) */
160 	while (1) {
161 		timr0 = regs->RTC_TIMR;
162 		calr0 = regs->RTC_CALR;
163 		timr1 = regs->RTC_TIMR;
164 		calr1 = regs->RTC_CALR;
165 
166 		if ((timr0 == timr1) && (calr0 == calr1)) {
167 			break;
168 		}
169 	}
170 
171 	timeptr->tm_sec = bcd2bin(RTC_SAM_REG_GET_FIELD(timr0, TIMR_SEC));
172 	timeptr->tm_min = bcd2bin(RTC_SAM_REG_GET_FIELD(timr0, TIMR_MIN));
173 	timeptr->tm_hour = bcd2bin(RTC_SAM_REG_GET_FIELD(timr0, TIMR_HOUR));
174 	timeptr->tm_mday = bcd2bin(RTC_SAM_REG_GET_FIELD(calr0, CALR_DATE));
175 	timeptr->tm_mon = bcd2bin(RTC_SAM_REG_GET_FIELD(calr0, CALR_MONTH)) - 1;
176 
177 	timeptr->tm_year = bcd2bin(RTC_SAM_REG_GET_FIELD(calr0, CALR_YEAR));
178 	timeptr->tm_year += ((int)bcd2bin(RTC_SAM_REG_GET_FIELD(calr0, CALR_CENT))) * 100;
179 	timeptr->tm_year -= 1900;
180 
181 	timeptr->tm_wday = bcd2bin(RTC_SAM_REG_GET_FIELD(calr0, CALR_DAY)) - 1;
182 	timeptr->tm_yday = -1;
183 	timeptr->tm_isdst = -1;
184 	timeptr->tm_nsec = 0;
185 	return 0;
186 }
187 
rtc_sam_isr(const struct device * dev)188 static void rtc_sam_isr(const struct device *dev)
189 {
190 	struct rtc_sam_data *data = dev->data;
191 	const struct rtc_sam_config *config = dev->config;
192 	Rtc *regs = config->regs;
193 
194 	uint32_t sr = regs->RTC_SR;
195 
196 	if (sr & RTC_SR_ACKUPD) {
197 		regs->RTC_SCCR = RTC_SCCR_ACKCLR;
198 		k_sem_give(&data->cr_upd_ack_sem);
199 	}
200 
201 #ifdef CONFIG_RTC_ALARM
202 	if (sr & RTC_SR_ALARM) {
203 		regs->RTC_SCCR = RTC_SCCR_ALRCLR;
204 		if (data->alarm_callback != NULL) {
205 			data->alarm_callback(dev, 0, data->alarm_user_data);
206 		}
207 	}
208 #endif /* CONFIG_RTC_ALARM */
209 
210 #ifdef CONFIG_RTC_UPDATE
211 	if (sr & RTC_SR_SEC) {
212 		regs->RTC_SCCR = RTC_SCCR_SECCLR;
213 		if (data->update_callback != NULL) {
214 			data->update_callback(dev, data->update_user_data);
215 		}
216 
217 		k_sem_give(&data->cr_sec_evt_sem);
218 	}
219 #endif /* CONFIG_RTC_UPDATE */
220 }
221 
222 #ifdef CONFIG_RTC_ALARM
rtc_sam_alarm_get_supported_mask(void)223 static uint16_t rtc_sam_alarm_get_supported_mask(void)
224 {
225 	return (RTC_ALARM_TIME_MASK_SECOND
226 	      | RTC_ALARM_TIME_MASK_MINUTE
227 	      | RTC_ALARM_TIME_MASK_HOUR
228 	      | RTC_ALARM_TIME_MASK_MONTHDAY
229 	      | RTC_ALARM_TIME_MASK_MONTH);
230 }
231 
rtc_atmel_timalr_from_tm(const struct rtc_time * timeptr,uint32_t mask)232 static uint32_t rtc_atmel_timalr_from_tm(const struct rtc_time *timeptr, uint32_t mask)
233 {
234 	uint32_t timalr = 0;
235 
236 	if (mask & RTC_ALARM_TIME_MASK_SECOND) {
237 		timalr |= RTC_TIMALR_SECEN;
238 		timalr |= RTC_TIMALR_SEC(bin2bcd(timeptr->tm_sec));
239 	}
240 
241 	if (mask & RTC_ALARM_TIME_MASK_MINUTE) {
242 		timalr |= RTC_TIMALR_MINEN;
243 		timalr |= RTC_TIMALR_MIN(bin2bcd(timeptr->tm_min));
244 	}
245 
246 	if (mask & RTC_ALARM_TIME_MASK_HOUR) {
247 		timalr |= RTC_TIMALR_HOUREN;
248 		timalr |= RTC_TIMALR_HOUR(bin2bcd(timeptr->tm_hour));
249 	}
250 
251 	return timalr;
252 }
253 
rtc_atmel_calalr_from_tm(const struct rtc_time * timeptr,uint32_t mask)254 static uint32_t rtc_atmel_calalr_from_tm(const struct rtc_time *timeptr, uint32_t mask)
255 {
256 	uint32_t calalr = RTC_CALALR_MONTH(1) | RTC_CALALR_DATE(1);
257 
258 	if (mask & RTC_ALARM_TIME_MASK_MONTH) {
259 		calalr |= RTC_CALALR_MTHEN;
260 		calalr |= RTC_CALALR_MONTH(bin2bcd(timeptr->tm_mon + 1));
261 	}
262 
263 	if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) {
264 		calalr |= RTC_CALALR_DATEEN;
265 		calalr |= RTC_CALALR_DATE(bin2bcd(timeptr->tm_mday));
266 	}
267 
268 	return calalr;
269 }
270 
rtc_sam_alarm_mask_from_timalr(uint32_t timalr)271 static uint32_t rtc_sam_alarm_mask_from_timalr(uint32_t timalr)
272 {
273 	uint32_t mask = 0;
274 
275 	if (timalr & RTC_TIMALR_SECEN) {
276 		mask |= RTC_ALARM_TIME_MASK_SECOND;
277 	}
278 
279 	if (timalr & RTC_TIMALR_MINEN) {
280 		mask |= RTC_ALARM_TIME_MASK_MINUTE;
281 	}
282 
283 	if (timalr & RTC_TIMALR_HOUREN) {
284 		mask |= RTC_ALARM_TIME_MASK_HOUR;
285 	}
286 
287 	return mask;
288 }
289 
rtc_sam_alarm_mask_from_calalr(uint32_t calalr)290 static uint32_t rtc_sam_alarm_mask_from_calalr(uint32_t calalr)
291 {
292 	uint32_t mask = 0;
293 
294 	if (calalr & RTC_CALALR_MTHEN) {
295 		mask |= RTC_ALARM_TIME_MASK_MONTH;
296 	}
297 
298 	if (calalr & RTC_CALALR_DATEEN) {
299 		mask |= RTC_ALARM_TIME_MASK_MONTHDAY;
300 	}
301 
302 	return mask;
303 }
304 
rtc_sam_tm_from_timalr_calalr(struct rtc_time * timeptr,uint32_t mask,uint32_t timalr,uint32_t calalr)305 static void rtc_sam_tm_from_timalr_calalr(struct rtc_time *timeptr, uint32_t mask,
306 						 uint32_t timalr, uint32_t calalr)
307 {
308 	memset(timeptr, 0x00, sizeof(*timeptr));
309 
310 	if (mask & RTC_ALARM_TIME_MASK_SECOND) {
311 		timeptr->tm_sec = bcd2bin(RTC_SAM_REG_GET_FIELD(timalr, TIMALR_SEC));
312 	}
313 
314 	if (mask & RTC_ALARM_TIME_MASK_MINUTE) {
315 		timeptr->tm_min = bcd2bin(RTC_SAM_REG_GET_FIELD(timalr, TIMALR_MIN));
316 	}
317 
318 	if (mask & RTC_ALARM_TIME_MASK_HOUR) {
319 		timeptr->tm_hour = bcd2bin(RTC_SAM_REG_GET_FIELD(timalr, TIMALR_HOUR));
320 	}
321 
322 	if (mask & RTC_ALARM_TIME_MASK_MONTHDAY) {
323 		timeptr->tm_mday = bcd2bin(RTC_SAM_REG_GET_FIELD(calalr, CALALR_DATE));
324 	}
325 
326 	if (mask & RTC_ALARM_TIME_MASK_MONTH) {
327 		timeptr->tm_mon = bcd2bin(RTC_SAM_REG_GET_FIELD(calalr, CALALR_MONTH)) - 1;
328 	}
329 }
330 
rtc_sam_alarm_get_supported_fields(const struct device * dev,uint16_t id,uint16_t * mask)331 static int rtc_sam_alarm_get_supported_fields(const struct device *dev, uint16_t id,
332 					      uint16_t *mask)
333 {
334 	ARG_UNUSED(dev);
335 	ARG_UNUSED(id);
336 
337 	*mask = rtc_sam_alarm_get_supported_mask();
338 	return 0;
339 }
340 
rtc_sam_alarm_set_time(const struct device * dev,uint16_t id,uint16_t mask,const struct rtc_time * timeptr)341 static int rtc_sam_alarm_set_time(const struct device *dev, uint16_t id, uint16_t mask,
342 				  const struct rtc_time *timeptr)
343 {
344 	struct rtc_sam_data *data = dev->data;
345 	const struct rtc_sam_config *config = dev->config;
346 	Rtc *regs = config->regs;
347 
348 	uint32_t timalr;
349 	uint32_t calalr;
350 	uint32_t mask_supported;
351 
352 	mask_supported = rtc_sam_alarm_get_supported_mask();
353 
354 	if ((id != 0)) {
355 		return -EINVAL;
356 	}
357 
358 	if ((mask > 0) && (timeptr == NULL)) {
359 		return -EINVAL;
360 	}
361 
362 	if (mask & ~mask_supported) {
363 		return -EINVAL;
364 	}
365 
366 	if (rtc_utils_validate_rtc_time(timeptr, mask) == false) {
367 		return -EINVAL;
368 	}
369 
370 	timalr = rtc_atmel_timalr_from_tm(timeptr, mask);
371 	calalr = rtc_atmel_calalr_from_tm(timeptr, mask);
372 
373 	k_spinlock_key_t key = k_spin_lock(&data->lock);
374 
375 	irq_disable(config->irq_num);
376 	rtc_sam_disable_wp();
377 
378 	/* Set RTC alarm time */
379 	regs->RTC_TIMALR = timalr;
380 	regs->RTC_CALALR = calalr;
381 
382 	rtc_sam_enable_wp();
383 
384 	/* Clear alarm pending status */
385 	regs->RTC_SCCR = RTC_SCCR_ALRCLR;
386 
387 	irq_enable(config->irq_num);
388 	k_spin_unlock(&data->lock, key);
389 	return 0;
390 }
391 
rtc_sam_alarm_get_time(const struct device * dev,uint16_t id,uint16_t * mask,struct rtc_time * timeptr)392 static int rtc_sam_alarm_get_time(const struct device *dev, uint16_t id, uint16_t *mask,
393 				  struct rtc_time *timeptr)
394 {
395 	struct rtc_sam_data *data = dev->data;
396 	const struct rtc_sam_config *config = dev->config;
397 	Rtc *regs = config->regs;
398 
399 	uint32_t timalr;
400 	uint32_t calalr;
401 
402 	if ((id != 0) || (mask == NULL) || (timeptr == NULL)) {
403 		return -EINVAL;
404 	}
405 
406 	k_spinlock_key_t key = k_spin_lock(&data->lock);
407 
408 	timalr = regs->RTC_TIMALR;
409 	calalr = regs->RTC_CALALR;
410 
411 	k_spin_unlock(&data->lock, key);
412 
413 	*mask = rtc_sam_alarm_mask_from_timalr(timalr);
414 	*mask |= rtc_sam_alarm_mask_from_calalr(calalr);
415 
416 	rtc_sam_tm_from_timalr_calalr(timeptr, *mask, timalr, calalr);
417 	return 0;
418 }
419 
rtc_sam_alarm_is_pending(const struct device * dev,uint16_t id)420 static int rtc_sam_alarm_is_pending(const struct device *dev, uint16_t id)
421 {
422 	struct rtc_sam_data *data = dev->data;
423 	const struct rtc_sam_config *config = dev->config;
424 	Rtc *regs = config->regs;
425 
426 	if (id != 0) {
427 		return -EINVAL;
428 	}
429 
430 	k_spinlock_key_t key = k_spin_lock(&data->lock);
431 
432 	if ((regs->RTC_SR & RTC_SR_ALARM) == 0) {
433 		k_spin_unlock(&data->lock, key);
434 
435 		return 0;
436 	}
437 
438 	regs->RTC_SCCR = RTC_SCCR_ALRCLR;
439 	k_spin_unlock(&data->lock, key);
440 	return 1;
441 }
442 
rtc_sam_alarm_set_callback(const struct device * dev,uint16_t id,rtc_alarm_callback callback,void * user_data)443 static int rtc_sam_alarm_set_callback(const struct device *dev, uint16_t id,
444 				      rtc_alarm_callback callback, void *user_data)
445 {
446 	struct rtc_sam_data *data = dev->data;
447 	const struct rtc_sam_config *config = dev->config;
448 	Rtc *regs = config->regs;
449 
450 	if (id != 0) {
451 		return -EINVAL;
452 	}
453 
454 	k_spinlock_key_t key = k_spin_lock(&data->lock);
455 
456 	irq_disable(config->irq_num);
457 	data->alarm_callback = callback;
458 	data->alarm_user_data = user_data;
459 
460 	if (data->alarm_callback) {
461 		regs->RTC_IER = RTC_IER_ALREN;
462 	} else {
463 		regs->RTC_IDR = RTC_IDR_ALRDIS;
464 	}
465 
466 	irq_enable(config->irq_num);
467 	k_spin_unlock(&data->lock, key);
468 	return 0;
469 }
470 #endif /* CONFIG_RTC_ALARM */
471 
472 #ifdef CONFIG_RTC_UPDATE
rtc_sam_update_set_callback(const struct device * dev,rtc_update_callback callback,void * user_data)473 static int rtc_sam_update_set_callback(const struct device *dev, rtc_update_callback callback,
474 				       void *user_data)
475 {
476 	struct rtc_sam_data *data = dev->data;
477 	const struct rtc_sam_config *config = dev->config;
478 	Rtc *regs = config->regs;
479 
480 	k_spinlock_key_t key = k_spin_lock(&data->lock);
481 
482 	irq_disable(config->irq_num);
483 
484 	data->update_callback = callback;
485 	data->update_user_data = user_data;
486 
487 	if (data->update_callback) {
488 		regs->RTC_IER = RTC_IER_SECEN;
489 	} else {
490 		regs->RTC_IDR = RTC_IDR_SECDIS;
491 	}
492 
493 	irq_enable(config->irq_num);
494 
495 	k_spin_unlock(&data->lock, key);
496 
497 	return 0;
498 }
499 #endif /* CONFIG_RTC_UPDATE */
500 
501 #ifdef CONFIG_RTC_CALIBRATION
rtc_sam_set_calibration(const struct device * dev,int32_t calibration)502 static int rtc_sam_set_calibration(const struct device *dev, int32_t calibration)
503 {
504 	struct rtc_sam_data *data = dev->data;
505 	const struct rtc_sam_config *config = dev->config;
506 	Rtc *regs = config->regs;
507 	bool negative_calibration;
508 	bool high_calibration;
509 	uint32_t slow_clock_calibration;
510 	uint32_t mr;
511 
512 	if ((calibration < RTC_SAM_CALIBRATE_PPB_MIN) ||
513 	    (calibration > RTC_SAM_CALIBRATE_PPB_MAX)) {
514 		return -EINVAL;
515 	}
516 
517 	/* The value written to the register is absolute */
518 	if (calibration < 0) {
519 		negative_calibration = true;
520 		calibration = -calibration;
521 	} else {
522 		negative_calibration = false;
523 	}
524 
525 	/*
526 	 * Formula adapted from
527 	 * Atmel-11157-32-bit-Cortex-M4-Microcontroller-SAM4E16-SAM4E8_Datasheet.pdf
528 	 * section 15.6.2
529 	 *
530 	 * Formula if RTC_MR_HIGHPPM is 0
531 	 *
532 	 *   RTC_MR_CORRECTION = (3906 / (20 * ppm)) - 1
533 	 *
534 	 * Formula if RTC_MR_HIGHPPM is 1
535 	 *
536 	 *   RTC_MR_CORRECTION = (3906 / ppm) - 1
537 	 *
538 	 * Since we are working with ppb, we adapt the formula by increasing the
539 	 * terms of the fraction by 1000, turning the ppm into ppb
540 	 *
541 	 * Adapted formula if RTC_MR_HIGHPPM is 0
542 	 *
543 	 *   RTC_MR_CORRECTION = (3906000 / (20 * ppb)) - 1
544 	 *
545 	 * Adapted formula  if RTC_MR_HIGHPPM is 1
546 	 *
547 	 *   RTC_MR_CORRECTION = (3906000 / ppb) - 1
548 	 */
549 	if (calibration < RTC_SAM_CALIBRATE_PPB_QUANTA) {
550 		high_calibration = false;
551 		slow_clock_calibration = 0;
552 	} else if (calibration < RTC_SAM_CALIBRATE_PPB_LOW_SCALE) {
553 		high_calibration = false;
554 		slow_clock_calibration = (uint32_t)((3906000 / (20 * calibration)) - 1);
555 	} else {
556 		high_calibration = true;
557 		slow_clock_calibration = (uint32_t)((3906000 / calibration) - 1);
558 	}
559 
560 	k_spinlock_key_t key = k_spin_lock(&data->lock);
561 
562 	rtc_sam_disable_wp();
563 
564 	mr = regs->RTC_MR;
565 
566 	if (negative_calibration == true) {
567 		mr |= RTC_MR_NEGPPM;
568 	} else {
569 		mr &= ~RTC_MR_NEGPPM;
570 	}
571 
572 	mr &= ~RTC_MR_CORRECTION_Msk;
573 	mr |= RTC_MR_CORRECTION(slow_clock_calibration);
574 
575 	if (high_calibration == true) {
576 		mr |= RTC_MR_HIGHPPM;
577 	} else {
578 		mr &= ~RTC_MR_HIGHPPM;
579 	}
580 
581 	regs->RTC_MR = mr;
582 
583 	rtc_sam_enable_wp();
584 
585 	k_spin_unlock(&data->lock, key);
586 
587 	return 0;
588 }
589 
rtc_sam_get_calibration(const struct device * dev,int32_t * calibration)590 static int rtc_sam_get_calibration(const struct device *dev, int32_t *calibration)
591 {
592 	const struct rtc_sam_config *config = dev->config;
593 	Rtc *regs = config->regs;
594 
595 	uint32_t mr;
596 	int32_t correction;
597 
598 	if (calibration == NULL) {
599 		return -EINVAL;
600 	}
601 
602 	mr = regs->RTC_MR;
603 
604 	correction = (int32_t)RTC_SAM_REG_GET_FIELD(mr, MR_CORRECTION);
605 
606 	/* Formula documented in rtc_sam_set_calibration() */
607 	if (correction == 0) {
608 		*calibration = 0;
609 	} else if (mr & RTC_MR_HIGHPPM) {
610 		*calibration = 3906000 / (correction + 1);
611 	} else {
612 		*calibration = 3906000 / ((correction + 1) * 20);
613 	}
614 
615 	if (mr & RTC_MR_NEGPPM) {
616 		*calibration = -*calibration;
617 	}
618 
619 	return 0;
620 }
621 #endif /* CONFIG_RTC_CALIBRATION */
622 
623 static DEVICE_API(rtc, rtc_sam_driver_api) = {
624 	.set_time = rtc_sam_set_time,
625 	.get_time = rtc_sam_get_time,
626 #ifdef CONFIG_RTC_ALARM
627 	.alarm_get_supported_fields = rtc_sam_alarm_get_supported_fields,
628 	.alarm_set_time = rtc_sam_alarm_set_time,
629 	.alarm_get_time = rtc_sam_alarm_get_time,
630 	.alarm_is_pending = rtc_sam_alarm_is_pending,
631 	.alarm_set_callback = rtc_sam_alarm_set_callback,
632 #endif /* CONFIG_RTC_ALARM */
633 #ifdef CONFIG_RTC_UPDATE
634 	.update_set_callback = rtc_sam_update_set_callback,
635 #endif /* CONFIG_RTC_UPDATE */
636 #ifdef CONFIG_RTC_CALIBRATION
637 	.set_calibration = rtc_sam_set_calibration,
638 	.get_calibration = rtc_sam_get_calibration,
639 #endif /* CONFIG_RTC_CALIBRATION */
640 };
641 
rtc_sam_init(const struct device * dev)642 static int rtc_sam_init(const struct device *dev)
643 {
644 	struct rtc_sam_data *data = dev->data;
645 	const struct rtc_sam_config *config = dev->config;
646 	Rtc *regs = config->regs;
647 
648 	rtc_sam_disable_wp();
649 #ifdef RTC_MR_PERSIAN
650 	regs->RTC_MR &= ~(RTC_MR_HRMOD | RTC_MR_PERSIAN);
651 #else
652 	regs->RTC_MR &= ~RTC_MR_HRMOD;
653 #endif
654 	regs->RTC_CR = 0;
655 	rtc_sam_enable_wp();
656 	regs->RTC_IDR = (RTC_IDR_ACKDIS
657 			       | RTC_IDR_ALRDIS
658 			       | RTC_IDR_SECDIS
659 			       | RTC_IDR_TIMDIS
660 			       | RTC_IDR_CALDIS
661 			       | RTC_IDR_TDERRDIS);
662 
663 	k_sem_init(&data->cr_sec_evt_sem, 0, 1);
664 	k_sem_init(&data->cr_upd_ack_sem, 0, 1);
665 	config->irq_init_fn_ptr();
666 	irq_enable(config->irq_num);
667 	return 0;
668 }
669 
670 #define RTC_SAM_DEVICE(id)						\
671 	static void rtc_sam_irq_init_##id(void)				\
672 	{								\
673 		IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority),	\
674 			    rtc_sam_isr, DEVICE_DT_INST_GET(id), 0);	\
675 	}								\
676 									\
677 	static const struct rtc_sam_config rtc_sam_config_##id = {	\
678 		.regs = (Rtc *)DT_INST_REG_ADDR(id),			\
679 		.irq_num = DT_INST_IRQN(id),				\
680 		.irq_init_fn_ptr = rtc_sam_irq_init_##id,		\
681 	};								\
682 									\
683 	static struct rtc_sam_data rtc_sam_data_##id;			\
684 									\
685 	DEVICE_DT_INST_DEFINE(id, rtc_sam_init, NULL,			\
686 			      &rtc_sam_data_##id,			\
687 			      &rtc_sam_config_##id, POST_KERNEL,	\
688 			      CONFIG_RTC_INIT_PRIORITY,			\
689 			      &rtc_sam_driver_api);
690 
691 DT_INST_FOREACH_STATUS_OKAY(RTC_SAM_DEVICE);
692