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