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 "sli_hfxo_manager.h"
34 #include "sl_hfxo_manager.h"
35 #include "sl_hfxo_manager_config.h"
36 #include "sl_status.h"
37 #include <stdbool.h>
38
39 /*******************************************************************************
40 ********************************* DEFINES *********************************
41 ******************************************************************************/
42
43 #if (defined(SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT) \
44 && (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1) \
45 && defined(SL_CATALOG_POWER_MANAGER_DEEPSLEEP_BLOCKING_HFXO_RESTORE_PRESENT))
46 #error Component power_manager_deepsleep_blocking_hfxo_restore is not compatible with SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT configuration
47 #endif
48
49 // Defines for hidden field FORCERAWCLK in HFXO_CTRL register
50 #define _HFXO_MANAGER_CTRL_FORCERAWCLK_SHIFT 31
51 #define _HFXO_MANAGER_CTRL_FORCERAWCLK_MASK 0x80000000UL
52 #define HFXO_MANAGER_CTRL_FORCERAWCLK (0x1UL << _HFXO_MANAGER_CTRL_FORCERAWCLK_SHIFT)
53
54 // Defines for hidden PKDETCTRL register
55 #define HFXO_MANAGER_PKDETCTRL (*((volatile uint32_t *)(HFXO0_BASE + 0x34UL)))
56 #define _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT 8
57 #define _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK 0xF00UL
58 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V105MV (0x00000000UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
59 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V132MV (0x00000001UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
60 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V157MV (0x00000002UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
61 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V184MV (0x00000003UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
62 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V210MV (0x00000004UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
63 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V236MV (0x00000005UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
64 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V262MV (0x00000006UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
65 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V289MV (0x00000007UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
66 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V315MV (0x00000008UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
67 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V341MV (0x00000009UL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
68 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V367MV (0x0000000AUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
69 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V394MV (0x0000000BUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
70 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V420MV (0x0000000CUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
71 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V446MV (0x0000000DUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
72 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V472MV (0x0000000EUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
73 #define HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V499MV (0x0000000FUL << _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_SHIFT)
74
75 // IRQ Name depending on devices
76 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
77 #define HFXO_IRQ_NUMBER HFXO00_IRQn
78 #define HFXO_IRQ_HANDLER_FUNCTION HFXO00_IRQHandler
79 #else
80 #define HFXO_IRQ_NUMBER HFXO0_IRQn
81 #define HFXO_IRQ_HANDLER_FUNCTION HFXO0_IRQHandler
82 #endif
83
84 // Default values for the Sleepy Crystal settings
85 // Should be enough to guaranty HFXO startup
86 #define SLEEPY_XTAL_SETTING_DEFAULT_PKDETTHSTARTUPI HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_V157MV
87 #define SLEEPY_XTAL_SETTING_DEFAULT_CTUNEANA 100u
88 #define SLEEPY_XTAL_SETTING_DEFAULT_COREBIAS 255u
89
90 /*******************************************************************************
91 *************************** LOCAL VARIABLES ********************************
92 ******************************************************************************/
93
94 // Error flag to indicate if we failed the startup process
95 static bool error_flag = false;
96
97 #if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
98 // Error retry counter
99 static uint8_t error_try_cnt = 0;
100
101 // Error State status
102 static bool in_error_state = false;
103
104 // Variables to save normal settings
105 static uint32_t pkdettusstartupi_saved;
106 static uint32_t ctunexiana_saved;
107 static uint32_t ctunexoana_saved;
108 static uint32_t corebiasana_saved;
109 static uint32_t corebiasstartup_saved;
110 static uint32_t corebiasstartupi_saved;
111
112 // Variables for Sleepy Crystal settings
113 static uint32_t sleepy_xtal_settings_pkdettusstartupi = SLEEPY_XTAL_SETTING_DEFAULT_PKDETTHSTARTUPI; // Value already shifted
114 static uint32_t sleepy_xtal_settings_ctuneana = SLEEPY_XTAL_SETTING_DEFAULT_CTUNEANA;
115 static uint32_t sleepy_xtal_settings_corebias = SLEEPY_XTAL_SETTING_DEFAULT_COREBIAS;
116 #endif
117
118 /***************************************************************************//**
119 * HFXO ready notification callback for internal use with power manager
120 ******************************************************************************/
121 __WEAK void sli_hfxo_manager_notify_ready_for_power_manager(void);
122
123 /***************************************************************************//**
124 * HFXO PRS ready notification callback for internal use with power manager
125 ******************************************************************************/
126 __WEAK void sli_hfxo_notify_ready_for_power_manager_from_prs(void);
127
128 /***************************************************************************//**
129 * Hardware specific initialization.
130 ******************************************************************************/
sli_hfxo_manager_init_hardware(void)131 void sli_hfxo_manager_init_hardware(void)
132 {
133 // Increase HFXO Interrupt priority so that it won't be masked by BASEPRI
134 // and will preempt other interrupts.
135 NVIC_SetPriority(HFXO_IRQ_NUMBER, 2);
136
137 // Enable HFXO Interrupt if HFXO is used
138 #if _SILICON_LABS_32B_SERIES_2_CONFIG >= 2
139 CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
140 #endif
141
142 HFXO0->IEN_CLR = HFXO_IEN_RDY | HFXO_IEN_DNSERR | HFXO_IEN_COREBIASOPTERR;
143 #if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
144 HFXO0->IEN_CLR = HFXO_IEN_PRSRDY;
145 #endif
146
147 HFXO0->IF_CLR = HFXO_IF_RDY | HFXO_IF_DNSERR | HFXO_IEN_COREBIASOPTERR;
148 #if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
149 HFXO0->IF_CLR = HFXO_IF_PRSRDY;
150 #endif
151
152 NVIC_ClearPendingIRQ(HFXO_IRQ_NUMBER);
153 NVIC_EnableIRQ(HFXO_IRQ_NUMBER);
154
155 HFXO0->IEN_SET = HFXO_IEN_RDY | HFXO_IEN_DNSERR | HFXO_IEN_COREBIASOPTERR;
156
157 #if defined(HFXO_MANAGER_SLEEPTIMER_SYSRTC_INTEGRATION_ON)
158 HFXO0->IEN_SET = HFXO_IEN_PRSRDY;
159 HFXO0->CTRL &= ~(_HFXO_CTRL_DISONDEMANDPRS_MASK & HFXO_CTRL_DISONDEMANDPRS_DEFAULT);
160 HFXO0->CTRL |= HFXO_CTRL_PRSSTATUSSEL1_ENS;
161 #endif
162 }
163
164 /***************************************************************************//**
165 * Updates sleepy crystal settings in specific hardware registers.
166 ******************************************************************************/
sli_hfxo_manager_update_sleepy_xtal_settings_hardware(sl_hfxo_manager_sleepy_xtal_settings_t * settings)167 sl_status_t sli_hfxo_manager_update_sleepy_xtal_settings_hardware(sl_hfxo_manager_sleepy_xtal_settings_t *settings)
168 {
169 (void)settings;
170
171 #if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
172 EFM_ASSERT(settings->ana_ctune <= (_HFXO_XTALCTRL_CTUNEXIANA_MASK >> _HFXO_XTALCTRL_CTUNEXIANA_SHIFT));
173 EFM_ASSERT(settings->core_bias_current <= (_HFXO_XTALCTRL_COREBIASANA_MASK >> _HFXO_XTALCTRL_COREBIASANA_SHIFT));
174
175 sleepy_xtal_settings_ctuneana = settings->ana_ctune;
176 sleepy_xtal_settings_corebias = settings->core_bias_current;
177
178 return SL_STATUS_OK;
179 #else
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 sli_hfxo_manager_retrieve_begining_startup_measurement();
237
238 // Notify power manager HFXO is ready
239 sli_hfxo_notify_ready_for_power_manager_from_prs();
240 sli_hfxo_manager_notify_ready_for_power_manager();
241
242 // Update sleep on isr exit flag
243 sli_sleeptimer_update_sleep_on_isr_exit(true);
244
245 // Reset PRS signal through Sleeptimer
246 sli_sleeptimer_reset_prs_signal();
247 }
248 #endif
249
250 // RDY Interrupt Flag Handling
251 if (irq_flag & HFXO_IF_RDY) {
252 // Clear Ready flag
253 HFXO0->IF_CLR = irq_flag & HFXO_IF_RDY;
254
255 #if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
256 if (error_flag) {
257 // Clear error flag, i.e. we successfully stated HFXO with the modified settings
258 error_flag = false;
259
260 // If it's the first time we succeed after an error, try back the normal settings
261 if (error_try_cnt <= 1) {
262 // Disable HFXO.
263 HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
264 HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
265
266 while ((HFXO0->STATUS & HFXO_STATUS_ENS) != 0) {
267 }
268
269 // Put back normal settings
270 HFXO_MANAGER_PKDETCTRL = (HFXO_MANAGER_PKDETCTRL & ~_HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK) | pkdettusstartupi_saved;
271 HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~(_HFXO_XTALCTRL_CTUNEXIANA_MASK | _HFXO_XTALCTRL_CTUNEXOANA_MASK))
272 | ctunexiana_saved
273 | ctunexoana_saved;
274 HFXO0->XTALCFG = (HFXO0->XTALCFG & ~(_HFXO_XTALCFG_COREBIASSTARTUPI_MASK | _HFXO_XTALCFG_COREBIASSTARTUP_MASK))
275 | corebiasstartup_saved
276 | corebiasstartupi_saved;
277 HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~_HFXO_XTALCTRL_COREBIASANA_MASK) | corebiasana_saved;
278
279 // Put back FORCEEN and DISONDEMAND state
280 if (!disondemand) {
281 HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
282 } else {
283 HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
284 }
285 if (forceen) {
286 HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
287 } else {
288 HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
289 }
290 } else {
291 // Call notification function to tell users that sleepy crystal settings are kept
292 // This should only happen if you are in test condition or if you have a bad crystal.
293 sl_hfxo_manager_notify_consecutive_failed_startups();
294 in_error_state = true;
295 }
296 } else {
297 sli_hfxo_manager_end_startup_measurement();
298
299 sli_hfxo_manager_notify_ready_for_power_manager();
300
301 // Clear counter since we successfully started HFXO with normal settings
302 // or we are just keeping sleepy crystal settings indefinitely.
303 error_try_cnt = 0;
304 }
305 #else
306 sli_hfxo_manager_end_startup_measurement();
307
308 sli_hfxo_manager_notify_ready_for_power_manager();
309 #endif
310 }
311
312 // DNSERR Interrupt Flag Handling
313 if (irq_flag & HFXO_IF_DNSERR) {
314 // Clear error flag
315 HFXO0->IF_CLR = irq_flag & HFXO_IF_DNSERR;
316
317 #if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
318 // We should not fail twice in a row
319 EFM_ASSERT(error_flag == false);
320
321 // Update global variables related to error.
322 error_flag = true;
323 error_try_cnt++;
324
325 // Save current settings
326 pkdettusstartupi_saved = (HFXO_MANAGER_PKDETCTRL & _HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK);
327 ctunexiana_saved = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_CTUNEXIANA_MASK);
328 ctunexoana_saved = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_CTUNEXOANA_MASK);
329 corebiasana_saved = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_COREBIASANA_MASK);
330 corebiasstartup_saved = (HFXO0->XTALCFG & _HFXO_XTALCFG_COREBIASSTARTUP_MASK);
331 corebiasstartupi_saved = (HFXO0->XTALCFG & _HFXO_XTALCFG_COREBIASSTARTUPI_MASK);
332
333 // Disable HFXO.
334 HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
335 HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
336
337 // Use FORCERAWCLK bit to exit error state when disabling
338 HFXO0->CTRL_SET = HFXO_MANAGER_CTRL_FORCERAWCLK;
339 while ((HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) != 0U) {
340 }
341 HFXO0->CTRL_CLR = HFXO_MANAGER_CTRL_FORCERAWCLK;
342
343 // Change settings:
344 //Reduce Peak Detection Threshold for Startup Intermediate stage to 2 (V157MV)
345 HFXO_MANAGER_PKDETCTRL = (HFXO_MANAGER_PKDETCTRL & ~_HFXO_MANAGER_PKDETCTRL_PKDETTHSTARTUPI_MASK) | sleepy_xtal_settings_pkdettusstartupi;
346 // Reduce CTUNE values for steady stage
347 if (((ctunexiana_saved >> _HFXO_XTALCTRL_CTUNEXIANA_SHIFT) > 100)
348 || ((ctunexoana_saved >> _HFXO_XTALCTRL_CTUNEXOANA_SHIFT) > 100)) {
349 HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~(_HFXO_XTALCTRL_CTUNEXIANA_MASK | _HFXO_XTALCTRL_CTUNEXOANA_MASK))
350 | (sleepy_xtal_settings_ctuneana << _HFXO_XTALCTRL_CTUNEXIANA_SHIFT)
351 | (sleepy_xtal_settings_ctuneana << _HFXO_XTALCTRL_CTUNEXOANA_SHIFT);
352 }
353 // Increase core bias current at all stages
354 HFXO0->XTALCFG = (HFXO0->XTALCFG & ~(_HFXO_XTALCFG_COREBIASSTARTUPI_MASK | _HFXO_XTALCFG_COREBIASSTARTUP_MASK))
355 | ((sleepy_xtal_settings_corebias >> 2) << _HFXO_XTALCFG_COREBIASSTARTUPI_SHIFT)
356 | ((sleepy_xtal_settings_corebias >> 2) << _HFXO_XTALCFG_COREBIASSTARTUP_SHIFT);
357 HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~_HFXO_XTALCTRL_COREBIASANA_MASK)
358 | (sleepy_xtal_settings_corebias << _HFXO_XTALCTRL_COREBIASANA_SHIFT);
359
360 // Put back FORCEEN and DISONDEMAND state
361 if (!disondemand) {
362 HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
363 } else {
364 HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
365 }
366 if (forceen) {
367 HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
368 } else {
369 HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
370 }
371 #endif
372 }
373
374 if (irq_flag & HFXO_IF_COREBIASOPTERR) {
375 // Clear Core Bias Optimization error flag
376 HFXO0->IF_CLR = irq_flag & HFXO_IF_COREBIASOPTERR;
377
378 #if (SL_HFXO_MANAGER_SLEEPY_CRYSTAL_SUPPORT == 1)
379 // In case the Core Bias Optimization fails during error handling,
380 // we disable it
381 if (in_error_state == true) {
382 // Disable HFXO.
383 HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
384 HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
385
386 while ((HFXO0->STATUS & HFXO_STATUS_ENS) != 0) {
387 }
388
389 // Skip Core Bias Optimization in case of error
390 HFXO0->XTALCTRL_SET = HFXO_XTALCTRL_SKIPCOREBIASOPT;
391
392 // Put back FORCEEN and DISONDEMAND state
393 if (!disondemand) {
394 HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
395 } else {
396 HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
397 }
398 if (forceen) {
399 HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
400 } else {
401 HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
402 }
403 }
404 #endif
405 }
406 }
407 #endif // _SILICON_LABS_32B_SERIES_2
408