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