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