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