1 /******************************************************************************
2  *
3  * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
4  * Analog Devices, Inc.),
5  * Copyright (C) 2023-2024 Analog Devices, Inc. All Rights Reserved. This software
6  * is proprietary to Analog Devices, Inc. and its licensors.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  ******************************************************************************/
21 
22 #include <stdbool.h>
23 #include <stddef.h>
24 
25 #include "gpio_regs.h"
26 #include "mxc_delay.h"
27 #include "mxc_device.h"
28 #include "mxc_errors.h"
29 #include "mxc_sys.h"
30 #include "rtc.h"
31 #include "rtc_reva.h"
32 #include "tmr.h"
33 
34 #if TARGET_NUM == 32650
35 #include "pwrseq_regs.h"
36 #endif
37 
MXC_RTC_RevA_waitBusyToClear(void)38 static void MXC_RTC_RevA_waitBusyToClear(void)
39 {
40     while (MXC_RTC_REVA_IS_BUSY) {}
41 }
42 
MXC_RTC_RevA_GetBusyFlag(mxc_rtc_reva_regs_t * rtc)43 int MXC_RTC_RevA_GetBusyFlag(mxc_rtc_reva_regs_t *rtc)
44 {
45     if (MXC_RTC_REVA_IS_BUSY) {
46         return E_BUSY;
47     }
48     return E_SUCCESS;
49 }
50 
MXC_RTC_RevA_EnableInt(mxc_rtc_reva_regs_t * rtc,uint32_t mask)51 int MXC_RTC_RevA_EnableInt(mxc_rtc_reva_regs_t *rtc, uint32_t mask)
52 {
53     mask &= (MXC_F_RTC_REVA_CTRL_TOD_ALARM_IE | MXC_F_RTC_REVA_CTRL_SSEC_ALARM_IE |
54              MXC_F_RTC_REVA_CTRL_RDY_IE);
55 
56     if (!mask) {
57         /* No bits set? Wasn't something we can enable. */
58         return E_BAD_PARAM;
59     }
60 
61     MXC_RTC_RevA_waitBusyToClear();
62 
63     rtc->ctrl |= mask;
64 
65     /* If TOD and SSEC interrupt enable, check busy after CTRL register write*/
66     mask &= ~MXC_F_RTC_REVA_CTRL_RDY_IE;
67 
68     if (mask) {
69         MXC_RTC_RevA_waitBusyToClear();
70     }
71     return E_SUCCESS;
72 }
73 
MXC_RTC_RevA_DisableInt(mxc_rtc_reva_regs_t * rtc,uint32_t mask)74 int MXC_RTC_RevA_DisableInt(mxc_rtc_reva_regs_t *rtc, uint32_t mask)
75 {
76     mask &= (MXC_F_RTC_REVA_CTRL_TOD_ALARM_IE | MXC_F_RTC_REVA_CTRL_SSEC_ALARM_IE |
77              MXC_F_RTC_REVA_CTRL_RDY_IE);
78 
79     if (!mask) {
80         /* No bits set? Wasn't something we can enable. */
81         return E_BAD_PARAM;
82     }
83 
84     MXC_RTC_RevA_waitBusyToClear();
85 
86     rtc->ctrl &= ~mask;
87 
88     /* If TOD and SSEC interrupt enable, check busy after CTRL register write*/
89     mask &= ~MXC_F_RTC_REVA_CTRL_RDY_IE;
90 
91     if (mask) {
92         MXC_RTC_RevA_waitBusyToClear();
93     }
94     return E_SUCCESS;
95 }
96 
MXC_RTC_RevA_SetTimeofdayAlarm(mxc_rtc_reva_regs_t * rtc,uint32_t ras)97 int MXC_RTC_RevA_SetTimeofdayAlarm(mxc_rtc_reva_regs_t *rtc, uint32_t ras)
98 {
99     // ras can only be written if BUSY = 0 & (RTCE = 0 or ADE = 0);
100     if (MXC_RTC_RevA_GetBusyFlag(rtc)) {
101         return E_BUSY;
102     }
103 
104     rtc->toda = (ras << MXC_F_RTC_REVA_TODA_TOD_ALARM_POS) & MXC_F_RTC_REVA_TODA_TOD_ALARM;
105 
106     return E_SUCCESS;
107 }
108 
MXC_RTC_RevA_SetSubsecondAlarm(mxc_rtc_reva_regs_t * rtc,uint32_t rssa)109 int MXC_RTC_RevA_SetSubsecondAlarm(mxc_rtc_reva_regs_t *rtc, uint32_t rssa)
110 {
111     // ras can only be written if BUSY = 0 & (RTCE = 0 or ASE = 0);
112     if (MXC_RTC_RevA_GetBusyFlag(rtc)) {
113         return E_BUSY;
114     }
115 
116     rtc->sseca = (rssa << MXC_F_RTC_REVA_SSECA_SSEC_ALARM_POS) & MXC_F_RTC_REVA_SSECA_SSEC_ALARM;
117 
118     return E_SUCCESS;
119 }
120 
MXC_RTC_RevA_Start(mxc_rtc_reva_regs_t * rtc)121 int MXC_RTC_RevA_Start(mxc_rtc_reva_regs_t *rtc)
122 {
123     if (MXC_RTC_RevA_GetBusyFlag(rtc)) {
124         return E_BUSY;
125     }
126 
127     rtc->ctrl |= MXC_F_RTC_REVA_CTRL_WR_EN; // Allow writing to registers
128 
129     MXC_RTC_RevA_waitBusyToClear();
130 
131     // Can only write if WE=1 and BUSY=0
132     rtc->ctrl |= MXC_F_RTC_REVA_CTRL_EN; // setting RTCE = 1
133 
134     MXC_RTC_RevA_waitBusyToClear();
135 
136     rtc->ctrl &= ~MXC_F_RTC_REVA_CTRL_WR_EN; // Prevent Writing...
137 
138     return E_SUCCESS;
139 }
140 
MXC_RTC_RevA_Stop(mxc_rtc_reva_regs_t * rtc)141 int MXC_RTC_RevA_Stop(mxc_rtc_reva_regs_t *rtc)
142 {
143     if (MXC_RTC_RevA_GetBusyFlag(rtc)) {
144         return E_BUSY;
145     }
146 
147     rtc->ctrl |= MXC_F_RTC_REVA_CTRL_WR_EN; // Allow writing to registers
148 
149     MXC_RTC_RevA_waitBusyToClear();
150 
151     // Can only write if WE=1 and BUSY=0
152     rtc->ctrl &= ~MXC_F_RTC_REVA_CTRL_EN; // setting RTCE = 0
153 
154     MXC_RTC_RevA_waitBusyToClear();
155 
156     rtc->ctrl &= ~MXC_F_RTC_REVA_CTRL_WR_EN; // Prevent Writing...
157 
158     return E_SUCCESS;
159 }
160 
MXC_RTC_RevA_Init(mxc_rtc_reva_regs_t * rtc,uint32_t sec,uint32_t ssec)161 int MXC_RTC_RevA_Init(mxc_rtc_reva_regs_t *rtc, uint32_t sec, uint32_t ssec)
162 {
163     if (MXC_RTC_RevA_GetBusyFlag(rtc)) {
164         return E_BUSY;
165     }
166 
167     rtc->ctrl = MXC_F_RTC_REVA_CTRL_WR_EN; //  Allow Writes
168 
169     MXC_RTC_RevA_waitBusyToClear();
170 
171     rtc->ctrl = MXC_RTC_REVA_CTRL_RESET_DEFAULT; // Start with a Clean Register
172 
173     MXC_RTC_RevA_waitBusyToClear();
174 
175     rtc->ctrl |= MXC_F_RTC_REVA_CTRL_WR_EN; // Set Write Enable, allow writing to reg.
176 
177     MXC_RTC_RevA_waitBusyToClear();
178 
179     rtc->ssec = ssec;
180 
181     MXC_RTC_RevA_waitBusyToClear();
182 
183     rtc->sec = sec;
184 
185     MXC_RTC_RevA_waitBusyToClear();
186 
187     rtc->ctrl &= ~MXC_F_RTC_REVA_CTRL_WR_EN; // Prevent Writing...
188 
189     return E_SUCCESS;
190 }
191 
MXC_RTC_RevA_SquareWave(mxc_rtc_reva_regs_t * rtc,mxc_rtc_reva_sqwave_en_t sqe,mxc_rtc_freq_sel_t ft)192 int MXC_RTC_RevA_SquareWave(mxc_rtc_reva_regs_t *rtc, mxc_rtc_reva_sqwave_en_t sqe,
193                             mxc_rtc_freq_sel_t ft)
194 {
195     if (MXC_RTC_RevA_GetBusyFlag(rtc)) {
196         return E_BUSY;
197     }
198 
199     rtc->ctrl |= MXC_F_RTC_REVA_CTRL_WR_EN; // Allow writing to registers
200 
201     MXC_RTC_RevA_waitBusyToClear();
202 
203     if (sqe == MXC_RTC_REVA_SQUARE_WAVE_ENABLED) {
204         if (ft == MXC_RTC_F_32KHZ) { // if 32KHz output is selected...
205             rtc->oscctrl |= MXC_F_RTC_REVA_OSCCTRL_SQW_32K; // Enable 32KHz wave
206 
207             MXC_RTC_RevA_waitBusyToClear();
208 
209             rtc->ctrl |= MXC_F_RTC_REVA_CTRL_SQW_EN; // Enable output on the pin
210         } else { // if 1Hz, 512Hz, 4KHz output is selected
211             rtc->oscctrl &=
212                 ~MXC_F_RTC_REVA_OSCCTRL_SQW_32K; // Must make sure that the 32KHz is disabled
213 
214             MXC_RTC_RevA_waitBusyToClear();
215 
216             rtc->ctrl &= ~MXC_F_RTC_REVA_CTRL_SQW_SEL;
217 
218             MXC_RTC_RevA_waitBusyToClear();
219 
220             rtc->ctrl |= (MXC_F_RTC_REVA_CTRL_SQW_EN | ft); // Enable Sq. wave,
221         }
222 
223         MXC_RTC_RevA_waitBusyToClear();
224 
225         rtc->ctrl |= MXC_F_RTC_REVA_CTRL_EN; // Enable Real Time Clock
226     } else { // Turn off the square wave output on the pin
227         rtc->oscctrl &=
228             ~MXC_F_RTC_REVA_OSCCTRL_SQW_32K; // Must make sure that the 32KHz is disabled
229 
230         MXC_RTC_RevA_waitBusyToClear();
231 
232         rtc->ctrl &= ~MXC_F_RTC_REVA_CTRL_SQW_EN; // No sq. wave output
233     }
234 
235     MXC_RTC_RevA_waitBusyToClear();
236 
237     rtc->ctrl &= ~MXC_F_RTC_REVA_CTRL_WR_EN; // Disable Writing to register
238 
239     return E_SUCCESS;
240 }
241 
MXC_RTC_RevA_Trim(mxc_rtc_reva_regs_t * rtc,int8_t trim)242 int MXC_RTC_RevA_Trim(mxc_rtc_reva_regs_t *rtc, int8_t trim)
243 {
244     if (MXC_RTC_RevA_GetBusyFlag(rtc)) {
245         return E_BUSY;
246     }
247 
248     rtc->ctrl |= MXC_F_RTC_REVA_CTRL_WR_EN;
249 
250     MXC_RTC_RevA_waitBusyToClear();
251 
252     MXC_SETFIELD(rtc->trim, MXC_F_RTC_REVA_TRIM_TRIM, trim << MXC_F_RTC_REVA_TRIM_TRIM_POS);
253 
254     MXC_RTC_RevA_waitBusyToClear();
255 
256     rtc->ctrl &= ~MXC_F_RTC_REVA_CTRL_WR_EN; // Disable Writing to register
257 
258     return E_SUCCESS;
259 }
260 
MXC_RTC_RevA_GetFlags(mxc_rtc_reva_regs_t * rtc)261 int MXC_RTC_RevA_GetFlags(mxc_rtc_reva_regs_t *rtc)
262 {
263     return rtc->ctrl & (MXC_F_RTC_REVA_CTRL_TOD_ALARM | MXC_F_RTC_REVA_CTRL_SSEC_ALARM |
264                         MXC_F_RTC_REVA_CTRL_RDY);
265 }
266 
MXC_RTC_RevA_ClearFlags(mxc_rtc_reva_regs_t * rtc,int flags)267 int MXC_RTC_RevA_ClearFlags(mxc_rtc_reva_regs_t *rtc, int flags)
268 {
269     rtc->ctrl &= ~(flags & (MXC_F_RTC_REVA_CTRL_TOD_ALARM | MXC_F_RTC_REVA_CTRL_SSEC_ALARM |
270                             MXC_F_RTC_REVA_CTRL_RDY));
271 
272     return E_SUCCESS;
273 }
274 
MXC_RTC_RevA_GetSubSecond(mxc_rtc_reva_regs_t * rtc)275 int MXC_RTC_RevA_GetSubSecond(mxc_rtc_reva_regs_t *rtc)
276 {
277     if (MXC_RTC_RevA_GetBusyFlag(rtc)) {
278         return E_BUSY;
279     }
280 
281 #if TARGET_NUM == 32650
282     int ssec;
283     if (ChipRevision > 0xA1) {
284         ssec = ((MXC_PWRSEQ->ctrl >> 12) & 0xF00) | (rtc->ssec & 0xFF);
285     } else {
286         ssec = rtc->ssec;
287     }
288     return ssec;
289 #else
290     return rtc->ssec;
291 #endif
292 }
293 
MXC_RTC_RevA_GetSecond(mxc_rtc_reva_regs_t * rtc)294 int MXC_RTC_RevA_GetSecond(mxc_rtc_reva_regs_t *rtc)
295 {
296     if (MXC_RTC_RevA_GetBusyFlag(rtc)) {
297         return E_BUSY;
298     }
299 
300     return rtc->sec;
301 }
302 
MXC_RTC_RevA_GetSubSeconds(mxc_rtc_reva_regs_t * rtc,uint32_t * ssec)303 int MXC_RTC_RevA_GetSubSeconds(mxc_rtc_reva_regs_t *rtc, uint32_t *ssec)
304 {
305     if (MXC_RTC_RevA_GetBusyFlag(rtc)) {
306         return E_BUSY;
307     } else if (ssec == NULL) {
308         return E_NULL_PTR;
309     }
310 
311 #if TARGET_NUM == 32650
312     uint32_t sub_sec;
313     if (ChipRevision > 0xA1) {
314         sub_sec = ((MXC_PWRSEQ->ctrl >> 12) & 0xF00) | (rtc->ssec & 0xFF);
315     } else {
316         sub_sec = rtc->ssec;
317     }
318 
319     *ssec = sub_sec;
320 #else
321     *ssec = rtc->ssec;
322 #endif
323 
324     return E_NO_ERROR;
325 }
326 
MXC_RTC_RevA_GetSeconds(mxc_rtc_reva_regs_t * rtc,uint32_t * sec)327 int MXC_RTC_RevA_GetSeconds(mxc_rtc_reva_regs_t *rtc, uint32_t *sec)
328 {
329     if (MXC_RTC_RevA_GetBusyFlag(rtc)) {
330         return E_BUSY;
331     } else if (sec == NULL) {
332         return E_NULL_PTR;
333     }
334 
335     *sec = rtc->sec;
336 
337     return E_NO_ERROR;
338 }
339 
MXC_RTC_RevA_GetTime(mxc_rtc_reva_regs_t * rtc,uint32_t * sec,uint32_t * subsec)340 int MXC_RTC_RevA_GetTime(mxc_rtc_reva_regs_t *rtc, uint32_t *sec, uint32_t *subsec)
341 {
342     int32_t temp_sec = 0;
343 
344     if (sec == NULL || subsec == NULL) {
345         return E_NULL_PTR;
346     }
347 
348     do {
349         // Check if an update is about to happen.
350         if (!(rtc->ctrl & MXC_F_RTC_REVA_CTRL_RDY)) {
351             return E_BUSY;
352         }
353 
354         // Read the seconds count.
355         temp_sec = MXC_RTC_RevA_GetSecond(rtc);
356 
357         if (temp_sec == E_BUSY) {
358             return E_BUSY;
359         }
360 
361         // Check if an update is about to happen.
362         if (!(rtc->ctrl & MXC_F_RTC_REVA_CTRL_RDY)) {
363             return E_BUSY;
364         }
365 
366         // Read the sub-seconds count.
367         *subsec = MXC_RTC_RevA_GetSubSecond(rtc);
368 
369         // Check if an update is about to happen.
370         if (!(rtc->ctrl & MXC_F_RTC_REVA_CTRL_RDY)) {
371             return E_BUSY;
372         }
373 
374         // Read the seconds count.
375         *sec = MXC_RTC_RevA_GetSecond(rtc);
376 
377         // Repeat until a steady state is reached.
378     } while (temp_sec != *sec);
379 
380     return E_NO_ERROR;
381 }
382 
MXC_RTC_RevA_TrimCrystal(mxc_rtc_reva_regs_t * rtc,mxc_tmr_regs_t * tmr)383 int MXC_RTC_RevA_TrimCrystal(mxc_rtc_reva_regs_t *rtc, mxc_tmr_regs_t *tmr)
384 {
385     int err, ppm = 0;
386     uint32_t sec = 0, ssec = 0, ctrl = 0;
387     uint32_t sec_sample[MXC_RTC_REVA_TRIM_PERIODS + 1] = { 0 };
388     uint32_t ssec_sample[MXC_RTC_REVA_TRIM_PERIODS + 1] = { 0 };
389     bool rtc_en = true;
390 
391     if (!(rtc->ctrl & MXC_F_RTC_REVA_CTRL_EN)) { // If RTC not enable, initialize it
392         rtc_en = false;
393 
394         // Save state
395         while (MXC_RTC_RevA_GetTime(rtc, &sec, &ssec) < 0) {}
396         while (rtc->ctrl & MXC_F_RTC_CTRL_BUSY) {}
397         ctrl = rtc->ctrl;
398 
399         if ((err = MXC_RTC_Init(0, 0)) != E_NO_ERROR) {
400             return err;
401         }
402         MXC_RTC_Start();
403     }
404 
405     MXC_TMR_ClearFlags(tmr);
406     MXC_TMR_Start(tmr); // Sample the RTC ticks in MXC_RTC_REVA_TRIM_PERIODS number of periods
407     while (MXC_RTC_RevA_GetTime(rtc, &sec_sample[0], &ssec_sample[0]) < 0) {}
408 
409     for (int i = 1; i < (MXC_RTC_REVA_TRIM_PERIODS + 1); i++) {
410         // Wait for time trim period to elapse
411         while (!(MXC_TMR_GetFlags(tmr) & MXC_RTC_TRIM_TMR_IRQ)) {}
412 
413         // Take time sample
414         while (MXC_RTC_RevA_GetTime(rtc, &sec_sample[i], &ssec_sample[i]) < 0) {}
415 
416         MXC_TMR_ClearFlags(tmr);
417     }
418 
419     MXC_TMR_Stop(tmr); // Shutdown timer
420     MXC_TMR_Shutdown(tmr);
421 
422     if (!rtc_en) { // If RTC wasn't enabled entering the function, restore state
423         MXC_RTC_Stop();
424 
425         while (rtc->ctrl & MXC_F_RTC_REVA_CTRL_BUSY) {}
426         MXC_SETFIELD(rtc->ssec, MXC_F_RTC_REVA_SSEC_SSEC, (ssec << MXC_F_RTC_REVA_SSEC_SSEC_POS));
427         while (rtc->ctrl & MXC_F_RTC_REVA_CTRL_BUSY) {}
428         MXC_SETFIELD(rtc->sec, MXC_F_RTC_REVA_SEC_SEC, (sec << MXC_F_RTC_REVA_SEC_SEC_POS));
429         while (rtc->ctrl & MXC_F_RTC_REVA_CTRL_BUSY) {}
430         rtc->ctrl = ctrl;
431     }
432 
433     for (int i = 0; i < MXC_RTC_REVA_TRIM_PERIODS;
434          i++) { // Get total error in RTC ticks over MXC_RTC_REVA_TRIM_PERIODS number of sample periods
435         if (sec_sample[i] < sec_sample[i + 1]) {
436             ppm += MXC_RTC_REVA_TICKS_PER_PERIOD -
437                    ((MXC_RTC_MAX_SSEC - ssec_sample[i]) + ssec_sample[i + 1]);
438         } else {
439             ppm += MXC_RTC_REVA_TICKS_PER_PERIOD - (ssec_sample[i + 1] - ssec_sample[i]);
440         }
441     }
442 
443     ppm /= MXC_RTC_REVA_TRIM_PERIODS;
444     ppm = PPM(ppm); // Convert total error to PPM and set trim
445     if (ppm < -128 || ppm > 127) {
446         return E_OVERFLOW;
447     }
448 
449     return MXC_RTC_RevA_Trim(rtc, (int8_t)ppm); // Set Trim
450 }
451