1 /*
2  * Copyright 2022-2024 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_vbat.h"
9 
10 /*******************************************************************************
11  * Definitions
12  ******************************************************************************/
13 
14 /* Component ID definition, used by tools. */
15 #ifndef FSL_COMPONENT_ID
16 #define FSL_COMPONENT_ID "platform.drivers.mcx_vbat"
17 #endif
18 
19 /*******************************************************************************
20  * Prototypes
21  ******************************************************************************/
22 
23 /*******************************************************************************
24  * Variables
25  ******************************************************************************/
26 
27 /*******************************************************************************
28  * Code
29  ******************************************************************************/
30 
31 /*!
32  * brief Configure internal 16kHz free running oscillator, including enabel FRO16k, gate FRO16k output.
33  *
34  * param base VBAT peripheral base address.
35  * param config Pointer to vbat_fro16k_config_t structure.
36  */
VBAT_ConfigFRO16k(VBAT_Type * base,const vbat_fro16k_config_t * config)37 void VBAT_ConfigFRO16k(VBAT_Type *base, const vbat_fro16k_config_t *config)
38 {
39     assert(config != NULL);
40 
41     VBAT_EnableFRO16k(base, config->enableFRO16k);
42     VBAT_UngateFRO16k(base, config->enabledConnectionsMask);
43 }
44 
45 #if (defined(FSL_FEATURE_MCX_VBAT_HAS_OSCCTL_REG) && FSL_FEATURE_MCX_VBAT_HAS_OSCCTL_REG)
46 /*!
47  * brief Set 32k crystal oscillator mode and load capacitance for the XTAL/EXTAL pin.
48  *
49  * param base VBAT peripheral base address.
50  * param operateMode Specify the crystal oscillator mode, please refer to vbat_osc32k_operate_mode_t.
51  * param xtalCap Specify the internal capacitance for the XTAL pin from the capacitor bank.
52  * param extalCap Specify the internal capacitance for the EXTAL pin from the capacitor bank.
53  *
54  * retval kStatus_VBAT_WrongCapacitanceValue The load capacitance value to set is not align with operate mode's
55  * requirements.
56  * retval kStatus_Success Success to set operate mode and load capacitance.
57  */
VBAT_SetCrystalOsc32kModeAndLoadCapacitance(VBAT_Type * base,vbat_osc32k_operate_mode_t operateMode,vbat_osc32k_load_capacitance_select_t xtalCap,vbat_osc32k_load_capacitance_select_t extalCap)58 status_t VBAT_SetCrystalOsc32kModeAndLoadCapacitance(VBAT_Type *base,
59                                                      vbat_osc32k_operate_mode_t operateMode,
60                                                      vbat_osc32k_load_capacitance_select_t xtalCap,
61                                                      vbat_osc32k_load_capacitance_select_t extalCap)
62 {
63     if (operateMode == kVBAT_Osc32kEnabledToTransconductanceMode)
64     {
65         if (((uint8_t)extalCap & 0x1U) == 0U)
66         {
67             return kStatus_VBAT_WrongCapacitanceValue;
68         }
69     }
70 
71     if (operateMode == kVBAT_Osc32kEnabledToLowPowerSwitchedMode)
72     {
73         if ((extalCap != kVBAT_Osc32kCrystalLoadCap0pF) && (xtalCap != kVBAT_Osc32kCrystalLoadCap0pF))
74         {
75             return kStatus_VBAT_WrongCapacitanceValue;
76         }
77     }
78 
79     if (operateMode == kVBAT_Osc32kEnabledToLowPowerBackupMode)
80     {
81         if (((uint8_t)extalCap & 0x1U) != 0U)
82         {
83             return kStatus_VBAT_WrongCapacitanceValue;
84         }
85     }
86 
87     if ((xtalCap != kVBAT_Osc32kCrystalLoadCapBankDisabled) && (extalCap != kVBAT_Osc32kCrystalLoadCapBankDisabled))
88     {
89         base->OSCCTLA |= VBAT_OSCCTLA_CAP_SEL_EN_MASK;
90         base->OSCCTLB &= ~VBAT_OSCCTLA_CAP_SEL_EN_MASK;
91         base->OSCCTLA = ((base->OSCCTLA & ~(VBAT_OSCCTLA_EXTAL_CAP_SEL_MASK | VBAT_OSCCTLA_XTAL_CAP_SEL_MASK)) |
92                          (VBAT_OSCCTLA_XTAL_CAP_SEL(xtalCap) | VBAT_OSCCTLA_EXTAL_CAP_SEL(extalCap)));
93         base->OSCCTLB = ((base->OSCCTLB & ~(VBAT_OSCCTLA_EXTAL_CAP_SEL_MASK | VBAT_OSCCTLA_XTAL_CAP_SEL_MASK)) |
94                          VBAT_OSCCTLA_XTAL_CAP_SEL(~(uint32_t)xtalCap) | VBAT_OSCCTLA_EXTAL_CAP_SEL(~(uint32_t)extalCap));
95     }
96 
97     base->OSCCTLA = (((base->OSCCTLA & ~VBAT_OSCCTLA_MODE_EN_MASK)) | VBAT_OSCCTLA_MODE_EN(operateMode));
98     base->OSCCTLB = ((base->OSCCTLB & ~VBAT_OSCCTLA_MODE_EN_MASK) | VBAT_OSCCTLA_MODE_EN(~(uint32_t)operateMode));
99 
100     return kStatus_Success;
101 }
102 #endif /* FSL_FEATURE_MCX_VBAT_HAS_OSCCTL_REG */
103 
104 #if (defined(FSL_FEATURE_MCX_VBAT_HAS_LDOCTL_REG) && FSL_FEATURE_MCX_VBAT_HAS_LDOCTL_REG)
105 /*!
106  * brief Enable/disable Bandgap.
107  *
108  * note The FRO16K must be enabled before enableing the bandgap.
109  * note This setting can be locked by VBAT_LockRamLdoSettings() function.
110  *
111  * param base VBAT peripheral base address.
112  * param enable Used to enable/disable bandgap.
113  *      - \b true Enable the bandgap.
114  *      - \b false Disable the bandgap.
115  *
116  * retval kStatus_Success Success to enable/disable the bandgap.
117  * retval kStatus_VBAT_Fro16kNotEnabled Fail to enable the bandgap due to FRO16k is not enabled previously.
118  */
VBAT_EnableBandgap(VBAT_Type * base,bool enable)119 status_t VBAT_EnableBandgap(VBAT_Type *base, bool enable)
120 {
121     status_t status = kStatus_Success;
122 
123     if (enable)
124     {
125         if (VBAT_CheckFRO16kEnabled(base))
126         {
127             base->LDOCTLA |= VBAT_LDOCTLA_BG_EN_MASK;
128             base->LDOCTLB &= ~VBAT_LDOCTLA_BG_EN_MASK;
129         }
130         else
131         {
132             /* FRO16K must be enabled before enabling the Bandgap. */
133             status = kStatus_VBAT_Fro16kNotEnabled;
134         }
135     }
136     else
137     {
138         base->LDOCTLA &= ~VBAT_LDOCTLA_BG_EN_MASK;
139         base->LDOCTLB |= VBAT_LDOCTLA_BG_EN_MASK;
140     }
141 
142     return status;
143 }
144 
145 /*!
146  * brief Enable/disable Backup RAM Regulator(RAM_LDO).
147  *
148  * note This setting can be locked by VBAT_LockRamLdoSettings() function.
149  *
150  * param base VBAT peripheral base address.
151  * param enable Used to enable/disable RAM_LDO.
152  *          - \b true Enable backup SRAM regulator.
153  *          - \b false Disable backup SRAM regulator.
154  *
155  * retval kStatusSuccess Success to enable/disable backup SRAM regulator.
156  * retval kStatus_VBAT_Fro16kNotEnabled Fail to enable backup SRAM regulator due to FRO16k is not enabled previously.
157  * retval kStatus_VBAT_BandgapNotEnabled Fail to enable backup SRAM regulator due to the bandgap is not enabled
158  * previously.
159  */
VBAT_EnableBackupSRAMRegulator(VBAT_Type * base,bool enable)160 status_t VBAT_EnableBackupSRAMRegulator(VBAT_Type *base, bool enable)
161 {
162     status_t status = kStatus_Success;
163 
164     if (enable)
165     {
166         if (VBAT_CheckFRO16kEnabled(base))
167         {
168             if (VBAT_CheckBandgapEnabled(base))
169             {
170                 base->LDOCTLA |= VBAT_LDOCTLA_LDO_EN_MASK;
171                 base->LDOCTLB &= ~VBAT_LDOCTLA_LDO_EN_MASK;
172                 /* Polling until LDO is enabled. */
173                 while ((base->STATUSA & VBAT_STATUSA_LDO_RDY_MASK) == 0UL)
174                 {
175                 }
176             }
177             else
178             {
179                 /* The bandgap must be enabled previously. */
180                 status = kStatus_VBAT_BandgapNotEnabled;
181             }
182         }
183         else
184         {
185             /* FRO16k must be enabled previously. */
186             status = kStatus_VBAT_Fro16kNotEnabled;
187         }
188     }
189     else
190     {
191         base->LDOCTLA &= ~VBAT_LDOCTLA_LDO_EN_MASK;
192         base->LDOCTLB |= VBAT_LDOCTLA_LDO_EN_MASK;
193     }
194 
195     return status;
196 }
197 
198 /*!
199  * brief Switch the SRAM to be powered by VBAT.
200  *
201  * param base VBAT peripheral base address.
202  *
203  * retval kStatusSuccess Success to Switch SRAM powered by VBAT.
204  * retval kStatus_VBAT_Fro16kNotEnabled Fail to switch SRAM powered by VBAT due to FRO16K not enabled previously.
205  */
VBAT_SwitchSRAMPowerByLDOSRAM(VBAT_Type * base)206 status_t VBAT_SwitchSRAMPowerByLDOSRAM(VBAT_Type *base)
207 {
208     status_t status = kStatus_Success;
209 
210     status = VBAT_EnableBandgap(base, true);
211 
212     if (status == kStatus_Success)
213     {
214         VBAT_EnableBandgapRefreshMode(base, true);
215         (void)VBAT_EnableBackupSRAMRegulator(base, true);
216 
217         /* Isolate the SRAM array */
218         base->LDORAMC |= VBAT_LDORAMC_ISO_MASK;
219         /* Switch the supply to VBAT LDO. */
220         base->LDORAMC |= VBAT_LDORAMC_SWI_MASK;
221     }
222 
223     return status;
224 }
225 #endif /* FSL_FEATURE_MCX_VBAT_HAS_LDOCTL_REG */
226 
227 #if (defined(FSL_FEATURE_MCX_VBAT_HAS_BANDGAP_TIMER) && FSL_FEATURE_MCX_VBAT_HAS_BANDGAP_TIMER)
228 /*!
229  * brief Enable/disable Bandgap timer.
230  *
231  * note The bandgap timer is available when the bandgap is enabled and are clocked by the FRO16k.
232  *
233  * param base VBAT peripheral base address.
234  * param enable Used to enable/disable bandgap timer.
235  * param timerIdMask The mask of bandgap timer Id, should be the OR'ed value of vbat_bandgap_timer_id_t.
236  *
237  * retval kStatus_Success Success to enable/disable selected bandgap timer.
238  * retval kStatus_VBAT_Fro16kNotEnabled Fail to enable/disable selected bandgap timer due to FRO16k not enabled
239  * previously. retval kStatus_VBAT_BandgapNotEnabled Fail to enable/disable selected bandgap timer due to bandgap not
240  * enabled previously.
241  */
VBAT_EnableBandgapTimer(VBAT_Type * base,bool enable,uint8_t timerIdMask)242 status_t VBAT_EnableBandgapTimer(VBAT_Type *base, bool enable, uint8_t timerIdMask)
243 {
244     status_t status = kStatus_Success;
245 
246     if (enable)
247     {
248         if (VBAT_CheckFRO16kEnabled(base))
249         {
250             if (VBAT_CheckBandgapEnabled(base))
251             {
252                 if ((timerIdMask & (uint8_t)kVBAT_BandgapTimer0) != 0U)
253                 {
254                     base->LDOTIMER0 |= VBAT_LDOTIMER0_TIMEN_MASK;
255                 }
256 
257                 if ((timerIdMask & (uint8_t)kVBAT_BandgapTimer1) != 0U)
258                 {
259                     base->LDOTIMER1 |= VBAT_LDOTIMER1_TIMEN_MASK;
260                 }
261             }
262             else
263             {
264                 /* Bandgap must be enabled previously. */
265                 status = kStatus_VBAT_BandgapNotEnabled;
266             }
267         }
268         else
269         {
270             /* FRO16K must be enabled previously. */
271             status = kStatus_VBAT_Fro16kNotEnabled;
272         }
273     }
274     else
275     {
276         if ((timerIdMask & (uint8_t)kVBAT_BandgapTimer0) != 0U)
277         {
278             base->LDOTIMER0 &= ~VBAT_LDOTIMER0_TIMEN_MASK;
279         }
280 
281         if ((timerIdMask & (uint8_t)kVBAT_BandgapTimer1) != 0U)
282         {
283             base->LDOTIMER1 &= ~VBAT_LDOTIMER1_TIMEN_MASK;
284         }
285     }
286 
287     return status;
288 }
289 
290 /*!
291  * brief Set bandgap timer0 timeout value.
292  *
293  * param base VBAT peripheral base address.
294  * param timeoutPeriod Bandgap timer timeout value, please refer to vbat_bandgap_timer0_timeout_period_t.
295  */
VBAT_SetBandgapTimer0TimeoutValue(VBAT_Type * base,vbat_bandgap_timer0_timeout_period_t timeoutPeriod)296 void VBAT_SetBandgapTimer0TimeoutValue(VBAT_Type *base, vbat_bandgap_timer0_timeout_period_t timeoutPeriod)
297 {
298     bool timerEnabled = false;
299 
300     timerEnabled = ((base->LDOTIMER0 & VBAT_LDOTIMER0_TIMEN_MASK) != 0UL) ? true : false;
301 
302     if (timerEnabled)
303     {
304         base->LDOTIMER0 &= ~VBAT_LDOTIMER0_TIMEN_MASK;
305     }
306 
307     base->LDOTIMER0 = ((base->LDOTIMER0 & (~VBAT_LDOTIMER0_TIMCFG_MASK)) | VBAT_LDOTIMER0_TIMCFG(timeoutPeriod));
308 
309     if (timerEnabled)
310     {
311         base->LDOTIMER0 |= VBAT_LDOTIMER0_TIMEN_MASK;
312     }
313 }
314 
315 /*!
316  * brief Set bandgap timer1 timeout value.
317  *
318  * note The timeout value can only be changed when the timer is disabled.
319  *
320  * param base VBAT peripheral base address.
321  * param timeoutPeriod The bandgap timerout 1 period, in number of seconds, ranging from 0 to 65535s.
322  */
VBAT_SetBandgapTimer1TimeoutValue(VBAT_Type * base,uint32_t timeoutPeriod)323 void VBAT_SetBandgapTimer1TimeoutValue(VBAT_Type *base, uint32_t timeoutPeriod)
324 {
325     bool timerEnabled = false;
326 
327     timerEnabled = ((base->LDOTIMER1 & VBAT_LDOTIMER1_TIMEN_MASK) != 0UL) ? true : false;
328 
329     if (timerEnabled)
330     {
331         base->LDOTIMER1 &= ~VBAT_LDOTIMER1_TIMEN_MASK;
332     }
333 
334     base->LDOTIMER1 = ((base->LDOTIMER1 & (~VBAT_LDOTIMER1_TIMCFG_MASK)) | VBAT_LDOTIMER1_TIMCFG(timeoutPeriod));
335 
336     if (timerEnabled)
337     {
338         base->LDOTIMER1 |= VBAT_LDOTIMER1_TIMEN_MASK;
339     }
340 }
341 #endif /* FSL_FEATURE_MCX_VBAT_HAS_BANDGAP_TIMER */
342 
343 #if (defined(FSL_FEATURE_MCX_VBAT_HAS_CLKMON_REG) && FSL_FEATURE_MCX_VBAT_HAS_CLKMON_REG)
344 /*!
345  * brief Initializes the VBAT clock monitor, enable clock monitor and set the clock monitor configuration.
346  *
347  * note Both FRO16K and OSC32K should be enabled and stable before invoking this function.
348  *
349  * param base VBAT peripheral base address.
350  * param config Pointer to vbat_clock_monitor_config_t structure.
351  *
352  * retval kStatus_Success Clock monitor is initialized successfully.
353  * retval kStatus_VBAT_Fro16kNotEnabled FRO16K is not enabled.
354  * retval kStatus_VBAT_Osc32kNotReady OSC32K is not ready.
355  * retval kStatus_VBAT_ClockMonitorLocked Clock monitor is locked.
356  */
VBAT_InitClockMonitor(VBAT_Type * base,const vbat_clock_monitor_config_t * config)357 status_t VBAT_InitClockMonitor(VBAT_Type *base, const vbat_clock_monitor_config_t *config)
358 {
359     assert(config != NULL);
360 
361     status_t status = kStatus_Success;
362 
363     if (VBAT_CheckFRO16kEnabled(base))
364     {
365         if ((VBAT_GetStatusFlags(base) & kVBAT_StatusFlagOsc32kReady) != 0UL)
366         {
367             if (VBAT_CheckClockMonitorControlLocked(base))
368             {
369                 status = kStatus_VBAT_ClockMonitorLocked;
370             }
371             else
372             {
373                 /* Disable clock monitor before configuring clock monitor. */
374                 VBAT_EnableClockMonitor(base, false);
375                 /* Set clock monitor divide trim value. */
376                 VBAT_SetClockMonitorDivideTrim(base, config->divideTrim);
377                 /* Set clock monitor frequency trim value. */
378                 VBAT_SetClockMonitorFrequencyTrim(base, config->freqTrim);
379                 /* Enable clock monitor. */
380                 VBAT_EnableClockMonitor(base, true);
381 
382                 if (config->lock)
383                 {
384                     VBAT_LockClockMonitorControl(base);
385                 }
386             }
387         }
388         else
389         {
390             status = kStatus_VBAT_OSC32KNotReady;
391         }
392     }
393     else
394     {
395         status = kStatus_VBAT_Fro16kNotEnabled;
396     }
397 
398     return status;
399 }
400 
401 /*!
402  * brief Deinitialize the VBAT clock monitor.
403  *
404  * param base VBAT peripheral base address.
405  *
406  * retval kStatus_Success Clock monitor is de-initialized successfully.
407  * retval kStatus_VBAT_ClockMonitorLocked Control of Clock monitor is locked.
408  */
VBAT_DeinitMonitor(VBAT_Type * base)409 status_t VBAT_DeinitMonitor(VBAT_Type *base)
410 {
411     if (VBAT_CheckClockMonitorControlLocked(base))
412     {
413         return kStatus_VBAT_ClockMonitorLocked;
414     }
415 
416     VBAT_EnableClockMonitor(base, false);
417 
418     return kStatus_Success;
419 }
420 #endif /* FSL_FEATURE_MCX_VBAT_HAS_CLKMON_REG */
421 
422 #if (defined(FSL_FEATURE_MCX_VBAT_HAS_TAMPER_REG) && FSL_FEATURE_MCX_VBAT_HAS_TAMPER_REG)
423 /*!
424  * brief Initialize tamper control.
425  *
426  * note Both FRO16K and bandgap should be enabled before calling this function.
427  *
428  * param base VBAT peripheral base address.
429  * param config Pointer to vbat_tamper_config_t structure.
430  *
431  * retval kStatus_Success Tamper is initialized successfully.
432  * retval kStatus_VBAT_TamperLocked Tamper control is locked.
433  * retval kStatus_VBAT_BandgapNotEnabled Bandgap is not enabled.
434  * retval kStatus_VBAT_Fro16kNotEnabled FRO 16K is not enabled.
435  */
VBAT_InitTamper(VBAT_Type * base,const vbat_tamper_config_t * config)436 status_t VBAT_InitTamper(VBAT_Type *base, const vbat_tamper_config_t *config)
437 {
438     assert(config != NULL);
439 
440     status_t status = kStatus_Success;
441 
442     if (VBAT_CheckFRO16kEnabled(base))
443     {
444         if (VBAT_CheckBandgapEnabled(base))
445         {
446             if (VBAT_CheckTamperControlLocked(base))
447             {
448                 return kStatus_VBAT_TamperLocked;
449             }
450             else
451             {
452                 base->TAMCTLA = ((base->TAMCTLA & (~VBAT_TAMCTLA_VOLT_EN_MASK | VBAT_TAMCTLA_TEMP_EN_MASK)) |
453                                  VBAT_TAMCTLA_VOLT_EN(config->enableVoltageDetect) |
454                                  VBAT_TAMCTLA_TEMP_EN(config->enableTemperatureDetect));
455                 base->TAMCTLB = ((base->TAMCTLB & (~VBAT_TAMCTLA_VOLT_EN_MASK | VBAT_TAMCTLA_TEMP_EN_MASK)) |
456                                  VBAT_TAMCTLA_VOLT_EN((config->enableVoltageDetect) ? 0U : 1U) |
457                                  VBAT_TAMCTLA_TEMP_EN((config->enableTemperatureDetect) ? 0U : 1U));
458 
459                 if (config->lock)
460                 {
461                     VBAT_LockTamperControl(base);
462                 }
463             }
464         }
465         else
466         {
467             status = kStatus_VBAT_BandgapNotEnabled;
468         }
469     }
470     else
471     {
472         status = kStatus_VBAT_Fro16kNotEnabled;
473     }
474 
475     return status;
476 }
477 
478 /*!
479  * brief De-initialize tamper control.
480  *
481  * param base VBAT peripheral base address.
482  *
483  * retval kStatus_Success Tamper is de-initialized successfully.
484  * retval kStatus_VBAT_TamperLocked Tamper control is locked.
485  */
VBAT_DeinitTamper(VBAT_Type * base)486 status_t VBAT_DeinitTamper(VBAT_Type *base)
487 {
488     if (VBAT_CheckTamperControlLocked(base))
489     {
490         return kStatus_VBAT_TamperLocked;
491     }
492 
493     base->TAMCTLA &= ~(VBAT_TAMCTLA_VOLT_EN_MASK | VBAT_TAMCTLA_TEMP_EN_MASK);
494     base->TAMCTLB |= (VBAT_TAMCTLA_VOLT_EN_MASK | VBAT_TAMCTLA_TEMP_EN_MASK);
495 
496     return kStatus_Success;
497 }
498 #endif /* FSL_FEATURE_MCX_VBAT_HAS_TAMPER_REG */
499