1 /*
2  * Copyright (c) 2017-2019, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQueueNTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33  *  ======== PowerCC26X2_calibrateRCOSC.c ========
34  */
35 
36 #include <stdbool.h>
37 
38 #include <ti/drivers/dpl/HwiP.h>
39 
40 #include <ti/drivers/Power.h>
41 #include <ti/drivers/power/PowerCC26X2.h>
42 
43 #include <ti/devices/DeviceFamily.h>
44 #include DeviceFamily_constructPath(inc/hw_aux_evctl.h)
45 #include DeviceFamily_constructPath(inc/hw_aux_smph.h)
46 #include DeviceFamily_constructPath(inc/hw_aux_sysif.h)
47 #include DeviceFamily_constructPath(inc/hw_aux_tdc.h)
48 #include DeviceFamily_constructPath(inc/hw_ddi_0_osc.h)
49 #include DeviceFamily_constructPath(inc/hw_ddi.h)
50 #include DeviceFamily_constructPath(driverlib/aon_batmon.h)
51 #include DeviceFamily_constructPath(driverlib/ddi.h)
52 #include DeviceFamily_constructPath(driverlib/ioc.h)
53 #include DeviceFamily_constructPath(driverlib/osc.h)
54 #include DeviceFamily_constructPath(driverlib/sys_ctrl.h)
55 
56 #define AUX_TDC_SEMAPHORE_NUMBER                     1     /* semaphore 1 protects TDC */
57 #define NUM_RCOSC_LF_PERIODS_TO_MEASURE              32    /* x RCOSC_LF periods vs XOSC_HF */
58 #define NUM_RCOSC_HF_PERIODS_TO_MEASURE              1     /* x RCOSC_HF periods vs XOSC_HF */
59 #define ACLK_REF_SRC_RCOSC_HF                        0     /* Use RCOSC_HF for ACLK REF */
60 #define ACLK_REF_SRC_RCOSC_LF                        2     /* Use RCOSC_LF for ACLK REF */
61 #define SCLK_LF_OPTION_RCOSC_LF                      3     /* defined in cc26_ccfg.xls */
62 #define RCOSC_HF_LOW_THRESHOLD_TDC_VALUE             1535  /* If TDC value is within threshold range, no need for another TDC measurement */
63 #define RCOSC_HF_PERFECT_TDC_VALUE                   1536  /* RCOSC_HF runs at perfect 48 MHz when ending up with this TDC value */
64 #define RCOSC_HF_HIGH_THRESHOLD_TDC_VALUE            1537  /* If TDC value is within threshold range, no need for another TDC measurement */
65 
66 #define DDI_0_OSC_O_CTL1_LOCAL                       0x00000004             /* offset */
67 #define DDI_0_OSC_CTL1_RCOSCHFCTRIMFRACT_LOCAL_M     0x007C0000             /* mask */
68 #define DDI_0_OSC_CTL1_RCOSCHFCTRIMFRACT_LOCAL_S     18                     /* shift */
69 #define DDI_0_OSC_CTL1_RCOSCHFCTRIMFRACT_EN_LOCAL_M  0x00020000             /* mask */
70 #define DDI_0_OSC_CTL1_RCOSCHFCTRIMFRACT_EN_LOCAL_S  17                     /* shift */
71 #define DDI_0_OSC_ATESTCTL_SET_RCOSC_HF_FINE_RESISTOR_LOCAL_M 0x00000C00    /* offset */
72 #define DDI_0_OSC_ATESTCTL_SET_RCOSC_HF_FINE_RESISTOR_LOCAL_S 10            /* shift */
73 
74 /* AUX ISR states */
75 #define WAIT_SMPH       0   /* just took SMPH, start RCOSC_LF */
76 #define CAL_RCOSC_LF    1   /* just finished RCOSC_LF, start first RCOSC_HF */
77 #define CAL_RCOSC_HF1   2   /* just finished 1st RCOSC_HF, start 2nd */
78 #define CAL_RCOSC_HF2   3   /* just finished 2nd RCOSC_HF, decide best */
79 
80 /* calibration states */
81 #define PowerCC26X2_STATE_TDC_INIT  0
82 #define PowerCC26X2_STATE_CAL_LF_1  1
83 #define PowerCC26X2_STATE_CAL_LF_2  2
84 #define PowerCC26X2_STATE_CAL_HF1_1 3
85 #define PowerCC26X2_STATE_CAL_HF1_2 4
86 #define PowerCC26X2_STATE_CAL_HF2   5
87 #define PowerCC26X2_STATE_CLEANUP   6
88 
89 /* FSM results */
90 typedef enum {
91     PowerCC26X2_FSM_RESULT_RUN_FSM,
92     PowerCC26X2_FSM_RESULT_WAIT_FOR_TDC,
93     PowerCC26X2_FSM_RESULT_DONE,
94     PowerCC26X2_FSM_RESULT_ERROR,
95 } PowerCC26X2_FsmResult;
96 
97 /* macros */
98 #define Min(a,b)        (((a)<(b))?(a):(b))
99 #define Max(a,b)        (((a)>(b))?(a):(b))
100 #define Abs(x)          ((x) < 0 ? -(x) : (x))
101 #define Scale_rndInf(x)  ((3 * (x) + (((x) < 0) ? -2 : 2)) / 4)
102 
103 #ifndef PowerCC26X2_INSTRUMENT_RCOSC_CALIBRATION
104     #define PowerCC26X2_INSTRUMENT_RCOSC_CALIBRATION 0
105 #endif
106 
107 #if PowerCC26X2_INSTRUMENT_RCOSC_CALIBRATION
108 volatile unsigned int gotSEM = 0;
109 volatile unsigned int calLFi = 0;
110 volatile unsigned int calHF1i = 0;
111 volatile unsigned int calHF2i = 0;
112 volatile bool doneCal = false;
113 unsigned int tdcResult_LF = 0;
114 unsigned int tdcResult_HF1 = 0;
115 unsigned int tdcResult_HF2 = 0;
116 unsigned int numISRs = 0;
117 #endif
118 
119 /* Forward declarations */
120 static bool getTdcSemaphore();
121 static void updateSubSecInc(uint32_t tdcResult);
122 static void calibrateRcoscHf1(int32_t tdcResult);
123 static void calibrateRcoscHf2(int32_t tdcResult);
124 static PowerCC26X2_FsmResult runCalibrateFsm(void);
125 void PowerCC26X2_calibrate(void);
126 void PowerCC26X2_RCOSC_clockFunc(uintptr_t arg);
127 
128 /* Externs */
129 extern PowerCC26X2_ModuleState PowerCC26X2_module;
130 extern const PowerCC26X2_Config PowerCC26X2_config;
131 
132 /*
133  *  ======== PowerCC26X2_initiateCalibration ========
134  *  Initiate calibration of RCOSC_LF and RCOSCHF
135  */
PowerCC26X2_initiateCalibration()136 bool PowerCC26X2_initiateCalibration()
137 {
138     unsigned int hwiKey;
139     bool busy = false;
140     bool status;
141     bool gotSem;
142 
143     if ((PowerCC26X2_module.calLF == false) &&
144         (PowerCC26X2_config.calibrateRCOSC_HF == false)) {
145         return (false);
146     }
147 
148     /* make sure calibration is not already in progress */
149     hwiKey = HwiP_disable();
150 
151     if (PowerCC26X2_module.busyCal == false) {
152         PowerCC26X2_module.busyCal = true;
153     }
154     else {
155         busy = true;
156     }
157 
158     HwiP_restore(hwiKey);
159 
160     if (busy == true) {
161         return (false);
162     }
163 
164 #if PowerCC26X2_INSTRUMENT_RCOSC_CALIBRATION
165     gotSEM = 0;
166     calLFi = 0;
167     calHF1i = 0;
168     calHF2i = 0;
169     doneCal = false;
170 #endif
171 
172     /* set contraint to prohibit standby during calibration sequence */
173     Power_setConstraint(PowerCC26XX_DISALLOW_STANDBY);
174 
175     /* set dependency to keep XOSC_HF active during calibration sequence */
176     Power_setDependency(PowerCC26XX_XOSC_HF);
177 
178     /* initiate acquisition of semaphore protecting TDC */
179     gotSem = getTdcSemaphore();
180 
181     /* if didn't acquire semaphore, must wait for autotake ISR */
182     if (gotSem == false) {
183         PowerCC26X2_module.auxHwiState = WAIT_SMPH;
184         status = false;  /* false: don't do anything else until acquire SMPH */
185     }
186 
187     /* else, semaphore acquired, OK to proceed with first measurement */
188     else {
189 #if PowerCC26X2_INSTRUMENT_RCOSC_CALIBRATION
190         gotSEM = 1;
191 #endif
192         status = true;   /* true: OK to start first measurement */
193     }
194 
195     return (status);
196 }
197 
198 /*
199  *  ======== PowerCC26X2_auxISR ========
200  *  ISR for the AUX combo interrupt event.  Implements Hwi state machine to
201  *  step through the RCOSC calibration steps.
202  */
PowerCC26X2_auxISR(uintptr_t arg)203 void PowerCC26X2_auxISR(uintptr_t arg)
204 {
205     uint32_t tdcResult;
206 
207 #if PowerCC26X2_INSTRUMENT_RCOSC_CALIBRATION
208     numISRs++;
209 #endif
210 
211     /*
212     * disable all events that are part of AUX_COMBINED_INTERRUPT.
213     * This interrupt is reserved for use during RCOSC calibration.
214     * Other AUX perihperals that want to generate interrupts to CM3
215     * must use dedicated interrupt lines or go through AON combined.
216     */
217     HWREG(AUX_EVCTL_BASE + AUX_EVCTL_O_COMBEVTOMCUMASK) = 0;
218 
219     /* ****** state = WAIT_SMPH: arrive here if just took the SMPH ****** */
220     if (PowerCC26X2_module.auxHwiState == WAIT_SMPH) {
221 #if PowerCC26X2_INSTRUMENT_RCOSC_CALIBRATION
222         gotSEM = 1;
223 #endif
224     }
225 
226     /* **** state = CAL_RCOSC_LF: here when just finished LF counting **** */
227     else if (PowerCC26X2_module.auxHwiState == CAL_RCOSC_LF) {
228 
229         tdcResult = HWREG(AUX_TDC_BASE + AUX_TDC_O_RESULT);
230 
231 #if PowerCC26X2_INSTRUMENT_RCOSC_CALIBRATION
232         tdcResult_LF = tdcResult;
233 #endif
234         /* update the RTC SUBSECINC register based on LF measurement result */
235         updateSubSecInc(tdcResult);
236 #if PowerCC26X2_INSTRUMENT_RCOSC_CALIBRATION
237         calLFi = 1;
238 #endif
239         /* if doing HF calibration initiate it now */
240         if (PowerCC26X2_config.calibrateRCOSC_HF) {
241             PowerCC26X2_module.calStep = PowerCC26X2_STATE_CAL_LF_2;  /* next: trigger LF */
242         }
243 
244         /* else, start cleanup */
245         else {
246             PowerCC26X2_module.calStep = PowerCC26X2_STATE_CLEANUP; /* next: cleanup */
247         }
248     }
249 
250     /* ****** state = CAL_RCOSC_HF1: here when just finished 1st RCOSC_HF */
251     else if (PowerCC26X2_module.auxHwiState == CAL_RCOSC_HF1) {
252 
253         tdcResult = HWREG(AUX_TDC_BASE + AUX_TDC_O_RESULT);
254 
255 #if PowerCC26X2_INSTRUMENT_RCOSC_CALIBRATION
256         tdcResult_HF1 = tdcResult;
257         calHF1i = 1;
258 #endif
259 
260         /* use first HF measurement to setup new trim values */
261         calibrateRcoscHf1(tdcResult);
262 
263         /* if HF setting perfect, nothing more to do, calibration is done */
264         if ((tdcResult >= RCOSC_HF_LOW_THRESHOLD_TDC_VALUE) &&
265             (tdcResult <= RCOSC_HF_HIGH_THRESHOLD_TDC_VALUE)) {
266             PowerCC26X2_module.calStep = PowerCC26X2_STATE_CLEANUP;  /* next: cleanup */
267         }
268 
269         /* else, tweak trims, initiate another HF measurement */
270         else {
271 
272             PowerCC26X2_module.calStep = PowerCC26X2_STATE_CAL_HF1_2;  /* next: HF meas. #2 */
273         }
274     }
275 
276     /* ****** state = just finished second RCOSC_HF measurement ****** */
277     else if (PowerCC26X2_module.auxHwiState == CAL_RCOSC_HF2) {
278 
279         tdcResult = HWREG(AUX_TDC_BASE + AUX_TDC_O_RESULT);
280 
281 #if PowerCC26X2_INSTRUMENT_RCOSC_CALIBRATION
282         tdcResult_HF2 = tdcResult;
283 #endif
284         /* look for improvement on #2, else revert to previous trim values */
285         calibrateRcoscHf2(tdcResult);
286 
287         PowerCC26X2_module.calStep = PowerCC26X2_STATE_CLEANUP;    /* next: cleanup */
288     }
289 
290     /* do the next calibration step... */
291     PowerCC26X2_calibrate();
292 }
293 
294 /*
295  *  ======== PowerCC26X2_calibrate ========
296  */
PowerCC26X2_calibrate(void)297 void PowerCC26X2_calibrate(void)
298 {
299     PowerCC26X2_FsmResult fsmResult;
300 
301     do {
302         fsmResult = runCalibrateFsm();
303     } while (fsmResult == PowerCC26X2_FSM_RESULT_RUN_FSM);
304 
305     switch (fsmResult) {
306         case PowerCC26X2_FSM_RESULT_WAIT_FOR_TDC:
307             /* Intentional fall-through */
308         case PowerCC26X2_FSM_RESULT_DONE:
309             /* Do nothing. Calibration is complete or the
310              * TDC harware will execute in the background
311              * and continue the operation. */
312             break;
313         default:
314             /* Something went wrong. No good way to recover. */
315             while(1);
316     }
317 }
318 
319 /*
320  *  ======== runCalibrateFsm ========
321  *  Execute one state of the clock calibration FSM.
322  */
runCalibrateFsm(void)323 static PowerCC26X2_FsmResult runCalibrateFsm(void) {
324 
325     switch (PowerCC26X2_module.calStep) {
326 
327         case PowerCC26X2_STATE_TDC_INIT:
328 
329             /* Turn on TDC clock */
330             HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_TDCCLKCTL) = AUX_SYSIF_TDCCLKCTL_REQ;
331 
332             /* set saturation config to 2^24 */
333             HWREG(AUX_TDC_BASE + AUX_TDC_O_SATCFG) = AUX_TDC_SATCFG_LIMIT_R24;
334 
335             /* set start and stop trigger sources and polarity */
336             HWREG(AUX_TDC_BASE + AUX_TDC_O_TRIGSRC) =
337                 (AUX_TDC_TRIGSRC_STOP_SRC_ACLK_REF |
338                  AUX_TDC_TRIGSRC_STOP_POL_HIGH) |
339                 (AUX_TDC_TRIGSRC_START_SRC_ACLK_REF |
340                  AUX_TDC_TRIGSRC_START_POL_HIGH);
341 
342             /* set TDC_SRC clock to be XOSC_HF/2 = 24 MHz */
343             DDI16BitfieldWrite(AUX_DDI0_OSC_BASE,
344                                DDI_0_OSC_O_CTL0,
345                                DDI_0_OSC_CTL0_ACLK_TDC_SRC_SEL_M,
346                                DDI_0_OSC_CTL0_ACLK_TDC_SRC_SEL_S, 2);
347 
348             /* read back to ensure no race condition between OSC_DIG and AUX_SYSIF */
349             DDI16BitfieldRead(AUX_DDI0_OSC_BASE,
350                               DDI_0_OSC_O_CTL0,
351                               DDI_0_OSC_CTL0_ACLK_TDC_SRC_SEL_M,
352                               DDI_0_OSC_CTL0_ACLK_TDC_SRC_SEL_S);
353 
354             /* set AUX_SYSIF:TDCCLKCTL.REQ... */
355             HWREG(AUX_SYSIF_BASE +AUX_SYSIF_O_TDCCLKCTL) = AUX_SYSIF_TDCCLKCTL_REQ;
356 
357             /* finish wait for AUX_SYSIF:TDCCLKCTL.ACK to be set ... */
358             while(!(HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_TDCCLKCTL) &
359                 AUX_SYSIF_TDCCLKCTL_ACK));
360 
361             /* Enable trig count */
362             HWREG(AUX_TDC_BASE + AUX_TDC_O_TRIGCNTCFG) = AUX_TDC_TRIGCNTCFG_EN;
363 
364             /* if LF calibration enabled start LF measurement */
365             if (PowerCC26X2_module.calLF) {
366 
367                /* clear UPD_REQ, new sub-second increment is NOT available */
368                 HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_RTCSUBSECINCCTL) = 0;
369 
370                 /* set next Swi state */
371                 PowerCC26X2_module.calStep = PowerCC26X2_STATE_CAL_LF_1;
372             }
373 
374             /* else, start first HF measurement */
375             else {
376                 /* set next Swi state */
377                 PowerCC26X2_module.calStep = PowerCC26X2_STATE_CAL_HF1_1;
378             }
379 
380             /* abort TDC */
381             HWREG(AUX_TDC_BASE + AUX_TDC_O_CTL) = AUX_TDC_CTL_CMD_ABORT;
382 
383             /* clear AUX_SYSIFTDCREFCLKCTL.REQ... */
384             HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_TDCREFCLKCTL) = 0;
385 
386             /* finish wait for AUX_SYSIFTDCREFCLKCTL.ACK to be cleared ... */
387             while(HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_TDCREFCLKCTL) & AUX_SYSIF_TDCREFCLKCTL_ACK);
388 
389             return PowerCC26X2_FSM_RESULT_RUN_FSM;
390 
391         case PowerCC26X2_STATE_CAL_LF_1:
392 
393             /* set next Hwi state before triggering TDC */
394             PowerCC26X2_module.auxHwiState = CAL_RCOSC_LF;
395 
396             /* set the ACLK reference clock */
397             DDI16BitfieldWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_CTL0,
398                        DDI_0_OSC_CTL0_ACLK_REF_SRC_SEL_M,
399                        DDI_0_OSC_CTL0_ACLK_REF_SRC_SEL_S,
400                        ACLK_REF_SRC_RCOSC_LF);
401 
402             /* set AUX_SYSIFTDCREFCLKCTL.REQ */
403             HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_TDCREFCLKCTL) = AUX_SYSIF_TDCREFCLKCTL_REQ;
404 
405             /* Delay for ~110us total until TDCRECLKCTL_ACK is ready */
406             ClockP_start(ClockP_handle(&PowerCC26X2_module.calibrationClock));
407 
408             return PowerCC26X2_FSM_RESULT_WAIT_FOR_TDC;
409 
410         case PowerCC26X2_STATE_CAL_LF_2:
411 
412             PowerCC26X2_module.calStep = PowerCC26X2_STATE_CAL_HF1_1;
413 
414             /* clear AUX_SYSIFTDCREFCLKCTL.REQ... */
415             HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_TDCREFCLKCTL) = 0;
416 
417             /* wait for AUX_SYSIFTDCREFCLKCTL.ACK to be cleared ... */
418             while(HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_TDCREFCLKCTL) & AUX_SYSIF_TDCREFCLKCTL_ACK);
419 
420             return PowerCC26X2_FSM_RESULT_RUN_FSM;
421 
422         case PowerCC26X2_STATE_CAL_HF1_1:
423 
424             PowerCC26X2_module.auxHwiState = CAL_RCOSC_HF1;
425 
426             /* set the ACLK reference clock */
427             DDI16BitfieldWrite(AUX_DDI0_OSC_BASE,
428                                DDI_0_OSC_O_CTL0,
429                                DDI_0_OSC_CTL0_ACLK_REF_SRC_SEL_M,
430                                DDI_0_OSC_CTL0_ACLK_REF_SRC_SEL_S,
431                                ACLK_REF_SRC_RCOSC_HF);
432 
433             /* read back to ensure no race condition between OSC_DIG and AUX_SYSIF */
434             DDI16BitfieldRead(AUX_DDI0_OSC_BASE,
435                               DDI_0_OSC_O_CTL0,
436                               DDI_0_OSC_CTL0_ACLK_REF_SRC_SEL_M,
437                               DDI_0_OSC_CTL0_ACLK_REF_SRC_SEL_M);
438 
439             /* set AUX_SYSIFTDCREFCLKCTL.REQ */
440             HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_TDCREFCLKCTL) = AUX_SYSIF_TDCREFCLKCTL_REQ;
441 
442             /* Delay for ~110us total until TDCRECLKCTL_ACK is ready */
443             ClockP_start(ClockP_handle(&PowerCC26X2_module.calibrationClock));
444 
445             return PowerCC26X2_FSM_RESULT_WAIT_FOR_TDC;
446 
447         case PowerCC26X2_STATE_CAL_HF1_2:
448 
449             PowerCC26X2_module.calStep = PowerCC26X2_STATE_CAL_HF2;
450 
451             /* clear AUX_SYSIFTDCREFCLKCTL.REQ... */
452             HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_TDCREFCLKCTL) = 0;
453 
454             /* wait for AUX_SYSIFTDCREFCLKCTL.ACK to be cleared ... */
455             while(HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_TDCREFCLKCTL) & AUX_SYSIF_TDCREFCLKCTL_ACK);
456 
457             return PowerCC26X2_FSM_RESULT_RUN_FSM;
458 
459         case PowerCC26X2_STATE_CAL_HF2:
460 
461             PowerCC26X2_module.auxHwiState = CAL_RCOSC_HF2;
462 
463             /* set the ACLK reference clock */
464             DDI16BitfieldWrite(AUX_DDI0_OSC_BASE,
465                                DDI_0_OSC_O_CTL0,
466                                DDI_0_OSC_CTL0_ACLK_REF_SRC_SEL_M,
467                                DDI_0_OSC_CTL0_ACLK_REF_SRC_SEL_S,
468                                ACLK_REF_SRC_RCOSC_HF);
469 
470             /* read back to ensure no race condition between OSC_DIG and AUX_SYSIF */
471             DDI16BitfieldRead(AUX_DDI0_OSC_BASE,
472                               DDI_0_OSC_O_CTL0,
473                               DDI_0_OSC_CTL0_ACLK_REF_SRC_SEL_M,
474                               DDI_0_OSC_CTL0_ACLK_REF_SRC_SEL_M);
475 
476             /* set AUX_SYSIFTDCREFCLKCTL.REQ */
477             HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_TDCREFCLKCTL) = AUX_SYSIF_TDCREFCLKCTL_REQ;
478 
479             /* Delay for ~110us total until TDCRECLKCTL_ACK is ready */
480             ClockP_start(ClockP_handle(&PowerCC26X2_module.calibrationClock));
481 
482             return PowerCC26X2_FSM_RESULT_WAIT_FOR_TDC;
483 
484         case PowerCC26X2_STATE_CLEANUP:
485 
486             /* release the TDC clock request */
487             HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_TDCCLKCTL) = 0;
488 
489             /* release the TDC reference clock request */
490             HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_TDCREFCLKCTL) = 0;
491 
492             /* wait for AUX_SYSIF:TDCCLKCTL.ACK to be cleared ... */
493             while ((HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_TDCCLKCTL) &
494                 AUX_SYSIF_TDCCLKCTL_ACK));
495             /* wait for AUX_SYSIFTDCREFCLKCTL.ACK to be cleared ... */
496             while(HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_TDCREFCLKCTL) &
497                 AUX_SYSIF_TDCREFCLKCTL_ACK);
498 
499             /*
500             * Disable all interrupts as part of AUX_COMBINED interrupt
501             * Once we release semaphore, the sensor controller is allowed
502             * to use the TDC. When it does, we must ensure that this
503             * does not cause any unexpected interrupts to the CM3.
504             */
505             HWREG(AUX_EVCTL_BASE + AUX_EVCTL_O_COMBEVTOMCUMASK) = 0;
506 
507             /* release AUX semaphore */
508             HWREG(AUX_SMPH_BASE + AUX_SMPH_O_SMPH1) = 1;
509 
510             /* release the power down constraints and XOSC_HF dependency */
511             Power_releaseDependency(PowerCC26XX_XOSC_HF);
512             Power_releaseConstraint(PowerCC26XX_DISALLOW_STANDBY);
513 
514             /* set next state */
515             PowerCC26X2_module.calStep = PowerCC26X2_STATE_TDC_INIT;
516 
517 #if PowerCC26X2_INSTRUMENT_RCOSC_CALIBRATION
518             doneCal = true;
519             calHF2i = 1;
520 #endif
521             PowerCC26X2_module.busyCal = false;
522 
523             return PowerCC26X2_FSM_RESULT_DONE;
524 
525         default:
526             return PowerCC26X2_FSM_RESULT_ERROR;
527     }
528 }
529 
PowerCC26X2_RCOSC_clockFunc(uintptr_t arg)530 void PowerCC26X2_RCOSC_clockFunc(uintptr_t arg) {
531 
532     /* Wait any remaining time for TDCREFCLKCTL_ACK. Should not spin here at all. */
533     while(!(HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_TDCREFCLKCTL) & AUX_SYSIF_TDCREFCLKCTL_ACK));
534 
535     /* Set number of periods of ACLK to count */
536     if (PowerCC26X2_module.calStep == PowerCC26X2_STATE_CAL_LF_1) {
537         HWREG(AUX_TDC_BASE + AUX_TDC_O_TRIGCNTLOAD) = NUM_RCOSC_LF_PERIODS_TO_MEASURE;
538     }
539     else {
540         HWREG(AUX_TDC_BASE + AUX_TDC_O_TRIGCNTLOAD) = NUM_RCOSC_HF_PERIODS_TO_MEASURE;
541     }
542 
543     /* Reset/clear result of TDC */
544     HWREG(AUX_TDC_BASE + AUX_TDC_O_CTL) = AUX_TDC_CTL_CMD_CLR_RESULT;
545 
546     /* Clear possible pending interrupt source */
547     HWREG(AUX_EVCTL_BASE + AUX_EVCTL_O_EVTOMCUFLAGSCLR) = AUX_EVCTL_EVTOMCUFLAGSCLR_AUX_TDC_DONE;
548 
549     /* Enable TDC done interrupt as part of AUX_COMBINED interrupt */
550     HWREG(AUX_EVCTL_BASE + AUX_EVCTL_O_COMBEVTOMCUMASK) = AUX_EVCTL_EVTOMCUFLAGSCLR_AUX_TDC_DONE;
551 
552     /* Run TDC (start synchronously) */
553     HWREG(AUX_TDC_BASE + AUX_TDC_O_CTL) = AUX_TDC_CTL_CMD_RUN_SYNC_START;
554 }
555 
556 /*
557  *  ======== getTdcSemaphore ========
558  *  Get TDC semaphore (number 1)
559  */
getTdcSemaphore()560 static bool getTdcSemaphore()
561 {
562     unsigned int own;
563 
564     /* try to acquire SMPH */
565     own = HWREG(AUX_SMPH_BASE + AUX_SMPH_O_SMPH1);
566 
567     /* if acquired SMPH: done */
568     if (own != 0) {
569         return (true);
570     }
571 
572     /* clear the interrupt source, can only be cleared when we don't have semaphore */
573     HWREG(AUX_EVCTL_BASE + AUX_EVCTL_O_EVTOMCUFLAGSCLR) = AUX_EVCTL_EVTOMCUFLAGSCLR_AUX_SMPH_AUTOTAKE_DONE;
574 
575     /*
576      * else, did not acquire the semaphore, enable SMPH_AUTOTAKE_DONE event
577      * (don't OR, write entire register, no other interrupts can be enabled!)
578      */
579     HWREG(AUX_EVCTL_BASE + AUX_EVCTL_O_COMBEVTOMCUMASK) = AUX_EVCTL_COMBEVTOMCUMASK_AUX_SMPH_AUTOTAKE_DONE;
580 
581     /* start AUTOTAKE of semaphore for TDC access */
582     HWREG(AUX_SMPH_BASE + AUX_SMPH_O_AUTOTAKE) = AUX_TDC_SEMAPHORE_NUMBER;
583 
584     return (false);
585 }
586 
587 /*
588  *  ======== updateSubSecInc ========
589  *  Update the SUBSECINC register based on measured RCOSC_LF frequency
590  */
updateSubSecInc(uint32_t tdcResult)591 static void updateSubSecInc(uint32_t tdcResult)
592 {
593     int32_t newSubSecInc;
594     uint32_t oldSubSecInc;
595     uint32_t subSecInc;
596     int32_t hposcOffset;
597     int32_t hposcOffsetInv;
598 
599     /*
600      * Calculate the new SUBSECINC
601      * Here's the formula: AON_RTC:SUBSECINC = (45813 * NR) / 256
602      * Based on measuring 32 LF clock periods
603      */
604     newSubSecInc = (45813 * tdcResult) / 256;
605 
606     /* Compensate HPOSC drift if HPOSC is in use */
607     if(OSC_IsHPOSCEnabled()) {
608         /* Get the HPOSC relative offset at this temperature */
609         hposcOffset = OSC_HPOSCRelativeFrequencyOffsetGet(AONBatMonTemperatureGetDegC());
610         /* Convert to RF core format */
611         hposcOffsetInv = OSC_HPOSCRelativeFrequencyOffsetToRFCoreFormatConvert(hposcOffset);
612         /* Adjust SUBSECINC */
613         newSubSecInc += (((newSubSecInc >> 4) * (hposcOffsetInv >> 3)) >> 15);
614     }
615 
616     /* Apply filter, but not for first calibration */
617     if (PowerCC26X2_module.firstLF) {
618         /* Don't apply filter first time, to converge faster */
619         subSecInc = newSubSecInc;
620         /* No longer first measurement */
621         PowerCC26X2_module.firstLF = false;
622     }
623     else {
624         /* Read old SUBSECINC value */
625         oldSubSecInc = HWREG(AON_RTC_BASE + AON_RTC_O_SUBSECINC) & 0x00FFFFFF;
626         /* Apply filter, 0.5 times old value, 0.5 times new value */
627         subSecInc = (oldSubSecInc * 1 + newSubSecInc * 1) / 2;
628     }
629 
630     /* Update SUBSECINC values */
631     HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_RTCSUBSECINC0) = subSecInc;
632     HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_RTCSUBSECINC1) = subSecInc >> 16;
633 
634     /* update to use new values */
635     HWREG(AUX_SYSIF_BASE + AUX_SYSIF_O_RTCSUBSECINCCTL) = AUX_SYSIF_RTCSUBSECINCCTL_UPD_REQ;
636 }
637 
638 /*
639  *  ======== PowerCC26X2_calibrateRcoscHf1 ========
640  *  Calibrate RCOSC_HF agains XOSC_HF: compute and setup new trims
641  */
calibrateRcoscHf1(int32_t tdcResult)642 static void calibrateRcoscHf1(int32_t tdcResult)
643 {
644     /* *** STEP 1: Find RCOSC_HF-XOSC_HF frequency offset with current trim settings */
645     /* Read in current trim settings */
646     PowerCC26X2_module.nCtrimCurr =
647         (DDI32RegRead(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_RCOSCHFCTL) &
648         DDI_0_OSC_RCOSCHFCTL_RCOSCHF_CTRIM_M) >>
649         DDI_0_OSC_RCOSCHFCTL_RCOSCHF_CTRIM_S;
650 
651     PowerCC26X2_module.nCtrimFractCurr =
652         (DDI32RegRead(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_CTL1_LOCAL)
653         & DDI_0_OSC_CTL1_RCOSCHFCTRIMFRACT_LOCAL_M) >>
654         DDI_0_OSC_CTL1_RCOSCHFCTRIMFRACT_LOCAL_S;
655 
656     PowerCC26X2_module.nRtrimCurr =
657         (DDI32RegRead(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_ATESTCTL)
658         & DDI_0_OSC_ATESTCTL_SET_RCOSC_HF_FINE_RESISTOR_LOCAL_M) >>
659         DDI_0_OSC_ATESTCTL_SET_RCOSC_HF_FINE_RESISTOR_LOCAL_S;
660 
661 
662     /*
663      * Find RCOSC_HF-XOSC_HF frequency offset with current trim settings
664      *   Positive value => RCOSC_HF runs slow, CTRIM(FRACT) should be increased
665      *   Negative value => RCOSC_HF runs fast, CTRIM(FRACT) should be decreased
666      * Resolution: 31.25 kHz; CTRIMFRACT resolution ~30 kHz
667      */
668     PowerCC26X2_module.nDeltaFreqCurr = (int32_t) tdcResult - RCOSC_HF_PERFECT_TDC_VALUE;
669 
670     /* *** STEP 2: Attempt to calculate more optimal settings */
671     if (PowerCC26X2_module.nDeltaFreqCurr == 0) {
672         /* If perfect, don't perform second measurement and keep current settings */
673         PowerCC26X2_module.bRefine = false;
674         return;
675     }
676     if (PowerCC26X2_module.bRefine) {
677         /*
678          * Trying to find better match across CTRIM/RTRIM. Due to mismatches the
679          * first try might not have been more optimal than the current setting.
680          * Continue refining, starting from stored values
681          */
682     } else {
683         /* Start from current values */
684         PowerCC26X2_module.nCtrimFractNew = PowerCC26X2_module.nCtrimFractCurr;
685         PowerCC26X2_module.nCtrimNew      = PowerCC26X2_module.nCtrimCurr;
686         PowerCC26X2_module.nRtrimNew      = PowerCC26X2_module.nRtrimCurr;
687         PowerCC26X2_module.nDeltaFreqNew  = PowerCC26X2_module.nDeltaFreqCurr;
688     }
689 
690     /*
691      * Calculate change to CTRIMFRACT with safe assumptions of gain,
692      * apply delta to current CTRIMFRACT and convert to valid CTRIM/CTRIMFRACT
693      */
694     PowerCC26X2_module.nCtrimFractNew = PowerCC26X2_module.nCtrimFractNew +
695                                         Scale_rndInf(PowerCC26X2_module.nDeltaFreqNew);
696     PowerCC26X2_module.nCtrimNew = PowerCC26X2_module.nCtrimCurr;
697 
698     /* One step of CTRIM is about 500 kHz, so limit to one CTRIM step */
699     if (PowerCC26X2_module.nCtrimFractNew < 1) {
700         if (PowerCC26X2_module.nRtrimNew == 3) {
701             /* We try the slow RTRIM in this CTRIM first */
702             PowerCC26X2_module.nCtrimFractNew = Max(1, PowerCC26X2_module.nCtrimFractNew + 21);
703             PowerCC26X2_module.nRtrimNew = 0;
704         }
705         else {
706             /* Step down one CTRIM and use fast RTRIM */
707             PowerCC26X2_module.nCtrimFractNew = Max(1, PowerCC26X2_module.nCtrimFractNew + 32 - 21);
708             PowerCC26X2_module.nCtrimNew = Max(0, PowerCC26X2_module.nCtrimNew - 1);
709             PowerCC26X2_module.nRtrimNew = 3;
710         }
711     }
712     else if (PowerCC26X2_module.nCtrimFractNew > 30) {
713         if (PowerCC26X2_module.nRtrimNew == 0) {
714             /* We try the slow RTRIM in this CTRIM first */
715             PowerCC26X2_module.nCtrimFractNew = Min(30, PowerCC26X2_module.nCtrimFractNew - 21);
716             PowerCC26X2_module.nRtrimNew = 3;
717         }
718         else {
719             /* Step down one CTRIM and use fast RTRIM */
720             PowerCC26X2_module.nCtrimFractNew = Min(30, PowerCC26X2_module.nCtrimFractNew - 32 + 21);
721             PowerCC26X2_module.nCtrimNew = Min(0x3F, PowerCC26X2_module.nCtrimNew + 1);
722             PowerCC26X2_module.nRtrimNew = 0;
723         }
724     }
725     else
726     {
727         /* We're within sweet spot of current CTRIM => no change */
728     }
729 
730     /* Find RCOSC_HF vs XOSC_HF frequency offset with new trim settings */
731     DDI16BitfieldWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_RCOSCHFCTL,
732                            DDI_0_OSC_RCOSCHFCTL_RCOSCHF_CTRIM_M,
733                            DDI_0_OSC_RCOSCHFCTL_RCOSCHF_CTRIM_S,
734                            PowerCC26X2_module.nCtrimNew);
735 
736     /* Enable RCOSCHFCTRIMFRACT_EN */
737     DDI16BitfieldWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_CTL1_LOCAL,
738                            DDI_0_OSC_CTL1_RCOSCHFCTRIMFRACT_EN_LOCAL_M,
739                            DDI_0_OSC_CTL1_RCOSCHFCTRIMFRACT_EN_LOCAL_S,
740                            1);
741 
742     /* Modify CTRIM_FRACT */
743     DDI16BitfieldWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_CTL1_LOCAL,
744                            DDI_0_OSC_CTL1_RCOSCHFCTRIMFRACT_LOCAL_M,
745                            DDI_0_OSC_CTL1_RCOSCHFCTRIMFRACT_LOCAL_S,
746                            PowerCC26X2_module.nCtrimFractNew);
747 
748     /* Modify RTRIM */
749     DDI16BitfieldWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_ATESTCTL,
750                            DDI_0_OSC_ATESTCTL_SET_RCOSC_HF_FINE_RESISTOR_LOCAL_M,
751                            DDI_0_OSC_ATESTCTL_SET_RCOSC_HF_FINE_RESISTOR_LOCAL_S,
752                            PowerCC26X2_module.nRtrimNew);
753 }
754 
755 /*
756  *  ======== Power_calibrateRcoscHf2 ========
757  *  Calibrate RCOSC_HF agains XOSC_HF: determine better result, set new trims
758  */
calibrateRcoscHf2(int32_t tdcResult)759 static void calibrateRcoscHf2(int32_t tdcResult)
760 {
761 
762     PowerCC26X2_module.nDeltaFreqNew = (int32_t) tdcResult - RCOSC_HF_PERFECT_TDC_VALUE;
763     /* Calculate new delta freq */
764 
765     /* *** STEP 4: Determine whether the new settings are better or worse */
766     if (Abs(PowerCC26X2_module.nDeltaFreqNew) <= Abs(PowerCC26X2_module.nDeltaFreqCurr)) {
767         /* New settings are better or same -> make current by keeping in registers */
768         PowerCC26X2_module.bRefine = false;
769     }
770     else {
771         /* First measurement was better than second, restore current settings */
772         DDI16BitfieldWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_RCOSCHFCTL,
773                            DDI_0_OSC_RCOSCHFCTL_RCOSCHF_CTRIM_M,
774                            DDI_0_OSC_RCOSCHFCTL_RCOSCHF_CTRIM_S,
775                            PowerCC26X2_module.nCtrimCurr);
776 
777         DDI16BitfieldWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_CTL1_LOCAL,
778                            DDI_0_OSC_CTL1_RCOSCHFCTRIMFRACT_LOCAL_M,
779                            DDI_0_OSC_CTL1_RCOSCHFCTRIMFRACT_LOCAL_S,
780                            PowerCC26X2_module.nCtrimFractCurr);
781 
782         DDI16BitfieldWrite(AUX_DDI0_OSC_BASE, DDI_0_OSC_O_ATESTCTL,
783                            DDI_0_OSC_ATESTCTL_SET_RCOSC_HF_FINE_RESISTOR_LOCAL_M,
784                            DDI_0_OSC_ATESTCTL_SET_RCOSC_HF_FINE_RESISTOR_LOCAL_S,
785                            PowerCC26X2_module.nRtrimCurr);
786 
787         /* Enter a refinement mode where we keep searching for better matches */
788         PowerCC26X2_module.bRefine = true;
789     }
790 
791 }
792