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