1 /* ****************************************************************************
2  * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
18  * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * Except as contained in this notice, the name of Maxim Integrated
23  * Products, Inc. shall not be used except as stated in the Maxim Integrated
24  * Products, Inc. Branding Policy.
25  *
26  * The mere transfer of this software does not imply any licenses
27  * of trade secrets, proprietary technology, copyrights, patents,
28  * trademarks, maskwork rights, or any other form of intellectual
29  * property whatsoever. Maxim Integrated Products, Inc. retains all
30  * ownership rights.
31  *
32  *
33  **************************************************************************** */
34 
35 #include "mxc_config.h"
36 #include "rtc_regs.h"
37 #include "rtc.h"
38 #include "mxc_sys.h"
39 #include "mxc_delay.h"
40 #include "gpio_regs.h"
41 #include "mxc_errors.h"
42 
43 #if TARGET == 32650
44     #include "pwrseq_regs.h"
45 #endif
46 
47 #define RTC_CTRL_RESET_DEFAULT (0x0000UL)
48 #define RTC_IS_BUSY (MXC_RTC->ctrl & MXC_F_RTC_CTRL_BUSY)
49 #define RTC_IS_ENABLED (MXC_RTC->ctrl & MXC_F_RTC_CTRL_RTCE)
50 
51 #define BUSY_TIMEOUT 1000   // Timeout counts for the Busy bit
52 
53 // *****************************************************************************
RTC_EnableTimeofdayInterrupt(mxc_rtc_regs_t * rtc)54 int RTC_EnableTimeofdayInterrupt(mxc_rtc_regs_t *rtc)
55 {
56     if (RTC_CheckBusy()) {
57         return E_BUSY;
58     }
59 
60     rtc->ctrl |= MXC_F_RTC_CTRL_ADE;   // Enable Time-of-day Interrupt
61     return E_SUCCESS;
62 }
63 
64 // *****************************************************************************
RTC_DisableTimeofdayInterrupt(mxc_rtc_regs_t * rtc)65 int RTC_DisableTimeofdayInterrupt(mxc_rtc_regs_t *rtc)
66 {
67 
68     if (RTC_CheckBusy()) {
69         return E_BUSY;
70     }
71 
72     rtc->ctrl &= ~MXC_F_RTC_CTRL_ADE;    // Disable Time-of-day Interrupt
73 
74     if (RTC_CheckBusy()) {
75         return E_BUSY;
76     }
77 
78     return E_SUCCESS;
79 }
80 
81 // *****************************************************************************
RTC_EnableSubsecondInterrupt(mxc_rtc_regs_t * rtc)82 int RTC_EnableSubsecondInterrupt(mxc_rtc_regs_t *rtc)
83 {
84     if (RTC_CheckBusy()) {
85         return E_BUSY;
86     }
87 
88     rtc->ctrl |= MXC_F_RTC_CTRL_ASE;    // Enable Sub-Second Interrupt
89 
90     return E_SUCCESS;
91 }
92 
93 // *****************************************************************************
RTC_DisableSubsecondInterrupt(mxc_rtc_regs_t * rtc)94 int RTC_DisableSubsecondInterrupt(mxc_rtc_regs_t *rtc)
95 {
96 
97     if (RTC_CheckBusy()) {
98         return E_BUSY;
99     }
100 
101     rtc->ctrl &= ~MXC_F_RTC_CTRL_ASE;    // Alarm Sub-Second Interrupt disabled
102 
103     if (RTC_CheckBusy()) {
104         return E_BUSY;
105     }
106 
107     return E_SUCCESS;
108 }
109 
110 // *****************************************************************************
RTC_SetTimeofdayAlarm(mxc_rtc_regs_t * rtc,uint32_t ras)111 int RTC_SetTimeofdayAlarm(mxc_rtc_regs_t *rtc, uint32_t ras)
112 {
113     // ras can only be written if BUSY = 0 & (RTCE = 0 or ADE = 0);
114 
115 
116     if(RTC_DisableTimeofdayInterrupt(rtc) == E_BUSY) {
117         return E_BUSY;
118     }
119 
120     if (RTC_CheckBusy()) {
121         return E_BUSY;
122     }
123 
124     rtc->ras = (ras << MXC_F_RTC_RAS_RAS_POS) & MXC_F_RTC_RAS_RAS;
125 
126     if(RTC_EnableTimeofdayInterrupt(rtc) == E_BUSY) {
127         return E_BUSY;
128     }
129 
130     return E_SUCCESS;
131 }
132 
133 // *****************************************************************************
RTC_SetSubsecondAlarm(mxc_rtc_regs_t * rtc,uint32_t rssa)134 int RTC_SetSubsecondAlarm(mxc_rtc_regs_t *rtc, uint32_t rssa)
135 {
136     // ras can only be written if BUSY = 0 & (RTCE = 0 or ASE = 0);
137 
138     if(RTC_DisableSubsecondInterrupt(rtc) == E_BUSY) {
139         return E_BUSY;
140     }
141 
142     if (RTC_CheckBusy()) {
143         return E_BUSY;
144     }
145 
146     rtc->rssa =  (rssa << MXC_F_RTC_RSSA_RSSA_POS) & MXC_F_RTC_RSSA_RSSA;
147 
148     if(RTC_EnableSubsecondInterrupt(rtc) == E_BUSY) {
149         return E_BUSY;
150     }
151 
152     return E_SUCCESS;
153 }
154 
155 
156 // *****************************************************************************
RTC_EnableRTCE(mxc_rtc_regs_t * rtc)157 int RTC_EnableRTCE(mxc_rtc_regs_t *rtc)
158 {
159     if (RTC_CheckBusy()) {
160         return E_BUSY;
161     }
162 
163     rtc->ctrl |= MXC_F_RTC_CTRL_WE;       // Allow writing to registers
164     if (RTC_CheckBusy()) {
165         return E_BUSY;
166     }
167     // Can only write if WE=1 and BUSY=0
168     rtc->ctrl |= MXC_F_RTC_CTRL_RTCE;    // setting RTCE = 1
169     if (RTC_CheckBusy()) {
170         return E_BUSY;
171     }
172 
173     rtc->ctrl &= ~MXC_F_RTC_CTRL_WE;       // Prevent Writing...
174 
175     return E_SUCCESS;
176 }
177 
178 // *****************************************************************************
RTC_DisableRTCE(mxc_rtc_regs_t * rtc)179 int RTC_DisableRTCE(mxc_rtc_regs_t *rtc)
180 {
181     if (RTC_CheckBusy()) {
182         return E_BUSY;
183     }
184 
185     rtc->ctrl |= MXC_F_RTC_CTRL_WE;      // Allow writing to registers
186     if (RTC_CheckBusy()) {
187         return E_BUSY;
188     }
189 
190     // Can only write if WE=1 and BUSY=0
191     rtc->ctrl &= ~MXC_F_RTC_CTRL_RTCE;  // setting RTCE = 0
192     if (RTC_CheckBusy()) {
193         return E_BUSY;
194     }
195 
196     rtc->ctrl &= ~MXC_F_RTC_CTRL_WE;       // Prevent Writing...
197 
198     return E_SUCCESS;
199 }
200 
201 
202 // *****************************************************************************
RTC_Init(mxc_rtc_regs_t * rtc,uint32_t sec,uint8_t ssec,sys_cfg_rtc_t * sys_cfg)203 int RTC_Init(mxc_rtc_regs_t *rtc, uint32_t sec, uint8_t ssec, sys_cfg_rtc_t *sys_cfg)
204 {
205 #if((TARGET == 32650) || (TARGET == 32660))
206     SYS_ClockEnable_X32K(sys_cfg);
207 #else
208     SYS_RTCClockEnable(sys_cfg);
209 #endif
210 
211     if (RTC_CheckBusy()) {
212         return E_BUSY;
213     }
214 
215     rtc->ctrl = MXC_F_RTC_CTRL_WE;        //  Allow Writes
216     if (RTC_CheckBusy()) {
217         return E_BUSY;
218     }
219 
220     rtc->ctrl = RTC_CTRL_RESET_DEFAULT;  // Start with a Clean Register
221     if (RTC_CheckBusy()) {
222         return E_BUSY;
223     }
224 
225     rtc->ctrl |= MXC_F_RTC_CTRL_WE;      // Set Write Enable, allow writing to reg.
226     if (RTC_CheckBusy()) {
227         return E_BUSY;
228     }
229 
230     rtc->ssec = ssec;
231     if (RTC_CheckBusy()) {
232         return E_BUSY;
233     }
234 
235     rtc->sec = sec;
236     if (RTC_CheckBusy()) {
237         return E_BUSY;
238     }
239 
240     rtc->ctrl &= ~MXC_F_RTC_CTRL_WE;       // Prevent Writing...
241 
242     return E_SUCCESS;
243 }
244 
245 // *****************************************************************************
RTC_SquareWave(mxc_rtc_regs_t * rtc,rtc_sqwave_en_t sqe,rtc_freq_sel_t ft,rtc_osc_mode_t x32kmd,const sys_cfg_rtc_t * sys_cfg)246 int RTC_SquareWave(mxc_rtc_regs_t *rtc, rtc_sqwave_en_t sqe, rtc_freq_sel_t ft,
247                    rtc_osc_mode_t x32kmd, const sys_cfg_rtc_t* sys_cfg)
248 {
249 
250     SYS_RTC_SqwavInit(sys_cfg);  // Set the Output pins for the squarewave.
251 
252     if (RTC_CheckBusy()) {
253         return E_BUSY;
254     }
255 
256     rtc->ctrl |= MXC_F_RTC_CTRL_WE;   // Allow writing to registers
257 
258     if (RTC_CheckBusy()) {
259         return E_BUSY;
260     }
261 
262     if (sqe == SQUARE_WAVE_ENABLED) {
263         if (ft == F_32KHZ){        // if 32KHz output is selected...
264             rtc->oscctrl |= MXC_F_RTC_OSCCTRL_OUT32K;   // Enable 32KHz wave
265             if (RTC_CheckBusy()) {
266                 return E_BUSY;
267             }
268             rtc->ctrl |= MXC_F_RTC_CTRL_SQE;                  // Enable output on the pin
269         } else {                  // if 1Hz, 512Hz, 4KHz output is selected
270 
271             rtc->oscctrl &= ~MXC_F_RTC_OSCCTRL_OUT32K;  // Must make sure that the 32KHz is disabled
272             if (RTC_CheckBusy()) {
273                 return E_BUSY;
274             }
275             rtc->ctrl &= ~(MXC_F_RTC_CTRL_FT | MXC_F_RTC_CTRL_X32KMD);
276             if (RTC_CheckBusy()) {
277                 return E_BUSY;
278             }
279             rtc->ctrl |= (MXC_F_RTC_CTRL_SQE | ft | x32kmd);  // Enable Sq. wave,
280         }
281 
282         if (RTC_CheckBusy()) {
283             return E_BUSY;
284         }
285         rtc->ctrl |= MXC_F_RTC_CTRL_RTCE;     // Enable Real Time Clock
286     } else { // Turn off the square wave output on the pin
287 
288         rtc->oscctrl &= ~MXC_F_RTC_OSCCTRL_OUT32K;     // Must make sure that the 32KHz is disabled
289         if (RTC_CheckBusy()) {
290             return E_BUSY;
291         }
292         rtc->ctrl &= ~MXC_F_RTC_CTRL_SQE;  // No sq. wave output
293     }
294 
295     if (RTC_CheckBusy()) {
296         return E_BUSY;
297     }
298     rtc->ctrl &= ~MXC_F_RTC_CTRL_WE;       // Disable Writing to register
299 
300     return E_SUCCESS;
301 }
302 
303 // *****************************************************************************
RTC_Trim(mxc_rtc_regs_t * rtc,int8_t trim)304 int RTC_Trim(mxc_rtc_regs_t *rtc, int8_t trim)
305 {
306 
307     if (RTC_CheckBusy()) {
308         return E_BUSY;
309     }
310 
311     rtc->ctrl |= MXC_F_RTC_CTRL_WE;
312 
313     if (RTC_CheckBusy()) {
314         return E_BUSY;
315     }
316 
317     MXC_SETFIELD(rtc->trim, MXC_F_RTC_TRIM_TRIM, trim << MXC_F_RTC_TRIM_TRIM_POS);
318 
319     if (RTC_CheckBusy()) {
320         return E_BUSY;
321     }
322     rtc->ctrl &= ~MXC_F_RTC_CTRL_WE;       // Disable Writing to register
323 
324     return E_SUCCESS;
325 }
326 
327 // *****************************************************************************
RTC_CheckBusy(void)328 int RTC_CheckBusy(void)
329 {
330     // Time-out transfer if it takes > BUSY_TIMEOUT microseconds
331     mxc_delay_start(MXC_DELAY_USEC(BUSY_TIMEOUT));
332     while (RTC_IS_BUSY) {
333         if (mxc_delay_check() != E_BUSY){
334             return E_BUSY;
335         }
336     }
337     mxc_delay_stop();
338     return E_SUCCESS;
339 }
340 
341 // *****************************************************************************
RTC_GetFlags(void)342 int RTC_GetFlags(void)
343 {
344     return MXC_RTC->ctrl & (MXC_F_RTC_CTRL_ALDF | MXC_F_RTC_CTRL_ALSF | MXC_F_RTC_CTRL_RDY);
345 }
346 
347 // *****************************************************************************
RTC_ClearFlags(int flags)348 int RTC_ClearFlags(int flags)
349 {
350     if (RTC_CheckBusy()) {
351         return E_BUSY;
352     }
353     MXC_RTC->ctrl &= ~(flags & (MXC_F_RTC_CTRL_ALDF | MXC_F_RTC_CTRL_ALSF | MXC_F_RTC_CTRL_RDY));
354 
355     return E_SUCCESS;
356 }
357 
358 // *****************************************************************************
RTC_GetSubSecond(void)359 int RTC_GetSubSecond(void)
360 {
361 #if TARGET == 32650
362     int ssec;
363     if(ChipRevision > 0xA1){
364         ssec = ((MXC_PWRSEQ->lpcn >> 12)& 0xF00) | (MXC_RTC->ssec & 0xFF);
365     }else{
366         ssec = MXC_RTC->ssec;
367     }
368         return ssec;
369 #else
370     return MXC_RTC->ssec;
371 #endif
372 }
373 
374 // *****************************************************************************
RTC_GetSecond(void)375 int RTC_GetSecond(void)
376 {
377     return MXC_RTC->sec;
378 }
379 
380 // *****************************************************************************
RTC_GetTime(uint32_t * sec,uint32_t * subsec)381 int RTC_GetTime(uint32_t* sec, uint32_t* subsec)
382 {
383     uint32_t temp_sec;
384     do {
385         // Check if an update is about to happen.
386         if(!(MXC_RTC->ctrl & MXC_F_RTC_CTRL_RDY)) {
387             return E_BUSY;
388         }
389 
390         // Read the seconds count.
391         temp_sec = RTC_GetSecond();
392 
393         // Check if an update is about to happen.
394         if(!(MXC_RTC->ctrl & MXC_F_RTC_CTRL_RDY)) {
395             return E_BUSY;
396         }
397 
398         // Read the sub-seconds count.
399         *subsec = RTC_GetSubSecond();
400 
401         // Check if an update is about to happen.
402         if(!(MXC_RTC->ctrl & MXC_F_RTC_CTRL_RDY)) {
403             return E_BUSY;
404         }
405 
406         // Read the seconds count.
407         *sec = RTC_GetSecond();
408 
409         // Repeat until a steady state is reached.
410     } while (temp_sec != *sec);
411 
412     return E_NO_ERROR;
413 }
414 
415 // *****************************************************************************
RTC_IsEnabled(void)416 int RTC_IsEnabled(void)
417 {
418     return RTC_IS_ENABLED;
419 }
420