]> git.sur5r.net Git - freertos/blob
58163eb34ec88300f6e78e981396eb8fa1c47a9c
[freertos] /
1 /******************************************************************************
2 *
3 * Copyright (C) 2015 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 THE
22 * XILINX CONSORTIUM 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_0
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 * </pre>
56 *
57 ******************************************************************************/
58
59 /***************************** Include Files *********************************/
60
61 #include "xrtcpsu.h"
62
63 /************************** Constant Definitions *****************************/
64
65 /**************************** Type Definitions *******************************/
66
67 /***************** Macros (Inline Functions) Definitions *********************/
68
69 /************************** Variable Definitions *****************************/
70
71 static const u32 DaysInMonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
72
73 /************************** Function Prototypes ******************************/
74
75 static void XRtcPsu_StubHandler(void *CallBackRef, u32 Event);
76
77 /*****************************************************************************/
78 /*
79 *
80 * This function initializes a XRtcPsu instance/driver.
81 *
82 * The initialization entails:
83 * - Initialize all members of the XRtcPsu structure.
84 *
85 * @param        InstancePtr is a pointer to the XRtcPsu instance.
86 * @param        ConfigPtr points to the XRtcPsu device configuration structure.
87 * @param        EffectiveAddr is the device base address in the virtual memory
88 *               address space. If the address translation is not used then the
89 *               physical address is passed.
90 *               Unexpected errors may occur if the address mapping is changed
91 *               after this function is invoked.
92 *
93 * @return       XST_SUCCESS always.
94 *
95 * @note         None.
96 *
97 ******************************************************************************/
98 s32 XRtcPsu_CfgInitialize(XRtcPsu *InstancePtr, XRtcPsu_Config *ConfigPtr,
99                                 u32 EffectiveAddr)
100 {
101         s32 Status;
102         u32 ControlRegister;
103         Xil_AssertNonvoid(InstancePtr != NULL);
104         Xil_AssertNonvoid(ConfigPtr != NULL);
105
106         /*
107          * Set some default values for instance data, don't indicate the device
108          * is ready to use until everything has been initialized successfully.
109          */
110         InstancePtr->IsReady = 0U;
111         InstancePtr->RtcConfig.BaseAddr = EffectiveAddr;
112         InstancePtr->RtcConfig.DeviceId = ConfigPtr->DeviceId;
113
114         if(InstancePtr->OscillatorFreq == 0U) {
115                 InstancePtr->CalibrationValue = XRTC_CALIBRATION_VALUE;
116                 InstancePtr->OscillatorFreq = XRTC_TYPICAL_OSC_FREQ;
117         }
118
119         /* Set all handlers to stub values, let user configure this data later. */
120         InstancePtr->Handler = XRtcPsu_StubHandler;
121
122         InstancePtr->IsPeriodicAlarm = 0U;
123
124         /* Set the calibration value in calibration register. */
125         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_CALIB_WR_OFFSET,
126                                 InstancePtr->CalibrationValue);
127
128         /* Set the Oscillator crystal and Battery switch enable in control register. */
129         ControlRegister = XRtcPsu_ReadReg(InstancePtr->RtcConfig.BaseAddr + XRTC_CTL_OFFSET);
130         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_CTL_OFFSET,
131                         (ControlRegister | (u32)XRTCPSU_CRYSTAL_OSC_EN | (u32)XRTC_CTL_BATTERY_EN_MASK));
132
133         /* Clear the Interrupt Status and Disable the interrupts. */
134         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_INT_STS_OFFSET,
135                         ((u32)XRTC_INT_STS_ALRM_MASK | (u32)XRTC_INT_STS_SECS_MASK));
136         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr + XRTC_INT_DIS_OFFSET,
137                         ((u32)XRTC_INT_DIS_ALRM_MASK | (u32)XRTC_INT_DIS_SECS_MASK));
138
139         /* Indicate the component is now ready to use. */
140         InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
141
142         Status = XST_SUCCESS;
143         return Status;
144 }
145
146 /****************************************************************************/
147 /**
148 *
149 * This function is a stub handler that is the default handler such that if the
150 * application has not set the handler when interrupts are enabled, this
151 * function will be called.
152 *
153 * @param        CallBackRef is unused by this function.
154 * @param        Event is unused by this function.
155 *
156 * @return       None.
157 *
158 * @note         None.
159 *
160 *****************************************************************************/
161 static void XRtcPsu_StubHandler(void *CallBackRef, u32 Event)
162 {
163         (void *) CallBackRef;
164         (void) Event;
165         /* Assert occurs always since this is a stub and should never be called */
166         Xil_AssertVoidAlways();
167 }
168
169 /****************************************************************************/
170 /**
171 *
172 * This function sets the alarm value of RTC device.
173 *
174 * @param        InstancePtr is a pointer to the XRtcPsu instance
175 * @param        Alarm is the desired alarm time for RTC.
176 * @param        Periodic says whether the alarm need to set at periodic
177 *                       Intervals or a one-time alarm.
178 *
179 * @return       None.
180 *
181 * @note         None.
182 *
183 *****************************************************************************/
184 void XRtcPsu_SetAlarm(XRtcPsu *InstancePtr, u32 Alarm, u32 Periodic)
185 {
186         Xil_AssertVoid(InstancePtr != NULL);
187         Xil_AssertVoid(Alarm != 0U);
188         Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
189         Xil_AssertVoid((Alarm - XRtcPsu_GetCurrentTime(InstancePtr)) > (u32)0);
190
191         XRtcPsu_WriteReg(InstancePtr->RtcConfig.BaseAddr+XRTC_ALRM_OFFSET, Alarm);
192         if(Periodic != 0U) {
193                 InstancePtr->IsPeriodicAlarm = 1U;
194                 InstancePtr->PeriodicAlarmTime =
195                                 Alarm - XRtcPsu_GetCurrentTime(InstancePtr);
196         }
197 }
198
199
200 /****************************************************************************/
201 /**
202 *
203 * This function translates time in seconds to a YEAR:MON:DAY HR:MIN:SEC
204 * format and saves it in the DT structure variable. It also reports the weekday.
205 *
206 * @param        Seconds is the time value that has to be shown in DateTime
207 *                       format.
208 * @param        dt is the DateTime format variable that stores the translated
209 *                       time.
210 *
211 * @return       None.
212 *
213 * @note         This API supports this century i.e., 2000 - 2099 years only.
214 *
215 *****************************************************************************/
216 void XRtcPsu_SecToDateTime(u32 Seconds, XRtcPsu_DT *dt)
217 {
218         u32 CurrentTime, TempDays, Leap, DaysPerMonth;
219
220         CurrentTime = Seconds;
221         dt->Sec = CurrentTime % 60U;
222         CurrentTime /= 60U;
223         dt->Min = CurrentTime % 60U;
224         CurrentTime /= 60U;
225         dt->Hour = CurrentTime % 24U;
226         TempDays = CurrentTime / 24U;
227
228         if (TempDays == 0U) {
229                 TempDays = 1U;
230         }
231         dt->WeekDay = TempDays % 7U;
232
233         for (dt->Year = 0U; dt->Year <= 99U; ++(dt->Year)) {
234                 if ((dt->Year % 4U) == 0U ) {
235                         Leap = 1U;
236                 }
237                 else {
238                         Leap = 0U;
239                 }
240                 if (TempDays < (365U + Leap)) {
241                         break;
242                 }
243                 TempDays -= (365U + Leap);
244         }
245
246         for (dt->Month = 1U; dt->Month >= 1U; ++(dt->Month)) {
247                 DaysPerMonth = DaysInMonth[dt->Month - 1];
248                 if ((Leap == 1U) && (dt->Month == 2U)) {
249                         DaysPerMonth++;
250                 }
251                 if (TempDays < DaysPerMonth) {
252                         break;
253                 }
254                 TempDays -= DaysPerMonth;
255         }
256
257         dt->Day = TempDays;
258         dt->Year += 2000U;
259 }
260
261 /****************************************************************************/
262 /**
263 *
264 * This function translates time in YEAR:MON:DAY HR:MIN:SEC format to
265 * seconds.
266 *
267 * @param        dt is a pointer to a DatetTime format structure variable
268 *                       of time that has to be shown in seconds.
269 *
270 * @return       Seconds value of provided in dt time.
271 *
272 * @note         None.
273 *
274 *****************************************************************************/
275 u32 XRtcPsu_DateTimeToSec(XRtcPsu_DT *dt)
276 {
277         u32 i, Days;
278         u32 Seconds;
279         Xil_AssertNonvoid(dt != NULL);
280
281         if (dt->Year >= 2000U) {
282                 dt->Year -= 2000U;
283         }
284
285         for (i = 1U; i < dt->Month; i++) {
286                 dt->Day += (u32)DaysInMonth[i-1];
287         }
288
289         if ((dt->Month > 2U) && ((dt->Year % 4U) == 0U)) {
290                 dt->Day++;
291         }
292         Days = dt->Day + (365U * dt->Year) + ((dt->Year + 3U) / 4U);
293         Seconds = (((((Days * 24U) + dt->Hour) * 60U) + dt->Min) * 60U) + dt->Sec;
294         return Seconds;
295 }
296
297 /****************************************************************************/
298 /**
299 *
300 * This function calculates the calibration value depending on the actual
301 * realworld time and also helps in deriving new calibration value if
302 * the user wishes to change his oscillator frequency.TimeReal is generally the
303 * internet time with EPOCH time as reference i.e.,1/1/1970 1st second.
304 * But this RTC driver assumes start time from 1/1/2000 1st second. Hence,if
305 * the user maps the internet time InternetTimeInSecs, then he has to use
306 *       XRtcPsu_SecToDateTime(InternetTimeInSecs,&InternetTime),
307 *       TimeReal = XRtcPsu_DateTimeToSec(InternetTime)
308 *       consecutively to arrive at TimeReal value.
309 *
310 * @param        InstancePtr is a pointer to the XRtcPsu instance.
311 * @param        TimeReal is the actual realworld time generally an
312 *               network time / Internet time in seconds.
313 *
314 * @param        CrystalOscFreq is the Oscillator new frequency. Say, If the user
315 *               is going with the typical 32768Hz, then he inputs the same
316 *               frequency value.
317 *
318 * @return       None.
319 *
320 * @note         After Calculating the calibration register, user / application has to
321 *                       call again CfgInitialize API to bring the new calibration into effect.
322 *
323 *****************************************************************************/
324 void XRtcPsu_CalculateCalibration(XRtcPsu *InstancePtr,u32 TimeReal,
325                 u32 CrystalOscFreq)
326 {
327         u32 ReadTime, SetTime;
328         u32 Cprev,Fprev,Cnew,Fnew,Xf,Calibration;
329         Xil_AssertVoid(TimeReal != 0U);
330         Xil_AssertVoid(CrystalOscFreq != 0U);
331
332         ReadTime = XRtcPsu_GetCurrentTime(InstancePtr);
333         SetTime = XRtcPsu_GetLastSetTime(InstancePtr);
334         Calibration = XRtcPsu_GetCalibration(InstancePtr);
335         /*
336          * When board gets reseted, Calibration value is zero
337          * and Last setTime will be marked as 1st  second. This implies
338          * CurrentTime to be in few seconds say something in tens. TimeReal will
339          * be huge, say something in thousands. So to prevent such reset case, Cnew
340          * and Fnew will not be calculated.
341          */
342         if((Calibration == 0U) || (CrystalOscFreq != InstancePtr->OscillatorFreq)) {
343                 Cnew = CrystalOscFreq - (u32)1;
344                 Fnew = 0U;
345         } else {
346                 Cprev = Calibration & XRTC_CALIB_RD_MAX_TCK_MASK;
347                 Fprev = Calibration & XRTC_CALIB_RD_FRACTN_DATA_MASK;
348
349                 Xf = ((ReadTime - SetTime) * ((Cprev+1U) + ((Fprev+1U)/16U))) / (TimeReal - SetTime);
350                 Cnew = (u32)(Xf) - (u32)1;
351                 Fnew = XRtcPsu_RoundOff((Xf - Cnew) * 16U) - (u32)1;
352         }
353
354         Calibration = (Fnew << XRTC_CALIB_RD_FRACTN_DATA_SHIFT) + Cnew;
355         Calibration |= XRTC_CALIB_RD_FRACTN_EN_MASK;
356
357         InstancePtr->CalibrationValue = Calibration;
358         InstancePtr->OscillatorFreq = CrystalOscFreq;
359 }
360
361 /****************************************************************************/
362 /**
363 *
364 * This function returns the seconds event status by reading
365 * interrupt status register.
366 *
367 * @param        InstancePtr is a pointer to the XRtcPsu instance.
368 *
369 * @return       Returns 1 if a new second event is generated.Else 0..
370 *
371 * @note         This API is used in polled mode operation of RTC.
372 *                       This also clears interrupt status seconds bit.
373 *
374 *****************************************************************************/
375 u32 XRtcPsu_IsSecondsEventGenerated(XRtcPsu *InstancePtr)
376 {
377         u32 Status;
378
379         /* Loop the interrupt status register for Seconds Event */
380         if ((XRtcPsu_ReadReg(InstancePtr->RtcConfig.BaseAddr +
381                         XRTC_INT_STS_OFFSET) & (XRTC_INT_STS_SECS_MASK)) == 0U) {
382                 Status = 0U;
383         } else {
384                 /* Clear the interrupt status register */
385                 XRtcPsu_WriteReg((InstancePtr)->RtcConfig.BaseAddr +
386                                 XRTC_INT_STS_OFFSET, XRTC_INT_STS_SECS_MASK);
387                 Status = 1U;
388         }
389         return Status;
390 }
391
392 /****************************************************************************/
393 /**
394 *
395 * This function returns the alarm event status by reading
396 * interrupt status register.
397 *
398 * @param        InstancePtr is a pointer to the XRtcPsu instance.
399 *
400 * @return       Returns 1 if the alarm event is generated.Else 0.
401 *
402 * @note         This API is used in polled mode operation of RTC.
403 *                       This also clears interrupt status alarm bit.
404 *
405 *****************************************************************************/
406 u32 XRtcPsu_IsAlarmEventGenerated(XRtcPsu *InstancePtr)
407 {
408         u32 Status;
409
410         /* Loop the interrupt status register for Alarm Event */
411         if ((XRtcPsu_ReadReg(InstancePtr->RtcConfig.BaseAddr +
412                         XRTC_INT_STS_OFFSET) & (XRTC_INT_STS_ALRM_MASK)) == 0U) {
413                 Status = 0U;
414         } else {
415                 /* Clear the interrupt status register */
416                 XRtcPsu_WriteReg((InstancePtr)->RtcConfig.BaseAddr +
417                                 XRTC_INT_STS_OFFSET, XRTC_INT_STS_ALRM_MASK);
418                 Status = 1U;
419         }
420         return Status;
421 }
422 /** @} */