1 /*******************************************************************************
2  * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * PoalrFire SoC Microprocessor Subsystem RTC bare metal driver implementation.
7  */
8 #include <string.h>
9 #include "mpfs_hal/mss_hal.h"
10 #include "mss_rtc_regs.h"
11 #include "mss_rtc.h"
12 
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16 
17 /*-------------------------------------------------------------------------*//**
18  * CONTROL_REG register masks.
19  */
20 #define CONTROL_RUNNING_MASK        0x00000001u
21 #define CONTROL_RTC_START_MASK      0x00000001u
22 #define CONTROL_RTC_STOP_MASK       0x00000002u
23 #define CONTROL_ALARM_ON_MASK       0x00000004u
24 #define CONTROL_ALARM_OFF_MASK      0x00000008u
25 #define CONTROL_RESET_MASK          0x00000010u
26 #define CONTROL_UPLOAD_MASK         0x00000020u
27 #define CONTROL_WAKEUP_CLR_MASK     0x00000100u
28 #define CONTROL_UPDATED_MASK        0x00000400u
29 
30 /*-------------------------------------------------------------------------*//**
31  * MODE_REG register masks.
32  */
33 #define MODE_CLK_MODE_MASK          0x00000001u
34 #define MODE_WAKEUP_EN_MASK         0x00000002u
35 #define MODE_WAKEUP_RESET_MASK      0x00000004u
36 #define MODE_WAKEUP_CONTINUE_MASK   0x00000008u
37 
38 /*-------------------------------------------------------------------------*//**
39  * Other masks.
40  */
41 #define MAX_BINARY_HIGHER_COUNT     0x7FFu
42 #define MASK_32_BIT                 0xFFFFFFFFu
43 #define MAX_PRESCALAR_COUNT         0x03FFFFFFu
44 #define CALENDAR_SHIFT              8u
45 
46 /*-------------------------------------------------------------------------*//**
47  * Index into look-up table.
48  */
49 #define SECONDS     0
50 #define MINUTES     1
51 #define HOURS       2
52 #define DAYS        3
53 #define MONTHS      4
54 #define YEARS       5
55 #define WEEKDAYS    6
56 #define WEEKS       7
57 
58 /*-------------------------------------------------------------------------*//**
59  * A pointer to the RTC_TypeDef structure is used to configure the user selected
60  * RTC. This pointer is used by all the mss RTC driver function to carry out the
61  * required functionality.
62  */
63 RTC_TypeDef *      mss_rtc;
64 
65 static uint8_t
66 get_clock_mode
67 (
68     void
69 );
70 
71 static void
72 set_rtc_mode
73 (
74     uint8_t requested_mode
75 );
76 
77 static void add_alarm_cfg_values
78 (
79     uint8_t calendar_item,
80     uint32_t * p_calendar_value,
81     uint32_t * p_compare_mask
82 );
83 
84 /*-------------------------------------------------------------------------*//**
85  * See "mss_rtc.h" for details of how to use this function.
86  */
87 void
MSS_RTC_init(RTC_TypeDef * base_address,uint8_t mode,uint32_t prescaler)88 MSS_RTC_init
89 (
90     RTC_TypeDef *base_address,
91     uint8_t mode,
92     uint32_t prescaler
93 )
94 {
95     ASSERT(prescaler <= MAX_PRESCALAR_COUNT);
96 
97     /* Assigning the user selected MSS RTC base address to global RTC structure
98      * pointer so that the other driver functions can use it.
99      */
100     mss_rtc = base_address;
101 
102     if (prescaler <= MAX_PRESCALAR_COUNT)
103     {
104         /* Stop the RTC. */
105         MSS_RTC_stop();
106 
107         /* Disable alarm. */
108         mss_rtc->CONTROL_REG = CONTROL_ALARM_OFF_MASK;
109 
110         /* Disable Interrupt */
111         MSS_RTC_disable_irq();
112 
113         /* Clear RTC wake up interrupt signal */
114         MSS_RTC_clear_irq();
115 
116         /* Select mode of operation, including the wake configuration. */
117         if (MSS_RTC_CALENDAR_MODE == mode)
118         {
119             mss_rtc->MODE_REG = MODE_CLK_MODE_MASK;
120         }
121         else
122         {
123             mss_rtc->MODE_REG = 0u;
124         }
125 
126         /* Reset the alarm and compare registers to a known value. */
127         mss_rtc->ALARM_LOWER_REG = 0u;
128         mss_rtc->ALARM_UPPER_REG = 0u;
129         mss_rtc->COMPARE_LOWER_REG = 0u;
130         mss_rtc->COMPARE_UPPER_REG = 0u;
131 
132         /* Reset the calendar counters */
133         MSS_RTC_reset_counter();
134 
135         /* Set new Prescaler value */
136         mss_rtc->PRESCALER_REG = prescaler;
137     }
138 }
139 
140 /*-------------------------------------------------------------------------*//**
141   See "mss_rtc.h" for details of how to use this function.
142  */
143 void
MSS_RTC_set_calendar_count(const mss_rtc_calender_t * new_rtc_value)144 MSS_RTC_set_calendar_count
145 (
146     const mss_rtc_calender_t *new_rtc_value
147 )
148 {
149     uint8_t error = 0u;
150     uint8_t clock_mode;
151 
152     const uint8_t g_rtc_max_count_lut[] =
153     {
154        /* Calendar mode */
155         59u,    /* Seconds */
156         59u,    /* Minutes */
157         23u,    /* Hours   */
158         31u,    /* Days    */
159         12u,    /* Months  */
160         254u,   /* Years   */
161         7u,     /* Weekdays */
162         52u     /* Week    */
163     };
164 
165     const uint8_t g_rtc_min_count_lut[] =
166     {
167        /* Calendar mode */
168         0u, /* Seconds */
169         0u, /* Minutes */
170         0u, /* Hours   */
171         1u, /* Days    */
172         1u, /* Months  */
173         0u, /* Years   */
174         1u, /* Weekdays */
175         1u  /* Week    */
176     };
177 
178     /* Assert if the values cross the limit */
179     ASSERT(new_rtc_value->second >= g_rtc_min_count_lut[SECONDS]);
180     ASSERT(new_rtc_value->second <= g_rtc_max_count_lut[SECONDS]);
181     ASSERT(new_rtc_value->minute >= g_rtc_min_count_lut[MINUTES]);
182     ASSERT(new_rtc_value->minute <= g_rtc_max_count_lut[MINUTES]);
183     ASSERT(new_rtc_value->hour >= g_rtc_min_count_lut[HOURS]);
184     ASSERT(new_rtc_value->hour <= g_rtc_max_count_lut[HOURS]);
185     ASSERT(new_rtc_value->day >= g_rtc_min_count_lut[DAYS]);
186     ASSERT(new_rtc_value->day <= g_rtc_max_count_lut[DAYS]);
187     ASSERT(new_rtc_value->month >= g_rtc_min_count_lut[MONTHS]);
188     ASSERT(new_rtc_value->month <= g_rtc_max_count_lut[MONTHS]);
189     ASSERT(new_rtc_value->year >= g_rtc_min_count_lut[YEARS]);
190     ASSERT(new_rtc_value->year <= g_rtc_max_count_lut[YEARS]);
191     ASSERT(new_rtc_value->weekday >= g_rtc_min_count_lut[WEEKDAYS]);
192     ASSERT(new_rtc_value->weekday <= g_rtc_max_count_lut[WEEKDAYS]);
193     ASSERT(new_rtc_value->week >= g_rtc_min_count_lut[WEEKS]);
194     ASSERT(new_rtc_value->week <= g_rtc_max_count_lut[WEEKS]);
195 
196     if (new_rtc_value->second < g_rtc_min_count_lut[SECONDS]) {error = 1u;}
197     if (new_rtc_value->second > g_rtc_max_count_lut[SECONDS]) {error = 1u;}
198     if (new_rtc_value->minute < g_rtc_min_count_lut[MINUTES]) {error = 1u;}
199     if (new_rtc_value->minute > g_rtc_max_count_lut[MINUTES]) {error = 1u;}
200     if (new_rtc_value->hour < g_rtc_min_count_lut[HOURS]) {error = 1u;}
201     if (new_rtc_value->hour > g_rtc_max_count_lut[HOURS]) {error = 1u;}
202     if (new_rtc_value->day < g_rtc_min_count_lut[DAYS]) {error = 1u;}
203     if (new_rtc_value->day > g_rtc_max_count_lut[DAYS]) {error = 1u;}
204     if (new_rtc_value->month < g_rtc_min_count_lut[MONTHS]) {error = 1u;}
205     if (new_rtc_value->month > g_rtc_max_count_lut[MONTHS]) {error = 1u;}
206     if (new_rtc_value->year < g_rtc_min_count_lut[YEARS]) {error = 1u;}
207     if (new_rtc_value->year > g_rtc_max_count_lut[YEARS]) {error = 1u;}
208     if (new_rtc_value->weekday < g_rtc_min_count_lut[WEEKDAYS]) {error = 1u;}
209     if (new_rtc_value->weekday > g_rtc_max_count_lut[WEEKDAYS]) {error = 1u;}
210     if (new_rtc_value->week < g_rtc_min_count_lut[WEEKS]) {error = 1u;}
211     if (new_rtc_value->week > g_rtc_max_count_lut[WEEKS]) {error = 1u;}
212 
213     /* This function can only be used when the RTC is configured to operate in
214      * calendar counter mode. */
215     clock_mode = get_clock_mode();
216     ASSERT(MSS_RTC_CALENDAR_MODE == clock_mode);
217 
218     if ((0u == error) && (MSS_RTC_CALENDAR_MODE == clock_mode))
219     {
220         uint32_t upload_in_progress;
221 
222        /* Write the RTC new value. */
223         mss_rtc->SECONDS_REG = new_rtc_value->second;
224         mss_rtc->MINUTES_REG = new_rtc_value->minute;
225         mss_rtc->HOURS_REG = new_rtc_value->hour;
226         mss_rtc->DAY_REG = new_rtc_value->day;
227         mss_rtc->MONTH_REG = new_rtc_value->month;
228         mss_rtc->YEAR_REG = new_rtc_value->year;
229         mss_rtc->WEEKDAY_REG = new_rtc_value->weekday;
230         mss_rtc->WEEK_REG = new_rtc_value->week;
231 
232         /* Data is copied, now issue upload command */
233         mss_rtc->CONTROL_REG = CONTROL_UPLOAD_MASK ;
234 
235         /* Wait for the upload to complete. */
236         do {
237             upload_in_progress = mss_rtc->CONTROL_REG & CONTROL_UPLOAD_MASK;
238         } while (upload_in_progress);
239     }
240 }
241 
242 /*-------------------------------------------------------------------------*//**
243  * See "mss_rtc.h" for details of how to use this function.
244  */
245 void
MSS_RTC_set_binary_count(uint64_t new_rtc_value)246 MSS_RTC_set_binary_count
247 (
248     uint64_t new_rtc_value
249 )
250 {
251     uint8_t clock_mode;
252 
253     /* This function can only be used when the RTC is configured to operate in
254      * binary counter mode. */
255     clock_mode = get_clock_mode();
256     ASSERT(MSS_RTC_BINARY_MODE == clock_mode);
257 
258     if (MSS_RTC_BINARY_MODE == clock_mode)
259     {
260         uint32_t rtc_upper_32_bit_value;
261 
262         rtc_upper_32_bit_value = (uint32_t)(new_rtc_value >> 32u) & MASK_32_BIT;
263 
264         /* Assert if the values cross the limit */
265         ASSERT(rtc_upper_32_bit_value <= MAX_BINARY_HIGHER_COUNT);
266 
267         if (rtc_upper_32_bit_value <= MAX_BINARY_HIGHER_COUNT)
268         {
269             uint32_t upload_in_progress;
270 
271             /* Write the RTC new value. */
272             mss_rtc->DATE_TIME_LOWER_REG = (uint32_t)new_rtc_value;
273             mss_rtc->DATE_TIME_UPPER_REG =
274                     (uint32_t)(( new_rtc_value >> 32u) & MAX_BINARY_HIGHER_COUNT);
275 
276             /* Data is copied, now issue upload command */
277             mss_rtc->CONTROL_REG = CONTROL_UPLOAD_MASK;
278 
279             /* Wait for the upload to complete. */
280             do {
281                 upload_in_progress = mss_rtc->CONTROL_REG & CONTROL_UPLOAD_MASK;
282             } while (upload_in_progress);
283         }
284     }
285 }
286 
287 /*-------------------------------------------------------------------------*//**
288  * See "mss_rtc.h" for details of how to use this function.
289  */
290 void
MSS_RTC_get_calendar_count(mss_rtc_calender_t * p_rtc_calendar)291 MSS_RTC_get_calendar_count
292 (
293     mss_rtc_calender_t *p_rtc_calendar
294 )
295 {
296     uint8_t clock_mode;
297     /* This function can only be used when the RTC is configured to operate in
298      * calendar counter mode. */
299     clock_mode = get_clock_mode();
300     ASSERT(MSS_RTC_CALENDAR_MODE == clock_mode);
301 
302     if (MSS_RTC_CALENDAR_MODE == clock_mode)
303     {
304         p_rtc_calendar->second = (uint8_t)mss_rtc->SECONDS_REG;
305         p_rtc_calendar->minute = (uint8_t)mss_rtc->MINUTES_REG;
306         p_rtc_calendar->hour = (uint8_t)mss_rtc->HOURS_REG;
307         p_rtc_calendar->day = (uint8_t)mss_rtc->DAY_REG;
308         p_rtc_calendar->month = (uint8_t)mss_rtc->MONTH_REG;
309         p_rtc_calendar->year = (uint8_t)mss_rtc->YEAR_REG;
310         p_rtc_calendar->weekday = (uint8_t)mss_rtc->WEEKDAY_REG;
311         p_rtc_calendar->week = (uint8_t)mss_rtc->WEEK_REG;
312     }
313     else
314     {
315         /* Set returned calendar count to zero if the RTC is not configured for
316          * calendar counter mode. This should make incorrect release application
317          * code behave consistently and help application debugging. */
318         memset(p_rtc_calendar, 0, sizeof(mss_rtc_calender_t));
319     }
320 }
321 
322 /*-------------------------------------------------------------------------*//**
323  * See "mss_rtc.h" for details of how to use this function.
324  */
325 uint64_t
MSS_RTC_get_binary_count(void)326 MSS_RTC_get_binary_count
327 (
328     void
329 )
330 {
331     uint64_t rtc_count;
332     uint8_t clock_mode;
333 
334     /* This function can only be used when the RTC is configured to operate in
335      * binary counter mode. */
336     clock_mode = get_clock_mode();
337     ASSERT(MSS_RTC_BINARY_MODE == clock_mode);
338 
339     if (MSS_RTC_BINARY_MODE == clock_mode)
340     {
341         rtc_count = mss_rtc->DATE_TIME_LOWER_REG;
342         rtc_count = rtc_count | ((uint64_t)mss_rtc->DATE_TIME_UPPER_REG << 32u);
343     }
344     else
345     {
346         /* Set returned binary count to zero if the RTC is not configured for
347          * binary counter mode. This should make incorrect release application
348          * code behave consistently and help application debugging. */
349         rtc_count = 0u;
350     }
351 
352     return rtc_count;
353 }
354 
add_alarm_cfg_values(uint8_t calendar_item,uint32_t * p_calendar_value,uint32_t * p_compare_mask)355 static void add_alarm_cfg_values
356 (
357     uint8_t calendar_item,
358     uint32_t * p_calendar_value,
359     uint32_t * p_compare_mask
360 )
361 {
362     if (MSS_RTC_CALENDAR_DONT_CARE == calendar_item)
363     {
364         *p_calendar_value = (uint32_t)(*p_calendar_value << CALENDAR_SHIFT);
365         *p_compare_mask = (uint32_t)(*p_compare_mask << CALENDAR_SHIFT);
366     }
367     else
368     {
369         *p_calendar_value = (uint32_t)((*p_calendar_value << CALENDAR_SHIFT) |
370                                        (uint32_t)calendar_item);
371         *p_compare_mask = (uint32_t)((*p_compare_mask << CALENDAR_SHIFT) |
372                                      (uint32_t)0xFFu);
373     }
374 }
375 
376 /*-------------------------------------------------------------------------*//**
377  * See "mss_rtc.h" for details of how to use this function.
378  */
MSS_RTC_set_calendar_count_alarm(const mss_rtc_calender_t * alarm_value)379 void MSS_RTC_set_calendar_count_alarm
380 (
381     const mss_rtc_calender_t * alarm_value
382 )
383 {
384     uint32_t calendar_value;
385     uint32_t compare_mask;
386     uint8_t mode;
387 
388     mode = (uint8_t)(mss_rtc->MODE_REG & MODE_CLK_MODE_MASK);
389 
390     /* This function can only be used with the RTC set to operate in calendar
391      * mode. */
392     ASSERT(MSS_RTC_CALENDAR_MODE == mode);
393 
394     if (MSS_RTC_CALENDAR_MODE == mode)
395     {
396         uint8_t required_mode_reg;
397 
398         /* Disable the alarm before updating */
399         mss_rtc->CONTROL_REG = CONTROL_ALARM_OFF_MASK;
400 
401         /* Set alarm and compare lower registers. */
402         calendar_value = 0u;
403         compare_mask = 0u;
404 
405         add_alarm_cfg_values(alarm_value->day, &calendar_value, &compare_mask);
406         add_alarm_cfg_values(alarm_value->hour, &calendar_value, &compare_mask);
407         add_alarm_cfg_values(alarm_value->minute, &calendar_value, &compare_mask);
408         add_alarm_cfg_values(alarm_value->second, &calendar_value, &compare_mask);
409 
410         mss_rtc->ALARM_LOWER_REG = calendar_value;
411         mss_rtc->COMPARE_LOWER_REG = compare_mask;
412 
413         /* Set alarm and compare upper registers. */
414         calendar_value = 0u;
415         compare_mask = 0u;
416 
417         add_alarm_cfg_values(alarm_value->week, &calendar_value, &compare_mask);
418         add_alarm_cfg_values(alarm_value->weekday, &calendar_value, &compare_mask);
419         add_alarm_cfg_values(alarm_value->year, &calendar_value, &compare_mask);
420         add_alarm_cfg_values(alarm_value->month, &calendar_value, &compare_mask);
421 
422         mss_rtc->ALARM_UPPER_REG = calendar_value;
423         mss_rtc->COMPARE_UPPER_REG = compare_mask;
424 
425         /* Configure the RTC to enable the alarm. */
426         required_mode_reg = mode | MODE_WAKEUP_EN_MASK | MODE_WAKEUP_CONTINUE_MASK;
427         set_rtc_mode(required_mode_reg);
428 
429         /* Enable the alarm */
430         mss_rtc->CONTROL_REG = CONTROL_ALARM_ON_MASK ;
431     }
432 }
433 
434 /*-------------------------------------------------------------------------*//**
435   We only write the RTC mode register if really required because the RTC needs
436   to be stopped for the mode register to be written. Stopping the RTC every time
437   the wake-up alarm configuration is set might induce drift on the RTC time.
438   This function is intended to be used when setting alarms.
439  */
440 static void
set_rtc_mode(uint8_t requested_mode)441 set_rtc_mode
442 (
443     uint8_t requested_mode
444 )
445 {
446     if (mss_rtc->MODE_REG != requested_mode)
447     {
448         uint32_t rtc_running;
449         rtc_running = mss_rtc->CONTROL_REG & CONTROL_RUNNING_MASK;
450         if (rtc_running)
451         {
452             /* Stop the RTC in order to change the mode register content. */
453             MSS_RTC_stop();
454             mss_rtc->MODE_REG = requested_mode;
455             MSS_RTC_start();
456         }
457         else
458         {
459             mss_rtc->MODE_REG = requested_mode;
460         }
461     }
462 }
463 
464 /*-------------------------------------------------------------------------*//**
465  * See "mss_rtc.h" for details of how to use this function.
466  */
467 void
MSS_RTC_set_binary_count_alarm(uint64_t alarm_value,mss_rtc_alarm_type_t alarm_type)468 MSS_RTC_set_binary_count_alarm
469 (
470     uint64_t alarm_value,
471     mss_rtc_alarm_type_t alarm_type
472 )
473 {
474     uint8_t mode;
475 
476     mode = (uint8_t)(mss_rtc->MODE_REG & MODE_CLK_MODE_MASK);
477 
478     /* This function can only be used with the RTC set to operate in binary
479      * counter mode. */
480     ASSERT(MSS_RTC_BINARY_MODE == mode);
481     if (MSS_RTC_BINARY_MODE == mode)
482     {
483         uint8_t required_mode_reg;
484 
485         /* Disable the alarm before updating */
486         mss_rtc->CONTROL_REG = CONTROL_ALARM_OFF_MASK;
487 
488         /* Set the alarm value. */
489         mss_rtc->COMPARE_LOWER_REG = COMPARE_ALL_BITS;
490         mss_rtc->COMPARE_UPPER_REG = COMPARE_ALL_BITS;
491         mss_rtc->ALARM_LOWER_REG = (uint32_t)alarm_value;
492         mss_rtc->ALARM_UPPER_REG = (uint32_t)(alarm_value >> 32u);
493 
494         /* Configure the RTC to enable the alarm. */
495         required_mode_reg = mode | MODE_WAKEUP_EN_MASK | MODE_WAKEUP_CONTINUE_MASK;
496         if (MSS_RTC_PERIODIC_ALARM == alarm_type)
497         {
498             /* The RTC binary counter will be fully reset when the alarm occurs.
499              * The counter will continue counting while the wake-up interrupt is
500              * active. */
501             required_mode_reg |= MODE_WAKEUP_RESET_MASK;
502         }
503         set_rtc_mode(required_mode_reg);
504 
505         /* Enable the alarm */
506         mss_rtc->CONTROL_REG = CONTROL_ALARM_ON_MASK;
507 
508         uint8_t test = get_clock_mode();
509     }
510 }
511 
512 /*-------------------------------------------------------------------------*//**
513  * See "mss_rtc.h" for details of how to use this function.
514  */
515 void
MSS_RTC_start(void)516 MSS_RTC_start
517 (
518     void
519 )
520 {
521     mss_rtc->CONTROL_REG = CONTROL_RTC_START_MASK;
522 }
523 
524 /*-------------------------------------------------------------------------*//**
525  * See "mss_rtc.h" for details of how to use this function.
526  */
527 void
MSS_RTC_stop(void)528 MSS_RTC_stop
529 (
530     void
531 )
532 {
533     uint32_t rtc_running;
534 
535     /* Send command to stop RTC. */
536     mss_rtc->CONTROL_REG = CONTROL_RTC_STOP_MASK;
537 
538     /* Wait for RTC internal synchronization to take place and RTC to actually
539      * stop. */
540     do {
541         rtc_running =  mss_rtc->CONTROL_REG & CONTROL_RUNNING_MASK;
542     } while(rtc_running);
543 }
544 
545 /*-------------------------------------------------------------------------*//**
546  * See "mss_rtc.h" for details of how to use this function.
547  */
548 void
MSS_RTC_reset_counter(void)549 MSS_RTC_reset_counter
550 (
551     void
552 )
553 {
554     uint32_t upload_in_progress;
555 
556     mss_rtc->CONTROL_REG = CONTROL_RESET_MASK;
557 
558     /* Wait for the upload to complete. */
559     do {
560         upload_in_progress = mss_rtc->CONTROL_REG & CONTROL_UPLOAD_MASK;
561     } while (upload_in_progress);
562 }
563 
564 /*-------------------------------------------------------------------------*//**
565  * See "mss_rtc.h" for details of how to use this function.
566  */
567 uint32_t
MSS_RTC_get_update_flag(void)568 MSS_RTC_get_update_flag
569 (
570     void
571 )
572 {
573     uint32_t updated;
574     updated = mss_rtc->CONTROL_REG & CONTROL_UPDATED_MASK;
575     return updated;
576 }
577 
578 /*-------------------------------------------------------------------------*//**
579  * See "mss_rtc.h" for details of how to use this function.
580  */
581 void
MSS_RTC_clear_update_flag(void)582 MSS_RTC_clear_update_flag
583 (
584     void
585 )
586 {
587     /* Clear the "updated" control bit. */
588     mss_rtc->CONTROL_REG = CONTROL_UPDATED_MASK;
589 }
590 
591 /*-------------------------------------------------------------------------*//**
592  * See "mss_rtc.h" for details of how to use this function.
593  */
594 void
MSS_RTC_enable_irq(void)595 MSS_RTC_enable_irq
596 (
597     void
598 )
599 {
600     /* Only the PLIC level interrupt enable is performed within this function.
601      * The RTC level interrupt enable is performed within the alarm setting
602      * functions.
603      * This avoid the MODE register being modified whenever  RTC
604      * interrupts are enabled/disabled. */
605     PLIC_EnableIRQ(RTC_WAKEUP_PLIC);
606 }
607 
608 /*-------------------------------------------------------------------------*//**
609  * See "mss_rtc.h" for details of how to use this function.
610  */
611 void
MSS_RTC_disable_irq(void)612 MSS_RTC_disable_irq
613 (
614     void
615 )
616 {
617     /* Only the PLIC level interrupt disable is performed within this function.
618      * This avoid the MODE register being modified whenever RTC
619      * interrupts are enabled/disabled. */
620     PLIC_DisableIRQ(RTC_WAKEUP_PLIC);
621 }
622 
623 /*-------------------------------------------------------------------------*//**
624  * See "mss_rtc.h" for details of how to use this function.
625  */
626 void
MSS_RTC_clear_irq(void)627 MSS_RTC_clear_irq
628 (
629     void
630 )
631 {
632     volatile uint32_t dummy_read;
633 
634     /* Clear wake up interrupt signal */
635     mss_rtc->CONTROL_REG = CONTROL_WAKEUP_CLR_MASK;
636 
637     /* Ensure that the posted write to the CONTROL_REG register completed before
638      * returning from this function. Not doing this may result in the interrupt
639      * only being cleared some time after this function returns. */
640     dummy_read = mss_rtc->CONTROL_REG;
641 
642     /* Dummy operation to avoid warning message */
643     ++dummy_read;
644 }
645 
646 /*-------------------------------------------------------------------------*//**
647   The get_clock_mode() function gets the clock mode of RTC hardware.
648   Possible clock modes are:
649     MSS_RTC_CALENDAR_MODE
650     MSS_RTC_BINARY_MODE
651  */
652 static uint8_t
get_clock_mode(void)653 get_clock_mode
654 (
655     void
656 )
657 {
658     uint8_t clock_mode;
659 
660     clock_mode = (uint8_t)(mss_rtc->MODE_REG & MODE_CLK_MODE_MASK);
661 
662     return(clock_mode);
663 }
664 
665 #ifdef __cplusplus
666 }
667 #endif
668