1 /***************************************************************************//**
2  * @file
3  * @brief HFXO Manager HAL series 2 Devices.
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2019 Silicon Laboratories Inc. www.silabs.com</b>
7  *******************************************************************************
8  *
9  * SPDX-License-Identifier: Zlib
10  *
11  * The licensor of this software is Silicon Laboratories Inc.
12  *
13  * This software is provided 'as-is', without any express or implied
14  * warranty. In no event will the authors be held liable for any damages
15  * arising from the use of this software.
16  *
17  * Permission is granted to anyone to use this software for any purpose,
18  * including commercial applications, and to alter it and redistribute it
19  * freely, subject to the following restrictions:
20  *
21  * 1. The origin of this software must not be misrepresented; you must not
22  *    claim that you wrote the original software. If you use this software
23  *    in a product, an acknowledgment in the product documentation would be
24  *    appreciated but is not required.
25  * 2. Altered source versions must be plainly marked as such, and must not be
26  *    misrepresented as being the original software.
27  * 3. This notice may not be removed or altered from any source distribution.
28  *
29  ******************************************************************************/
30 #include "em_device.h"
31 #if defined(_SILICON_LABS_32B_SERIES_2)
32 #include "sl_assert.h"
33 #include "sl_core.h"
34 #include "sli_hfxo_manager.h"
35 #include "sl_hfxo_manager.h"
36 #include "sl_hfxo_manager_config.h"
37 #include "sl_status.h"
38 #include <stdbool.h>
39 
40 /*******************************************************************************
41  *********************************   DEFINES   *********************************
42  ******************************************************************************/
43 
44 #if (defined(SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT) \
45   && (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)   \
46   && defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT))
47 #error Component power_manager_deepsleep_blocking_hfxo_restore is not compatible with SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT configuration
48 #endif
49 
50 // Defines for hidden field FORCERAWCLK in HFXO_CTRL register
51 #define _HFXO_MANAGER_CTRL_FORCERAWCLK_SHIFT                  31
52 #define _HFXO_MANAGER_CTRL_FORCERAWCLK_MASK                   0x80000000UL
53 #define HFXO_MANAGER_CTRL_FORCERAWCLK                        (0x1UL << _HFXO_MANAGER_CTRL_FORCERAWCLK_SHIFT)
54 
55 // Defines for hidden PKDETCTRL register
56 #define HFXO_MANAGER_PKDETCTRL                                (*((volatile uint32_t *)(HFXO0_BASE + 0x34UL)))
57 #define _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT           8
58 #define _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK            0xF00UL
59 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V105MV          (0x00000000UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
60 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V132MV          (0x00000001UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
61 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V157MV          (0x00000002UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
62 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V184MV          (0x00000003UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
63 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V210MV          (0x00000004UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
64 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V236MV          (0x00000005UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
65 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V262MV          (0x00000006UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
66 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V289MV          (0x00000007UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
67 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V315MV          (0x00000008UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
68 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V341MV          (0x00000009UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
69 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V367MV          (0x0000000AUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
70 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V394MV          (0x0000000BUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
71 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V420MV          (0x0000000CUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
72 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V446MV          (0x0000000DUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
73 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V472MV          (0x0000000EUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
74 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V499MV          (0x0000000FUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
75 
76 // IRQ Name depending on devices
77 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
78 #define HFXO_IRQ_NUMBER  HFXO00_IRQn
79 #define HFXO_IRQ_HANDLER_FUNCTION  HFXO00_IRQHandler
80 #else
81 #define HFXO_IRQ_NUMBER  HFXO0_IRQn
82 #define HFXO_IRQ_HANDLER_FUNCTION  HFXO0_IRQHandler
83 #endif
84 
85 // Default values for the Sleepy Crystal settings
86 // Should be enough to guaranty HFXO startup
87 #define SLEEPY_XTAL_SETTING_DEFAULT_PKDETTHSTARTUPI  HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V157MV
88 #define SLEEPY_XTAL_SETTING_DEFAULT_CTUNEANA         100u
89 #define SLEEPY_XTAL_SETTING_DEFAULT_COREBIAS         255u
90 
91 /*******************************************************************************
92  ***************************  LOCAL VARIABLES   ********************************
93  ******************************************************************************/
94 
95 // Error flag to indicate if we failed the startup process
96 static volatile bool error_flag = false;
97 
98 #if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
99 // Error retry counter
100 static volatile uint8_t error_try_cnt = 0;
101 
102 // Error State status
103 static volatile bool in_error_state = false;
104 
105 // Variables to save normal settings
106 static uint32_t pkdettusstartupi_saved;
107 static uint32_t ctunexiana_saved;
108 static uint32_t ctunexoana_saved;
109 static uint32_t corebiasana_saved;
110 static uint32_t corebiasstartup_saved;
111 static uint32_t corebiasstartupi_saved;
112 
113 // Variables for Sleepy Crystal settings
114 static uint32_t sleepy_xtal_settings_pkdettusstartupi = SLEEPY_XTAL_SETTING_DEFAULT_PKDETTHSTARTUPI; // Value already shifted
115 static uint32_t sleepy_xtal_settings_ctuneana = SLEEPY_XTAL_SETTING_DEFAULT_CTUNEANA;
116 static uint32_t sleepy_xtal_settings_corebias = SLEEPY_XTAL_SETTING_DEFAULT_COREBIAS;
117 #endif
118 
119 /***************************************************************************//**
120  * HFXO ready notification callback for internal use with power manager
121  ******************************************************************************/
122 __WEAK void sli_hfxo_manager_notify_ready_for_power_manager(void);
123 
124 /***************************************************************************//**
125  * HFXO PRS ready notification callback for internal use with power manager
126  ******************************************************************************/
127 __WEAK void sli_hfxo_notify_ready_for_power_manager_from_prs(void);
128 
129 /***************************************************************************//**
130  * Hardware specific initialization.
131  ******************************************************************************/
sli_hfxo_manager_init_hardware(void)132 void sli_hfxo_manager_init_hardware(void)
133 {
134   // Increase HFXO Interrupt priority so that it won't be masked by BASEPRI
135   // and will preempt other interrupts.
136   NVIC_SetPriority(HFXO_IRQ_NUMBER, CORE_ATOMIC_BASE_PRIORITY_LEVEL - 1);
137 
138   // Enable HFXO Interrupt if HFXO is used
139 #if _SILICON_LABS_32B_SERIES_2_CONFIG >= 2
140   CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
141 #endif
142 
143   HFXO0->IEN_CLR = HFXO_IEN_RDY | HFXO_IEN_DNSERR | HFXO_IEN_COREBIASOPTERR;
144 #if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
145   HFXO0->IEN_CLR = HFXO_IEN_PRSRDY;
146 #endif
147 
148   HFXO0->IF_CLR = HFXO_IF_RDY | HFXO_IF_DNSERR | HFXO_IEN_COREBIASOPTERR;
149 #if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
150   HFXO0->IF_CLR = HFXO_IF_PRSRDY;
151 #endif
152 
153   NVIC_ClearPendingIRQ(HFXO_IRQ_NUMBER);
154   NVIC_EnableIRQ(HFXO_IRQ_NUMBER);
155 
156   HFXO0->IEN_SET = HFXO_IEN_RDY | HFXO_IEN_DNSERR | HFXO_IEN_COREBIASOPTERR;
157 
158 #if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
159   HFXO0->IEN_SET = HFXO_IEN_PRSRDY;
160   HFXO0->CTRL &= ~(_HFXO_CTRL_DISONDEMANDPRS_MASK & HFXO_CTRL_DISONDEMANDPRS_DEFAULT);
161   HFXO0->CTRL |= HFXO_CTRL_PRSSTATUSSEL1_ENS;
162 #endif
163 }
164 
165 /***************************************************************************//**
166  * Updates sleepy crystal settings in specific hardware registers.
167  ******************************************************************************/
sli_hfxo_manager_update_sleepy_xtal_settings_hardware(const sl_hfxo_manager_sleepy_xtal_settings_t * settings)168 sl_status_t sli_hfxo_manager_update_sleepy_xtal_settings_hardware(const sl_hfxo_manager_sleepy_xtal_settings_t *settings)
169 {
170 #if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
171   EFM_ASSERT(settings->ana_ctune <= (_HFXO_XTALCTRL_CTUNEXIANA_MASK >> _HFXO_XTALCTRL_CTUNEXIANA_SHIFT));
172   EFM_ASSERT(settings->core_bias_current <= (_HFXO_XTALCTRL_COREBIASANA_MASK >> _HFXO_XTALCTRL_COREBIASANA_SHIFT));
173 
174   sleepy_xtal_settings_ctuneana = settings->ana_ctune;
175   sleepy_xtal_settings_corebias = settings->core_bias_current;
176 
177   return SL_STATUS_OK;
178 #else
179   (void)settings;
180   return SL_STATUS_NOT_AVAILABLE;
181 #endif
182 }
183 
184 /***************************************************************************//**
185  * Checks if HFXO is ready and, if needed, waits for it to be.
186  *
187  * @note This will also make sure we are not in the process of restarting HFXO
188  *       with different settings.
189  ******************************************************************************/
sli_hfxo_manager_is_hfxo_ready(bool wait)190 bool sli_hfxo_manager_is_hfxo_ready(bool wait)
191 {
192   bool ready = false;
193 
194   do {
195 #if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
196     ready = (((HFXO0->STATUS & (HFXO_STATUS_RDY | HFXO_STATUS_PRSRDY)) != 0) && !error_flag) ? true : false;
197 #else
198     ready = (((HFXO0->STATUS & HFXO_STATUS_RDY) != 0) && !error_flag) ? true : false;
199 #endif
200   } while (!ready && wait);
201 
202   return ready;
203 }
204 
205 #if (SL_HFXO_MANAGER_CUSTOM_HFXO_IRQ_HANDLER == 0)
206 /*******************************************************************************
207  * HFXO interrupt handler.
208  *
209  * @note  The HFXOx_IRQHandler provided by HFXO Manager will call
210  *        @ref sl_hfxo_manager_irq_handler. Configure SL_HFXO_MANAGER_CUSTOM_HFXO_IRQ_HANDLER
211  *        if the application wants to implement its own HFXOx_IRQHandler.
212  ******************************************************************************/
HFXO_IRQ_HANDLER_FUNCTION(void)213 void HFXO_IRQ_HANDLER_FUNCTION(void)
214 {
215   sl_hfxo_manager_irq_handler();
216 }
217 #endif
218 
219 /*******************************************************************************
220  * HFXO Manager HFXO interrupt handler.
221  ******************************************************************************/
sl_hfxo_manager_irq_handler(void)222 void sl_hfxo_manager_irq_handler(void)
223 {
224   uint32_t irq_flag = HFXO0->IF;
225 #if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
226   bool disondemand =  (HFXO0->CTRL & _HFXO_CTRL_DISONDEMAND_MASK) ? true : false;
227   bool forceen = (HFXO0->CTRL & _HFXO_CTRL_FORCEEN_MASK) ? true : false;
228 #endif
229 
230 #if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
231   if (irq_flag & HFXO_IF_PRSRDY) {
232     // Clear PRS RDY flag and EM23ONDEMAND
233     HFXO0->IF_CLR = irq_flag & HFXO_IF_PRSRDY;
234     HFXO0->CTRL_CLR = HFXO_CTRL_EM23ONDEMAND;
235 
236     // Only retrieve start of measurement if HFXO is not already ready.
237     if ((HFXO0->STATUS & HFXO_STATUS_RDY) == 0) {
238       sli_hfxo_manager_retrieve_begining_startup_measurement();
239     }
240 
241     // Notify power manager HFXO is ready
242     sli_hfxo_notify_ready_for_power_manager_from_prs();
243     sli_hfxo_manager_notify_ready_for_power_manager();
244 
245     // Update sleep on isr exit flag
246     sli_sleeptimer_update_sleep_on_isr_exit(true);
247 
248     // Reset PRS signal through Sleeptimer
249     sli_sleeptimer_reset_prs_signal();
250   }
251 #endif
252 
253   // RDY Interrupt Flag Handling
254   if (irq_flag & HFXO_IF_RDY) {
255     // Clear Ready flag
256     HFXO0->IF_CLR = irq_flag & HFXO_IF_RDY;
257 
258 #if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
259     if (error_flag) {
260       // Clear error flag, i.e. we successfully stated HFXO with the modified settings
261       error_flag = false;
262 
263       // If it's the first time we succeed after an error, try back the normal settings
264       if (error_try_cnt <= 1) {
265         // Disable HFXO.
266         HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
267         HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
268 
269         while ((HFXO0->STATUS & HFXO_STATUS_ENS) != 0) {
270         }
271 
272         // Put back normal settings
273         HFXO_MANAGER_PKDETCTRL = (HFXO_MANAGER_PKDETCTRL & ~_HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK) | pkdettusstartupi_saved;
274         HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~(_HFXO_XTALCTRL_CTUNEXIANA_MASK | _HFXO_XTALCTRL_CTUNEXOANA_MASK))
275                           | ctunexiana_saved
276                           | ctunexoana_saved;
277         HFXO0->XTALCFG = (HFXO0->XTALCFG & ~(_HFXO_XTALCFG_COREBIASSTARTUPI_MASK | _HFXO_XTALCFG_COREBIASSTARTUP_MASK))
278                          | corebiasstartup_saved
279                          | corebiasstartupi_saved;
280         HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~_HFXO_XTALCTRL_COREBIASANA_MASK) | corebiasana_saved;
281 
282         // Put back FORCEEN and DISONDEMAND state
283         if (!disondemand) {
284           HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
285         } else {
286           HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
287         }
288         if (forceen) {
289           HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
290         } else {
291           HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
292         }
293       } else {
294         // Call notification function to tell users that sleepy crystal settings are kept
295         // This should only happen if you are in test condition or if you have a bad crystal.
296         sl_hfxo_manager_notify_consecutive_failed_startups();
297         in_error_state = true;
298       }
299     } else {
300       sli_hfxo_manager_end_startup_measurement();
301 
302       sli_hfxo_manager_notify_ready_for_power_manager();
303 
304       // Clear counter since we successfully started HFXO with normal settings
305       // or we are just keeping sleepy crystal settings indefinitely.
306       error_try_cnt = 0;
307     }
308 #else
309     sli_hfxo_manager_end_startup_measurement();
310 
311     sli_hfxo_manager_notify_ready_for_power_manager();
312 #endif
313   }
314 
315   // DNSERR Interrupt Flag Handling
316   if (irq_flag & HFXO_IF_DNSERR) {
317     // Clear error flag
318     HFXO0->IF_CLR = irq_flag & HFXO_IF_DNSERR;
319 
320 #if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
321     // We should not fail twice in a row
322     EFM_ASSERT(error_flag == false);
323 
324     // Update global variables related to error.
325     error_flag = true;
326     error_try_cnt++;
327 
328     // Save current settings
329     pkdettusstartupi_saved = (HFXO_MANAGER_PKDETCTRL & _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK);
330     ctunexiana_saved = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_CTUNEXIANA_MASK);
331     ctunexoana_saved = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_CTUNEXOANA_MASK);
332     corebiasana_saved = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_COREBIASANA_MASK);
333     corebiasstartup_saved = (HFXO0->XTALCFG & _HFXO_XTALCFG_COREBIASSTARTUP_MASK);
334     corebiasstartupi_saved = (HFXO0->XTALCFG & _HFXO_XTALCFG_COREBIASSTARTUPI_MASK);
335 
336     // Disable HFXO.
337     HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
338     HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
339 
340     // Use FORCERAWCLK bit to exit error state when disabling
341     HFXO0->CTRL_SET = HFXO_MANAGER_CTRL_FORCERAWCLK;
342     while ((HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) != 0U) {
343     }
344     HFXO0->CTRL_CLR = HFXO_MANAGER_CTRL_FORCERAWCLK;
345 
346     // Change settings:
347     //Reduce Peak Detection Threshold for Startup Intermediate stage to 2 (V157MV)
348     HFXO_MANAGER_PKDETCTRL = (HFXO_MANAGER_PKDETCTRL & ~_HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK) | sleepy_xtal_settings_pkdettusstartupi;
349     // Reduce CTUNE values for steady stage
350     if (((ctunexiana_saved >> _HFXO_XTALCTRL_CTUNEXIANA_SHIFT) > 100)
351         || ((ctunexoana_saved >> _HFXO_XTALCTRL_CTUNEXOANA_SHIFT) > 100)) {
352       HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~(_HFXO_XTALCTRL_CTUNEXIANA_MASK | _HFXO_XTALCTRL_CTUNEXOANA_MASK))
353                         | (sleepy_xtal_settings_ctuneana << _HFXO_XTALCTRL_CTUNEXIANA_SHIFT)
354                         | (sleepy_xtal_settings_ctuneana << _HFXO_XTALCTRL_CTUNEXOANA_SHIFT);
355     }
356     // Increase core bias current at all stages
357     HFXO0->XTALCFG = (HFXO0->XTALCFG & ~(_HFXO_XTALCFG_COREBIASSTARTUPI_MASK | _HFXO_XTALCFG_COREBIASSTARTUP_MASK))
358                      | ((sleepy_xtal_settings_corebias >> 2) << _HFXO_XTALCFG_COREBIASSTARTUPI_SHIFT)
359                      | ((sleepy_xtal_settings_corebias >> 2) << _HFXO_XTALCFG_COREBIASSTARTUP_SHIFT);
360     HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~_HFXO_XTALCTRL_COREBIASANA_MASK)
361                       | (sleepy_xtal_settings_corebias << _HFXO_XTALCTRL_COREBIASANA_SHIFT);
362 
363     // Put back FORCEEN and DISONDEMAND state
364     if (!disondemand) {
365       HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
366     } else {
367       HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
368     }
369     if (forceen) {
370       HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
371     } else {
372       HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
373     }
374 #endif
375   }
376 
377   if (irq_flag & HFXO_IF_COREBIASOPTERR) {
378     // Clear Core Bias Optimization error flag
379     HFXO0->IF_CLR = irq_flag & HFXO_IF_COREBIASOPTERR;
380 
381 #if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
382     // In case the Core Bias Optimization fails during error handling,
383     // we disable it
384     if (in_error_state == true) {
385       // Disable HFXO.
386       HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
387       HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
388 
389       while ((HFXO0->STATUS & HFXO_STATUS_ENS) != 0) {
390       }
391 
392       // Skip Core Bias Optimization in case of error
393       HFXO0->XTALCTRL_SET = HFXO_XTALCTRL_SKIPCOREBIASOPT;
394 
395       // Put back FORCEEN and DISONDEMAND state
396       if (!disondemand) {
397         HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
398       } else {
399         HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
400       }
401       if (forceen) {
402         HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
403       } else {
404         HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
405       }
406     }
407 #endif
408   }
409 }
410 #endif // _SILICON_LABS_32B_SERIES_2
411