]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_A53_64-bit_UltraScale_MPSoC/RTOSDemo_A53_bsp/psu_cortexa53_0/libsrc/rtcpsu_v1_5/src/xrtcpsu.c
Update Zynq, MPSoc Cortex-A53 and MPSoc Cortex-R5 demo projects to build with the...
[freertos] / FreeRTOS / Demo / CORTEX_A53_64-bit_UltraScale_MPSoC / RTOSDemo_A53_bsp / psu_cortexa53_0 / libsrc / rtcpsu_v1_5 / src / xrtcpsu.c
1 /******************************************************************************
2 *
3 * Copyright (C) 2015 - 2017 Xilinx, Inc.  All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * Use of the Software is limited solely to applications:
16 * (a) running on a Xilinx device, or
17 * (b) that interact with a Xilinx device through a bus or interconnect.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * XILINX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 *
27 * Except as contained in this notice, the name of the Xilinx shall not be used
28 * in advertising or otherwise to promote the sale, use or other dealings in
29 * this Software without prior written authorization from Xilinx.
30 *
31 ******************************************************************************/
32 /*****************************************************************************/
33 /**
34 *
35 * @file xrtcpsu.c
36 * @addtogroup rtcpsu_v1_5
37 * @{
38 *
39 * Functions in this file are the minimum required functions for the XRtcPsu
40 * driver. See xrtcpsu.h for a detailed description of the driver.
41 *
42 * @note         None.
43 *
44 *
45 * <pre>
46 * MODIFICATION HISTORY:
47 *
48 * Ver   Who    Date     Changes
49 * ----- -----  -------- -----------------------------------------------
50 * 1.00  kvn    04/21/15 First release
51 * 1.1   kvn    09/25/15 Modify control register to enable battery
52 *                       switching when vcc_psaux is not available.
53 * 1.2          02/15/16 Corrected Calibration mask and Fractional
54 *                       mask in CalculateCalibration API.
55 * 1.3   vak    04/25/16 Corrected the RTC read and write time logic(cr#948833).
56 * 1.5   ms     08/27/17 Fixed compilation warnings.
57 *       ms     08/29/17 Updated code as per source code style.
58 * </pre>
59 *
60 ******************************************************************************/
61
62 /***************************** Include Files *********************************/
63
64 #include "xrtcpsu.h"
65 #include "xrtcpsu_hw.h"
66
67 /************************** Constant Definitions *****************************/
68
69 /**************************** Type Definitions *******************************/
70
71 /***************** Macros (Inline Functions) Definitions *********************/
72
73 /************************** Variable Definitions *****************************/
74
75 static const u32 DaysInMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
76
77 /************************** Function Prototypes ******************************/
78
79 static void XRtcPsu_StubHandler(void *CallBackRef, u32 Event);
80
81 /*****************************************************************************/
82 /*
83 *
84 * This function initializes a XRtcPsu instance/driver.
85 *
86 * The initialization entails:
87 * - Initialize all members of the XRtcPsu structure.
88 *
89 * @param        InstancePtr is a pointer to the XRtcPsu instance.
90 * @param        ConfigPtr points to the XRtcPsu device configuration structure.
91 * @param        EffectiveAddr is the device base address in the virtual memory
92 *               address space. If the address translation is not used then the
93 *               physical address is passed.
94 *               Unexpected errors may occur if the address mapping is changed
95 *               after this function is invoked.
96 *
97 * @return       XST_SUCCESS always.
98 *
99 * @note         None.
100 *
101 ******************************************************************************/
102 s32 XRtcPsu_CfgInitialize(XRtcPsu *InstancePtr, XRtcPsu_Config *ConfigPtr,
103                                 u32 EffectiveAddr)
104 {
105         s32 Status;
106         u32 ControlRegister;
107         Xil_AssertNonvoid(InstancePtr != NULL);
108         Xil_AssertNonvoid(ConfigPtr != NULL);
109
110         /*
111          * Set some default values for instance data, don't indicate the device
112          * is ready to use until everything has been initialized successfully.
113          */
114         InstancePtr->IsReady = 0U;
115         InstancePtr->RtcConfig.BaseAddr = EffectiveAddr;
116         InstancePtr->RtcConfig.DeviceId = ConfigPtr->DeviceId;
117
118         if(InstancePtr->OscillatorFreq == 0U) {
119                 InstancePtr->CalibrationValue = XRTC_CALIBRATION_VALUE;
120                 InstancePtr->OscillatorFreq = XRTC_TYPICAL_OSC_FREQ;
121         }
122
123         /* Set all handlers to stub values, let user configure this data later. */
124         InstancePtr->Handler = XRtcPsu_StubHandler;
125
126         InstancePtr->IsPeriodicAlarm = 0U;
127
128         /* Set the calibration value in calibration register. */
129         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_CALIB_WR_OFFSET,
130                                 InstancePtr->CalibrationValue);
131
132         /* Set the Oscillator crystal and Battery switch enable in control register. */
133         ControlRegister = XRtcPsu_ReadReg(InstancePtr->RtcConfig.BaseAddr + XRTC_CTL_OFFSET);
134         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_CTL_OFFSET,
135                         (ControlRegister | (u32)XRTCPSU_CRYSTAL_OSC_EN | (u32)XRTC_CTL_BATTERY_EN_MASK));
136
137         /* Clear the Interrupt Status and Disable the interrupts. */
138         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_INT_STS_OFFSET,
139                         ((u32)XRTC_INT_STS_ALRM_MASK | (u32)XRTC_INT_STS_SECS_MASK));
140         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_INT_DIS_OFFSET,
141                         ((u32)XRTC_INT_DIS_ALRM_MASK | (u32)XRTC_INT_DIS_SECS_MASK));
142
143         /* Indicate the component is now ready to use. */
144         InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
145
146         /* Clear TimeUpdated and CurrTimeUpdated */
147         InstancePtr->TimeUpdated = 0;
148         InstancePtr->CurrTimeUpdated = 0;
149
150         Status = XST_SUCCESS;
151         return Status;
152 }
153
154 /****************************************************************************/
155 /**
156 *
157 * This function is a stub handler that is the default handler such that if the
158 * application has not set the handler when interrupts are enabled, this
159 * function will be called.
160 *
161 * @param        CallBackRef is unused by this function.
162 * @param        Event is unused by this function.
163 *
164 * @return       None.
165 *
166 * @note         None.
167 *
168 *****************************************************************************/
169 static void XRtcPsu_StubHandler(void *CallBackRef, u32 Event)
170 {
171         (void) CallBackRef;
172         (void) Event;
173         /* Assert occurs always since this is a stub and should never be called */
174         Xil_AssertVoidAlways();
175 }
176
177 /****************************************************************************/
178 /**
179 *
180 * This function sets the RTC time by writing into rtc write register.
181 *
182 * @param        InstancePtr is a pointer to the XRtcPsu instance.
183 * @param        Time that should be updated into RTC write register.
184 *
185 * @return       None.
186 *
187 * @note         None.
188 *
189 *****************************************************************************/
190 void XRtcPsu_SetTime(XRtcPsu *InstancePtr,u32 Time)
191 {
192         /* Set the calibration value in calibration register, so that
193          * next Second is triggered exactly at 1 sec period
194          */
195         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_CALIB_WR_OFFSET,
196                                                         InstancePtr->CalibrationValue);
197         /* clear the RTC secs interrupt from status register */
198         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_INT_STS_OFFSET,
199                                                                 XRTC_INT_STS_SECS_MASK);
200         InstancePtr->CurrTimeUpdated = 0;
201         /* Update the flag before setting the time */
202         InstancePtr->TimeUpdated = 1;
203         /* Since RTC takes 1 sec to update the time into current time register, write
204          * load time + 1sec into the set time register.
205          */
206         XRtcPsu_WriteSetTime(InstancePtr, Time + 1);
207 }
208
209 /****************************************************************************/
210 /**
211 *
212 * This function gets the current RTC time.
213 *
214 * @param        InstancePtr is a pointer to the XRtcPsu instance.
215 *
216 * @return       RTC Current time.
217 *
218 * @note         None.
219 *
220 *****************************************************************************/
221 u32 XRtcPsu_GetCurrentTime(XRtcPsu *InstancePtr)
222 {
223         u32 Status;
224         u32 IntMask;
225         u32 CurrTime;
226
227         IntMask = XRtcPsu_ReadReg(InstancePtr->RtcConfig.BaseAddr + XRTC_INT_MSK_OFFSET);
228
229         if((IntMask & XRTC_INT_STS_SECS_MASK) != (u32)0) {
230                 /* We come here if interrupts are disabled */
231                 Status = XRtcPsu_ReadReg(InstancePtr->RtcConfig.BaseAddr + XRTC_INT_STS_OFFSET);
232                 if((InstancePtr->TimeUpdated == (u32)1) &&
233                         (Status & XRTC_INT_STS_SECS_MASK) == (u32)0) {
234                         /* Give the previous written time */
235                         CurrTime = XRtcPsu_GetLastSetTime(InstancePtr) - 1;
236                 } else {
237                         /* Clear TimeUpdated */
238                         if((InstancePtr->TimeUpdated == (u32)1) &&
239                                 ((Status & XRTC_INT_STS_SECS_MASK) == (u32)1)) {
240                                 InstancePtr->TimeUpdated = (u32)0;
241                         }
242
243                         /* RTC time got updated */
244                         CurrTime = XRtcPsu_ReadCurrentTime(InstancePtr);
245                 }
246         } else {
247                 /* We come here if interrupts are enabled */
248                 if((InstancePtr->TimeUpdated == (u32)1) &&
249                         (InstancePtr->CurrTimeUpdated == (u32)0)) {
250                         /* Give the previous written time -1 sec */
251                         CurrTime = XRtcPsu_GetLastSetTime(InstancePtr) - 1;
252                 } else {
253                         /* Clear TimeUpdated */
254                         if(InstancePtr->TimeUpdated == (u32)1)
255                                 InstancePtr->TimeUpdated = (u32)0;
256                         /* RTC time got updated */
257                         CurrTime = XRtcPsu_ReadCurrentTime(InstancePtr);
258                 }
259         }
260         return CurrTime;
261 }
262
263 /****************************************************************************/
264 /**
265 *
266 * This function sets the alarm value of RTC device.
267 *
268 * @param        InstancePtr is a pointer to the XRtcPsu instance
269 * @param        Alarm is the desired alarm time for RTC.
270 * @param        Periodic says whether the alarm need to set at periodic
271 *                       Intervals or a one-time alarm.
272 *
273 * @return       None.
274 *
275 * @note         None.
276 *
277 *****************************************************************************/
278 void XRtcPsu_SetAlarm(XRtcPsu *InstancePtr, u32 Alarm, u32 Periodic)
279 {
280         Xil_AssertVoid(InstancePtr != NULL);
281         Xil_AssertVoid(Alarm != 0U);
282         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
283         Xil_AssertVoid((Alarm - XRtcPsu_GetCurrentTime(InstancePtr)) > (u32)0);
284
285         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr+XRTC_ALRM_OFFSET, Alarm);
286         if(Periodic != 0U) {
287                 InstancePtr->IsPeriodicAlarm = 1U;
288                 InstancePtr->PeriodicAlarmTime =
289                                 Alarm - XRtcPsu_GetCurrentTime(InstancePtr);
290         }
291 }
292
293
294 /****************************************************************************/
295 /**
296 *
297 * This function translates time in seconds to a YEAR:MON:DAY HR:MIN:SEC
298 * format and saves it in the DT structure variable. It also reports the weekday.
299 *
300 * @param        Seconds is the time value that has to be shown in DateTime
301 *               format.
302 * @param        dt is the DateTime format variable that stores the translated
303 *               time.
304 *
305 * @return       None.
306 *
307 * @note         This API supports this century i.e., 2000 - 2099 years only.
308 *
309 *****************************************************************************/
310 void XRtcPsu_SecToDateTime(u32 Seconds, XRtcPsu_DT *dt)
311 {
312         u32 CurrentTime;
313         u32 TempDays;
314         u32 DaysPerMonth;
315         u32 Leap = 0U;
316
317         CurrentTime = Seconds;
318         dt->Sec = CurrentTime % 60U;
319         CurrentTime /= 60U;
320         dt->Min = CurrentTime % 60U;
321         CurrentTime /= 60U;
322         dt->Hour = CurrentTime % 24U;
323         TempDays = CurrentTime / 24U;
324
325         if (TempDays == 0U) {
326                 TempDays = 1U;
327         }
328         dt->WeekDay = TempDays % 7U;
329
330         for (dt->Year = 0U; dt->Year <= 99U; ++(dt->Year)) {
331                 if ((dt->Year % 4U) == 0U ) {
332                         Leap = 1U;
333                 }
334                 else {
335                         Leap = 0U;
336                 }
337                 if (TempDays < (365U + Leap)) {
338                         break;
339                 }
340                 TempDays -= (365U + Leap);
341         }
342
343         for (dt->Month = 1U; dt->Month >= 1U; ++(dt->Month)) {
344                 DaysPerMonth = DaysInMonth[dt->Month - 1];
345                 if ((Leap == 1U) && (dt->Month == 2U)) {
346                         DaysPerMonth++;
347                 }
348                 if (TempDays < DaysPerMonth) {
349                         break;
350                 }
351                 TempDays -= DaysPerMonth;
352         }
353
354         dt->Day = TempDays;
355         dt->Year += 2000U;
356 }
357
358 /****************************************************************************/
359 /**
360 *
361 * This function translates time in YEAR:MON:DAY HR:MIN:SEC format to
362 * seconds.
363 *
364 * @param        dt is a pointer to a DatetTime format structure variable
365 *                       of time that has to be shown in seconds.
366 *
367 * @return       Seconds value of provided in dt time.
368 *
369 * @note         None.
370 *
371 *****************************************************************************/
372 u32 XRtcPsu_DateTimeToSec(XRtcPsu_DT *dt)
373 {
374         u32 i;
375         u32 Days;
376         u32 Seconds;
377         Xil_AssertNonvoid(dt != NULL);
378
379         if (dt->Year >= 2000U) {
380                 dt->Year -= 2000U;
381         }
382
383         for (i = 1U; i < dt->Month; i++) {
384                 dt->Day += (u32)DaysInMonth[i-1];
385         }
386
387         if ((dt->Month > 2U) && ((dt->Year % 4U) == 0U)) {
388                 dt->Day++;
389         }
390         Days = dt->Day + (365U * dt->Year) + ((dt->Year + 3U) / 4U);
391         Seconds = (((((Days * 24U) + dt->Hour) * 60U) + dt->Min) * 60U) + dt->Sec;
392         return Seconds;
393 }
394
395 /****************************************************************************/
396 /**
397 *
398 * This function calculates the calibration value depending on the actual
399 * realworld time and also helps in deriving new calibration value if
400 * the user wishes to change his oscillator frequency.TimeReal is generally the
401 * internet time with EPOCH time as reference i.e.,1/1/1970 1st second.
402 * But this RTC driver assumes start time from 1/1/2000 1st second. Hence,if
403 * the user maps the internet time InternetTimeInSecs, then he has to use
404 *       XRtcPsu_SecToDateTime(InternetTimeInSecs,&InternetTime),
405 *       TimeReal = XRtcPsu_DateTimeToSec(InternetTime)
406 *       consecutively to arrive at TimeReal value.
407 *
408 * @param        InstancePtr is a pointer to the XRtcPsu instance.
409 * @param        TimeReal is the actual realworld time generally an
410 *               network time / Internet time in seconds.
411 *
412 * @param        CrystalOscFreq is the Oscillator new frequency. Say, If the user
413 *               is going with the typical 32768Hz, then he inputs the same
414 *               frequency value.
415 *
416 * @return       None.
417 *
418 * @note         After Calculating the calibration register, user / application has to
419 *                       call again CfgInitialize API to bring the new calibration into effect.
420 *
421 *****************************************************************************/
422 void XRtcPsu_CalculateCalibration(XRtcPsu *InstancePtr,u32 TimeReal,
423                 u32 CrystalOscFreq)
424 {
425         u32 ReadTime;
426         u32 SetTime;
427         u32 Cprev;
428         u32 Fprev;
429         u32 Cnew;
430         u32 Fnew;
431         u32 Calibration;
432         float Xf;
433         Xil_AssertVoid(TimeReal != 0U);
434         Xil_AssertVoid(CrystalOscFreq != 0U);
435
436         ReadTime = XRtcPsu_GetCurrentTime(InstancePtr);
437         SetTime = XRtcPsu_GetLastSetTime(InstancePtr);
438         Calibration = XRtcPsu_GetCalibration(InstancePtr);
439         /*
440          * When board gets reseted, Calibration value is zero
441          * and Last setTime will be marked as 1st  second. This implies
442          * CurrentTime to be in few seconds say something in tens. TimeReal will
443          * be huge, say something in thousands. So to prevent such reset case, Cnew
444          * and Fnew will not be calculated.
445          */
446         if((Calibration == 0U) || (CrystalOscFreq != InstancePtr->OscillatorFreq)) {
447                 Cnew = CrystalOscFreq - (u32)1;
448                 Fnew = 0U;
449         } else {
450                 Cprev = Calibration & XRTC_CALIB_RD_MAX_TCK_MASK;
451                 Fprev = Calibration & XRTC_CALIB_RD_FRACTN_DATA_MASK;
452
453                 Xf = ((ReadTime - SetTime) * ((Cprev+1U) + ((Fprev+1U)/16U))) / (TimeReal - SetTime);
454                 Cnew = (u32)(Xf) - (u32)1;
455                 Fnew = XRtcPsu_RoundOff((Xf - Cnew) * 16U) - (u32)1;
456         }
457
458         Calibration = (Fnew << XRTC_CALIB_RD_FRACTN_DATA_SHIFT) + Cnew;
459         Calibration |= XRTC_CALIB_RD_FRACTN_EN_MASK;
460
461         InstancePtr->CalibrationValue = Calibration;
462         InstancePtr->OscillatorFreq = CrystalOscFreq;
463 }
464
465 /****************************************************************************/
466 /**
467 *
468 * This function returns the seconds event status by reading
469 * interrupt status register.
470 *
471 * @param        InstancePtr is a pointer to the XRtcPsu instance.
472 *
473 * @return       Returns 1 if a new second event is generated.Else 0..
474 *
475 * @note         This API is used in polled mode operation of RTC.
476 *                       This also clears interrupt status seconds bit.
477 *
478 *****************************************************************************/
479 u32 XRtcPsu_IsSecondsEventGenerated(XRtcPsu *InstancePtr)
480 {
481         u32 Status;
482
483         /* Loop the interrupt status register for Seconds Event */
484         if ((XRtcPsu_ReadReg(InstancePtr->RtcConfig.BaseAddr +
485                         XRTC_INT_STS_OFFSET) & (XRTC_INT_STS_SECS_MASK)) == 0U) {
486                 Status = 0U;
487         } else {
488                 /* Clear the interrupt status register */
489                 XRtcPsu_WriteReg((InstancePtr)->RtcConfig.BaseAddr +
490                                 XRTC_INT_STS_OFFSET, XRTC_INT_STS_SECS_MASK);
491                 Status = 1U;
492         }
493         return Status;
494 }
495
496 /****************************************************************************/
497 /**
498 *
499 * This function returns the alarm event status by reading
500 * interrupt status register.
501 *
502 * @param        InstancePtr is a pointer to the XRtcPsu instance.
503 *
504 * @return       Returns 1 if the alarm event is generated.Else 0.
505 *
506 * @note         This API is used in polled mode operation of RTC.
507 *                       This also clears interrupt status alarm bit.
508 *
509 *****************************************************************************/
510 u32 XRtcPsu_IsAlarmEventGenerated(XRtcPsu *InstancePtr)
511 {
512         u32 Status;
513
514         /* Loop the interrupt status register for Alarm Event */
515         if ((XRtcPsu_ReadReg(InstancePtr->RtcConfig.BaseAddr +
516                         XRTC_INT_STS_OFFSET) & (XRTC_INT_STS_ALRM_MASK)) == 0U) {
517                 Status = 0U;
518         } else {
519                 /* Clear the interrupt status register */
520                 XRtcPsu_WriteReg((InstancePtr)->RtcConfig.BaseAddr +
521                                 XRTC_INT_STS_OFFSET, XRTC_INT_STS_ALRM_MASK);
522                 Status = 1U;
523         }
524         return Status;
525 }
526 /** @} */