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