1 /*
2  * Copyright 2018 NXP
3  * All rights reserved.
4  *
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_common.h"
10 #include "fsl_adapter_rtc.h"
11 #include "fsl_rtc.h"
12 
13 /************************************************************************************
14 *************************************************************************************
15 * Private prototypes
16 *************************************************************************************
17 ************************************************************************************/
18 static bool gRTCInitFlag = false;
19 
20 static hal_rtc_callback_t rtcCallback;
21 static void *rtcCbparam;
22 /*
23  * \brief Holds time offset in microseconds, used to calculate the date
24  */
25 static volatile uint64_t gRTCTimeOffset;
26 
27 /*
28  * \brief Holds time prescaler offset in ticks, used to calculate the date
29  */
30 static volatile uint32_t gRTCPrescalerOffset;
31 
32 /************************************************************************************
33 *************************************************************************************
34 * Private memory declarations
35 *************************************************************************************
36 ************************************************************************************/
37 void RTC_IRQHandler(void);
RTC_IRQHandler(void)38 void RTC_IRQHandler(void)
39 {
40     uint32_t status = RTC_GetStatusFlags(RTC);
41 
42     if (0U != (status & (uint32_t)kRTC_AlarmFlag))
43     {
44         /* Clear alarm flag */
45         RTC_ClearStatusFlags(RTC, (uint32_t)kRTC_AlarmInterruptEnable);
46     }
47     else if (0U != (status & (uint32_t)kRTC_TimeInvalidFlag))
48     {
49         /* Clear timer invalid flag */
50         RTC_ClearStatusFlags(RTC, (uint32_t)kRTC_TimeInvalidFlag);
51     }
52     else
53     {
54         /*MISRA rule 15.7*/
55     }
56 
57     if (NULL != rtcCallback)
58     {
59         rtcCallback(rtcCbparam);
60     }
61     SDK_ISR_EXIT_BARRIER;
62 }
63 
64 /************************************************************************************
65 *************************************************************************************
66 * Public functions
67 *************************************************************************************
68 ************************************************************************************/
HAL_RTCInit(void)69 void HAL_RTCInit(void)
70 {
71     rtc_config_t rtcConfig;
72     rtc_datetime_t date;
73     const rtc_config_t *rtcConfigure = (void *)&rtcConfig;
74     if (!gRTCInitFlag)
75     {
76         RTC_GetDefaultConfig(&rtcConfig);
77         RTC_Init(RTC, rtcConfigure);
78         /* Select RTC clock source */
79         RTC_SetClockSource(RTC);
80         date.year   = 2018U;
81         date.month  = 5U;
82         date.day    = 30U;
83         date.hour   = 19U;
84         date.minute = 0;
85         date.second = 0;
86 
87         const rtc_datetime_t *rtcDate = (void *)&date;
88         /* RTC time counter has to be stopped before setting the date & time in the TSR register */
89         RTC_StopTimer(RTC);
90 
91         /* Set RTC time to default */
92         (void)RTC_SetDatetime(RTC, rtcDate);
93         RTC_StartTimer(RTC);
94         gRTCInitFlag = true;
95         /* Enable RTC alarm interrupt */
96         RTC_EnableInterrupts(RTC, (uint32_t)kRTC_AlarmInterruptEnable);
97         /* Enable at the NVIC */
98         (void)EnableIRQ(RTC_IRQn);
99     }
100 }
101 
102 /*! -------------------------------------------------------------------------
103  * \brief  Returns the absolute time at the moment of the call.
104  * \return Absolute time at the moment of the call in microseconds.
105  *---------------------------------------------------------------------------*/
HAL_RTCGetTimestamp(void)106 uint64_t HAL_RTCGetTimestamp(void)
107 {
108     uint32_t seconds1, seconds2, prescaler0, prescaler1, prescaler2;
109     uint64_t useconds, offset, prescalerOffset;
110 
111     if (!gRTCInitFlag)
112     {
113         useconds = 0;
114         offset   = 0;
115     }
116     else
117     {
118         uint32_t regPrimask = DisableGlobalIRQ();
119         offset              = gRTCTimeOffset;
120         prescalerOffset     = gRTCPrescalerOffset;
121 
122         prescaler0 = RTC->TPR;
123         seconds1   = RTC->TSR;
124         prescaler1 = RTC->TPR;
125         seconds2   = RTC->TSR;
126         prescaler2 = RTC->TPR;
127         EnableGlobalIRQ(regPrimask);
128 
129         prescaler0 &= 0x7fffU;
130         seconds1 -= 1U;
131         prescaler1 &= 0x7fffU;
132         seconds2 -= 1U;
133         prescaler2 &= 0x7fffU;
134 
135         if (seconds1 != seconds2)
136         {
137             seconds1   = seconds2;
138             prescaler1 = prescaler2;
139         }
140         else
141         {
142             if (prescaler1 != prescaler2)
143             {
144                 prescaler1 = prescaler0;
145             }
146         }
147 
148         useconds = ((prescaler1 + prescalerOffset + ((uint64_t)seconds1 << 15)) * 15625ULL) >> 9;
149     }
150 
151     return useconds + offset;
152 }
153 
154 #if (defined(RTC_FUNCTIONS_ENABLE) && (RTC_FUNCTIONS_ENABLE > 0))
155 /*! -------------------------------------------------------------------------
156  * \brief     Sets the absolute time.
157  * \param[in] microseconds - Time in microseconds.
158  *---------------------------------------------------------------------------*/
HAL_RTCSetTime(uint64_t microseconds)159 void HAL_RTCSetTime(uint64_t microseconds)
160 {
161     uint32_t prescaler;
162     uint32_t seconds = (uint32_t)(microseconds / 1000000ULL);
163     uint32_t ms      = (uint32_t)(microseconds % 1000000ULL);
164     /* microseconds = prescaler * 1_000_000 / 32768 = prescaler * 5^6 / 2^9 */
165     /* prescaler  = microseconds *2^9 /5^6 */
166     prescaler = (ms << 9) / 15625UL;
167 
168     RTC_StopTimer(RTC);
169     RTC->TSR = seconds;
170     RTC->TPR = prescaler;
171 
172     RTC_StartTimer(RTC);
173 }
174 
175 /*! -------------------------------------------------------------------------
176  * \brief     Sets the alarm absolute time in seconds.
177  * \param[in] seconds - Time in seconds for the alarm.
178  * \param[in] callback - Callback function pointer.
179  * \param[in] param - Parameter for callback.
180  *---------------------------------------------------------------------------*/
HAL_RTCSetAlarm(uint64_t microseconds,hal_rtc_callback_t callback,void * param)181 void HAL_RTCSetAlarm(uint64_t microseconds, hal_rtc_callback_t callback, void *param)
182 {
183     /* Set alarm time in seconds */
184     RTC->TAR = (uint32_t)(microseconds / 1000000ULL);
185 
186     rtcCallback = callback;
187     rtcCbparam  = param;
188 }
189 
190 /*! -------------------------------------------------------------------------
191  * \brief Sets the alarm relative time in seconds.
192  * \param[in] seconds - Time in seconds for the alarm.
193  * \param[in] callback - Callback function pointer.
194  * \param[in] param - Parameter for callback.
195  *---------------------------------------------------------------------------*/
HAL_RTCSetAlarmRelative(uint32_t seconds,hal_rtc_callback_t callback,void * param)196 void HAL_RTCSetAlarmRelative(uint32_t seconds, hal_rtc_callback_t callback, void *param)
197 {
198     uint32_t newSeconds;
199     newSeconds  = RTC->TSR + seconds;
200     RTC->TAR    = newSeconds;
201     rtcCallback = callback;
202     rtcCbparam  = param;
203 }
204 #endif /* RTC_FUNCTIONS_ENABLE */
205