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