1 /***************************************************************************//**
2  * @file
3  * @brief Clock management unit (CMU) Peripheral API
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2018 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_cmu.h"
31 #if defined(CMU_PRESENT)
32 
33 #include <stddef.h>
34 #include <limits.h>
35 #include "sl_assert.h"
36 #include "em_bus.h"
37 #include "sl_common.h"
38 #include "em_emu.h"
39 #include "em_gpio.h"
40 #include "em_system.h"
41 #if defined(SYSCFG_PRESENT)
42 #include "em_syscfg.h"
43 #endif
44 #include "em_msc.h"
45 #if defined(SL_COMPONENT_CATALOG_PRESENT)
46 #include "sl_component_catalog.h"
47 #endif
48 
49 /***************************************************************************//**
50  * @addtogroup cmu CMU - Clock Management Unit
51  * @brief Clock management unit (CMU) Peripheral API
52  * @details
53  *  This module contains functions for the CMU peripheral of Silicon Labs 32-bit
54  *  MCUs and SoCs. The CMU module controls oscillators, clocks gates, clock
55  *  multiplexers, pre-scalers, calibration modules and wait-states.
56  * @{
57  ******************************************************************************/
58 #if defined(_SILICON_LABS_32B_SERIES_2)
59 
60 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
61 
62 /*******************************************************************************
63  ******************************   DEFINES   ************************************
64  ******************************************************************************/
65 
66 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
67 // Maximum allowed core frequency vs. wait-states on flash accesses.
68 #define CMU_MAX_FREQ_0WS_1V1              40000000UL
69 
70 #define CMU_MAX_FREQ_0WS_1V0              40000000UL
71 
72 // Maximum allowed core frequency vs. wait-states on sram accesses.
73 #define CMU_MAX_SRAM_FREQ_0WS             50000000UL
74 #define CMU_MAX_SRAM_FREQ_1WS             80000000UL
75 
76 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_2) \
77   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)  \
78   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_9)
79 #define CMU_MAX_FREQ_0WS_1V1              40000000UL
80 
81 #define CMU_MAX_FREQ_0WS_1V0              40000000UL
82 #elif defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3) \
83   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)  \
84   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6)  \
85   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
86 // Maximum allowed core frequency vs. wait-states and vscale on flash accesses.
87 #define CMU_MAX_FREQ_0WS_1V1              40000000UL
88 
89 #define CMU_MAX_FREQ_0WS_1V0              20000000UL
90 #elif (_SILICON_LABS_32B_SERIES_2_CONFIG == 5)
91 #define CMU_MAX_FREQ_0WS_1V1              25000000UL
92 #define CMU_MAX_FREQ_1WS_1V1              50000000UL
93 #define CMU_MAX_FREQ_2WS_1V1              75000000UL
94 #else
95       #warning "MCU flash wait states not supported"
96 #endif
97 
98 // Maximum allowed PCLK frequency.
99 #define CMU_MAX_PCLK_FREQ                 50000000UL
100 
101 // Maximum allowed RHCLK frequency.
102 #define CMU_MAX_RHCLK_FREQ                40000000UL
103 
104 #if defined(EMU_VSCALE_EM01_PRESENT)
105 // This macro is intended to be used as input to CMU_UpdateWaitStates()
106 #define VSCALE_DEFAULT    (2 - (int)EMU_VScaleGet())
107 #else
108 #define VSCALE_DEFAULT    VSCALE_EM01_HIGH_PERFORMANCE
109 #endif
110 
111 #if defined(PLFRCO_PRESENT)
112 // Typical frequency for HFXO as recommanded in the datasheets.
113 // see AN0016: Oscillator Design Considerations
114 //
115 // Recommended for most wireless applications
116 // to meet transceiver electrical specifications
117 #define XTAL_38M4                         38400000UL
118 // Recommended for implementing Z-Wave devices
119 #define XTAL_39M0                         39000000UL
120 // High Precision mode calibration Counts for 38.4MHz
121 #define LFRCO_NOMCAL_XTAL_38M4            _LFRCO_NOMCAL_RESETVALUE
122 #define LFRCO_NOMCALINV_XTAL_38M4         _LFRCO_NOMCALINV_RESETVALUE
123 // High Precision mode calibration Counts for 39.0MHz.
124 #define LFRCO_NOMCAL_XTAL_39M0            0x0005CFBBUL
125 #define LFRCO_NOMCALINV_XTAL_39M0         0x0000581AUL
126 #endif
127 
128 #define PLL0_USB_OUTPUT_FREQ              48000000UL
129 
130 /*******************************************************************************
131  **************************   LOCAL VARIABLES   ********************************
132  ******************************************************************************/
133 
134 // Table of HFRCOCAL values and their associated min/max frequencies and
135 // optional band enumerator.
136 static const struct hfrcoCalTableElement{
137   uint32_t  minFreq;
138   uint32_t  maxFreq;
139   uint32_t  value;
140   CMU_HFRCODPLLFreq_TypeDef band;
141 } hfrcoCalTable[] =
142 {
143   //  minFreq   maxFreq    HFRCOCAL value  band
144   {  900000UL, 1080000UL, 0x82401F00UL, cmuHFRCODPLLFreq_1M0Hz         },
145   { 1080000UL, 1300000UL, 0xA2411F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
146   { 1300000UL, 1530000UL, 0xA2421F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
147   { 1530000UL, 1800000UL, 0xB6439F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
148   { 1800000UL, 2150000UL, 0x81401F00UL, cmuHFRCODPLLFreq_2M0Hz         },
149   { 2150000UL, 2600000UL, 0xA1411F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
150   { 2600000UL, 3050000UL, 0xA1421F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
151   { 3050000UL, 3600000UL, 0xB5439F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
152   { 3600000UL, 4300000UL, 0x80401F00UL, cmuHFRCODPLLFreq_4M0Hz         },
153   { 4300000UL, 5200000UL, 0xA0411F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
154   { 5200000UL, 6100000UL, 0xA0421F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
155   { 6100000UL, 7800000UL, 0xB4439F00UL, cmuHFRCODPLLFreq_7M0Hz         },
156   { 7800000UL, 9800000UL, 0xB4449F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0   },
157   { 9800000UL, 11800000UL, 0xB4459F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0  },
158   { 11800000UL, 14400000UL, 0xB4669F00UL, cmuHFRCODPLLFreq_13M0Hz      },
159   { 14400000UL, 17200000UL, 0xB4679F00UL, cmuHFRCODPLLFreq_16M0Hz      },
160   { 17200000UL, 19700000UL, 0xA8689F00UL, cmuHFRCODPLLFreq_19M0Hz      },
161   { 19700000UL, 23800000UL, 0xB8899F3AUL, (CMU_HFRCODPLLFreq_TypeDef)0 },
162   { 23800000UL, 28700000UL, 0xB88A9F00UL, cmuHFRCODPLLFreq_26M0Hz      },
163   { 28700000UL, 34800000UL, 0xB8AB9F00UL, cmuHFRCODPLLFreq_32M0Hz      },
164   { 34800000UL, 42800000UL, 0xA8CC9F00UL, cmuHFRCODPLLFreq_38M0Hz      },
165   { 42800000UL, 51600000UL, 0xACED9F00UL, cmuHFRCODPLLFreq_48M0Hz      },
166   { 51600000UL, 60500000UL, 0xBCEE9F00UL, cmuHFRCODPLLFreq_56M0Hz      },
167   { 60500000UL, 72600000UL, 0xBCEF9F00UL, cmuHFRCODPLLFreq_64M0Hz      },
168   { 72600000UL, 80000000UL, 0xCCF09F00UL, cmuHFRCODPLLFreq_80M0Hz      },
169 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)
170   { 80000000UL, 100000000UL, 0xCCF19F00UL, cmuHFRCODPLLFreq_100M0Hz   }
171 #endif
172 };
173 
174 static uint16_t lfxo_precision = 0xFFFF;
175 static uint16_t hfxo_precision = 0xFFFF;
176 
177 #define HFRCOCALTABLE_ENTRIES (sizeof(hfrcoCalTable) \
178                                / sizeof(struct hfrcoCalTableElement))
179 
180 // CTUNE delta needed for some series 2 chips. This delta is added to the tuning capacitance on XO.
181 // The inter-chip buffered crystal sharing feature added from the EFR32xG23 creates an imbalance
182 // between XI and XO capacitance load internally on the chip. The delta allows to compensate for
183 // the difference.
184 #if defined(_SILICON_LABS_32B_SERIES_2)
185 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3)  \
186   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4) \
187   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5) \
188   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6) \
189   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
190 static int8_t ctuneDelta = 40; // Recommendation from analog team to counter the internal chip imbalance.
191 #else
192 static int8_t ctuneDelta = 0;
193 #endif
194 #endif
195 
196 static uint8_t pclkDiv = 0;
197 
198 /*******************************************************************************
199  **************************   LOCAL PROTOTYPES   *******************************
200  ******************************************************************************/
201 #if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
202 #if defined(PDM_PRESENT)
203 static void     em01GrpbClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
204 #endif
205 #if defined(EUART_PRESENT)
206 static void     euart0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
207 #endif
208 #if defined(EUSART_PRESENT)
209 static void     eusart0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
210 #if defined(_CMU_EM01GRPCCLKCTRL_MASK)
211 static void     em01GrpcClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
212 #endif
213 #endif
214 #if defined(LCD_PRESENT)
215 static void     lcdClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
216 #endif
217 #if defined(VDAC_PRESENT)
218 static void     vdac0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
219 #if (VDAC_COUNT > 1)
220 static void     vdac1ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
221 #endif
222 #endif
223 #if defined(PCNT_PRESENT)
224 static void     pcnt0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
225 #endif
226 #if defined(LESENSE_PRESENT)
227 static void     lesenseHFClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
228 #endif
229 #if (defined(CMU_SYSCLKCTRL_RHCLKPRESC) \
230   && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
231 static void     rhclkPrescMax(void);
232 static void     rhclkPrescOptimize(void);
233 #endif
234 #endif
235 
236 #if defined(HFRCOEM23_PRESENT)
237 static uint32_t HFRCOEM23DevinfoGet(CMU_HFRCOEM23Freq_TypeDef freq);
238 #endif
239 static void     traceClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
240 static void     dpllRefClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
241 static void     em01GrpaClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
242 static void     em23GrpaClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
243 static void     em4GrpaClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
244 __STATIC_INLINE uint32_t getWaitStatesByFrequencyAndVScale(uint32_t freq, int vscale);
245 static void     flashWaitStateControl(uint32_t coreFreq, int vscale);
246 static uint32_t HFRCODPLLDevinfoGet(CMU_HFRCODPLLFreq_TypeDef freq);
247 #if defined(IADC_PRESENT)
248 static void     iadcClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
249 #endif
250 static void     pclkDivMax(void);
251 static void     pclkDivOptimize(void);
252 #if defined(RTCC_PRESENT)
253 static void     rtccClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
254 #elif defined(SYSRTC_PRESENT)
255 static void     sysrtcClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
256 #endif
257 static void     waitStateMax(void);
258 static void     wdog0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
259 #if WDOG_COUNT > 1
260 static void     wdog1ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
261 #endif
262 static void     sysTickClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
263 #if defined(USB_PRESENT)
264 static void     usbClkGet(uint32_t *freq, CMU_Select_TypeDef *sel);
265 #endif
266 /** @endcond */
267 
268 // The following code is common for all SERIES_2 configurations.
269 
270 /*******************************************************************************
271  **************************   GLOBAL FUNCTIONS   *******************************
272  ******************************************************************************/
273 
274 /***************************************************************************//**
275  * @brief
276  *   Calibrate an oscillator.
277  *
278  * @details
279  *   Run a calibration of a selectable reference clock againt HCLK. Please
280  *   refer to the reference manual, CMU chapter, for further details.
281  *
282  * @note
283  *   This function will not return until calibration measurement is completed.
284  *
285  * @param[in] cycles
286  *   The number of HCLK cycles to run calibration. Increasing this number
287  *   increases precision, but the calibration will take more time.
288  *
289  * @param[in] ref
290  *   The reference clock used to compare against HCLK.
291  *
292  * @return
293  *   The number of ticks the selected reference clock ticked while running
294  *   cycles ticks of the HCLK clock.
295  ******************************************************************************/
CMU_Calibrate(uint32_t cycles,CMU_Select_TypeDef ref)296 uint32_t CMU_Calibrate(uint32_t cycles, CMU_Select_TypeDef ref)
297 {
298   // Check for cycle count overflow
299 #if defined(_CMU_CALCTRL_CALTOP_MASK)
300   EFM_ASSERT(cycles <= (_CMU_CALCTRL_CALTOP_MASK
301                         >> _CMU_CALCTRL_CALTOP_SHIFT));
302 #elif defined(_CMU_CALTOP_CALTOP_MASK)
303   EFM_ASSERT(cycles <= (_CMU_CALTOP_CALTOP_MASK
304                         >> _CMU_CALTOP_CALTOP_SHIFT));
305 #endif
306 
307   CMU_CalibrateConfig(cycles, cmuSelect_HCLK, ref);
308   CMU_CalibrateStart();
309   return CMU_CalibrateCountGet();
310 }
311 
312 /***************************************************************************//**
313  * @brief
314  *   Configure clock calibration.
315  *
316  * @details
317  *   Configure a calibration for a selectable clock source against another
318  *   selectable reference clock.
319  *   Refer to the reference manual, CMU chapter, for further details.
320  *
321  * @note
322  *   After configuration, a call to @ref CMU_CalibrateStart() is required, and
323  *   the resulting calibration value can be read with the
324  *   @ref CMU_CalibrateCountGet() function call.
325  *
326  * @param[in] downCycles
327  *   The number of downSel clock cycles to run calibration. Increasing this
328  *   number increases precision, but the calibration will take more time.
329  *
330  * @param[in] downSel
331  *   The clock which will be counted down downCycles cycles.
332  *
333  * @param[in] upSel
334  *   The reference clock, the number of cycles generated by this clock will
335  *   be counted and added up, the result can be given with the
336  *   @ref CMU_CalibrateCountGet() function call.
337  ******************************************************************************/
CMU_CalibrateConfig(uint32_t downCycles,CMU_Select_TypeDef downSel,CMU_Select_TypeDef upSel)338 void CMU_CalibrateConfig(uint32_t downCycles, CMU_Select_TypeDef downSel,
339                          CMU_Select_TypeDef upSel)
340 {
341   // Keep untouched configuration settings
342   uint32_t calCtrl = CMU->CALCTRL
343                      & ~(_CMU_CALCTRL_UPSEL_MASK
344                          | _CMU_CALCTRL_DOWNSEL_MASK
345 #if defined(_CMU_CALCTRL_CALTOP_MASK)
346                          | _CMU_CALCTRL_CALTOP_MASK
347 #endif
348                          );
349 
350   // Check for cycle count overflow
351 #if defined(_CMU_CALCTRL_CALTOP_MASK)
352   EFM_ASSERT(downCycles <= (_CMU_CALCTRL_CALTOP_MASK
353                             >> _CMU_CALCTRL_CALTOP_SHIFT));
354   calCtrl |= downCycles;
355 #elif defined(_CMU_CALTOP_CALTOP_MASK)
356   EFM_ASSERT(downCycles <= (_CMU_CALTOP_CALTOP_MASK >> _CMU_CALTOP_CALTOP_SHIFT));
357   CMU->CALTOP = downCycles << _CMU_CALTOP_CALTOP_SHIFT;
358 #endif
359 
360   // Set down counting clock source selector
361   switch (downSel) {
362     case cmuSelect_HCLK:
363       calCtrl |= CMU_CALCTRL_DOWNSEL_HCLK;
364       break;
365 
366     case cmuSelect_PRS:
367       calCtrl |= CMU_CALCTRL_DOWNSEL_PRS;
368       break;
369 
370     case cmuSelect_HFXO:
371       calCtrl |= CMU_CALCTRL_DOWNSEL_HFXO;
372       break;
373 
374     case cmuSelect_LFXO:
375       calCtrl |= CMU_CALCTRL_DOWNSEL_LFXO;
376       break;
377 
378     case cmuSelect_HFRCODPLL:
379       calCtrl |= CMU_CALCTRL_DOWNSEL_HFRCODPLL;
380       break;
381 
382 #if defined(HFRCOEM23_PRESENT)
383     case cmuSelect_HFRCOEM23:
384       calCtrl |= CMU_CALCTRL_DOWNSEL_HFRCOEM23;
385       break;
386 #endif
387 
388     case cmuSelect_FSRCO:
389       calCtrl |= CMU_CALCTRL_DOWNSEL_FSRCO;
390       break;
391 
392     case cmuSelect_LFRCO:
393 #if defined(PLFRCO_PRESENT)
394     case cmuSelect_PLFRCO:
395 #endif
396       calCtrl |= CMU_CALCTRL_DOWNSEL_LFRCO;
397       break;
398 
399     case cmuSelect_ULFRCO:
400       calCtrl |= CMU_CALCTRL_DOWNSEL_ULFRCO;
401       break;
402 
403     case cmuSelect_Disabled:
404       break;
405 
406     default:
407       EFM_ASSERT(false);
408       break;
409   }
410 
411   // Set up counting clock source selector
412   switch (upSel) {
413     case cmuSelect_PRS:
414       calCtrl |= CMU_CALCTRL_UPSEL_PRS;
415       break;
416 
417     case cmuSelect_HFXO:
418       calCtrl |= CMU_CALCTRL_UPSEL_HFXO;
419       break;
420 
421     case cmuSelect_LFXO:
422       calCtrl |= CMU_CALCTRL_UPSEL_LFXO;
423       break;
424 
425     case cmuSelect_HFRCODPLL:
426       calCtrl |= CMU_CALCTRL_UPSEL_HFRCODPLL;
427       break;
428 
429 #if defined(HFRCOEM23_PRESENT)
430     case cmuSelect_HFRCOEM23:
431       calCtrl |= CMU_CALCTRL_UPSEL_HFRCOEM23;
432       break;
433 #endif
434 
435     case cmuSelect_FSRCO:
436       calCtrl |= CMU_CALCTRL_UPSEL_FSRCO;
437       break;
438 
439     case cmuSelect_LFRCO:
440 #if defined(PLFRCO_PRESENT)
441     case cmuSelect_PLFRCO:
442 #endif
443       calCtrl |= CMU_CALCTRL_UPSEL_LFRCO;
444       break;
445 
446     case cmuSelect_ULFRCO:
447       calCtrl |= CMU_CALCTRL_UPSEL_ULFRCO;
448       break;
449 
450     case cmuSelect_Disabled:
451       break;
452 
453     default:
454       EFM_ASSERT(false);
455       break;
456   }
457 
458   CMU->CALCTRL = calCtrl;
459 }
460 
461 /***************************************************************************//**
462  * @brief
463  *    Get calibration count value.
464  *
465  * @note
466  *    If continuous calibration mode is active, calibration busy will almost
467  *    always be off, and reading the value will be just needed, where the normal
468  *    case would be that this function call has been triggered by the CALRDY
469  *    interrupt flag.
470  *
471  * @return
472  *    Calibration count, the number of UPSEL clocks (see @ref CMU_CalibrateConfig())
473  *    in the period of DOWNSEL oscillator clock cycles configured by a previous
474  *    write operation to CMU->CALCNT.
475  ******************************************************************************/
CMU_CalibrateCountGet(void)476 uint32_t CMU_CalibrateCountGet(void)
477 {
478   // Wait until calibration completes, UNLESS continuous calibration mode is on
479   if ((CMU->CALCTRL & CMU_CALCTRL_CONT) == 0UL) {
480     // Wait until calibration completes
481     while ((CMU->STATUS & CMU_STATUS_CALRDY) == 0UL) {
482     }
483   }
484   return CMU->CALCNT;
485 }
486 
487 /***************************************************************************//**
488  * @brief
489  *    Direct a clock to a GPIO pin.
490  *
491  * @param[in] clkNo
492  *   Selects between CLKOUT0, CLKOUT1 or CLKOUT2 outputs. Use values 0, 1 or 2.
493  *
494  * @param[in] sel
495  *   Select clock source.
496  *
497  * @param[in] clkDiv
498  *   Select a clock divisor (1..32). Only applicable when cmuSelect_EXPCLK is
499  *   selected as clock source.
500  *
501  * @param[in] port
502  *   GPIO port.
503  *
504  * @param[in] pin
505  *   GPIO pin.
506  *
507  * @note
508  *    Refer to the reference manual and the datasheet for details on which
509  *    GPIO port/pins that are available.
510  ******************************************************************************/
CMU_ClkOutPinConfig(uint32_t clkNo,CMU_Select_TypeDef sel,CMU_ClkDiv_TypeDef clkDiv,GPIO_Port_TypeDef port,unsigned int pin)511 void CMU_ClkOutPinConfig(uint32_t           clkNo,
512                          CMU_Select_TypeDef sel,
513                          CMU_ClkDiv_TypeDef clkDiv,
514                          GPIO_Port_TypeDef  port,
515                          unsigned int       pin)
516 {
517   uint32_t tmp = 0U, mask;
518 
519   EFM_ASSERT(pin <= 15U);
520 
521   switch (clkNo) {
522     case 0:
523     case 1:
524       EFM_ASSERT((port == 2U) || (port == 3U));
525       break;
526     case 2:
527       EFM_ASSERT((port == 0U) || (port == 1U));
528       break;
529     default:
530       EFM_ASSERT(false);
531       break;
532   }
533 
534   switch (sel) {
535     case cmuSelect_Disabled:
536       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_DISABLED;
537       break;
538 
539     case cmuSelect_FSRCO:
540       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_FSRCO;
541       break;
542 
543     case cmuSelect_HFXO:
544       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_HFXO;
545       break;
546 
547     case cmuSelect_HFRCODPLL:
548       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_HFRCODPLL;
549       break;
550 
551 #if defined(HFRCOEM23_PRESENT)
552     case cmuSelect_HFRCOEM23:
553       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_HFRCOEM23;
554       break;
555 #endif
556 
557     case cmuSelect_EXPCLK:
558       EFM_ASSERT((clkDiv > 0U) && (clkDiv <= 32U));
559       tmp  = CMU_EXPORTCLKCTRL_CLKOUTSEL0_HFEXPCLK;
560       break;
561 
562     case cmuSelect_LFXO:
563       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_LFXO;
564       break;
565 
566     case cmuSelect_LFRCO:
567 #if defined(PLFRCO_PRESENT)
568     case cmuSelect_PLFRCO:
569 #endif
570       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_LFRCO;
571       break;
572 
573     case cmuSelect_ULFRCO:
574       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_ULFRCO;
575       break;
576 
577     case cmuSelect_HCLK:
578       tmp = CMU_EXPORTCLKCTRL_CLKOUTSEL0_HCLK;
579       break;
580 
581     default:
582       EFM_ASSERT(false);
583       break;
584   }
585 
586   mask  = _CMU_EXPORTCLKCTRL_CLKOUTSEL0_MASK
587           << (clkNo * _CMU_EXPORTCLKCTRL_CLKOUTSEL1_SHIFT);
588   tmp <<= clkNo * _CMU_EXPORTCLKCTRL_CLKOUTSEL1_SHIFT;
589 
590   if (sel == cmuSelect_EXPCLK) {
591     tmp  |= (clkDiv - 1U) << _CMU_EXPORTCLKCTRL_PRESC_SHIFT;
592     mask |= _CMU_EXPORTCLKCTRL_PRESC_MASK;
593   }
594 
595   CMU->EXPORTCLKCTRL = (CMU->EXPORTCLKCTRL & ~mask) | tmp;
596 
597   if (sel == cmuSelect_Disabled) {
598     GPIO->CMUROUTE_CLR.ROUTEEN = GPIO_CMU_ROUTEEN_CLKOUT0PEN << clkNo;
599     GPIO_PinModeSet(port, pin, gpioModeDisabled, 0);
600   } else {
601     GPIO->CMUROUTE_SET.ROUTEEN = GPIO_CMU_ROUTEEN_CLKOUT0PEN << clkNo;
602     if (clkNo == 0U) {
603       GPIO->CMUROUTE.CLKOUT0ROUTE = (port << _GPIO_CMU_CLKOUT0ROUTE_PORT_SHIFT)
604                                     | (pin << _GPIO_CMU_CLKOUT0ROUTE_PIN_SHIFT);
605     } else if (clkNo == 1) {
606       GPIO->CMUROUTE.CLKOUT1ROUTE = (port << _GPIO_CMU_CLKOUT1ROUTE_PORT_SHIFT)
607                                     | (pin << _GPIO_CMU_CLKOUT1ROUTE_PIN_SHIFT);
608     } else {
609       GPIO->CMUROUTE.CLKOUT2ROUTE = (port << _GPIO_CMU_CLKOUT2ROUTE_PORT_SHIFT)
610                                     | (pin << _GPIO_CMU_CLKOUT2ROUTE_PIN_SHIFT);
611     }
612     GPIO_PinModeSet(port, pin, gpioModePushPull, 0);
613   }
614 }
615 
616 /***************************************************************************//**
617  * @brief
618  *   Get clock divisor.
619  *
620  * @param[in] clock
621  *   Clock point to get divisor for. Notice that not all clock points
622  *   have a divisors. Please refer to CMU overview in reference manual.
623  *
624  * @return
625  *   The current clock point divisor. 1 is returned
626  *   if @p clock specifies a clock point without divisor.
627  ******************************************************************************/
CMU_ClockDivGet(CMU_Clock_TypeDef clock)628 CMU_ClkDiv_TypeDef CMU_ClockDivGet(CMU_Clock_TypeDef clock)
629 {
630   uint32_t ret = 0U;
631 
632   switch (clock) {
633     case cmuClock_HCLK:
634     case cmuClock_CORE:
635       ret = (CMU->SYSCLKCTRL & _CMU_SYSCLKCTRL_HCLKPRESC_MASK)
636             >> _CMU_SYSCLKCTRL_HCLKPRESC_SHIFT;
637 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
638       if (ret == 2U ) {   // Unused value, illegal prescaler
639         EFM_ASSERT(false);
640       }
641 #elif (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
642       if (!((ret == _CMU_SYSCLKCTRL_HCLKPRESC_DIV1)
643             || (ret == _CMU_SYSCLKCTRL_HCLKPRESC_DIV2)
644             || (ret == _CMU_SYSCLKCTRL_HCLKPRESC_DIV4)
645             || (ret == _CMU_SYSCLKCTRL_HCLKPRESC_DIV8)
646             || (ret == _CMU_SYSCLKCTRL_HCLKPRESC_DIV16))) {
647         // Illegal prescaler
648         EFM_ASSERT(false);
649       }
650 #endif
651       break;
652 
653 #if defined(_CMU_TRACECLKCTRL_PRESC_MASK)
654     case cmuClock_TRACECLK:
655       ret = (CMU->TRACECLKCTRL & _CMU_TRACECLKCTRL_PRESC_MASK)
656             >> _CMU_TRACECLKCTRL_PRESC_SHIFT;
657       if (!((ret == _CMU_TRACECLKCTRL_PRESC_DIV1)
658             || (ret == _CMU_TRACECLKCTRL_PRESC_DIV2)
659 #if defined(_CMU_TRACECLKCTRL_PRESC_DIV3)
660             || (ret == _CMU_TRACECLKCTRL_PRESC_DIV3)
661 #endif
662             || (ret == _CMU_TRACECLKCTRL_PRESC_DIV4))) {
663         // Illegal prescaler
664         EFM_ASSERT(false);
665       }
666       break;
667 #endif
668 
669     case cmuClock_EXPCLK:
670       ret = (CMU->EXPORTCLKCTRL & _CMU_EXPORTCLKCTRL_PRESC_MASK)
671             >> _CMU_EXPORTCLKCTRL_PRESC_SHIFT;
672       break;
673 
674     case cmuClock_PCLK:
675       ret = (CMU->SYSCLKCTRL & _CMU_SYSCLKCTRL_PCLKPRESC_MASK)
676             >> _CMU_SYSCLKCTRL_PCLKPRESC_SHIFT;
677       break;
678 
679     default:
680       break;
681   }
682   return 1U + ret;
683 }
684 
685 /***************************************************************************//**
686  * @brief
687  *   Set clock divisor.
688  *
689  * @param[in] clock
690  *   Clock point to set divisor for. Notice that not all clock points
691  *   have a divisor, please refer to CMU overview in the reference
692  *   manual.
693  *
694  * @param[in] div
695  *   The clock divisor to use.
696  ******************************************************************************/
CMU_ClockDivSet(CMU_Clock_TypeDef clock,CMU_ClkDiv_TypeDef div)697 void CMU_ClockDivSet(CMU_Clock_TypeDef clock, CMU_ClkDiv_TypeDef div)
698 {
699 #if (defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)  \
700   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)  \
701   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6)  \
702   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)  \
703   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)  \
704   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_9)) \
705   && defined(CoreDebug_DEMCR_TRCENA_Msk)
706   bool restoreTrace;
707 #endif
708 
709   switch (clock) {
710     case cmuClock_HCLK:
711     case cmuClock_CORE:
712 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
713       EFM_ASSERT((div == 1U) || (div == 2U) || (div == 4U));
714 #elif (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
715       EFM_ASSERT((div == 1U) || (div == 2U) || (div == 4U)
716                  || (div == 8U) || (div == 16U));
717 #endif
718 
719       // Set max wait-states and PCLK divisor while changing core clock
720       waitStateMax();
721       pclkDivMax();
722 #if ((defined(CMU_SYSCLKCTRL_RHCLKPRESC)) \
723       && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
724       // Set largest prescaler for radio clock tree
725       rhclkPrescMax();
726 #endif
727 
728       // Set new divisor
729       CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_HCLKPRESC_MASK)
730                         | ((div - 1U) << _CMU_SYSCLKCTRL_HCLKPRESC_SHIFT);
731 
732       // Update CMSIS core clock variable and set optimum wait-states
733       CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
734 
735       // Set optimal PCLK divisor
736       pclkDivOptimize();
737 #if (defined(CMU_SYSCLKCTRL_RHCLKPRESC) \
738       && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
739       // Set optimal RHCLK prescaler
740       rhclkPrescOptimize();
741 #endif
742       break;
743 
744 #if defined(_CMU_TRACECLKCTRL_PRESC_MASK)
745     case cmuClock_TRACECLK:
746 #if (defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)      \
747       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)  \
748       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6)  \
749       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)  \
750       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)  \
751       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_9)) \
752       && defined(CoreDebug_DEMCR_TRCENA_Msk)
753       restoreTrace = CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk;
754       if (restoreTrace) {
755         CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
756       }
757 #endif
758 #if defined(_CMU_TRACECLKCTRL_PRESC_DIV3)
759       EFM_ASSERT((div == 1U) || (div == 2U) || (div == 3U) || (div == 4U));
760 #else
761       EFM_ASSERT((div == 1U) || (div == 2U) || (div == 4U));
762 #endif
763       CMU->TRACECLKCTRL = (CMU->TRACECLKCTRL & ~_CMU_TRACECLKCTRL_PRESC_MASK)
764                           | ((div - 1U) << _CMU_TRACECLKCTRL_PRESC_SHIFT);
765 #if (defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)      \
766       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)  \
767       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6)  \
768       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)  \
769       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)  \
770       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_9)) \
771       && defined(CoreDebug_DEMCR_TRCENA_Msk)
772       if (restoreTrace) {
773         CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
774       }
775 #endif
776       break;
777 #endif
778 
779     case cmuClock_EXPCLK:
780       EFM_ASSERT((div >= 1U) && (div <= 32U));
781       CMU->EXPORTCLKCTRL = (CMU->EXPORTCLKCTRL & ~_CMU_EXPORTCLKCTRL_PRESC_MASK)
782                            | ((div - 1U) << _CMU_EXPORTCLKCTRL_PRESC_SHIFT);
783       break;
784 
785     case cmuClock_PCLK:
786       EFM_ASSERT((div == 1U) || (div == 2U));
787       CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_PCLKPRESC_MASK)
788                         | ((div - 1U) << _CMU_SYSCLKCTRL_PCLKPRESC_SHIFT);
789       break;
790 
791     default:
792       EFM_ASSERT(false);
793       break;
794   }
795 }
796 
797 #if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
798 /***************************************************************************//**
799  * @brief
800  *   Enable/disable a clock.
801  *
802  * @details
803  *   Module clocks sre disabled after reset. If a module clock is disabled, the
804  *   registers of that module are not accessible and accessing such registers
805  *   will hardfault the Cortex core.
806  *
807  * @param[in] clock
808  *   The clock to enable/disable.
809  *
810  * @param[in] enable
811  *   @li true - enable specified clock.
812  *   @li false - disable specified clock.
813  ******************************************************************************/
CMU_ClockEnable(CMU_Clock_TypeDef clock,bool enable)814 SL_WEAK void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
815 {
816   volatile uint32_t *reg = NULL;
817   uint32_t          bit;
818 
819   /* Identify the enable register. */
820   if (((unsigned)clock >> CMU_EN_REG_POS) == CMU_NO_EN_REG) {
821     EFM_ASSERT(false);                      /* No enable for this clock. */
822   } else if (((unsigned)clock >> CMU_EN_REG_POS) == CMU_CLKEN0_EN_REG) {
823     reg = &CMU->CLKEN0;
824   } else if (((unsigned)clock >> CMU_EN_REG_POS) == CMU_CLKEN1_EN_REG) {
825     reg = &CMU->CLKEN1;
826 #if defined(_CMU_CLKEN2_MASK)
827   } else if (((unsigned)clock >> CMU_EN_REG_POS) == CMU_CLKEN2_EN_REG) {
828     reg = &CMU->CLKEN2;
829 #endif
830   } else {
831 #if defined(CRYPTOACC_PRESENT)
832     reg = &CMU->CRYPTOACCCLKCTRL;
833 #else
834     // No register to enable clock. Possible hard fault exception.
835     EFM_ASSERT(false);
836 #endif
837   }
838 
839   /* Get the bit position used to enable/disable. */
840   bit = ((unsigned)clock >> CMU_EN_BIT_POS) & CMU_EN_BIT_MASK;
841 
842   /* Set/clear bit as requested. */
843   BUS_RegBitWrite(reg, bit, (uint32_t)enable);
844 }
845 #endif // (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
846 
847 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
848 /***************************************************************************//**
849  * @brief
850  *   Get clock frequency for a clock point.
851  *
852  * @param[in] clock
853  *   Clock point to fetch frequency for.
854  *
855  * @return
856  *   The current frequency in Hz.
857  ******************************************************************************/
CMU_ClockFreqGet(CMU_Clock_TypeDef clock)858 uint32_t CMU_ClockFreqGet(CMU_Clock_TypeDef clock)
859 {
860   uint32_t ret = 0U;
861 
862   switch (clock) {
863     case cmuClock_SYSCLK:
864       ret = SystemSYSCLKGet();
865       break;
866 
867     case cmuClock_CORE:
868     case cmuClock_HCLK:
869     case cmuClock_LDMA:
870     case cmuClock_GPCRC:
871       ret = SystemHCLKGet();
872       break;
873 
874     case cmuClock_EXPCLK:
875       ret = SystemSYSCLKGet() / CMU_ClockDivGet(cmuClock_EXPCLK);
876       break;
877 
878     case cmuClock_I2C1:
879     case cmuClock_PRS:
880     case cmuClock_PCLK:
881     case cmuClock_GPIO:
882     case cmuClock_USART0:
883     case cmuClock_USART1:
884     case cmuClock_USART2:
885       ret = SystemHCLKGet() / CMU_ClockDivGet(cmuClock_PCLK);
886       break;
887 
888     case cmuClock_I2C0:
889     case cmuClock_LSPCLK:
890       ret = SystemHCLKGet() / CMU_ClockDivGet(cmuClock_PCLK) / 2U;
891       break;
892 
893 #if defined(IADC_PRESENT)
894     case cmuClock_IADC0:
895     case cmuClock_IADCCLK:
896       iadcClkGet(&ret, NULL);
897       break;
898 #endif
899 
900     case cmuClock_TIMER0:
901     case cmuClock_TIMER1:
902     case cmuClock_TIMER2:
903     case cmuClock_TIMER3:
904     case cmuClock_EM01GRPACLK:
905       em01GrpaClkGet(&ret, NULL);
906       break;
907 
908     case cmuClock_SYSTICK:
909       sysTickClkGet(&ret, NULL);
910       break;
911 
912     case cmuClock_LETIMER0:
913     case cmuClock_EM23GRPACLK:
914       em23GrpaClkGet(&ret, NULL);
915       break;
916 
917     case cmuClock_BURTC:
918     case cmuClock_EM4GRPACLK:
919       em4GrpaClkGet(&ret, NULL);
920       break;
921 
922     case cmuClock_WDOG0:
923     case cmuClock_WDOG0CLK:
924       wdog0ClkGet(&ret, NULL);
925       break;
926 
927     case cmuClock_WDOG1:
928     case cmuClock_WDOG1CLK:
929       wdog1ClkGet(&ret, NULL);
930       break;
931 
932     case cmuClock_DPLLREFCLK:
933       dpllRefClkGet(&ret, NULL);
934       break;
935 
936     case cmuClock_TRACECLK:
937       traceClkGet(&ret, NULL);
938       break;
939 
940     case cmuClock_RTCC:
941     case cmuClock_RTCCCLK:
942       rtccClkGet(&ret, NULL);
943       break;
944 
945     default:
946       EFM_ASSERT(false);
947       break;
948   }
949   return ret;
950 }
951 #endif // defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
952 
953 #if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
954 /***************************************************************************//**
955  * @brief
956  *   Get clock frequency for a clock point.
957  *
958  * @param[in] clock
959  *   Clock point to fetch frequency for.
960  *
961  * @return
962  *   The current frequency in Hz.
963  ******************************************************************************/
CMU_ClockFreqGet(CMU_Clock_TypeDef clock)964 uint32_t CMU_ClockFreqGet(CMU_Clock_TypeDef clock)
965 {
966   uint32_t ret = 0U;
967   uint32_t freq = 0U;
968 
969   switch (clock) {
970     case cmuClock_SYSCLK:
971       ret = SystemSYSCLKGet();
972       break;
973 
974     case cmuClock_HCLK:
975     case cmuClock_CORE:
976     case cmuClock_ICACHE:
977     case cmuClock_MSC:
978     case cmuClock_LDMA:
979     case cmuClock_SMU:
980 #if defined(RADIOAES_PRESENT)
981     case cmuClock_RADIOAES:
982 #endif
983 #if defined(CRYPTOACC_PRESENT)
984     case cmuClock_CRYPTOACC:
985     case cmuClock_CRYPTOAES:
986     case cmuClock_CRYPTOPK:
987 #endif
988 #if defined(MVP_PRESENT)
989     case cmuClock_MVP:
990 #endif
991       ret = SystemHCLKGet();
992       break;
993 
994     case cmuClock_EXPCLK:
995       ret = SystemSYSCLKGet() / CMU_ClockDivGet(cmuClock_EXPCLK);
996       break;
997 
998     case cmuClock_PCLK:
999 #if defined(USART_PRESENT)
1000     case cmuClock_USART0:
1001 #if USART_COUNT > 1
1002     case cmuClock_USART1:
1003 #endif
1004 #endif
1005     case cmuClock_I2C1:
1006 #if I2C_COUNT > 2
1007     case cmuClock_I2C2:
1008 #endif
1009 #if I2C_COUNT > 3
1010     case cmuClock_I2C3:
1011 #endif
1012     case cmuClock_PRS:
1013     case cmuClock_GPIO:
1014     case cmuClock_GPCRC:
1015     case cmuClock_LDMAXBAR:
1016     case cmuClock_SYSCFG:
1017     case cmuClock_DCDC:
1018     case cmuClock_BURAM:
1019     case cmuClock_DPLL0:
1020       ret = SystemHCLKGet() / CMU_ClockDivGet(cmuClock_PCLK);
1021       break;
1022 
1023     case cmuClock_LSPCLK:
1024     case cmuClock_I2C0:
1025     case cmuClock_AMUXCP0:
1026 #if defined(ACMP_PRESENT)
1027     case cmuClock_ACMP0:
1028 #if ACMP_COUNT > 1
1029     case cmuClock_ACMP1:
1030 #endif
1031 #endif
1032       ret = SystemHCLKGet() / CMU_ClockDivGet(cmuClock_PCLK) / 2U;
1033       break;
1034 
1035     case cmuClock_TRACECLK:
1036       traceClkGet(&freq, NULL);
1037       ret = freq / CMU_ClockDivGet(cmuClock_TRACECLK);
1038       break;
1039 
1040     case cmuClock_TIMER0:
1041     case cmuClock_TIMER1:
1042     case cmuClock_TIMER2:
1043     case cmuClock_TIMER3:
1044 #if TIMER_COUNT > 4
1045     case cmuClock_TIMER4:
1046 #endif
1047 #if TIMER_COUNT > 7
1048     case cmuClock_TIMER5:
1049     case cmuClock_TIMER6:
1050     case cmuClock_TIMER7:
1051 #endif
1052 #if TIMER_COUNT > 9
1053     case cmuClock_TIMER8:
1054     case cmuClock_TIMER9:
1055 #endif
1056 #if defined(KEYSCAN_PRESENT)
1057     case cmuClock_KEYSCAN:
1058 #endif
1059     case cmuClock_EM01GRPACLK:
1060       em01GrpaClkGet(&ret, NULL);
1061       break;
1062 #if defined(PDM_PRESENT)
1063     case cmuClock_PDM:
1064     case cmuClock_EM01GRPBCLK:
1065       em01GrpbClkGet(&ret, NULL);
1066       break;
1067 #endif
1068 #if defined(EUART_PRESENT)
1069     case cmuClock_EUART0:
1070     case cmuClock_EUART0CLK:
1071       euart0ClkGet(&ret, NULL);
1072       break;
1073 #endif
1074 #if defined(EUSART_PRESENT) && EUSART_COUNT > 0
1075     case cmuClock_EUSART0:
1076     case cmuClock_EUSART0CLK:
1077       eusart0ClkGet(&ret, NULL);
1078       break;
1079 #if defined(EUSART_PRESENT) && EUSART_COUNT > 1
1080     case cmuClock_EUSART1:
1081 #endif
1082 #if defined(EUSART_PRESENT) && EUSART_COUNT > 2
1083     case cmuClock_EUSART2:
1084 #endif
1085 #if defined(EUSART_PRESENT) && EUSART_COUNT > 3
1086     case cmuClock_EUSART3:
1087 #endif
1088 #if defined(EUSART_PRESENT) && EUSART_COUNT > 4
1089     case cmuClock_EUSART4:
1090 #endif
1091 #if defined(_CMU_EM01GRPCCLKCTRL_MASK)
1092     case cmuClock_EM01GRPCCLK:
1093       em01GrpcClkGet(&ret, NULL);
1094       break;
1095 #endif
1096 #endif
1097 
1098 #if defined(IADC_PRESENT)
1099     case cmuClock_IADC0:
1100     case cmuClock_IADCCLK:
1101       iadcClkGet(&ret, NULL);
1102       break;
1103 #endif
1104 
1105     case cmuClock_SYSTICK:
1106       sysTickClkGet(&ret, NULL);
1107       break;
1108 
1109     case cmuClock_LETIMER0:
1110     case cmuClock_EM23GRPACLK:
1111 #if defined(LESENSE_PRESENT)
1112     case cmuClock_LESENSE:
1113     case cmuClock_LESENSECLK:
1114 #endif
1115       em23GrpaClkGet(&ret, NULL);
1116       break;
1117 
1118     case cmuClock_WDOG0:
1119     case cmuClock_WDOG0CLK:
1120       wdog0ClkGet(&ret, NULL);
1121       break;
1122 #if WDOG_COUNT > 1
1123     case cmuClock_WDOG1:
1124     case cmuClock_WDOG1CLK:
1125       wdog1ClkGet(&ret, NULL);
1126       break;
1127 #endif
1128 #if defined(RTCC_PRESENT)
1129     case cmuClock_RTCC:
1130     case cmuClock_RTCCCLK:
1131       rtccClkGet(&ret, NULL);
1132       break;
1133 #endif
1134 #if defined(SYSRTC_PRESENT)
1135     case cmuClock_SYSRTC:
1136     case cmuClock_SYSRTCCLK:
1137       sysrtcClkGet(&ret, NULL);
1138       break;
1139 #endif
1140 #if defined(LCD_PRESENT)
1141     case cmuClock_LCD:
1142     case cmuClock_LCDCLK:
1143       lcdClkGet(&ret, NULL);
1144       break;
1145 #endif
1146 #if defined(VDAC_PRESENT)
1147     case cmuClock_VDAC0:
1148     case cmuClock_VDAC0CLK:
1149       vdac0ClkGet(&ret, NULL);
1150       break;
1151 #if (VDAC_COUNT > 1)
1152     case cmuClock_VDAC1:
1153     case cmuClock_VDAC1CLK:
1154       vdac1ClkGet(&ret, NULL);
1155       break;
1156 #endif
1157 #endif /* VDAC_PRESENT */
1158 #if defined(PCNT_PRESENT)
1159     case cmuClock_PCNT0:
1160     case cmuClock_PCNT0CLK:
1161       pcnt0ClkGet(&ret, NULL);
1162       break;
1163 #endif
1164 #if defined(LESENSE_PRESENT)
1165     case cmuClock_LESENSEHFCLK:
1166       lesenseHFClkGet(&ret, NULL);
1167       break;
1168 #endif
1169     case cmuClock_BURTC:
1170     case cmuClock_EM4GRPACLK:
1171 #if defined(ETAMPDET_PRESENT)
1172     case cmuClock_ETAMPDET:
1173 #endif
1174       em4GrpaClkGet(&ret, NULL);
1175       break;
1176 
1177 #if defined(USB_PRESENT)
1178     case cmuClock_USB:
1179       usbClkGet(&ret, NULL);
1180       break;
1181 #endif
1182 
1183     case cmuClock_DPLLREFCLK:
1184       dpllRefClkGet(&ret, NULL);
1185       break;
1186 
1187     default:
1188       EFM_ASSERT(false);
1189       break;
1190   }
1191 
1192   return ret;
1193 }
1194 #endif // (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
1195 
1196 /***************************************************************************//**
1197  * @brief
1198  *   Get currently selected reference clock used for a clock branch.
1199  *
1200  * @param[in] clock
1201  *   Clock branch to fetch selected ref. clock for.
1202  *
1203  * @return
1204  *   Reference clock used for clocking selected branch, #cmuSelect_Error if
1205  *   invalid @p clock provided.
1206  ******************************************************************************/
CMU_ClockSelectGet(CMU_Clock_TypeDef clock)1207 CMU_Select_TypeDef CMU_ClockSelectGet(CMU_Clock_TypeDef clock)
1208 {
1209   CMU_Select_TypeDef ret = cmuSelect_Error;
1210 
1211   switch (clock) {
1212 // -----------------------------------------------------------------------------
1213     case cmuClock_SYSCLK:
1214       switch (CMU->SYSCLKCTRL & _CMU_SYSCLKCTRL_CLKSEL_MASK) {
1215         case CMU_SYSCLKCTRL_CLKSEL_HFRCODPLL:
1216           ret = cmuSelect_HFRCODPLL;
1217           break;
1218 
1219         case CMU_SYSCLKCTRL_CLKSEL_HFXO:
1220           ret = cmuSelect_HFXO;
1221           break;
1222 
1223         case CMU_SYSCLKCTRL_CLKSEL_CLKIN0:
1224           ret = cmuSelect_CLKIN0;
1225           break;
1226 
1227         case CMU_SYSCLKCTRL_CLKSEL_FSRCO:
1228           ret = cmuSelect_FSRCO;
1229           break;
1230 
1231 #if defined(RFFPLL_PRESENT)
1232         case CMU_SYSCLKCTRL_CLKSEL_RFFPLL0SYS:
1233           ret = cmuSelect_RFFPLLSYS;
1234           break;
1235 #endif
1236         default:
1237           ret = cmuSelect_Error;
1238           EFM_ASSERT(false);
1239           break;
1240       }
1241       break;
1242 
1243 // -----------------------------------------------------------------------------
1244 #if defined(IADC_PRESENT)
1245     case cmuClock_IADC0:
1246     case cmuClock_IADCCLK:
1247       iadcClkGet(NULL, &ret);
1248       break;
1249 #endif
1250 // -----------------------------------------------------------------------------
1251     case cmuClock_TIMER0:
1252     case cmuClock_TIMER1:
1253     case cmuClock_TIMER2:
1254     case cmuClock_TIMER3:
1255 #if TIMER_COUNT > 4
1256     case cmuClock_TIMER4:
1257 #endif
1258 #if TIMER_COUNT > 7
1259     case cmuClock_TIMER5:
1260     case cmuClock_TIMER6:
1261     case cmuClock_TIMER7:
1262 #endif
1263 #if TIMER_COUNT > 9
1264     case cmuClock_TIMER8:
1265     case cmuClock_TIMER9:
1266 #endif
1267 #if defined(KEYSCAN_PRESENT)
1268     case cmuClock_KEYSCAN:
1269 #endif
1270     case cmuClock_EM01GRPACLK:
1271       em01GrpaClkGet(NULL, &ret);
1272       break;
1273 
1274 // -----------------------------------------------------------------------------
1275     case cmuClock_SYSTICK:
1276       sysTickClkGet(NULL, &ret);
1277       break;
1278 
1279     case cmuClock_LETIMER0:
1280     case cmuClock_EM23GRPACLK:
1281 #if defined(LESENSE_PRESENT)
1282     case cmuClock_LESENSE:
1283     case cmuClock_LESENSECLK:
1284 #endif
1285       em23GrpaClkGet(NULL, &ret);
1286       break;
1287 
1288 // -----------------------------------------------------------------------------
1289     case cmuClock_BURTC:
1290     case cmuClock_EM4GRPACLK:
1291 #if defined(ETAMPDET_PRESENT)
1292     case cmuClock_ETAMPDET:
1293 #endif
1294       em4GrpaClkGet(NULL, &ret);
1295       break;
1296 
1297 // -----------------------------------------------------------------------------
1298 #if defined(_CMU_EM01GRPBCLKCTRL_CLKSEL_MASK)
1299     case cmuClock_PDMREF:
1300     case cmuClock_EM01GRPBCLK:
1301       em01GrpbClkGet(NULL, &ret);
1302       break;
1303 #endif
1304 
1305 // -----------------------------------------------------------------------------
1306     case cmuClock_WDOG0:
1307     case cmuClock_WDOG0CLK:
1308       wdog0ClkGet(NULL, &ret);
1309       break;
1310 
1311 // -----------------------------------------------------------------------------
1312 #if defined(_CMU_WDOG1CLKCTRL_CLKSEL_MASK)
1313     case cmuClock_WDOG1:
1314     case cmuClock_WDOG1CLK:
1315       wdog1ClkGet(NULL, &ret);
1316       break;
1317 #endif
1318 
1319 // -----------------------------------------------------------------------------
1320     case cmuClock_DPLLREFCLK:
1321       dpllRefClkGet(NULL, &ret);
1322       break;
1323 
1324 // -----------------------------------------------------------------------------
1325 #if defined(_CMU_TRACECLKCTRL_CLKSEL_MASK)
1326     case cmuClock_TRACECLK:
1327       traceClkGet(NULL, &ret);
1328       break;
1329 #endif
1330 
1331 // -----------------------------------------------------------------------------
1332 #if defined(_CMU_EUART0CLKCTRL_CLKSEL_MASK)
1333     case cmuClock_EUART0:
1334     case cmuClock_EUART0CLK:
1335       euart0ClkGet(NULL, &ret);
1336       break;
1337 #elif defined(EUSART_PRESENT)
1338     case cmuClock_EUSART0:
1339     case cmuClock_EUSART0CLK:
1340       eusart0ClkGet(NULL, &ret);
1341       break;
1342 
1343 #if defined(EUSART_PRESENT) && EUSART_COUNT > 1
1344     case cmuClock_EUSART1:
1345 #endif
1346 #if defined(EUSART_PRESENT) && EUSART_COUNT > 2
1347     case cmuClock_EUSART2:
1348 #endif
1349 #if defined(EUSART_PRESENT) && EUSART_COUNT > 3
1350     case cmuClock_EUSART3:
1351 #endif
1352 #if defined(EUSART_PRESENT) && EUSART_COUNT > 4
1353     case cmuClock_EUSART4:
1354 #endif
1355 #if defined(_CMU_EM01GRPCCLKCTRL_MASK)
1356     case cmuClock_EM01GRPCCLK:
1357       em01GrpcClkGet(NULL, &ret);
1358       break;
1359 #endif
1360  #endif
1361 
1362 // -----------------------------------------------------------------------------
1363 #if defined(RTCC_PRESENT)
1364     case cmuClock_RTCC:
1365     case cmuClock_RTCCCLK:
1366       rtccClkGet(NULL, &ret);
1367       break;
1368 #endif
1369 // -----------------------------------------------------------------------------
1370 #if defined(SYSRTC_PRESENT)
1371     case cmuClock_SYSRTC:
1372     case cmuClock_SYSRTCCLK:
1373       sysrtcClkGet(NULL, &ret);
1374       break;
1375 #endif
1376 // -----------------------------------------------------------------------------
1377 #if defined(LCD_PRESENT)
1378     case cmuClock_LCD:
1379     case cmuClock_LCDCLK:
1380       lcdClkGet(NULL, &ret);
1381       break;
1382 #endif
1383 // -----------------------------------------------------------------------------
1384 #if defined(VDAC_PRESENT)
1385     case cmuClock_VDAC0:
1386     case cmuClock_VDAC0CLK:
1387       vdac0ClkGet(NULL, &ret);
1388       break;
1389 #if (VDAC_COUNT > 1)
1390     case cmuClock_VDAC1:
1391     case cmuClock_VDAC1CLK:
1392       vdac1ClkGet(NULL, &ret);
1393       break;
1394 #endif
1395 #endif
1396 // -----------------------------------------------------------------------------
1397 #if defined(PCNT_PRESENT)
1398     case cmuClock_PCNT0:
1399     case cmuClock_PCNT0CLK:
1400       pcnt0ClkGet(NULL, &ret);
1401       break;
1402 #endif
1403 // -----------------------------------------------------------------------------
1404 #if defined(LESENSE_PRESENT)
1405     case cmuClock_LESENSEHFCLK:
1406       lesenseHFClkGet(NULL, &ret);
1407       break;
1408 #endif
1409 // -----------------------------------------------------------------------------
1410 #if defined(USB_PRESENT)
1411     case cmuClock_USB:
1412       usbClkGet(NULL, &ret);
1413       break;
1414 #endif
1415 // -----------------------------------------------------------------------------
1416     default:
1417       EFM_ASSERT(false);
1418       break;
1419   }
1420   return ret;
1421 }
1422 
1423 /***************************************************************************//**
1424  * @brief Performs pre-clock-selection operations to initialize the system clock.
1425  *
1426  * @note FOR INTERNAL USE ONLY.
1427  *
1428  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
1429  *       the clock is SYSCLK.
1430  ******************************************************************************/
sli_em_cmu_SYSCLKInitPreClockSelect(void)1431 void sli_em_cmu_SYSCLKInitPreClockSelect(void)
1432 {
1433 #if defined(EMU_VSCALE_EM01_PRESENT)
1434   // VSCALE up before changing clock.
1435   EMU_VScaleEM01(emuVScaleEM01_HighPerformance, true);
1436 #endif
1437 
1438   // Save the previous PCLK divisor
1439   pclkDiv = CMU_ClockDivGet(cmuClock_PCLK);
1440 
1441   // Set max wait-states and PCLK divisor while changing core clock.
1442   waitStateMax();
1443   pclkDivMax();
1444 #if ((defined(CMU_SYSCLKCTRL_RHCLKPRESC)) \
1445   && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
1446   // Set largest prescaler for radio clock tree
1447   rhclkPrescMax();
1448 #endif
1449 }
1450 
1451 /***************************************************************************//**
1452  * @brief Performs post-clock-selection operations to initialize the system clock.
1453  *
1454  * @note FOR INTERNAL USE ONLY.
1455  *
1456  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
1457  *       the clock is SYSCLK.
1458  ******************************************************************************/
sli_em_cmu_SYSCLKInitPostClockSelect(bool optimize_divider)1459 void sli_em_cmu_SYSCLKInitPostClockSelect(bool optimize_divider)
1460 {
1461   // Update CMSIS core clock variable and set optimum wait-states.
1462   CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
1463 
1464 #if defined(EMU_VSCALE_EM01_PRESENT)
1465   // Check if possible to downscale VSCALE setting.
1466   EMU_VScaleEM01ByClock(0, true);
1467 #endif
1468 
1469   if (optimize_divider) {
1470     // Set optimal PCLK divisor
1471     pclkDivOptimize();
1472   } else {
1473     // Restore previous PCLK divisor
1474     CMU_ClockDivSet(cmuClock_PCLK, pclkDiv);
1475   }
1476 #if (defined(CMU_SYSCLKCTRL_RHCLKPRESC) \
1477   && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
1478   // Set optimal RHCLK prescaler
1479   rhclkPrescOptimize();
1480 #endif
1481 }
1482 
1483 /***************************************************************************//**
1484  * @brief Sets the HFXO0 FORCEEN bit.
1485  *
1486  * @note FOR INTERNAL USE ONLY.
1487  *
1488  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
1489  *       the clock is SYSCLK and the selected clock source is HFXO.
1490  ******************************************************************************/
sli_em_cmu_HFXOSetForceEnable(void)1491 void sli_em_cmu_HFXOSetForceEnable(void)
1492 {
1493 #if defined(_CMU_CLKEN0_MASK) && defined(CMU_CLKEN0_HFXO0)
1494   CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
1495 #endif
1496   HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
1497 }
1498 
1499 /***************************************************************************//**
1500  * @brief This function will set the SYSCFG->CFGSYSTIC<SYSTICEXTCLKEN> bit.
1501  *
1502  * @note FOR INTERNAL USE ONLY.
1503  *
1504  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
1505  *       the clock is SYSTICK.
1506  ******************************************************************************/
sli_em_cmu_SYSTICEXTCLKENSet(void)1507 void sli_em_cmu_SYSTICEXTCLKENSet(void)
1508 {
1509 #if !defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
1510   bool syscfgClkIsOff = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) == 0);
1511   CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
1512 #endif
1513 
1514   SYSCFG_setSysTicExtClkEnCfgSysTic();
1515 
1516 #if !defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
1517   if (syscfgClkIsOff) {
1518     CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
1519   }
1520 #endif
1521 }
1522 
1523 /***************************************************************************//**
1524  * @brief This function will clear the SYSCFG->CFGSYSTIC<SYSTICEXTCLKEN> bit.
1525  *
1526  * @note FOR INTERNAL USE ONLY.
1527  *
1528  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
1529  *       the clock is SYSTICK.
1530  ******************************************************************************/
sli_em_cmu_SYSTICEXTCLKENClear(void)1531 void sli_em_cmu_SYSTICEXTCLKENClear(void)
1532 {
1533 #if !defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
1534   bool syscfgClkIsOff = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) == 0);
1535   CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
1536 #endif
1537 
1538   SYSCFG_clearSysTicExtClkEnCfgSysTic();
1539 
1540 #if !defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
1541   if (syscfgClkIsOff) {
1542     CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
1543   }
1544 #endif
1545 }
1546 
1547 /***************************************************************************//**
1548  * @brief
1549  *   Select reference clock/oscillator used for a clock branch.
1550  *
1551  * @param[in] clock
1552  *   Clock branch to select reference clock for.
1553  *
1554  * @param[in] ref
1555  *   Reference selected for clocking, please refer to reference manual for
1556  *   for details on which reference is available for a specific clock branch.
1557  ******************************************************************************/
CMU_ClockSelectSet(CMU_Clock_TypeDef clock,CMU_Select_TypeDef ref)1558 void CMU_ClockSelectSet(CMU_Clock_TypeDef clock, CMU_Select_TypeDef ref)
1559 {
1560   uint32_t tmp = 0U;
1561   bool oscForceEnStatus = false;
1562 #if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
1563   bool syscfgClkIsOff = false;
1564 #endif
1565 #if (defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)  \
1566   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)  \
1567   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6)  \
1568   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)  \
1569   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)  \
1570   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_9)) \
1571   && defined(CoreDebug_DEMCR_TRCENA_Msk)
1572   bool restoreTrace;
1573 #endif
1574 
1575   switch (clock) {
1576 // -----------------------------------------------------------------------------
1577     case cmuClock_SYSCLK:
1578       switch (ref) {
1579         case cmuSelect_HFRCODPLL:
1580           tmp = CMU_SYSCLKCTRL_CLKSEL_HFRCODPLL;
1581           break;
1582 
1583         case cmuSelect_HFXO:
1584           tmp = CMU_SYSCLKCTRL_CLKSEL_HFXO;
1585 #if defined(_CMU_CLKEN0_MASK)
1586 #if defined(CMU_CLKEN0_HFXO0)
1587           CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
1588 #endif
1589 #endif
1590           // Make sure HFXO is enabled.
1591           oscForceEnStatus = (HFXO0->CTRL & HFXO_CTRL_DISONDEMAND) != 0;
1592           HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
1593           break;
1594 
1595         case cmuSelect_CLKIN0:
1596           tmp = CMU_SYSCLKCTRL_CLKSEL_CLKIN0;
1597           break;
1598 
1599         case cmuSelect_FSRCO:
1600           tmp = CMU_SYSCLKCTRL_CLKSEL_FSRCO;
1601           break;
1602 
1603 #if defined(RFFPLL_PRESENT)
1604         case cmuSelect_RFFPLLSYS:
1605           tmp = CMU_SYSCLKCTRL_CLKSEL_RFFPLL0SYS;
1606           break;
1607 #endif
1608 
1609         default:
1610           EFM_ASSERT(false);
1611           break;
1612       }
1613 
1614 #if defined(EMU_VSCALE_EM01_PRESENT)
1615       // VSCALE up before changing clock.
1616       EMU_VScaleEM01(emuVScaleEM01_HighPerformance, true);
1617 #endif
1618 
1619       // Set max wait-states and PCLK divisor while changing core clock.
1620       waitStateMax();
1621       pclkDivMax();
1622 #if ((defined(CMU_SYSCLKCTRL_RHCLKPRESC)) \
1623       && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
1624       // Set largest prescaler for radio clock tree
1625       rhclkPrescMax();
1626 #endif
1627 
1628       // Switch to selected oscillator.
1629       CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_CLKSEL_MASK) | tmp;
1630 
1631       // Update CMSIS core clock variable and set optimum wait-states.
1632       CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
1633 
1634 #if defined(EMU_VSCALE_EM01_PRESENT)
1635       // Check if possible to downscale VSCALE setting.
1636       EMU_VScaleEM01ByClock(0, true);
1637 #endif
1638 
1639       // Set optimal PCLK divisor
1640       pclkDivOptimize();
1641 #if (defined(CMU_SYSCLKCTRL_RHCLKPRESC) \
1642       && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
1643       // Set optimal RHCLK prescaler
1644       rhclkPrescOptimize();
1645 #endif
1646 
1647       if (oscForceEnStatus == false) {
1648         switch (ref) {
1649           case cmuSelect_HFXO:
1650             HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
1651 #if defined(HFXO_STATUS_SYNCBUSY)
1652             while ((HFXO0->STATUS & HFXO_STATUS_SYNCBUSY) != 0U) {
1653             }
1654 #endif
1655             break;
1656 
1657           default:
1658             break;
1659         }
1660       }
1661       break;
1662 
1663 // -----------------------------------------------------------------------------
1664 #if defined(IADC_PRESENT)
1665     case cmuClock_IADC0:
1666     case cmuClock_IADCCLK:
1667       switch (ref) {
1668         case cmuSelect_EM01GRPACLK:
1669           tmp = CMU_IADCCLKCTRL_CLKSEL_EM01GRPACLK;
1670           break;
1671 
1672 #if defined(HFRCOEM23_PRESENT)
1673         case cmuSelect_HFRCOEM23:
1674           tmp = CMU_IADCCLKCTRL_CLKSEL_HFRCOEM23;
1675           break;
1676 #endif
1677 
1678         case cmuSelect_FSRCO:
1679           tmp = CMU_IADCCLKCTRL_CLKSEL_FSRCO;
1680           break;
1681 
1682         default:
1683           EFM_ASSERT(false);
1684           break;
1685       }
1686       CMU->IADCCLKCTRL = (CMU->IADCCLKCTRL & ~_CMU_IADCCLKCTRL_CLKSEL_MASK)
1687                          | tmp;
1688       break;
1689 #endif
1690 
1691 // -----------------------------------------------------------------------------
1692     case cmuClock_TIMER0:
1693     case cmuClock_TIMER1:
1694     case cmuClock_TIMER2:
1695     case cmuClock_TIMER3:
1696 #if TIMER_COUNT > 4
1697     case cmuClock_TIMER4:
1698 #endif
1699 #if TIMER_COUNT > 7
1700     case cmuClock_TIMER5:
1701     case cmuClock_TIMER6:
1702     case cmuClock_TIMER7:
1703 #endif
1704 #if TIMER_COUNT > 9
1705     case cmuClock_TIMER8:
1706     case cmuClock_TIMER9:
1707 #endif
1708 #if defined(KEYSCAN_PRESENT)
1709     case cmuClock_KEYSCAN:
1710 #endif
1711     case cmuClock_EM01GRPACLK:
1712       switch (ref) {
1713         case cmuSelect_HFRCODPLL:
1714           tmp = CMU_EM01GRPACLKCTRL_CLKSEL_HFRCODPLL;
1715           break;
1716 
1717         case cmuSelect_HFXO:
1718           tmp = CMU_EM01GRPACLKCTRL_CLKSEL_HFXO;
1719           break;
1720 
1721 #if defined(HFRCOEM23_PRESENT)
1722         case cmuSelect_HFRCOEM23:
1723           tmp = CMU_EM01GRPACLKCTRL_CLKSEL_HFRCOEM23;
1724           break;
1725 #endif
1726 
1727         case cmuSelect_FSRCO:
1728           tmp = CMU_EM01GRPACLKCTRL_CLKSEL_FSRCO;
1729           break;
1730 
1731         case cmuSelect_Disabled:
1732           tmp = CMU_EM01GRPACLKCTRL_CLKSEL_DISABLED;
1733           break;
1734 
1735 #if defined(CMU_EM01GRPACLKCTRL_CLKSEL_HFRCODPLLRT)
1736         case cmuSelect_HFRCODPLLRT:
1737           tmp = CMU_EM01GRPACLKCTRL_CLKSEL_HFRCODPLLRT;
1738           break;
1739 #endif
1740 #if defined(CMU_EM01GRPACLKCTRL_CLKSEL_HFXORT)
1741         case cmuSelect_HFXORT:
1742           tmp = CMU_EM01GRPACLKCTRL_CLKSEL_HFXORT;
1743           break;
1744 #endif
1745         default:
1746           EFM_ASSERT(false);
1747           break;
1748       }
1749       CMU->EM01GRPACLKCTRL = (CMU->EM01GRPACLKCTRL
1750                               & ~_CMU_EM01GRPACLKCTRL_CLKSEL_MASK) | tmp;
1751       break;
1752 
1753 // -----------------------------------------------------------------------------
1754     case cmuClock_SYSTICK:
1755       switch (ref) {
1756         case cmuSelect_EM23GRPACLK:
1757         case cmuSelect_LFXO:
1758         case cmuSelect_LFRCO:
1759         case cmuSelect_ULFRCO:
1760 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
1761           SYSCFG_setSysTicExtClkEnCfgSysTic();
1762 #else
1763           syscfgClkIsOff = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) == 0);
1764           CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
1765           SYSCFG_setSysTicExtClkEnCfgSysTic();
1766           if (syscfgClkIsOff) {
1767             CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
1768           }
1769 #endif
1770           SysTick->CTRL = (SysTick->CTRL & ~SysTick_CTRL_CLKSOURCE_Msk);
1771           break;
1772         case cmuSelect_HCLK:
1773 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
1774           SYSCFG_clearSysTicExtClkEnCfgSysTic();
1775 #else
1776           syscfgClkIsOff = ((CMU->CLKEN0 & CMU_CLKEN0_SYSCFG) == 0);
1777           CMU->CLKEN0_SET = CMU_CLKEN0_SYSCFG;
1778           SYSCFG_clearSysTicExtClkEnCfgSysTic();
1779           if (syscfgClkIsOff) {
1780             CMU->CLKEN0_CLR = CMU_CLKEN0_SYSCFG;
1781           }
1782 #endif
1783           SysTick->CTRL = (SysTick->CTRL | SysTick_CTRL_CLKSOURCE_Msk);
1784           break;
1785         default:
1786           EFM_ASSERT(false);
1787           break;
1788       }
1789       break;
1790 
1791     case cmuClock_LETIMER0:
1792     case cmuClock_EM23GRPACLK:
1793 #if defined(LESENSE_PRESENT)
1794     case cmuClock_LESENSE:
1795     case cmuClock_LESENSECLK:
1796 #endif
1797       switch (ref) {
1798         case cmuSelect_LFRCO:
1799 #if defined(PLFRCO_PRESENT)
1800         case cmuSelect_PLFRCO:
1801 #endif
1802           tmp = CMU_EM23GRPACLKCTRL_CLKSEL_LFRCO;
1803           break;
1804 
1805         case cmuSelect_LFXO:
1806           tmp = CMU_EM23GRPACLKCTRL_CLKSEL_LFXO;
1807           break;
1808 
1809         case cmuSelect_ULFRCO:
1810           tmp = CMU_EM23GRPACLKCTRL_CLKSEL_ULFRCO;
1811           break;
1812 
1813         case cmuSelect_Disabled:
1814           tmp = CMU_EM23GRPACLKCTRL_CLKSEL_DISABLED;
1815           break;
1816 
1817         default:
1818           EFM_ASSERT(false);
1819           break;
1820       }
1821       CMU->EM23GRPACLKCTRL = (CMU->EM23GRPACLKCTRL
1822                               & ~_CMU_EM23GRPACLKCTRL_CLKSEL_MASK) | tmp;
1823       break;
1824 
1825 // -----------------------------------------------------------------------------
1826     case cmuClock_BURTC:
1827 #if defined(ETAMPDET_PRESENT)
1828     case cmuClock_ETAMPDET:
1829 #endif
1830     case cmuClock_EM4GRPACLK:
1831       switch (ref) {
1832         case cmuSelect_LFRCO:
1833 #if defined(PLFRCO_PRESENT)
1834         case cmuSelect_PLFRCO:
1835 #endif
1836           tmp = CMU_EM4GRPACLKCTRL_CLKSEL_LFRCO;
1837           break;
1838 
1839         case cmuSelect_LFXO:
1840           tmp = CMU_EM4GRPACLKCTRL_CLKSEL_LFXO;
1841           break;
1842 
1843         case cmuSelect_ULFRCO:
1844           tmp = CMU_EM4GRPACLKCTRL_CLKSEL_ULFRCO;
1845           break;
1846 
1847         case cmuSelect_Disabled:
1848           tmp = CMU_EM4GRPACLKCTRL_CLKSEL_DISABLED;
1849           break;
1850 
1851         default:
1852           EFM_ASSERT(false);
1853           break;
1854       }
1855       CMU->EM4GRPACLKCTRL = (CMU->EM4GRPACLKCTRL
1856                              & ~_CMU_EM4GRPACLKCTRL_CLKSEL_MASK) | tmp;
1857       break;
1858 
1859 #if defined(_CMU_EM01GRPBCLKCTRL_CLKSEL_MASK)
1860 // -----------------------------------------------------------------------------
1861     case cmuClock_PDMREF:
1862     case cmuClock_EM01GRPBCLK:
1863       switch (ref) {
1864         case cmuSelect_HFRCODPLL:
1865           tmp = CMU_EM01GRPBCLKCTRL_CLKSEL_HFRCODPLL;
1866           break;
1867 
1868         case cmuSelect_HFXO:
1869           tmp = CMU_EM01GRPBCLKCTRL_CLKSEL_HFXO;
1870           break;
1871 
1872         case cmuSelect_FSRCO:
1873           tmp = CMU_EM01GRPBCLKCTRL_CLKSEL_FSRCO;
1874           break;
1875 
1876         case cmuSelect_CLKIN0:
1877           tmp = CMU_EM01GRPBCLKCTRL_CLKSEL_CLKIN0;
1878           break;
1879 
1880         case cmuSelect_HFRCODPLLRT:
1881           tmp = CMU_EM01GRPBCLKCTRL_CLKSEL_HFRCODPLLRT;
1882           break;
1883 
1884         case cmuSelect_HFXORT:
1885           tmp = CMU_EM01GRPBCLKCTRL_CLKSEL_HFXORT;
1886           break;
1887 
1888         case cmuSelect_Disabled:
1889           tmp = CMU_EM01GRPBCLKCTRL_CLKSEL_DISABLED;
1890           break;
1891 
1892         default:
1893           EFM_ASSERT(false);
1894           break;
1895       }
1896       CMU->EM01GRPBCLKCTRL = (CMU->EM01GRPBCLKCTRL
1897                               & ~_CMU_EM01GRPBCLKCTRL_CLKSEL_MASK) | tmp;
1898       break;
1899 #endif
1900 
1901 // -----------------------------------------------------------------------------
1902     case cmuClock_WDOG0:
1903     case cmuClock_WDOG0CLK:
1904       switch (ref) {
1905         case cmuSelect_LFRCO:
1906 #if defined(PLFRCO_PRESENT)
1907         case cmuSelect_PLFRCO:
1908 #endif
1909           tmp = CMU_WDOG0CLKCTRL_CLKSEL_LFRCO;
1910           break;
1911 
1912         case cmuSelect_LFXO:
1913           tmp = CMU_WDOG0CLKCTRL_CLKSEL_LFXO;
1914           break;
1915 
1916         case cmuSelect_ULFRCO:
1917           tmp = CMU_WDOG0CLKCTRL_CLKSEL_ULFRCO;
1918           break;
1919 
1920         case cmuSelect_HCLKDIV1024:
1921           tmp = CMU_WDOG0CLKCTRL_CLKSEL_HCLKDIV1024;
1922           break;
1923 
1924         case cmuSelect_Disabled:
1925           tmp = CMU_WDOG0CLKCTRL_CLKSEL_DISABLED;
1926           break;
1927 
1928         default:
1929           EFM_ASSERT(false);
1930           break;
1931       }
1932       CMU->WDOG0CLKCTRL = (CMU->WDOG0CLKCTRL & ~_CMU_WDOG0CLKCTRL_CLKSEL_MASK)
1933                           | tmp;
1934       break;
1935 
1936 #if defined(_CMU_WDOG1CLKCTRL_CLKSEL_MASK)
1937 // -----------------------------------------------------------------------------
1938     case cmuClock_WDOG1:
1939     case cmuClock_WDOG1CLK:
1940       switch (ref) {
1941         case cmuSelect_LFRCO:
1942 #if defined(PLFRCO_PRESENT)
1943         case cmuSelect_PLFRCO:
1944 #endif
1945           tmp = CMU_WDOG1CLKCTRL_CLKSEL_LFRCO;
1946           break;
1947 
1948         case cmuSelect_LFXO:
1949           tmp = CMU_WDOG1CLKCTRL_CLKSEL_LFXO;
1950           break;
1951 
1952         case cmuSelect_ULFRCO:
1953           tmp = CMU_WDOG1CLKCTRL_CLKSEL_ULFRCO;
1954           break;
1955 
1956         case cmuSelect_HCLKDIV1024:
1957           tmp = CMU_WDOG1CLKCTRL_CLKSEL_HCLKDIV1024;
1958           break;
1959 
1960         case cmuSelect_Disabled:
1961           tmp = CMU_WDOG1CLKCTRL_CLKSEL_DISABLED;
1962           break;
1963 
1964         default:
1965           EFM_ASSERT(false);
1966           break;
1967       }
1968       CMU->WDOG1CLKCTRL = (CMU->WDOG1CLKCTRL & ~_CMU_WDOG1CLKCTRL_CLKSEL_MASK)
1969                           | tmp;
1970       break;
1971 #endif
1972 
1973 // -----------------------------------------------------------------------------
1974     case cmuClock_DPLLREFCLK:
1975       switch (ref) {
1976         case cmuSelect_HFXO:
1977           tmp = CMU_DPLLREFCLKCTRL_CLKSEL_HFXO;
1978           break;
1979 
1980         case cmuSelect_LFXO:
1981           tmp = CMU_DPLLREFCLKCTRL_CLKSEL_LFXO;
1982           break;
1983 
1984         case cmuSelect_CLKIN0:
1985           tmp = CMU_DPLLREFCLKCTRL_CLKSEL_CLKIN0;
1986           break;
1987 
1988         case cmuSelect_Disabled:
1989           tmp = CMU_DPLLREFCLKCTRL_CLKSEL_DISABLED;
1990           break;
1991 
1992         default:
1993           EFM_ASSERT(false);
1994           break;
1995       }
1996       CMU->DPLLREFCLKCTRL = (CMU->DPLLREFCLKCTRL
1997                              & ~_CMU_DPLLREFCLKCTRL_CLKSEL_MASK) | tmp;
1998       break;
1999 
2000 #if defined(_CMU_TRACECLKCTRL_CLKSEL_MASK)
2001 // -----------------------------------------------------------------------------
2002     case cmuClock_TRACECLK:
2003 #if (defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)      \
2004       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)  \
2005       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6)  \
2006       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)  \
2007       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)  \
2008       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_9)) \
2009       && defined(CoreDebug_DEMCR_TRCENA_Msk)
2010       restoreTrace = CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk;
2011       if (restoreTrace) {
2012         CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
2013       }
2014 #endif
2015       switch (ref) {
2016 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
2017         case cmuSelect_HCLK:
2018           tmp = CMU_TRACECLKCTRL_CLKSEL_HCLK;
2019           break;
2020 #endif
2021 
2022 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)        \
2023         || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5) \
2024         || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6) \
2025         || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7) \
2026         || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8) \
2027         || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_9)
2028         case cmuSelect_SYSCLK:
2029           tmp = CMU_TRACECLKCTRL_CLKSEL_SYSCLK;
2030           break;
2031 
2032         case cmuSelect_HFRCODPLLRT:
2033           tmp = CMU_TRACECLKCTRL_CLKSEL_HFRCODPLLRT;
2034           break;
2035 #endif
2036 
2037 #if defined(CMU_TRACECLKCTRL_CLKSEL_HFRCOEM23)
2038         case cmuSelect_HFRCOEM23:
2039           tmp = CMU_TRACECLKCTRL_CLKSEL_HFRCOEM23;
2040           break;
2041 #endif
2042 
2043         default:
2044           EFM_ASSERT(false);
2045           break;
2046       }
2047       CMU->TRACECLKCTRL = (CMU->TRACECLKCTRL & ~_CMU_TRACECLKCTRL_CLKSEL_MASK)
2048                           | tmp;
2049 #if (defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4)      \
2050       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)  \
2051       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6)  \
2052       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_7)  \
2053       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)  \
2054       || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_9)) \
2055       && defined(CoreDebug_DEMCR_TRCENA_Msk)
2056       if (restoreTrace) {
2057         CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
2058       }
2059 #endif
2060       break;
2061 #endif
2062 
2063 #if defined(_CMU_EUART0CLKCTRL_CLKSEL_MASK)
2064 // -----------------------------------------------------------------------------
2065     case cmuClock_EUART0:
2066     case cmuClock_EUART0CLK:
2067       switch (ref) {
2068         case cmuSelect_EM01GRPACLK:
2069           tmp = _CMU_EUART0CLKCTRL_CLKSEL_EM01GRPACLK;
2070           break;
2071 
2072         case cmuSelect_EM23GRPACLK:
2073           tmp = _CMU_EUART0CLKCTRL_CLKSEL_EM23GRPACLK;
2074           break;
2075 
2076         case cmuSelect_Disabled:
2077           tmp = _CMU_EUART0CLKCTRL_CLKSEL_DISABLED;
2078           break;
2079 
2080         default:
2081           EFM_ASSERT(false);
2082           break;
2083       }
2084       CMU->EUART0CLKCTRL = (CMU->EUART0CLKCTRL & ~_CMU_EUART0CLKCTRL_CLKSEL_MASK)
2085                            | tmp;
2086       break;
2087 #elif defined(EUSART_PRESENT)
2088     case cmuClock_EUSART0:
2089     case cmuClock_EUSART0CLK:
2090       switch (ref) {
2091 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPACLK)
2092         case cmuSelect_EM01GRPACLK:
2093           tmp = _CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPACLK;
2094           break;
2095 #endif
2096 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPCCLK)
2097         case cmuSelect_EM01GRPCCLK:
2098           tmp = _CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPCCLK;
2099           break;
2100 #endif
2101 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_EM23GRPACLK)
2102         case cmuSelect_EM23GRPACLK:
2103           tmp = _CMU_EUSART0CLKCTRL_CLKSEL_EM23GRPACLK;
2104           break;
2105 #endif
2106 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_FSRCO)
2107         case cmuSelect_FSRCO:
2108           tmp = _CMU_EUSART0CLKCTRL_CLKSEL_FSRCO;
2109           break;
2110 #endif
2111 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_HFRCOEM23)
2112         case cmuSelect_HFRCOEM23:
2113           tmp = _CMU_EUSART0CLKCTRL_CLKSEL_HFRCOEM23;
2114           break;
2115 #endif
2116 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_LFRCO)
2117         case cmuSelect_LFRCO:
2118 #if defined(PLFRCO_PRESENT)
2119         case cmuSelect_PLFRCO:
2120 #endif
2121           tmp = _CMU_EUSART0CLKCTRL_CLKSEL_LFRCO;
2122           break;
2123 #endif
2124 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_LFXO)
2125         case cmuSelect_LFXO:
2126           tmp = _CMU_EUSART0CLKCTRL_CLKSEL_LFXO;
2127           break;
2128 #endif
2129 
2130 #if defined(_CMU_EUSART0CLKCTRL_CLKSEL_DISABLED)
2131         case cmuSelect_Disabled:
2132           tmp = _CMU_EUSART0CLKCTRL_CLKSEL_DISABLED;
2133           break;
2134 #endif
2135 
2136         default:
2137           EFM_ASSERT(false);
2138           break;
2139       }
2140       CMU->EUSART0CLKCTRL = (CMU->EUSART0CLKCTRL & ~_CMU_EUSART0CLKCTRL_CLKSEL_MASK)
2141                             | tmp;
2142       break;
2143 
2144 #if defined(EUSART_PRESENT) && EUSART_COUNT > 1
2145     case cmuClock_EUSART1:
2146 #endif
2147 #if defined(EUSART_PRESENT) && EUSART_COUNT > 2
2148     case cmuClock_EUSART2:
2149 #endif
2150 #if defined(EUSART_PRESENT) && EUSART_COUNT > 3
2151     case cmuClock_EUSART3:
2152 #endif
2153 #if defined(EUSART_PRESENT) && EUSART_COUNT > 4
2154     case cmuClock_EUSART4:
2155 #endif
2156 #if defined(_CMU_EM01GRPCCLKCTRL_MASK)
2157     case cmuClock_EM01GRPCCLK:
2158       switch (ref) {
2159         case cmuSelect_HFRCODPLL:
2160           tmp = _CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCODPLL;
2161           break;
2162 
2163 #if defined(CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCODPLLRT)
2164         case cmuSelect_HFRCODPLLRT:
2165           tmp = CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCODPLLRT;
2166           break;
2167 #endif
2168 #if defined(_CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCOEM23)
2169         case cmuSelect_HFRCOEM23:
2170           tmp = _CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCOEM23;
2171           break;
2172 #endif
2173         case cmuSelect_FSRCO:
2174           tmp = _CMU_EM01GRPCCLKCTRL_CLKSEL_FSRCO;
2175           break;
2176 
2177         case cmuSelect_HFXO:
2178           tmp = _CMU_EM01GRPCCLKCTRL_CLKSEL_HFXO;
2179           break;
2180 
2181 #if defined(CMU_EM01GRPCCLKCTRL_CLKSEL_HFXORT)
2182         case cmuSelect_HFXORT:
2183           tmp = CMU_EM01GRPCCLKCTRL_CLKSEL_HFXORT;
2184           break;
2185 #endif
2186         default:
2187           EFM_ASSERT(false);
2188           break;
2189       }
2190       CMU->EM01GRPCCLKCTRL = (CMU->EM01GRPCCLKCTRL & ~_CMU_EM01GRPCCLKCTRL_CLKSEL_MASK)
2191                              | tmp;
2192       break;
2193 #endif
2194 #endif
2195 
2196 // -----------------------------------------------------------------------------
2197 #if defined (RTCC_PRESENT)
2198     case cmuClock_RTCC:
2199     case cmuClock_RTCCCLK:
2200       switch (ref) {
2201         case cmuSelect_LFRCO:
2202 #if defined(PLFRCO_PRESENT)
2203         case cmuSelect_PLFRCO:
2204 #endif
2205           tmp = CMU_RTCCCLKCTRL_CLKSEL_LFRCO;
2206           break;
2207 
2208         case cmuSelect_LFXO:
2209           tmp = CMU_RTCCCLKCTRL_CLKSEL_LFXO;
2210           break;
2211 
2212         case cmuSelect_ULFRCO:
2213           tmp = CMU_RTCCCLKCTRL_CLKSEL_ULFRCO;
2214           break;
2215 
2216         default:
2217           EFM_ASSERT(false);
2218           break;
2219       }
2220       CMU->RTCCCLKCTRL = (CMU->RTCCCLKCTRL & ~_CMU_RTCCCLKCTRL_CLKSEL_MASK)
2221                          | tmp;
2222       break;
2223 #endif
2224 // -----------------------------------------------------------------------------
2225 #if defined (SYSRTC_PRESENT)
2226     case cmuClock_SYSRTC:
2227     case cmuClock_SYSRTCCLK:
2228       switch (ref) {
2229         case cmuSelect_LFRCO:
2230 #if defined(PLFRCO_PRESENT)
2231         case cmuSelect_PLFRCO:
2232 #endif
2233           tmp = CMU_SYSRTC0CLKCTRL_CLKSEL_LFRCO;
2234           break;
2235 
2236         case cmuSelect_LFXO:
2237           tmp = CMU_SYSRTC0CLKCTRL_CLKSEL_LFXO;
2238           break;
2239 
2240         case cmuSelect_ULFRCO:
2241           tmp = CMU_SYSRTC0CLKCTRL_CLKSEL_ULFRCO;
2242           break;
2243 
2244         case cmuSelect_Disabled:
2245           tmp = CMU_SYSRTC0CLKCTRL_CLKSEL_DISABLED;
2246           break;
2247 
2248         default:
2249           EFM_ASSERT(false);
2250           break;
2251       }
2252       CMU->SYSRTC0CLKCTRL = (CMU->SYSRTC0CLKCTRL & ~_CMU_SYSRTC0CLKCTRL_CLKSEL_MASK)
2253                             | tmp;
2254       break;
2255 #endif
2256 // -----------------------------------------------------------------------------
2257 #if defined(LCD_PRESENT)
2258     case cmuClock_LCD:
2259     case cmuClock_LCDCLK:
2260       switch (ref) {
2261         case cmuSelect_LFRCO:
2262 #if defined(PLFRCO_PRESENT)
2263         case cmuSelect_PLFRCO:
2264 #endif
2265           tmp = CMU_LCDCLKCTRL_CLKSEL_LFRCO;
2266           break;
2267 
2268         case cmuSelect_LFXO:
2269           tmp = CMU_LCDCLKCTRL_CLKSEL_LFXO;
2270           break;
2271 
2272         case cmuSelect_ULFRCO:
2273           tmp = CMU_LCDCLKCTRL_CLKSEL_ULFRCO;
2274           break;
2275 
2276         default:
2277           EFM_ASSERT(false);
2278           break;
2279       }
2280       CMU->LCDCLKCTRL =  (CMU->LCDCLKCTRL  & ~_CMU_LCDCLKCTRL_CLKSEL_MASK)
2281                         | tmp;
2282       break;
2283 #endif
2284 // -----------------------------------------------------------------------------
2285 #if defined(VDAC_PRESENT)
2286     case cmuClock_VDAC0:
2287     case cmuClock_VDAC0CLK:
2288       switch (ref) {
2289         case cmuSelect_FSRCO:
2290           tmp = CMU_VDAC0CLKCTRL_CLKSEL_FSRCO;
2291           break;
2292         case cmuSelect_HFRCOEM23:
2293           tmp = CMU_VDAC0CLKCTRL_CLKSEL_HFRCOEM23;
2294           break;
2295         case cmuSelect_EM01GRPACLK:
2296           tmp = CMU_VDAC0CLKCTRL_CLKSEL_EM01GRPACLK;
2297           break;
2298         case cmuSelect_EM23GRPACLK:
2299           tmp = CMU_VDAC0CLKCTRL_CLKSEL_EM23GRPACLK;
2300           break;
2301 
2302         default:
2303           EFM_ASSERT(false);
2304           break;
2305       }
2306       CMU->VDAC0CLKCTRL = (CMU->VDAC0CLKCTRL & ~_CMU_VDAC0CLKCTRL_CLKSEL_MASK)
2307                           | tmp;
2308       break;
2309 #if (VDAC_COUNT > 1)
2310     case cmuClock_VDAC1:
2311     case cmuClock_VDAC1CLK:
2312       switch (ref) {
2313         case cmuSelect_FSRCO:
2314           tmp = CMU_VDAC1CLKCTRL_CLKSEL_FSRCO;
2315           break;
2316         case cmuSelect_HFRCOEM23:
2317           tmp = CMU_VDAC1CLKCTRL_CLKSEL_HFRCOEM23;
2318           break;
2319         case cmuSelect_EM01GRPACLK:
2320           tmp = CMU_VDAC1CLKCTRL_CLKSEL_EM01GRPACLK;
2321           break;
2322         case cmuSelect_EM23GRPACLK:
2323           tmp = CMU_VDAC1CLKCTRL_CLKSEL_EM23GRPACLK;
2324           break;
2325 
2326         default:
2327           EFM_ASSERT(false);
2328           break;
2329       }
2330       CMU->VDAC1CLKCTRL = (CMU->VDAC1CLKCTRL & ~_CMU_VDAC1CLKCTRL_CLKSEL_MASK)
2331                           | tmp;
2332       break;
2333 #endif
2334 #endif /* VDAC_PRESENT */
2335 // -----------------------------------------------------------------------------
2336 #if defined(PCNT_PRESENT)
2337     case cmuClock_PCNT0:
2338     case cmuClock_PCNT0CLK:
2339       switch (ref) {
2340         case cmuSelect_EM23GRPACLK:
2341           tmp = CMU_PCNT0CLKCTRL_CLKSEL_EM23GRPACLK;
2342           break;
2343 
2344         case cmuSelect_PCNTEXTCLK:
2345           tmp = CMU_PCNT0CLKCTRL_CLKSEL_PCNTS0;
2346           break;
2347 
2348         default:
2349           EFM_ASSERT(false);
2350           break;
2351       }
2352       CMU->PCNT0CLKCTRL = (CMU->PCNT0CLKCTRL & ~_CMU_PCNT0CLKCTRL_CLKSEL_MASK)
2353                           | tmp;
2354       break;
2355 #endif
2356 // -----------------------------------------------------------------------------
2357 #if defined(LESENSE_PRESENT)
2358     case cmuClock_LESENSEHFCLK:
2359       switch (ref) {
2360         case cmuSelect_FSRCO:
2361           tmp = CMU_LESENSEHFCLKCTRL_CLKSEL_FSRCO;
2362           break;
2363         case cmuSelect_HFRCOEM23:
2364           tmp = CMU_LESENSEHFCLKCTRL_CLKSEL_HFRCOEM23;
2365           break;
2366 
2367         default:
2368           EFM_ASSERT(false);
2369           break;
2370       }
2371       CMU->LESENSEHFCLKCTRL = (CMU->LESENSEHFCLKCTRL & ~_CMU_LESENSEHFCLKCTRL_CLKSEL_MASK)
2372                               | tmp;
2373       break;
2374 #endif
2375 // -----------------------------------------------------------------------------
2376 #if defined(USB_PRESENT)
2377     case cmuClock_USB:
2378       switch (ref) {
2379         case cmuSelect_USBPLL0:
2380           tmp = CMU_USB0CLKCTRL_CLKSEL_USBPLL0;
2381           break;
2382         case cmuSelect_LFXO:
2383           tmp = CMU_USB0CLKCTRL_CLKSEL_LFXO;
2384           break;
2385         case cmuSelect_LFRCO:
2386           tmp = CMU_USB0CLKCTRL_CLKSEL_LFRCO;
2387           break;
2388 
2389         default:
2390           EFM_ASSERT(false);
2391           break;
2392       }
2393       CMU->USB0CLKCTRL = (CMU->USB0CLKCTRL & ~_CMU_USB0CLKCTRL_CLKSEL_MASK)
2394                          | tmp;
2395       break;
2396 #endif
2397 // -----------------------------------------------------------------------------
2398     default:
2399       EFM_ASSERT(false);
2400       break;
2401   }
2402 }
2403 
2404 /***************************************************************************//**
2405  * @brief
2406  *   Gets the precision (in PPM) of the specified low frequency clock branch.
2407  *
2408  * @param[in] clock
2409  *   Clock branch.
2410  *
2411  * @return
2412  *   Precision, in PPM, of the specified clock branch.
2413  *
2414  * @note
2415  *   This function is only for internal usage.
2416  *
2417  * @note
2418  *   The current implementation of this function is used to determine if the
2419  *   clock has a precision <= 500 ppm or not (which is the minimum required
2420  *   for BLE). Future version of this function should provide more accurate
2421  *   precision numbers to allow for further optimizations from the stacks.
2422  ******************************************************************************/
CMU_LF_ClockPrecisionGet(CMU_Clock_TypeDef clock)2423 uint16_t CMU_LF_ClockPrecisionGet(CMU_Clock_TypeDef clock)
2424 {
2425   CMU_Select_TypeDef src = CMU_ClockSelectGet(clock);
2426   uint16_t precision;
2427 
2428   switch (src) {
2429     case cmuSelect_LFXO:
2430       precision = lfxo_precision;
2431       break;
2432 
2433 #if defined(PLFRCO_PRESENT)
2434 #if defined(LFRCO_CFG_HIGHPRECEN)
2435     case cmuSelect_LFRCO:
2436     case cmuSelect_PLFRCO:
2437 
2438       CMU->CLKEN0_SET = CMU_CLKEN0_LFRCO;
2439 
2440       if (LFRCO->CFG & _LFRCO_CFG_HIGHPRECEN_MASK) {
2441         precision = 500;
2442       } else {
2443         precision = 0xFFFF;
2444       }
2445       break;
2446 #endif
2447 #endif
2448 
2449     default:
2450       precision = 0xFFFF;
2451       break;
2452   }
2453 
2454   return precision;
2455 }
2456 
2457 /***************************************************************************//**
2458  * @brief
2459  *   Gets the precision (in PPM) of the specified high frequency clock branch.
2460  *
2461  * @param[in] clock
2462  *   Clock branch.
2463  *
2464  * @return
2465  *   Precision, in PPM, of the specified clock branch.
2466  *
2467  * @note
2468  *   This function is only for internal usage.
2469  *
2470  * @note
2471  *   The current implementation of this function is used to determine if the
2472  *   clock has a precision <= 500 ppm or not (which is the minimum required
2473  *   for BLE). Future version of this function should provide more accurate
2474  *   precision numbers to allow for further optimizations from the stacks.
2475  ******************************************************************************/
CMU_HF_ClockPrecisionGet(CMU_Clock_TypeDef clock)2476 uint16_t CMU_HF_ClockPrecisionGet(CMU_Clock_TypeDef clock)
2477 {
2478   CMU_Select_TypeDef src = CMU_ClockSelectGet(clock);
2479   uint16_t precision;
2480 
2481   switch (src) {
2482     case cmuSelect_HFXO:
2483       precision = hfxo_precision;
2484       break;
2485 
2486     case cmuSelect_HFRCODPLL:
2487       precision = 0xFFFF;
2488       break;
2489 
2490     default:
2491       precision = 0xFFFF;
2492       break;
2493   }
2494 
2495   return precision;
2496 }
2497 
2498 /***************************************************************************//**
2499  * @brief
2500  *   Get HFRCODPLL band in use.
2501  *
2502  * @return
2503  *   HFRCODPLL band in use.
2504  ******************************************************************************/
CMU_HFRCODPLLBandGet(void)2505 CMU_HFRCODPLLFreq_TypeDef CMU_HFRCODPLLBandGet(void)
2506 {
2507   return (CMU_HFRCODPLLFreq_TypeDef)SystemHFRCODPLLClockGet();
2508 }
2509 
2510 /***************************************************************************//**
2511  * @brief
2512  *   Set HFRCODPLL band and the tuning value based on the value in the
2513  *   calibration table made during production.
2514  *
2515  * @param[in] freq
2516  *   HFRCODPLL frequency band to activate.
2517  ******************************************************************************/
CMU_HFRCODPLLBandSet(CMU_HFRCODPLLFreq_TypeDef freq)2518 void CMU_HFRCODPLLBandSet(CMU_HFRCODPLLFreq_TypeDef freq)
2519 {
2520   uint32_t hfrcoFreqRangeExpected;
2521   uint32_t hfrcoFreqRangeActual;
2522   uint32_t hfrcoCalCurrent;
2523   uint32_t freqCal, sysFreq;
2524 #if defined(EMU_VSCALE_EM01_PRESENT)
2525   uint32_t prevFreq;
2526 #endif
2527 
2528   // Get calibration data from DEVINFO
2529   freqCal = HFRCODPLLDevinfoGet(freq);
2530   EFM_ASSERT((freqCal != 0UL) && (freqCal != UINT_MAX));
2531 
2532 #if defined(CMU_CLKEN0_DPLL0)
2533   CMU->CLKEN0_SET = CMU_CLKEN0_DPLL0 | CMU_CLKEN0_HFRCO0;
2534 #endif
2535 
2536   // Make sure DPLL is disabled before configuring
2537   if (DPLL0->EN == DPLL_EN_EN) {
2538     DPLL0->EN_CLR = DPLL_EN_EN;
2539 #if defined(DPLL_EN_DISABLING)
2540     while (DPLL0->EN & DPLL_EN_DISABLING) {
2541     }
2542 #else
2543     while ((DPLL0->STATUS & (DPLL_STATUS_ENS | DPLL_STATUS_RDY)) != 0UL) {
2544     }
2545 #endif
2546   }
2547 
2548   // Set max wait-states and PCLK divisor while changing core clock
2549   if (CMU_ClockSelectGet(cmuClock_SYSCLK) == cmuSelect_HFRCODPLL) {
2550     waitStateMax();
2551     pclkDivMax();
2552 #if ((defined(CMU_SYSCLKCTRL_RHCLKPRESC)) \
2553     && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
2554     // Set largest prescaler for radio clock tree
2555     rhclkPrescMax();
2556 #endif
2557   }
2558 
2559   // Set divider for 1, 2 and 4MHz bands
2560   freqCal &= ~_HFRCO_CAL_CLKDIV_MASK;
2561   switch (freq) {
2562     case cmuHFRCODPLLFreq_1M0Hz:
2563       freqCal |= HFRCO_CAL_CLKDIV_DIV4;
2564       break;
2565 
2566     case cmuHFRCODPLLFreq_2M0Hz:
2567       freqCal |= HFRCO_CAL_CLKDIV_DIV2;
2568       break;
2569 
2570     default:
2571       break;
2572   }
2573 
2574 #if defined(EMU_VSCALE_EM01_PRESENT)
2575   prevFreq = SystemHFRCODPLLClockGet();
2576 
2577   if ((uint32_t)freq > prevFreq) {
2578     /* When increasing frequency voltage scale must be done before the change. */
2579     EMU_VScaleEM01ByClock((uint32_t)freq, true);
2580   }
2581 #endif
2582 
2583   // updates to the CAL register are deferred if FREQBSY is high, so wait
2584   // until HFRCO is not busy to keep going
2585   while (HFRCO0->STATUS & (HFRCO_STATUS_SYNCBUSY | HFRCO_STATUS_FREQBSY)) {
2586   }
2587 
2588   /*
2589    * Some devices have clamped frequency ranges, so instead of the usual [0:16]
2590    * interval, the upper limit is 12. Hardware takes care of clamping the value,
2591    * but a situation might occur where tuning and frequency range are not
2592    * in sync. So try to detect if the value has been clamped, and if it happened
2593    * revert back to the previous value.
2594    */
2595   hfrcoCalCurrent = HFRCO0->CAL;
2596   HFRCO0->CAL = freqCal;
2597 
2598   // values are not shifted, not necessary for comparison
2599   hfrcoFreqRangeExpected = (freqCal     & _HFRCO_CAL_FREQRANGE_MASK);
2600   hfrcoFreqRangeActual   = (HFRCO0->CAL & _HFRCO_CAL_FREQRANGE_MASK);
2601 
2602   EFM_ASSERT(hfrcoFreqRangeExpected == hfrcoFreqRangeActual);
2603   if (hfrcoFreqRangeExpected == hfrcoFreqRangeActual) {
2604     // Update CMSIS HFRCODPLL frequency.
2605     SystemHFRCODPLLClockSet(freq);
2606   } else {
2607     // revert back to previous value
2608     HFRCO0->CAL = hfrcoCalCurrent;
2609 #if defined(EMU_VSCALE_EM01_PRESENT)
2610     freq = (CMU_HFRCODPLLFreq_TypeDef)prevFreq;
2611 #endif
2612   }
2613 
2614   // If HFRCODPLL is selected as SYSCLK (and HCLK), optimize flash access
2615   // wait-state configuration and PCLK divisor for this frequency.
2616   if (CMU_ClockSelectGet(cmuClock_SYSCLK) == cmuSelect_HFRCODPLL) {
2617     // Call @ref SystemCoreClockGet() to update CMSIS core clock variable.
2618     sysFreq = SystemCoreClockGet();
2619     EFM_ASSERT(sysFreq <= (uint32_t)freq);
2620     CMU_UpdateWaitStates(sysFreq, VSCALE_DEFAULT);
2621     pclkDivOptimize();
2622 #if (defined(CMU_SYSCLKCTRL_RHCLKPRESC) \
2623     && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
2624     // Set optimal RHCLK prescaler
2625     rhclkPrescOptimize();
2626 #endif
2627   }
2628 
2629 #if defined(EMU_VSCALE_EM01_PRESENT)
2630   if ((uint32_t)freq <= prevFreq) {
2631     /* When decreasing frequency voltage scale must be done after the change. */
2632     EMU_VScaleEM01ByClock(0, true);
2633   }
2634 #endif
2635 }
2636 
2637 /**************************************************************************//**
2638  * @brief
2639  *   Lock the DPLL to a given frequency.
2640  *   The frequency is given by: Fout = Fref * (N+1) / (M+1).
2641  *
2642  * @note
2643  *   This function does not check if the given N & M values will actually
2644  *   produce the desired target frequency. @n
2645  *   N & M limitations: @n
2646  *     300 < N <= 4095 @n
2647  *     0 <= M <= 4095 @n
2648  *   Any peripheral running off HFRCODPLL should be switched to a lower
2649  *   frequency clock (if possible) prior to calling this function to avoid
2650  *   over-clocking.
2651  *
2652  * @param[in] init
2653  *    DPLL setup parameter struct.
2654  *
2655  * @return
2656  *   Returns false on invalid target frequency or DPLL locking error.
2657  *****************************************************************************/
CMU_DPLLLock(const CMU_DPLLInit_TypeDef * init)2658 bool CMU_DPLLLock(const CMU_DPLLInit_TypeDef *init)
2659 {
2660   int index = 0;
2661   unsigned int i;
2662   bool hclkDivIncreased = false;
2663   uint32_t hfrcoCalVal, lockStatus = 0, hclkDiv = 0, sysFreq;
2664   uint32_t hfrcoFreqRangeExpected;
2665   uint32_t hfrcoFreqRangeActual;
2666   uint32_t hfrcoCalCurrent;
2667   bool hfrcoClamped = false;
2668   bool restoreDpll;
2669 
2670 #if defined(CMU_CLKEN0_DPLL0)
2671   CMU->CLKEN0_SET = CMU_CLKEN0_DPLL0 | CMU_CLKEN0_HFRCO0;
2672 #endif
2673 
2674   restoreDpll = DPLL0->EN & _DPLL_EN_EN_MASK;
2675 
2676   // Make sure DPLL is disabled before configuring
2677   DPLL0->EN_CLR = DPLL_EN_EN;
2678 #if defined(DPLL_EN_DISABLING)
2679   while (DPLL0->EN & DPLL_EN_DISABLING) {
2680   }
2681 #else
2682   while ((DPLL0->STATUS & (DPLL_STATUS_ENS | DPLL_STATUS_RDY)) != 0UL) {
2683   }
2684 #endif
2685   EFM_ASSERT(init->frequency >= hfrcoCalTable[0].minFreq);
2686   EFM_ASSERT(init->frequency
2687              <= hfrcoCalTable[HFRCOCALTABLE_ENTRIES - 1U].maxFreq);
2688 
2689   EFM_ASSERT(init->n > 300U);
2690   EFM_ASSERT(init->n <= (_DPLL_CFG1_N_MASK >> _DPLL_CFG1_N_SHIFT));
2691   EFM_ASSERT(init->m <= (_DPLL_CFG1_M_MASK >> _DPLL_CFG1_M_SHIFT));
2692 
2693 #if defined(EMU_VSCALE_EM01_PRESENT)
2694   if ((EMU_VScaleGet() == emuVScaleEM01_LowPower)
2695       && (init->frequency > CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX)) {
2696     EFM_ASSERT(false);
2697     return false;
2698   }
2699 #endif
2700 
2701   // Find correct HFRCODPLL band, and retrieve a HFRCOCAL value.
2702   for (i = 0; i < HFRCOCALTABLE_ENTRIES; i++) {
2703     if ((init->frequency    >= hfrcoCalTable[i].minFreq)
2704         && (init->frequency <= hfrcoCalTable[i].maxFreq)) {
2705       index = (int)i;                       // Correct band found
2706       break;
2707     }
2708   }
2709   if ((uint32_t)index == HFRCOCALTABLE_ENTRIES) {
2710     EFM_ASSERT(false);
2711     return false;                           // Target frequency out of spec.
2712   }
2713   hfrcoCalVal = hfrcoCalTable[index].value;
2714 
2715   // Check if a calibrated HFRCOCAL.TUNING value is present in device DI page.
2716   if (hfrcoCalTable[index].band != (CMU_HFRCODPLLFreq_TypeDef)0) {
2717     uint32_t tuning;
2718 
2719     tuning = (HFRCODPLLDevinfoGet(hfrcoCalTable[index].band)
2720               & _HFRCO_CAL_TUNING_MASK)
2721              >> _HFRCO_CAL_TUNING_SHIFT;
2722     hfrcoCalVal |= tuning << _HFRCO_CAL_TUNING_SHIFT;
2723   }
2724 
2725   if (CMU_ClockSelectGet(cmuClock_SYSCLK) == cmuSelect_HFRCODPLL) {
2726     // Set max wait-states and PCLK divisor while changing core clock
2727     waitStateMax();
2728     pclkDivMax();
2729 #if ((defined(CMU_SYSCLKCTRL_RHCLKPRESC)) \
2730     && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
2731     // Set largest prescaler for radio clock tree
2732     rhclkPrescMax();
2733 #endif
2734 
2735     // Increase HCLK divider value (if possible) while locking DPLL to
2736     // avoid over-clocking.
2737     hclkDiv = CMU_ClockDivGet(cmuClock_HCLK);
2738     hclkDivIncreased = true;
2739     if (hclkDiv == 1U) {
2740       CMU_ClockDivSet(cmuClock_HCLK, 2U);
2741     } else if (hclkDiv == 2U) {
2742       CMU_ClockDivSet(cmuClock_HCLK, 4U);
2743     } else {
2744       hclkDivIncreased = false;
2745     }
2746   }
2747 
2748   // updates to the CAL register are deferred if FREQBSY is high, so wait
2749   // until HFRCO is not busy to keep going
2750   while (HFRCO0->STATUS & (HFRCO_STATUS_SYNCBUSY | HFRCO_STATUS_FREQBSY)) {
2751   }
2752 
2753   /*
2754    * Some devices have clamped frequency ranges, so instead of the usual [0:16]
2755    * interval, the upper limit is 12. Hardware takes care of clamping the value,
2756    * but a situation might occur where tuning and frequency range are not
2757    * in sync. So try to detect if the value has been clamped, and if it happened
2758    * revert back to the previous value.
2759    */
2760   hfrcoCalCurrent = HFRCO0->CAL;
2761   HFRCO0->CAL = hfrcoCalVal;
2762 
2763   // values are not shifted, not necessary for comparison
2764   hfrcoFreqRangeExpected = (hfrcoCalVal & _HFRCO_CAL_FREQRANGE_MASK);
2765   hfrcoFreqRangeActual   = (HFRCO0->CAL & _HFRCO_CAL_FREQRANGE_MASK);
2766 
2767   EFM_ASSERT(hfrcoFreqRangeExpected == hfrcoFreqRangeActual);
2768   if (hfrcoFreqRangeExpected == hfrcoFreqRangeActual) {
2769     DPLL0->CFG1   = ((uint32_t)init->n   << _DPLL_CFG1_N_SHIFT)
2770                     | ((uint32_t)init->m << _DPLL_CFG1_M_SHIFT);
2771 
2772     /* For series 2 silicon, macro expansion is used to select clock
2773      * sources since it results in less code size when compared to the legacy
2774      * CMU_ClockSelectSet function.
2775      */
2776     if (init->refClk == cmuSelect_HFXO) {
2777       CMU_CLOCK_SELECT_SET(DPLLREFCLK, HFXO);
2778     } else if (init->refClk == cmuSelect_LFXO) {
2779       CMU_CLOCK_SELECT_SET(DPLLREFCLK, LFXO);
2780     } else if (init->refClk == cmuSelect_CLKIN0) {
2781       CMU_CLOCK_SELECT_SET(DPLLREFCLK, CLKIN0);
2782     }
2783 
2784     DPLL0->CFG = ((init->autoRecover ? 1UL : 0UL) << _DPLL_CFG_AUTORECOVER_SHIFT)
2785                  | ((init->ditherEn ? 1UL : 0UL)  << _DPLL_CFG_DITHEN_SHIFT)
2786                  | ((uint32_t)init->edgeSel  << _DPLL_CFG_EDGESEL_SHIFT)
2787                  | ((uint32_t)init->lockMode << _DPLL_CFG_MODE_SHIFT);
2788 
2789     // Update CMSIS HFRCODPLL frequency.
2790     SystemHFRCODPLLClockSet(init->frequency);
2791   } else {
2792     hfrcoClamped = true;
2793     HFRCO0->CAL = hfrcoCalCurrent;
2794   }
2795 
2796   /*
2797    * if HFRCO frequency range has been clamped, re-enable DPLL only if it was
2798    * previously enabled
2799    */
2800   if (!hfrcoClamped || restoreDpll) {
2801     DPLL0->IF_CLR = DPLL_IF_LOCK | DPLL_IF_LOCKFAILLOW | DPLL_IF_LOCKFAILHIGH;
2802 
2803     // Lock DPLL
2804     DPLL0->EN_SET = DPLL_EN_EN;
2805     while ((lockStatus = (DPLL0->IF & (DPLL_IF_LOCK
2806                                        | DPLL_IF_LOCKFAILLOW
2807                                        | DPLL_IF_LOCKFAILHIGH))) == 0UL) {
2808     }
2809   }
2810 
2811   if (CMU_ClockSelectGet(cmuClock_SYSCLK) == cmuSelect_HFRCODPLL) {
2812     if (hclkDivIncreased) {
2813       // Restore original HCLK divider
2814       CMU_ClockDivSet(cmuClock_HCLK, hclkDiv);
2815     }
2816 
2817     // Call @ref SystemCoreClockGet() to update CMSIS core clock variable.
2818     sysFreq = SystemCoreClockGet();
2819     EFM_ASSERT(sysFreq <= init->frequency);
2820     EFM_ASSERT(sysFreq <= SystemHFRCODPLLClockGet());
2821     EFM_ASSERT(init->frequency == SystemHFRCODPLLClockGet());
2822 
2823     // Set optimal wait-states and PCLK divisor
2824     CMU_UpdateWaitStates(sysFreq, VSCALE_DEFAULT);
2825     pclkDivOptimize();
2826 #if (defined(CMU_SYSCLKCTRL_RHCLKPRESC) \
2827     && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
2828     // Set optimal RHCLK prescaler
2829     rhclkPrescOptimize();
2830 #endif
2831   }
2832 
2833   if (hfrcoClamped) {
2834     return false;
2835   } else if (lockStatus == DPLL_IF_LOCK) {
2836     return true;
2837   }
2838   return false;
2839 }
2840 
2841 #if defined(USBPLL_PRESENT)
2842 /***************************************************************************//**
2843  * @brief
2844  *   Initialize the USB PLL control registers.
2845  *
2846  * @note
2847  *  The HFXO reference frequency must be updated if crystal value is
2848  *  different from default value.
2849  *
2850  * @param[in] pllInit
2851  *   USB PLL parameters
2852  ******************************************************************************/
CMU_USBPLLInit(const CMU_USBPLL_Init_TypeDef * pllInit)2853 void CMU_USBPLLInit(const CMU_USBPLL_Init_TypeDef *pllInit)
2854 {
2855   CMU->CLKEN1_SET = CMU_CLKEN1_USB;
2856 
2857   USBPLL0->LOCK = USBPLL_LOCK_LOCKKEY_UNLOCK;
2858 
2859   // Stop the PLL for configuration purposes
2860   USBPLL0->CTRL_SET = USBPLL_CTRL_DISONDEMAND;
2861   USBPLL0->CTRL_CLR = USBPLL_CTRL_FORCEEN;
2862 
2863   while (USBPLL0->STATUS & USBPLL_STATUS_PLLLOCK) ;
2864 
2865   if (pllInit->hfxoRefFreq == cmuHFXORefFreq_39M0Hz) {
2866     // Set DCO in low frequency mode for 39 MHz crystal.
2867     USBPLL0->DCOCTRL_SET = _USBPLL_DCOCTRL_DCOBIASHALF_MASK;
2868   } else {
2869     USBPLL0->DCOCTRL_CLR = _USBPLL_DCOCTRL_DCOBIASHALF_MASK;
2870   }
2871 
2872   while (USBPLL0->STATUS & USBPLL_STATUS_SYNCBUSY) ;
2873 
2874   USBPLL0->CTRL = (USBPLL0->CTRL & ~(_USBPLL_CTRL_SHUNTREGLPEN_MASK
2875                                      | _USBPLL_CTRL_DIVR_MASK
2876                                      | _USBPLL_CTRL_DIVX_MASK
2877                                      | _USBPLL_CTRL_DIVN_MASK
2878                                      | _USBPLL_CTRL_DISONDEMAND_MASK
2879                                      | _USBPLL_CTRL_FORCEEN_MASK))
2880                   | pllInit->hfxoRefFreq
2881                   | pllInit->shuntRegEn  << _USBPLL_CTRL_SHUNTREGLPEN_SHIFT
2882                   | pllInit->disOnDemand << _USBPLL_CTRL_DISONDEMAND_SHIFT
2883                   | pllInit->forceEn     << _USBPLL_CTRL_FORCEEN_SHIFT;
2884 
2885   while (USBPLL0->STATUS & USBPLL_STATUS_SYNCBUSY) ;
2886 
2887   if (pllInit->forceEn) {
2888     CMU_WaitUSBPLLLock();
2889   }
2890 
2891   if (pllInit->regLock) {
2892     USBPLL0->LOCK = ~USBPLL_LOCK_LOCKKEY_UNLOCK;
2893   }
2894 }
2895 #endif
2896 
2897 #if defined(RFFPLL_PRESENT)
2898 /***************************************************************************//**
2899  * @brief
2900  *   Initialize the RFFPLL control registers.
2901  *
2902  * @param[in] pllInit
2903  *   RFF PLL parameters
2904  ******************************************************************************/
CMU_RFFPLLInit(const CMU_RFFPLL_Init_TypeDef * pllInit)2905 void CMU_RFFPLLInit(const CMU_RFFPLL_Init_TypeDef *pllInit)
2906 {
2907   EFM_ASSERT(CMU_ClockSelectGet(cmuClock_SYSCLK) != cmuSelect_RFFPLLSYS);
2908   EFM_ASSERT(pllInit->dividerY >= 8 && pllInit->dividerY <= 31);
2909   EFM_ASSERT(pllInit->dividerX >= 4 && pllInit->dividerX <= 15);
2910   EFM_ASSERT(pllInit->dividerN >= 32 && pllInit->dividerN <= 127);
2911 
2912   CMU->CLKEN1_SET = CMU_CLKEN1_RFFPLL0;
2913 
2914   RFFPLL0->LOCK = RFFPLL_LOCK_LOCKKEY_UNLOCK;
2915 
2916   RFFPLL0->CTRL = (RFFPLL0->CTRL & ~(_RFFPLL_CTRL_DISONDEMAND_MASK | _RFFPLL_CTRL_FORCEEN_MASK))
2917                   | (pllInit->disOnDemand << _RFFPLL_CTRL_DISONDEMAND_SHIFT)
2918                   | (pllInit->forceEn     << _RFFPLL_CTRL_FORCEEN_SHIFT);
2919 
2920   RFFPLL0->RFFPLLCTRL1 = (RFFPLL0->RFFPLLCTRL1 & ~(_RFFPLL_RFFPLLCTRL1_DIVY_MASK | _RFFPLL_RFFPLLCTRL1_DIVX_MASK | _RFFPLL_RFFPLLCTRL1_DIVN_MASK))
2921                          | (pllInit->dividerY << _RFFPLL_RFFPLLCTRL1_DIVY_SHIFT)
2922                          | (pllInit->dividerX << _RFFPLL_RFFPLLCTRL1_DIVX_SHIFT)
2923                          | (pllInit->dividerN << _RFFPLL_RFFPLLCTRL1_DIVN_SHIFT);
2924 
2925   // Update CMSIS RFFPLL frequency.
2926   SystemRFFPLLClockSet(pllInit->frequency);
2927 
2928   if (pllInit->forceEn) {
2929     CMU_WaitRFFPLLLock();
2930   }
2931 
2932   if (pllInit->regLock) {
2933     RFFPLL0->LOCK = ~USBPLL_LOCK_LOCKKEY_UNLOCK;
2934   }
2935 }
2936 #endif
2937 
2938 /**************************************************************************//**
2939  * @brief
2940  *   Initialize all HFXO control registers.
2941  *
2942  * @note
2943  *   HFXO configuration should be obtained from a configuration tool,
2944  *   app note or crystal datasheet. This function returns early if HFXO is
2945  *   already selected as SYSCLK.
2946  *
2947  * @param[in] hfxoInit
2948  *    HFXO setup parameters.
2949  *****************************************************************************/
CMU_HFXOInit(const CMU_HFXOInit_TypeDef * hfxoInit)2950 void CMU_HFXOInit(const CMU_HFXOInit_TypeDef *hfxoInit)
2951 {
2952   // Check all initialization structure members which may overflow target
2953   // bitfield.
2954   EFM_ASSERT(hfxoInit->timeoutCbLsb
2955              <= (_HFXO_XTALCFG_TIMEOUTCBLSB_MASK
2956                  >> _HFXO_XTALCFG_TIMEOUTCBLSB_SHIFT));
2957   EFM_ASSERT(hfxoInit->timeoutSteadyFirstLock
2958              <= (_HFXO_XTALCFG_TIMEOUTSTEADY_MASK
2959                  >> _HFXO_XTALCFG_TIMEOUTSTEADY_SHIFT));
2960   EFM_ASSERT(hfxoInit->timeoutSteady
2961              <= (_HFXO_XTALCFG_TIMEOUTSTEADY_MASK
2962                  >> _HFXO_XTALCFG_TIMEOUTSTEADY_SHIFT));
2963   EFM_ASSERT(hfxoInit->ctuneXoStartup
2964              <= (_HFXO_XTALCFG_CTUNEXOSTARTUP_MASK
2965                  >> _HFXO_XTALCFG_CTUNEXOSTARTUP_SHIFT));
2966   EFM_ASSERT(hfxoInit->ctuneXiStartup
2967              <= (_HFXO_XTALCFG_CTUNEXISTARTUP_MASK
2968                  >> _HFXO_XTALCFG_CTUNEXISTARTUP_SHIFT));
2969   EFM_ASSERT(hfxoInit->coreBiasStartup
2970              <= (_HFXO_XTALCFG_COREBIASSTARTUP_MASK
2971                  >> _HFXO_XTALCFG_COREBIASSTARTUP_SHIFT));
2972   EFM_ASSERT(hfxoInit->imCoreBiasStartup
2973              <= (_HFXO_XTALCFG_COREBIASSTARTUPI_MASK
2974                  >> _HFXO_XTALCFG_COREBIASSTARTUPI_SHIFT));
2975   EFM_ASSERT(hfxoInit->coreDegenAna
2976              <= (_HFXO_XTALCTRL_COREDGENANA_MASK
2977                  >> _HFXO_XTALCTRL_COREDGENANA_SHIFT));
2978   EFM_ASSERT(hfxoInit->ctuneFixAna
2979              <= (_HFXO_XTALCTRL_CTUNEFIXANA_MASK
2980                  >> _HFXO_XTALCTRL_CTUNEFIXANA_SHIFT));
2981   EFM_ASSERT(hfxoInit->mode
2982              <= (_HFXO_CFG_MODE_MASK >> _HFXO_CFG_MODE_SHIFT));
2983 
2984   // Return early if HFXO is already selected as SYSCLK.
2985   if (CMU_ClockSelectGet(cmuClock_SYSCLK) == cmuSelect_HFXO) {
2986     return;
2987   }
2988 
2989 #if defined(CMU_CLKEN0_HFXO0)
2990   // Enable HFXO module clock.
2991   CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
2992 #endif
2993 
2994   // Unlock register interface.
2995   HFXO0->LOCK = HFXO_LOCK_LOCKKEY_UNLOCK;
2996 
2997   // Disable HFXO.
2998   HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND
2999 #if defined(_HFXO_CTRL_DISONDEMANDBUFOUT_MASK)
3000                     | HFXO_CTRL_DISONDEMANDBUFOUT
3001 #endif
3002   ;
3003   HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
3004   while ((HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) != 0U) {
3005   }
3006 #if defined(HFXO_STATUS_SYNCBUSY)
3007   while ((HFXO0->STATUS & HFXO_STATUS_SYNCBUSY) != 0U) {
3008   }
3009 #endif
3010 
3011 #if defined(_DEVINFO_HFXOCAL_VTRTRIMANA_MASK) && defined(_HFXO_BUFOUTTRIM_MASK) && defined(_HFXO_SWRST_MASK)
3012   {
3013     uint32_t tmp;
3014 
3015     tmp = BUS_RegMaskedRead(&DEVINFO->HFXOCAL,
3016                             _DEVINFO_HFXOCAL_VTRTRIMANA_MASK);
3017     tmp >>= _DEVINFO_HFXOCAL_VTRTRIMANA_SHIFT;
3018     BUS_RegMaskedWrite(&HFXO0->BUFOUTTRIM,
3019                        _HFXO_BUFOUTTRIM_VTRTRIMANA_MASK,
3020                        tmp << _HFXO_BUFOUTTRIM_VTRTRIMANA_SHIFT);
3021   }
3022 #endif
3023 
3024 #if defined(_DEVINFO_HFXOCAL_SHUNTBIASANA_MASK) && defined(_HFXO_LOWPWRCTRL_MASK) && defined(_HFXO_SWRST_MASK)
3025   {
3026     uint32_t tmp;
3027 
3028     tmp = BUS_RegMaskedRead(&DEVINFO->HFXOCAL,
3029                             _DEVINFO_HFXOCAL_SHUNTBIASANA_MASK);
3030     tmp >>= _DEVINFO_HFXOCAL_SHUNTBIASANA_SHIFT;
3031     BUS_RegMaskedWrite(&HFXO0->LOWPWRCTRL,
3032                        _HFXO_LOWPWRCTRL_SHUNTBIASANA_MASK,
3033                        tmp << _HFXO_LOWPWRCTRL_SHUNTBIASANA_SHIFT);
3034   }
3035 #endif
3036 
3037   // Configure HFXO as specified in initialization struct, use
3038   // timeoutSteadyFirstLock as TIMEOUTSTEADY value.
3039   HFXO0->XTALCFG =
3040     (uint32_t)((hfxoInit->timeoutCbLsb           << _HFXO_XTALCFG_TIMEOUTCBLSB_SHIFT)
3041                | (hfxoInit->timeoutSteadyFirstLock << _HFXO_XTALCFG_TIMEOUTSTEADY_SHIFT)
3042                | (hfxoInit->ctuneXoStartup         << _HFXO_XTALCFG_CTUNEXOSTARTUP_SHIFT)
3043                | (hfxoInit->ctuneXiStartup         << _HFXO_XTALCFG_CTUNEXISTARTUP_SHIFT)
3044                | (hfxoInit->coreBiasStartup        << _HFXO_XTALCFG_COREBIASSTARTUP_SHIFT)
3045                | (hfxoInit->imCoreBiasStartup      << _HFXO_XTALCFG_COREBIASSTARTUPI_SHIFT));
3046 
3047   HFXO0->XTALCTRL = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_SKIPCOREBIASOPT_MASK)
3048                     | (hfxoInit->coreDegenAna    << _HFXO_XTALCTRL_COREDGENANA_SHIFT)
3049                     | (hfxoInit->ctuneFixAna     << _HFXO_XTALCTRL_CTUNEFIXANA_SHIFT)
3050                     | (hfxoInit->ctuneXoAna      << _HFXO_XTALCTRL_CTUNEXOANA_SHIFT)
3051                     | (hfxoInit->ctuneXiAna      << _HFXO_XTALCTRL_CTUNEXIANA_SHIFT)
3052                     | (hfxoInit->coreBiasAna     << _HFXO_XTALCTRL_COREBIASANA_SHIFT);
3053 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3) \
3054   || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
3055   // See [PM-2871] for details.
3056   BUS_RegMaskedWrite((volatile uint32_t*)(HFXO0_BASE + 0x38U),
3057                      0x00000C00U,
3058                      0x00000002U << 10);
3059 #endif
3060 
3061   HFXO0->CFG = (HFXO0->CFG & ~(_HFXO_CFG_SQBUFSCHTRGANA_MASK
3062                                | _HFXO_CFG_ENXIDCBIASANA_MASK
3063                                | _HFXO_CFG_MODE_MASK))
3064                | ((hfxoInit->mode == cmuHfxoOscMode_Crystal)
3065                   ? 0 : HFXO_CFG_SQBUFSCHTRGANA)
3066                | (hfxoInit->enXiDcBiasAna    << _HFXO_CFG_ENXIDCBIASANA_SHIFT)
3067                | (hfxoInit->mode             << _HFXO_CFG_MODE_SHIFT);
3068 
3069   if (hfxoInit->mode == cmuHfxoOscMode_Crystal) {
3070     // Lock HFXO with FORCEEN bit set and DISONDEMAND bit cleared.
3071     HFXO0->CTRL = (HFXO0->CTRL & ~(_HFXO_CTRL_FORCEXO2GNDANA_MASK
3072                                    | _HFXO_CTRL_FORCEXI2GNDANA_MASK
3073                                    | _HFXO_CTRL_DISONDEMAND_MASK
3074 #if defined(HFXO_CTRL_EM23ONDEMAND)
3075                                    | _HFXO_CTRL_EM23ONDEMAND_MASK
3076 #endif
3077                                    | _HFXO_CTRL_FORCEEN_MASK))
3078                   | (hfxoInit->forceXo2GndAna << _HFXO_CTRL_FORCEXO2GNDANA_SHIFT)
3079                   | (hfxoInit->forceXi2GndAna << _HFXO_CTRL_FORCEXI2GNDANA_SHIFT)
3080 #if defined(HFXO_CTRL_EM23ONDEMAND)
3081                   | (hfxoInit->em23OnDemand   << _HFXO_CTRL_EM23ONDEMAND_SHIFT)
3082 #endif
3083                   | HFXO_CTRL_FORCEEN;
3084 
3085     // Wait for HFXO lock and core bias algorithm to complete.
3086 #if defined(HFXO_STATUS_FSMLOCK)
3087     while ((HFXO0->STATUS & (HFXO_STATUS_RDY | HFXO_STATUS_COREBIASOPTRDY
3088                              | HFXO_STATUS_ENS | HFXO_STATUS_FSMLOCK))
3089            != (HFXO_STATUS_RDY | HFXO_STATUS_COREBIASOPTRDY | HFXO_STATUS_ENS
3090                | HFXO_STATUS_FSMLOCK)) {
3091     }
3092 #else
3093     while ((HFXO0->STATUS & (HFXO_STATUS_RDY | HFXO_STATUS_COREBIASOPTRDY
3094                              | HFXO_STATUS_ENS))
3095            != (HFXO_STATUS_RDY | HFXO_STATUS_COREBIASOPTRDY | HFXO_STATUS_ENS)) {
3096     }
3097 #endif
3098     // Set DISONDEMAND to be able to enter new values for use on subsequent locks.
3099     HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
3100 #if defined(HFXO_CMD_MANUALOVERRIDE)
3101     HFXO0->CMD = HFXO_CMD_MANUALOVERRIDE;
3102 #endif
3103 #if defined(HFXO_STATUS_FSMLOCK)
3104     while ((HFXO0->STATUS & HFXO_STATUS_FSMLOCK) != 0) {
3105     }
3106 #endif
3107     // Set new TIMEOUTSTEADY value for use on subsequent locks.
3108     HFXO0->XTALCFG = (HFXO0->XTALCFG & ~_HFXO_XTALCFG_TIMEOUTSTEADY_MASK)
3109                      | (hfxoInit->timeoutSteady
3110                         << _HFXO_XTALCFG_TIMEOUTSTEADY_SHIFT);
3111 
3112     // Skip core bias algorithm on subsequent locks.
3113     HFXO0->XTALCTRL_SET = HFXO_XTALCTRL_SKIPCOREBIASOPT;
3114 
3115     if (hfxoInit->disOnDemand == false) {
3116       HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
3117     }
3118 
3119     if (hfxoInit->forceEn == false) {
3120       HFXO0->CTRL_CLR = HFXO_CTRL_FORCEEN;
3121 #if defined(HFXO_STATUS_SYNCBUSY)
3122       while ((HFXO0->STATUS & HFXO_STATUS_SYNCBUSY) != 0U) {
3123       }
3124 #endif
3125     }
3126   } else {
3127     // Lock HFXO in EXTERNAL SINE mode.
3128 
3129 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_3)    \
3130     || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_4) \
3131     || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_6) \
3132     || defined(_SILICON_LABS_32B_SERIES_2_CONFIG_8)
3133     //See [PM-3665] for details.
3134     if (hfxoInit->mode == cmuHfxoOscMode_ExternalSinePkDet) {
3135       HFXO0->XTALCFG = 0;
3136       HFXO0->XTALCTRL = 0;
3137 
3138       const uint32_t PKDETTHSTARTUP_PARAMETER_1 = 2UL;
3139       BUS_RegMaskedWrite((volatile uint32_t *)(HFXO0_BASE + 0x34U),
3140                          0x0000F000U | 0x00000F00U,
3141                          (PKDETTHSTARTUP_PARAMETER_1 << 12) | (PKDETTHSTARTUP_PARAMETER_1 << 8));
3142     }
3143 #endif
3144 
3145     HFXO0->CTRL = (HFXO0->CTRL & ~(_HFXO_CTRL_FORCEXO2GNDANA_MASK
3146                                    | _HFXO_CTRL_FORCEXI2GNDANA_MASK
3147                                    | _HFXO_CTRL_DISONDEMAND_MASK
3148 #if defined(HFXO_CTRL_EM23ONDEMAND)
3149                                    | _HFXO_CTRL_EM23ONDEMAND_MASK
3150 #endif
3151                                    | _HFXO_CTRL_FORCEEN_MASK))
3152                   | (hfxoInit->forceXo2GndAna << _HFXO_CTRL_FORCEXO2GNDANA_SHIFT)
3153                   | (hfxoInit->disOnDemand    << _HFXO_CTRL_DISONDEMAND_SHIFT)
3154 #if defined(HFXO_CTRL_EM23ONDEMAND)
3155                   | (hfxoInit->em23OnDemand   << _HFXO_CTRL_EM23ONDEMAND_SHIFT)
3156 #endif
3157                   | (hfxoInit->forceEn        << _HFXO_CTRL_FORCEEN_SHIFT);
3158   }
3159 
3160   if (hfxoInit->regLock) {
3161     HFXO0->LOCK = ~HFXO_LOCK_LOCKKEY_UNLOCK;
3162   }
3163 }
3164 
3165 #if defined(HFXO0_BUFOUT)
3166 /**************************************************************************//**
3167  * @brief
3168  *   Initialize HFXO Bufout (Crystal sharing) leader control registers.
3169  *   Configure the bufout request input GPIO as a clock request signal
3170  *   to add the crystal sharing follower chip as a source of clock request.
3171  *
3172  * @warning
3173  *   If EM2 capabilities are needed, a GPIO that fully retains its
3174  *   capabilities while in EM2 must be selected.
3175  *
3176  * @param[in] bufoutInit
3177  *   Bufout setup parameters.
3178  *
3179  * @param[in] port
3180  *   Bufout request GPIO port.
3181  *
3182  * @param[in] pin
3183  *   Bufout request GPIO pin.
3184  *****************************************************************************/
CMU_HFXOStartCrystalSharingLeader(const CMU_BUFOUTLeaderInit_TypeDef * bufoutInit,GPIO_Port_TypeDef port,unsigned int pin)3185 void CMU_HFXOStartCrystalSharingLeader(const CMU_BUFOUTLeaderInit_TypeDef *bufoutInit,
3186                                        GPIO_Port_TypeDef                   port,
3187                                        unsigned int                        pin)
3188 {
3189   EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin));
3190 
3191   // Configure Bufout request GPIO.
3192   GPIO_PinModeSet(port, pin, gpioModeInput, 0U);
3193   GPIO->SYXOROUTE[0].BUFOUTREQINASYNCROUTE = pin    << _GPIO_SYXO_BUFOUTREQINASYNCROUTE_PIN_SHIFT
3194                                              | port << _GPIO_SYXO_BUFOUTREQINASYNCROUTE_PORT_SHIFT;
3195 
3196   bool wasLocked = HFXO0->STATUS & HFXO_STATUS_LOCK_LOCKED ? true : false;
3197 
3198   // Unlock register interface.
3199   HFXO0->LOCK = HFXO_LOCK_LOCKKEY_UNLOCK;
3200 
3201   HFXO0->CTRL_CLR = _HFXO_CTRL_BUFOUTFREEZE_MASK | _HFXO_CTRL_DISONDEMANDBUFOUT_MASK;
3202 
3203   BUS_RegMaskedWrite(&HFXO0->BUFOUTCTRL,
3204                      _HFXO_BUFOUTCTRL_MINIMUMSTARTUPDELAY_MASK
3205                      | _HFXO_BUFOUTCTRL_TIMEOUTSTARTUP_MASK,
3206                      bufoutInit->minimalStartupDelay  << _HFXO_BUFOUTCTRL_MINIMUMSTARTUPDELAY_SHIFT
3207                      | bufoutInit->timeoutStartup       << _HFXO_BUFOUTCTRL_TIMEOUTSTARTUP_SHIFT);
3208 
3209   if (wasLocked) {
3210     HFXO0->LOCK = ~HFXO_LOCK_LOCKKEY_UNLOCK;
3211   }
3212 }
3213 #endif
3214 
3215 #if defined(_HFXO_CTRL_PRSSTATUSSEL0_MASK)
3216 /**************************************************************************//**
3217  * @brief
3218  *   Initialize HFXO Bufout (Crystal sharing) follower control registers.
3219  *   Configure the clock request signal to a specified GPIO to automatically
3220  *   request the high frequency crystal oscillator sine wave clock.
3221  *   This function must be used in conjunction with CMU_HFXOInit() configured
3222  *   with EXTERNAL_SINE or EXTERNAL_SINEPKDET mode.
3223  *
3224  * @warning
3225  *   If EM2 capabilities are needed, a GPIO that fully retains its
3226  *   capabilities while in EM2 must be selected.
3227  *
3228  * @note
3229  *   This function can be emulated on XG21/XG22 chips by controlling the clock
3230  *   request GPIO to ask the crystal sharing leader clock when needed.
3231  *
3232  * @param[in] prsStatusSelectOutput
3233  *    Selected HFXO PRS signal output.
3234  *
3235  * @param[in] prsAsyncCh
3236  *    PRS producer asynchronous signal channel.
3237  *
3238  * @param[in] port
3239  *    Bufout request GPIO port.
3240  *
3241  * @param[in] pin
3242  *    Bufout request GPIO pin.
3243  *****************************************************************************/
CMU_HFXOCrystalSharingFollowerInit(CMU_PRS_Status_Output_Select_TypeDef prsStatusSelectOutput,unsigned int prsAsyncCh,GPIO_Port_TypeDef port,unsigned int pin)3244 void CMU_HFXOCrystalSharingFollowerInit(CMU_PRS_Status_Output_Select_TypeDef prsStatusSelectOutput,
3245                                         unsigned int                         prsAsyncCh,
3246                                         GPIO_Port_TypeDef                    port,
3247                                         unsigned int                         pin)
3248 {
3249   EFM_ASSERT(prsAsyncCh < PRS_ASYNC_CH_NUM);
3250   EFM_ASSERT(GPIO_PORT_PIN_VALID(port, pin));
3251 
3252   uint32_t mask = 0U, prsSignal = 0U, value = 0U;
3253 
3254   switch (prsStatusSelectOutput) {
3255     case PRS_Status_select_0:
3256       mask      = _HFXO_CTRL_PRSSTATUSSEL0_MASK;
3257       value     = _HFXO_CTRL_PRSSTATUSSEL0_ENS << _HFXO_CTRL_PRSSTATUSSEL0_SHIFT;
3258       prsSignal = _PRS_ASYNC_CH_CTRL_SIGSEL_HFXO0LSTATUS;
3259       break;
3260 
3261     case PRS_Status_select_1:
3262 #if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
3263       // Power Manager module requires the HFXO PRS Producer output 1 for its usage.
3264       EFM_ASSERT(false);
3265 #else
3266       mask      = _HFXO_CTRL_PRSSTATUSSEL1_MASK;
3267       value     = _HFXO_CTRL_PRSSTATUSSEL1_ENS << _HFXO_CTRL_PRSSTATUSSEL1_SHIFT;
3268       prsSignal = _PRS_ASYNC_CH_CTRL_SIGSEL_HFXO0LSTATUS1;
3269 #endif
3270       break;
3271 
3272     default:
3273       EFM_ASSERT(false);
3274       break;
3275   }
3276 
3277   bool wasLocked = HFXO0->STATUS & HFXO_STATUS_LOCK_LOCKED ? true : false;
3278 
3279   // Unlock register interface.
3280   HFXO0->LOCK = HFXO_LOCK_LOCKKEY_UNLOCK;
3281 
3282   BUS_RegMaskedWrite(&HFXO0->CTRL, mask, value);
3283 
3284   if (wasLocked) {
3285     HFXO0->LOCK = ~HFXO_LOCK_LOCKKEY_UNLOCK;
3286   }
3287 
3288   value = _PRS_ASYNC_CH_CTRL_AUXSEL_DEFAULT     << _PRS_ASYNC_CH_CTRL_AUXSEL_SHIFT
3289           | _PRS_ASYNC_CH_CTRL_FNSEL_A          << _PRS_ASYNC_CH_CTRL_FNSEL_SHIFT
3290           | _PRS_ASYNC_CH_CTRL_SOURCESEL_HFXO0L << _PRS_ASYNC_CH_CTRL_SOURCESEL_SHIFT
3291           | prsSignal                           << _PRS_ASYNC_CH_CTRL_SIGSEL_SHIFT;
3292 
3293   mask = _PRS_ASYNC_CH_CTRL_AUXSEL_MASK
3294          | _PRS_ASYNC_CH_CTRL_FNSEL_MASK
3295          | _PRS_ASYNC_CH_CTRL_SOURCESEL_MASK
3296          | _PRS_ASYNC_CH_CTRL_SIGSEL_MASK;
3297 
3298   BUS_RegMaskedWrite(&(PRS->ASYNC_CH[prsAsyncCh].CTRL), mask, value);
3299 
3300   GPIO_PinModeSet(port, pin, gpioModeWiredOrPullDown, 0U);
3301 
3302   (&(GPIO->PRSROUTE[0].ASYNCH0ROUTE))[prsAsyncCh] = pin    << _GPIO_PRS_ASYNCH0ROUTE_PIN_SHIFT
3303                                                     | port << _GPIO_PRS_ASYNCH0ROUTE_PORT_SHIFT;
3304   GPIO->PRSROUTE[0].ROUTEEN = 1U << (_GPIO_PRS_ROUTEEN_ASYNCH0PEN_SHIFT + prsAsyncCh);
3305 }
3306 #endif
3307 
3308 /**************************************************************************//**
3309  * @brief
3310  *   Set the HFXO crystal tuning capacitance.
3311  *
3312  * @param[in] ctune
3313  *   The desired tuning capacitance value. Each step corresponds to
3314  *   approximately 80fF. Min value is 0. Max value is 255.
3315  *
3316  * @return
3317  *   SL_STATUS_OK if initialization parameter is valid.
3318  *   SL_STATUS_INVALID_PARAMETER if initialization parameter is invalid.
3319  *
3320  * @note
3321  *   While the oscillator is running in steady operation state, it may be
3322  *   desirable to modify the tuning capacitance via CTUNEXIANA and CTUNEXOANA
3323  *   fields in the HFXO_XTALCTRL register. When tuning, care should be taken to
3324  *   make small changes to the CTUNE registers. Ideally, change the CTUNE
3325  *   registers by one LSB at a time and alternate between the XI and XO
3326  *   registers. Sufficient wait time for settling, on the order of
3327  *   TIMEOUTSTEADY, should pass before new frequency measurement is taken.
3328  *****************************************************************************/
CMU_HFXOCTuneSet(uint32_t ctune)3329 SL_WEAK sl_status_t CMU_HFXOCTuneSet(uint32_t ctune)
3330 {
3331   uint32_t hfxoCtrlBkup = HFXO0->CTRL;
3332 
3333   // Make sure the given CTUNE value is within the allowable range
3334   if (ctune > (_HFXO_XTALCTRL_CTUNEXIANA_MASK >> _HFXO_XTALCTRL_CTUNEXIANA_SHIFT)) {
3335     return SL_STATUS_INVALID_PARAMETER;
3336   }
3337 
3338   // Keep oscillator running, if it is enabled
3339   if (HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) {
3340     HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
3341   }
3342 
3343   HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
3344 
3345 #if defined(HFXO_CMD_MANUALOVERRIDE)
3346   if (HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) {
3347     // Manual override needs COREBIASOPTRDY asserted,
3348     // or the command will be ignored.
3349     while ((HFXO0->STATUS & HFXO_STATUS_COREBIASOPTRDY) == 0) {
3350     }
3351   }
3352   HFXO0->CMD_SET = HFXO_CMD_MANUALOVERRIDE;
3353 #endif
3354 
3355 #if defined(HFXO_STATUS_FSMLOCK)
3356   while ((HFXO0->STATUS & HFXO_STATUS_FSMLOCK) != 0) {
3357     // Wait for crystal to switch modes.
3358   }
3359 #endif
3360 
3361   int32_t ctuneXoana = ctune + CMU_HFXOCTuneDeltaGet();
3362   if (ctuneXoana < 0) {
3363     ctuneXoana = 0;
3364   } else if (ctuneXoana > (int32_t)(_HFXO_XTALCTRL_CTUNEXOANA_MASK >> _HFXO_XTALCTRL_CTUNEXOANA_SHIFT)) {
3365     ctuneXoana = (int32_t)(_HFXO_XTALCTRL_CTUNEXOANA_MASK >> _HFXO_XTALCTRL_CTUNEXOANA_SHIFT); // Max value
3366   }
3367 
3368   HFXO0->XTALCTRL = ((HFXO0->XTALCTRL & ~(_HFXO_XTALCTRL_CTUNEXOANA_MASK | _HFXO_XTALCTRL_CTUNEXIANA_MASK))
3369                      | ((uint32_t)ctuneXoana << _HFXO_XTALCTRL_CTUNEXOANA_SHIFT)
3370                      | ((ctune << _HFXO_XTALCTRL_CTUNEXIANA_SHIFT) & _HFXO_XTALCTRL_CTUNEXIANA_MASK));
3371 
3372   BUS_RegMaskedWrite(&HFXO0->CTRL, _HFXO_CTRL_DISONDEMAND_MASK, hfxoCtrlBkup);
3373 
3374   // Unforce to return control to hardware request
3375   if (HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) {
3376     BUS_RegMaskedWrite(&HFXO0->CTRL, _HFXO_CTRL_FORCEEN_MASK, hfxoCtrlBkup);
3377   }
3378 
3379   return SL_STATUS_OK;
3380 }
3381 
3382 /**************************************************************************//**
3383  * @brief
3384  *   Get the HFXO crystal tuning capacitance.
3385  *
3386  * @return
3387  *   The HFXO crystal tuning capacitance.
3388  *
3389  * @note
3390      This function only returns the CTUNE XI value. The XO value can be
3391      different and can be found using the delta (difference between XI and XO).
3392      See @ref CMU_HFXOCTuneCurrentDeltaGet to retrieve the delta value.
3393  *****************************************************************************/
CMU_HFXOCTuneGet(void)3394 SL_WEAK uint32_t CMU_HFXOCTuneGet(void)
3395 {
3396   uint32_t ctune = 0;
3397   uint32_t hfxoCtrlBkup = HFXO0->CTRL;
3398 
3399   // Keep oscillator running, if it is enabled
3400   if (HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) {
3401     HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
3402   }
3403 
3404   HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
3405 
3406 #if defined(HFXO_CMD_MANUALOVERRIDE)
3407   if (HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) {
3408     // Manual override needs COREBIASOPTRDY asserted,
3409     // or the command will be ignored.
3410     while ((HFXO0->STATUS & HFXO_STATUS_COREBIASOPTRDY) == 0) {
3411     }
3412   }
3413   HFXO0->CMD_SET = HFXO_CMD_MANUALOVERRIDE;
3414 #endif
3415 
3416 #if defined(HFXO_STATUS_FSMLOCK)
3417   while ((HFXO0->STATUS & HFXO_STATUS_FSMLOCK) != 0) {
3418     // Wait for crystal to switch modes.
3419   }
3420 #endif
3421 
3422   ctune = ((HFXO0->XTALCTRL & _HFXO_XTALCTRL_CTUNEXIANA_MASK)
3423            >> _HFXO_XTALCTRL_CTUNEXIANA_SHIFT);
3424 
3425   BUS_RegMaskedWrite(&HFXO0->CTRL, _HFXO_CTRL_DISONDEMAND_MASK, hfxoCtrlBkup);
3426 
3427   // Unforce to return control to hardware request
3428   if (HFXO0->STATUS & _HFXO_STATUS_ENS_MASK) {
3429     BUS_RegMaskedWrite(&HFXO0->CTRL, _HFXO_CTRL_FORCEEN_MASK, hfxoCtrlBkup);
3430   }
3431 
3432   return ctune;
3433 }
3434 
3435 /**************************************************************************//**
3436  * @brief
3437  *   Set the HFXO crystal tuning delta.
3438  *
3439  * @param[in] delta
3440  *    Chip dependent crystal capacitor bank delta between HFXO XI and XO.
3441  *
3442  * @note
3443  *   The delta between XI and XO is applicable for the series 2 EFR32xG2x
3444  *   devices only. Neither XI nor XO is actually modified by this function,
3445  *   CMU_HFXOCTuneSet() needs to be called for the change to be propagated.
3446  *****************************************************************************/
CMU_HFXOCTuneDeltaSet(int32_t delta)3447 void CMU_HFXOCTuneDeltaSet(int32_t delta)
3448 {
3449   ctuneDelta = (int8_t)delta;
3450 }
3451 
3452 /**************************************************************************//**
3453  * @brief
3454  *   Get the HFXO crystal tuning delta. It can be default recommended delta value
3455  *   or value set by CMU_HFXOCTuneDeltaSet.
3456  *
3457  * @return
3458  *   Chip dependent crystal capacitor bank tuning delta.
3459  *****************************************************************************/
CMU_HFXOCTuneDeltaGet(void)3460 int32_t CMU_HFXOCTuneDeltaGet(void)
3461 {
3462   return (int32_t)ctuneDelta;
3463 }
3464 
3465 /**************************************************************************//**
3466  * @brief
3467  *   Get the current delta between HFXO XI and XO.
3468  *
3469  * @return
3470  *   the current delta between HFXO XI and XO.
3471  *****************************************************************************/
CMU_HFXOCTuneCurrentDeltaGet(void)3472 int32_t CMU_HFXOCTuneCurrentDeltaGet(void)
3473 {
3474   uint32_t ctune;
3475   uint32_t ctuneXO;
3476   int32_t ctuneCurrentDelta;
3477 
3478   ctune = ((HFXO0->XTALCTRL & _HFXO_XTALCTRL_CTUNEXIANA_MASK)
3479            >> _HFXO_XTALCTRL_CTUNEXIANA_SHIFT);
3480   ctuneXO = ((HFXO0->XTALCTRL & _HFXO_XTALCTRL_CTUNEXOANA_MASK)
3481              >> _HFXO_XTALCTRL_CTUNEXOANA_SHIFT);
3482   ctuneCurrentDelta = (int32_t)ctuneXO - (int32_t)ctune;
3483   return ctuneCurrentDelta;
3484 }
3485 
3486 /**************************************************************************//**
3487  * @brief
3488  *   Recalibrate the HFXO's Core Bias Current.
3489  *
3490  * @note
3491  *   Care should be taken when using this function as it can cause disturbance
3492  *   on the HFXO frequency while the optimization is underway. It's recommended
3493  *   to only use this function when HFXO isn't being used. It's also a blocking
3494  *   function that can be time consuming.
3495  *****************************************************************************/
CMU_HFXOCoreBiasCurrentCalibrate(void)3496 SL_WEAK void CMU_HFXOCoreBiasCurrentCalibrate(void)
3497 {
3498   uint32_t hfxoCtrlBkup = HFXO0->CTRL;
3499 
3500   // These two bits need to be set to allow writing the registers
3501   HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
3502   while ((HFXO0->STATUS & (HFXO_STATUS_COREBIASOPTRDY | HFXO_STATUS_RDY)) != (HFXO_STATUS_COREBIASOPTRDY | HFXO_STATUS_RDY)) {
3503     // Wait for crystal to startup
3504   }
3505 
3506   HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
3507 
3508 #if defined(HFXO_CMD_MANUALOVERRIDE)
3509   HFXO0->CMD_SET = HFXO_CMD_MANUALOVERRIDE;
3510 #endif
3511 
3512 #if defined(HFXO_STATUS_FSMLOCK)
3513   while ((HFXO0->STATUS & HFXO_STATUS_FSMLOCK) != 0) {
3514     // Wait for crystal to switch modes.
3515   }
3516 #endif
3517 
3518   while ((HFXO0->STATUS & (HFXO_STATUS_COREBIASOPTRDY | HFXO_STATUS_RDY | HFXO_STATUS_ENS))
3519          != (HFXO_STATUS_COREBIASOPTRDY | HFXO_STATUS_RDY | HFXO_STATUS_ENS)) {
3520     // Making sure HFXO is in steady state
3521   }
3522 
3523   // Start core bias optimization
3524   HFXO0->CMD_SET = HFXO_CMD_COREBIASOPT;
3525   while ((HFXO0->STATUS & HFXO_STATUS_COREBIASOPTRDY) == HFXO_STATUS_COREBIASOPTRDY) {
3526     // Wait for core bias optimization to start
3527   }
3528   while ((HFXO0->STATUS & HFXO_STATUS_COREBIASOPTRDY) == 0) {
3529     // Wait for core bias optimization to finish
3530   }
3531 
3532   // Force COREBIASANA bitfields modification
3533 #if defined(HFXO_CMD_MANUALOVERRIDE)
3534   HFXO0->CMD_SET = HFXO_CMD_MANUALOVERRIDE;
3535 #endif
3536 
3537   while ((HFXO0->STATUS & HFXO_STATUS_COREBIASOPTRDY) == 0) {
3538     // Wait for core bias current value to be written in COREBIASANA bitfields
3539   }
3540 
3541   BUS_RegMaskedWrite(&HFXO0->CTRL, (_HFXO_CTRL_DISONDEMAND_MASK | _HFXO_CTRL_FORCEEN_MASK), hfxoCtrlBkup);
3542 }
3543 
3544 /**************************************************************************//**
3545  * @brief
3546  *   Initialize LFXO control registers.
3547  *
3548  * @note
3549  *   LFXO configuration should be obtained from a configuration tool,
3550  *   app note or crystal datasheet. This function disables the LFXO to ensure
3551  *   a valid state before update.
3552  *
3553  * @param[in] lfxoInit
3554  *    LFXO setup parameters
3555  *****************************************************************************/
CMU_LFXOInit(const CMU_LFXOInit_TypeDef * lfxoInit)3556 void CMU_LFXOInit(const CMU_LFXOInit_TypeDef *lfxoInit)
3557 {
3558   EFM_ASSERT(lfxoInit->timeout
3559              <= (_LFXO_CFG_TIMEOUT_MASK  >> _LFXO_CFG_TIMEOUT_SHIFT));
3560   EFM_ASSERT(lfxoInit->mode
3561              <= (_LFXO_CFG_MODE_MASK >> _LFXO_CFG_MODE_SHIFT));
3562   EFM_ASSERT(lfxoInit->gain
3563              <= (_LFXO_CAL_GAIN_MASK >> _LFXO_CAL_GAIN_SHIFT));
3564   EFM_ASSERT(lfxoInit->capTune
3565              <= (_LFXO_CAL_CAPTUNE_MASK >> _LFXO_CAL_CAPTUNE_SHIFT));
3566 
3567   // Max internal capacitance tuning value is 0x4F (20 pF)
3568   uint8_t ctune = (uint8_t) SL_MIN(0x4FU, lfxoInit->capTune);
3569 
3570 #if defined(CMU_CLKEN0_LFXO)
3571   // Enable LFXO module clock.
3572   CMU->CLKEN0_SET = CMU_CLKEN0_LFXO;
3573 #endif
3574 
3575   // Unlock register interface
3576   LFXO->LOCK = LFXO_LOCK_LOCKKEY_UNLOCK;
3577 
3578   // Disable LFXO
3579   LFXO->CTRL_SET = LFXO_CTRL_DISONDEMAND;
3580   LFXO->CTRL_CLR = LFXO_CTRL_FORCEEN;
3581   while ((LFXO->STATUS & _LFXO_STATUS_ENS_MASK) != 0U) {
3582   }
3583 
3584   // Configure LFXO as specified
3585   LFXO->CAL = ((uint32_t)lfxoInit->gain  << _LFXO_CAL_GAIN_SHIFT)
3586               | ((uint32_t)ctune         << _LFXO_CAL_CAPTUNE_SHIFT);
3587 
3588   LFXO->CFG = (uint32_t)((lfxoInit->timeout           << _LFXO_CFG_TIMEOUT_SHIFT)
3589                          | (lfxoInit->mode            << _LFXO_CFG_MODE_SHIFT)
3590                          | (lfxoInit->highAmplitudeEn << _LFXO_CFG_HIGHAMPL_SHIFT)
3591                          | (lfxoInit->agcEn           << _LFXO_CFG_AGC_SHIFT));
3592 
3593   LFXO->CTRL = (uint32_t)((lfxoInit->failDetEM4WUEn   << _LFXO_CTRL_FAILDETEM4WUEN_SHIFT)
3594                           | (lfxoInit->failDetEn      << _LFXO_CTRL_FAILDETEN_SHIFT)
3595                           | (lfxoInit->disOnDemand    << _LFXO_CTRL_DISONDEMAND_SHIFT)
3596                           | (lfxoInit->forceEn        << _LFXO_CTRL_FORCEEN_SHIFT));
3597 
3598   if (lfxoInit->regLock) {
3599     LFXO->LOCK = ~LFXO_LOCK_LOCKKEY_UNLOCK;
3600   }
3601 }
3602 
3603 /**************************************************************************//**
3604  * @brief
3605  *   Sets LFXO's crystal precision, in PPM.
3606  *
3607  * @note
3608  *   LFXO precision should be obtained from a crystal datasheet.
3609  *
3610  * @param[in] precision
3611  *    LFXO's crystal precision, in PPM.
3612  *****************************************************************************/
CMU_LFXOPrecisionSet(uint16_t precision)3613 void CMU_LFXOPrecisionSet(uint16_t precision)
3614 {
3615   lfxo_precision = precision;
3616 }
3617 
3618 /**************************************************************************//**
3619  * @brief
3620  *   Gets LFXO's crystal precision, in PPM.
3621  *
3622  * @param[in] precision
3623  *    LFXO's crystal precision, in PPM.
3624  *****************************************************************************/
CMU_LFXOPrecisionGet(void)3625 uint16_t CMU_LFXOPrecisionGet(void)
3626 {
3627   return lfxo_precision;
3628 }
3629 
3630 /**************************************************************************//**
3631  * @brief
3632  *   Sets HFXO's crystal precision, in PPM.
3633  *
3634  * @note
3635  *   HFXO precision should be obtained from a crystal datasheet.
3636  *
3637  * @param[in] precision
3638  *    HFXO's crystal precision, in PPM.
3639  *****************************************************************************/
CMU_HFXOPrecisionSet(uint16_t precision)3640 void CMU_HFXOPrecisionSet(uint16_t precision)
3641 {
3642   hfxo_precision = precision;
3643 }
3644 
3645 /**************************************************************************//**
3646  * @brief
3647  *   Gets HFXO's crystal precision, in PPM.
3648  *
3649  * @param[in] precision
3650  *    HFXO's crystal precision, in PPM.
3651  *****************************************************************************/
CMU_HFXOPrecisionGet(void)3652 uint16_t CMU_HFXOPrecisionGet(void)
3653 {
3654   return hfxo_precision;
3655 }
3656 
3657 #if defined(PLFRCO_PRESENT)
3658 /**************************************************************************//**
3659  * @brief
3660  *   Configure the LFRCO precision.
3661  *
3662  * @details
3663  *   When enabling high precision mode on the LFRCO the hardware will tune
3664  *   the oscillator automatically using the HFXO as a reference.
3665  *
3666  * @note
3667  *   Refer to the reference manual and the datasheet for details about
3668  *   NOMCAL and NOMCALINV calibration count values.
3669  *
3670  * @param[in] precision
3671  *    LFRCO precision, this can be either high or default.
3672  *****************************************************************************/
CMU_LFRCOSetPrecision(CMU_Precision_TypeDef precision)3673 void CMU_LFRCOSetPrecision(CMU_Precision_TypeDef precision)
3674 {
3675   uint32_t ref = 0;
3676   uint32_t nomcal = 0;
3677   uint32_t nomcalinv = 0;
3678 
3679   CMU->CLKEN0_SET = CMU_CLKEN0_LFRCO;
3680 
3681   LFRCO->CTRL = LFRCO_CTRL_DISONDEMAND; // Force disable
3682   while ((LFRCO->STATUS & LFRCO_STATUS_ENS) != 0U) {
3683     // Wait for LFRCO to stop
3684   }
3685 
3686   if (precision == cmuPrecisionHigh) {
3687     ref = SystemHFXOClockGet();
3688     // Use precomputed value for HFXO typical frequencies
3689     if (ref == XTAL_38M4) {
3690       nomcal = LFRCO_NOMCAL_XTAL_38M4;
3691       nomcalinv = LFRCO_NOMCALINV_XTAL_38M4;
3692     } else if (ref == XTAL_39M0) {
3693       nomcal = LFRCO_NOMCAL_XTAL_39M0;
3694       nomcalinv = LFRCO_NOMCALINV_XTAL_39M0;
3695     } else {
3696       // Compute calibration count, based on HFXO frequency
3697       nomcal = (5 * ref) >> 9;
3698       nomcalinv = ((1UL << 31) / 5) << 2;
3699       nomcalinv /= (ref >> 9);
3700     }
3701 
3702     LFRCO->NOMCAL = nomcal;
3703     LFRCO->NOMCALINV = nomcalinv;
3704 
3705     LFRCO->CFG = LFRCO_CFG_HIGHPRECEN;
3706   } else {
3707     LFRCO->CFG = 0;
3708   }
3709   LFRCO->CTRL = _LFRCO_CTRL_RESETVALUE;
3710 }
3711 #endif
3712 
3713 /***************************************************************************//**
3714  * @brief
3715  *   Get oscillator frequency tuning setting.
3716  *
3717  * @param[in] osc
3718  *   Oscillator to get tuning value for.
3719  *
3720  * @return
3721  *   The oscillator frequency tuning setting in use.
3722  ******************************************************************************/
CMU_OscillatorTuningGet(CMU_Osc_TypeDef osc)3723 uint32_t CMU_OscillatorTuningGet(CMU_Osc_TypeDef osc)
3724 {
3725   uint32_t ret = 0U;
3726 
3727   switch (osc) {
3728 #if defined(_LFRCO_CAL_FREQTRIM_MASK)
3729     case cmuOsc_LFRCO:
3730 #if defined(CMU_CLKEN0_LFRCO)
3731       CMU->CLKEN0_SET = CMU_CLKEN0_LFRCO;
3732 #endif
3733       ret = (LFRCO->CAL & _LFRCO_CAL_FREQTRIM_MASK) >> _LFRCO_CAL_FREQTRIM_SHIFT;
3734       break;
3735 #endif
3736 
3737     case cmuOsc_HFRCODPLL:
3738 #if defined(CMU_CLKEN0_HFRCO0)
3739       CMU->CLKEN0_SET = CMU_CLKEN0_HFRCO0;
3740 #endif
3741       ret = (HFRCO0->CAL & _HFRCO_CAL_TUNING_MASK) >> _HFRCO_CAL_TUNING_SHIFT;
3742       break;
3743 
3744 #if defined(HFRCOEM23_PRESENT)
3745     case cmuOsc_HFRCOEM23:
3746       ret = (HFRCOEM23->CAL & _HFRCO_CAL_TUNING_MASK) >> _HFRCO_CAL_TUNING_SHIFT;
3747       break;
3748 #endif
3749 
3750     case cmuOsc_HFXO:
3751 #if defined(CMU_CLKEN0_HFXO0)
3752       CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
3753 #endif
3754       ret = (HFXO0->XTALCTRL & _HFXO_XTALCTRL_COREBIASANA_MASK) >> _HFXO_XTALCTRL_COREBIASANA_SHIFT;
3755       break;
3756 
3757     case cmuOsc_LFXO:
3758 #if defined(CMU_CLKEN0_LFXO)
3759       CMU->CLKEN0_SET = CMU_CLKEN0_LFXO;
3760 #endif
3761       ret = (LFXO->CAL & _LFXO_CAL_CAPTUNE_MASK) >> _LFXO_CAL_CAPTUNE_SHIFT;
3762       break;
3763 
3764     default:
3765       EFM_ASSERT(false);
3766       break;
3767   }
3768 
3769   return ret;
3770 }
3771 
3772 /***************************************************************************//**
3773  * @brief
3774  *   Set the oscillator frequency tuning control.
3775  *
3776  * @note
3777  *   Oscillator tuning is done during production, and the tuning value is
3778  *   automatically loaded after a reset. Changing the tuning value from the
3779  *   calibrated value is for more advanced use. Certain oscillators also have
3780  *   build-in tuning optimization.
3781  *
3782  * @param[in] osc
3783  *   Oscillator to set tuning value for.
3784  *
3785  * @param[in] val
3786  *   The oscillator frequency tuning setting to use.
3787  ******************************************************************************/
CMU_OscillatorTuningSet(CMU_Osc_TypeDef osc,uint32_t val)3788 void CMU_OscillatorTuningSet(CMU_Osc_TypeDef osc, uint32_t val)
3789 {
3790   bool disondemand = false;
3791   bool lfxo_lock_status = false;
3792   uint8_t ctune = 0;
3793 
3794   switch (osc) {
3795 #if defined(_LFRCO_CAL_FREQTRIM_MASK)
3796     case cmuOsc_LFRCO:
3797 #if defined(CMU_CLKEN0_LFRCO)
3798       CMU->CLKEN0_SET = CMU_CLKEN0_LFRCO;
3799 #endif
3800       EFM_ASSERT(val <= (_LFRCO_CAL_FREQTRIM_MASK
3801                          >> _LFRCO_CAL_FREQTRIM_SHIFT));
3802       val &= _LFRCO_CAL_FREQTRIM_MASK >> _LFRCO_CAL_FREQTRIM_SHIFT;
3803       while (LFRCO->SYNCBUSY != 0U) {
3804       }
3805       LFRCO->CAL = (LFRCO->CAL & ~_LFRCO_CAL_FREQTRIM_MASK)
3806                    | (val << _LFRCO_CAL_FREQTRIM_SHIFT);
3807       break;
3808 #endif
3809 
3810     case cmuOsc_HFRCODPLL:
3811 #if defined(CMU_CLKEN0_HFRCO0)
3812       CMU->CLKEN0_SET = CMU_CLKEN0_HFRCO0;
3813 #endif
3814       EFM_ASSERT(val <= (_HFRCO_CAL_TUNING_MASK >> _HFRCO_CAL_TUNING_SHIFT));
3815       val &= _HFRCO_CAL_TUNING_MASK >> _HFRCO_CAL_TUNING_SHIFT;
3816       while ((HFRCO0->STATUS & HFRCO_STATUS_SYNCBUSY) != 0UL) {
3817       }
3818       HFRCO0->CAL = (HFRCO0->CAL & ~_HFRCO_CAL_TUNING_MASK)
3819                     | (val << _HFRCO_CAL_TUNING_SHIFT);
3820       break;
3821 
3822 #if defined(HFRCOEM23_PRESENT)
3823     case cmuOsc_HFRCOEM23:
3824       EFM_ASSERT(val <= (_HFRCO_CAL_TUNING_MASK >> _HFRCO_CAL_TUNING_SHIFT));
3825       val &= _HFRCO_CAL_TUNING_MASK >> _HFRCO_CAL_TUNING_SHIFT;
3826       while ((HFRCOEM23->STATUS & HFRCO_STATUS_SYNCBUSY) != 0UL) {
3827       }
3828       HFRCOEM23->CAL = (HFRCOEM23->CAL & ~_HFRCO_CAL_TUNING_MASK)
3829                        | (val << _HFRCO_CAL_TUNING_SHIFT);
3830       break;
3831 #endif
3832 
3833     case cmuOsc_HFXO:
3834 #if defined(CMU_CLKEN0_HFXO0)
3835       CMU->CLKEN0_SET = CMU_CLKEN0_HFXO0;
3836 #endif
3837       EFM_ASSERT(val <= (_HFXO_XTALCTRL_COREBIASANA_MASK >> _HFXO_XTALCTRL_COREBIASANA_SHIFT));
3838       // Make sure HFXO is disable
3839       EFM_ASSERT((HFXO0->STATUS & HFXO_STATUS_ENS) == 0);
3840 
3841       // Set DISONDEMAND if not already set and wait for FSMLOCK to be clear so that
3842       // software can write to register
3843       disondemand = (HFXO0->CTRL & _HFXO_CTRL_DISONDEMAND_MASK) >> _HFXO_CTRL_DISONDEMAND_SHIFT;
3844       if (disondemand == false) {
3845         HFXO0->CTRL_SET = HFXO_CTRL_DISONDEMAND;
3846       }
3847 #if defined(HFXO_STATUS_FSMLOCK)
3848       while ((HFXO0->STATUS & HFXO_STATUS_FSMLOCK) != 0) {
3849       }
3850 #endif
3851       // Update Core Bias Ana setting and enable Optimization skip
3852       HFXO0->XTALCTRL = (HFXO0->XTALCTRL & ~_HFXO_XTALCTRL_COREBIASANA_MASK)
3853                         | (val << _HFXO_XTALCTRL_COREBIASANA_SHIFT)
3854                         | HFXO_XTALCTRL_SKIPCOREBIASOPT;
3855       // Clear back DISONDEMAND if needed
3856       if (disondemand == false) {
3857         HFXO0->CTRL_CLR = HFXO_CTRL_DISONDEMAND;
3858       }
3859       break;
3860 
3861     case cmuOsc_LFXO:
3862 #if defined(CMU_CLKEN0_LFXO)
3863       CMU->CLKEN0_SET = CMU_CLKEN0_LFXO;
3864 #endif
3865       lfxo_lock_status = (LFXO->STATUS & _LFXO_STATUS_LOCK_MASK) >> _LFXO_STATUS_LOCK_SHIFT;
3866       // Unlock register interface if register is locked before
3867       if (lfxo_lock_status == _LFXO_STATUS_LOCK_LOCKED) {
3868         LFXO->LOCK = LFXO_LOCK_LOCKKEY_UNLOCK;
3869       }
3870 
3871       EFM_ASSERT(val <= (_LFXO_CAL_CAPTUNE_MASK >> _LFXO_CAL_CAPTUNE_SHIFT));
3872       // Max internal capacitance tuning value is 0x4F (20 pF)
3873       ctune = (uint8_t) SL_MIN(0x4FU, val);
3874 
3875       // Wait for CALBSY bit to clear before writing the tuning value to CAL register
3876       while (((LFXO->SYNCBUSY & _LFXO_SYNCBUSY_CAL_MASK) >> _LFXO_SYNCBUSY_CAL_SHIFT) != 0U) {
3877       }
3878       LFXO->CAL = (LFXO->CAL & ~_LFXO_CAL_CAPTUNE_MASK)
3879                   | ((uint32_t)ctune << _LFXO_CAL_CAPTUNE_SHIFT);
3880 
3881       // Lock register interface again
3882       if (lfxo_lock_status == _LFXO_STATUS_LOCK_LOCKED) {
3883         LFXO->LOCK = ~LFXO_LOCK_LOCKKEY_UNLOCK;
3884       }
3885       break;
3886 
3887     default:
3888       EFM_ASSERT(false);
3889       break;
3890   }
3891 }
3892 
3893 /***************************************************************************//**
3894  * @brief
3895  *   Configure wait state settings necessary to switch to a given core clock
3896  *   frequency at a certain voltage scale level.
3897  *
3898  * @details
3899  *   This function will set up the necessary flash wait states. Updating the
3900  *   wait state configuration must be done before increasing the clock
3901  *   frequency and it must be done after decreasing the clock frequency.
3902  *   Updating the wait state configuration must be done before core voltage is
3903  *   decreased and it must be done after a core voltage is increased.
3904  *
3905  * @param[in] freq
3906  *   The core clock frequency to configure wait-states.
3907  *
3908  * @param[in] vscale
3909  *   The voltage scale to configure wait-states. Expected values are
3910  *   0 or 1, higher number is lower voltage.
3911  *   @li 0 = 1.1 V (VSCALE2)
3912  *   @li 1 = 1.0 V (VSCALE1)
3913  ******************************************************************************/
CMU_UpdateWaitStates(uint32_t freq,int vscale)3914 void CMU_UpdateWaitStates(uint32_t freq, int vscale)
3915 {
3916   if (vscale > 0) {
3917     flashWaitStateControl(freq, VSCALE_EM01_LOW_POWER);
3918   } else {
3919     flashWaitStateControl(freq, VSCALE_EM01_HIGH_PERFORMANCE);
3920   }
3921 }
3922 
3923 /**************************************************************************//**
3924  * @brief
3925  *   Select the PCNTn clock.
3926  *
3927  * @param[in] instance
3928  *   PCNT instance number to set selected clock source for.
3929  *
3930  * @param[in] external
3931  *   Set to true to select the external clock, false to select EM23GRPACLK.
3932  *****************************************************************************/
CMU_PCNTClockExternalSet(unsigned int instance,bool external)3933 void CMU_PCNTClockExternalSet(unsigned int instance, bool external)
3934 {
3935   (void)instance;
3936 #if defined(PCNT_PRESENT)
3937   if (external) {
3938     CMU->PCNT0CLKCTRL = CMU_PCNT0CLKCTRL_CLKSEL_PCNTS0;
3939   } else {
3940     CMU->PCNT0CLKCTRL = CMU_PCNT0CLKCTRL_CLKSEL_EM23GRPACLK;
3941   }
3942 #else
3943   (void)external;
3944 #endif
3945 }
3946 
3947 #if defined(HFRCOEM23_PRESENT)
3948 /***************************************************************************//**
3949  * @brief
3950  *   Get HFRCOEM23 band in use.
3951  *
3952  * @return
3953  *   HFRCOEM23 band in use.
3954  ******************************************************************************/
CMU_HFRCOEM23BandGet(void)3955 CMU_HFRCOEM23Freq_TypeDef CMU_HFRCOEM23BandGet(void)
3956 {
3957   return (CMU_HFRCOEM23Freq_TypeDef)SystemHFRCOEM23ClockGet();
3958 }
3959 
3960 /***************************************************************************//**
3961  * @brief
3962  *   Set HFRCOEM23 band and the tuning value based on the value in the
3963  *   calibration table made during production.
3964  *
3965  * @param[in] freq
3966  *   HFRCOEM23 frequency band to activate.
3967  ******************************************************************************/
CMU_HFRCOEM23BandSet(CMU_HFRCOEM23Freq_TypeDef freq)3968 void CMU_HFRCOEM23BandSet(CMU_HFRCOEM23Freq_TypeDef freq)
3969 {
3970   uint32_t freqCal;
3971 
3972   // Get calibration data from DEVINFO
3973   freqCal = HFRCOEM23DevinfoGet(freq);
3974   EFM_ASSERT((freqCal != 0UL) && (freqCal != UINT_MAX));
3975 #if defined(CMU_CLKEN0_HFRCOEM23)
3976   CMU->CLKEN0_SET = CMU_CLKEN0_HFRCOEM23;
3977 #endif
3978 
3979   // Set divider for 1, 2 and 4MHz bands
3980   freqCal &= ~_HFRCO_CAL_CLKDIV_MASK;
3981   switch (freq) {
3982     case cmuHFRCOEM23Freq_1M0Hz:
3983       freqCal |= HFRCO_CAL_CLKDIV_DIV4;
3984       break;
3985 
3986     case cmuHFRCOEM23Freq_2M0Hz:
3987       freqCal |= HFRCO_CAL_CLKDIV_DIV2;
3988       break;
3989 
3990     default:
3991       break;
3992   }
3993 
3994   // Activate new band selection
3995   HFRCOEM23->CAL = freqCal;
3996 }
3997 #endif // defined(HFRCOEM23_PRESENT)
3998 
3999 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
4000 
4001 /*******************************************************************************
4002  **************************   LOCAL FUNCTIONS   ********************************
4003  ******************************************************************************/
4004 
4005 #if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
4006 #if defined(PDM_PRESENT)
4007 /***************************************************************************//**
4008  * @brief
4009  *   Get selected oscillator and frequency for @ref cmuClock_EM01GRPBCLK
4010  *   clock tree.
4011  *
4012  * @param[out] freq
4013  *   The frequency.
4014  *
4015  * @param[out] sel
4016  *   The selected oscillator.
4017  ******************************************************************************/
em01GrpbClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4018 static void em01GrpbClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4019 {
4020   uint32_t f = 0U;
4021   CMU_Select_TypeDef s;
4022   switch (CMU->EM01GRPBCLKCTRL & _CMU_EM01GRPBCLKCTRL_CLKSEL_MASK) {
4023     case CMU_EM01GRPBCLKCTRL_CLKSEL_HFRCODPLL:
4024       f = SystemHFRCODPLLClockGet();
4025       s = cmuSelect_HFRCODPLL;
4026       break;
4027 
4028     case CMU_EM01GRPBCLKCTRL_CLKSEL_HFRCODPLLRT:
4029       f = SystemHFRCODPLLClockGet();
4030       s = cmuSelect_HFRCODPLLRT;
4031       break;
4032 
4033     case CMU_EM01GRPBCLKCTRL_CLKSEL_HFXO:
4034       f = SystemHFXOClockGet();
4035       s = cmuSelect_HFXO;
4036       break;
4037 
4038     case CMU_EM01GRPBCLKCTRL_CLKSEL_HFXORT:
4039       f = SystemHFXOClockGet();
4040       s = cmuSelect_HFXORT;
4041       break;
4042 
4043     case CMU_EM01GRPBCLKCTRL_CLKSEL_FSRCO:
4044       f = SystemFSRCOClockGet();
4045       s = cmuSelect_FSRCO;
4046       break;
4047 
4048     case CMU_EM01GRPBCLKCTRL_CLKSEL_CLKIN0:
4049       f = SystemCLKIN0Get();
4050       s = cmuSelect_CLKIN0;
4051       break;
4052 
4053     case CMU_EM01GRPBCLKCTRL_CLKSEL_DISABLED:
4054       s = cmuSelect_Disabled;
4055       break;
4056 
4057     default:
4058       s = cmuSelect_Error;
4059       EFM_ASSERT(false);
4060       break;
4061   }
4062   if (freq != NULL) {
4063     *freq = f;
4064   }
4065   if (sel != NULL) {
4066     *sel = s;
4067   }
4068 }
4069 #endif
4070 
4071 #if defined(EUART_PRESENT)
4072 /***************************************************************************//**
4073  * @brief
4074  *   Get selected oscillator and frequency for @ref cmuClock_EUART0CLK
4075  *   clock tree.
4076  *
4077  * @param[out] freq
4078  *   The frequency.
4079  *
4080  * @param[out] sel
4081  *   The selected oscillator.
4082  ******************************************************************************/
euart0ClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4083 static void euart0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4084 {
4085   switch (CMU->EUART0CLKCTRL & _CMU_EUART0CLKCTRL_CLKSEL_MASK) {
4086     case CMU_EUART0CLKCTRL_CLKSEL_EM01GRPACLK:
4087       em01GrpaClkGet(freq, sel);
4088       break;
4089 
4090     case CMU_EUART0CLKCTRL_CLKSEL_EM23GRPACLK:
4091       em23GrpaClkGet(freq, sel);
4092       break;
4093 
4094     default:
4095       if (freq != NULL) {
4096         *freq = 0U;
4097       }
4098       if (sel != NULL) {
4099         *sel = cmuSelect_Error;
4100       }
4101       EFM_ASSERT(false);
4102       break;
4103   }
4104 }
4105 #endif
4106 
4107 #if defined(EUSART_PRESENT)
4108 /***************************************************************************//**
4109  * @brief
4110  *   Get selected oscillator and frequency for @ref cmuClock_EUSART0CLK
4111  *   clock tree.
4112  *
4113  * @param[out] freq
4114  *   The frequency.
4115  *
4116  * @param[out] sel
4117  *   The selected oscillator.
4118  ******************************************************************************/
eusart0ClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4119 static void eusart0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4120 {
4121   uint32_t f = 0U;
4122   CMU_Select_TypeDef s;
4123 
4124   switch (CMU->EUSART0CLKCTRL & _CMU_EUSART0CLKCTRL_CLKSEL_MASK) {
4125 #if defined(CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPACLK)
4126     case CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPACLK:
4127       em01GrpaClkGet(&f, NULL);
4128       s = cmuSelect_EM01GRPACLK;
4129       break;
4130 #endif
4131 
4132 #if defined(CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPCCLK)
4133     case CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPCCLK:
4134       em01GrpcClkGet(&f, NULL);
4135       s = cmuSelect_EM01GRPCCLK;
4136       break;
4137 #endif
4138 
4139 #if defined(CMU_EUSART0CLKCTRL_CLKSEL_EM23GRPACLK)
4140     case CMU_EUSART0CLKCTRL_CLKSEL_EM23GRPACLK:
4141       em23GrpaClkGet(&f, NULL);
4142       s = cmuSelect_EM23GRPACLK;
4143       break;
4144 #endif
4145 
4146 #if defined(CMU_EUSART0CLKCTRL_CLKSEL_FSRCO)
4147     case CMU_EUSART0CLKCTRL_CLKSEL_FSRCO:
4148       f = SystemFSRCOClockGet();
4149       s = cmuSelect_FSRCO;
4150       break;
4151 #endif
4152 
4153 #if defined(CMU_EUSART0CLKCTRL_CLKSEL_HFRCOEM23)
4154     case CMU_EUSART0CLKCTRL_CLKSEL_HFRCOEM23:
4155       f = SystemHFRCOEM23ClockGet();
4156       s = cmuSelect_HFRCOEM23;
4157       break;
4158 #endif
4159 
4160 #if defined(CMU_EUSART0CLKCTRL_CLKSEL_LFRCO)
4161     case CMU_EUSART0CLKCTRL_CLKSEL_LFRCO:
4162       f = SystemLFRCOClockGet();
4163       s = cmuSelect_LFRCO;
4164       break;
4165 #endif
4166 
4167 #if defined(CMU_EUSART0CLKCTRL_CLKSEL_LFXO)
4168     case CMU_EUSART0CLKCTRL_CLKSEL_LFXO:
4169       f = SystemLFXOClockGet();
4170       s = cmuSelect_LFXO;
4171       break;
4172 #endif
4173 
4174 #if defined(CMU_EUSART0CLKCTRL_CLKSEL_DISABLED)
4175     case CMU_EUSART0CLKCTRL_CLKSEL_DISABLED:
4176       s = cmuSelect_Disabled;
4177       break;
4178 #endif
4179 
4180     default:
4181       s = cmuSelect_Error;
4182       EFM_ASSERT(false);
4183       break;
4184   }
4185   if (freq != NULL) {
4186     *freq = f;
4187   }
4188   if (sel != NULL) {
4189     *sel = s;
4190   }
4191 }
4192 
4193 #if defined(_CMU_EM01GRPCCLKCTRL_MASK)
4194 /**************************************************************************//**
4195 * @brief
4196 *   Get selected oscillator and frequency for @ref cmuClock_EM01GRPCCLK
4197 *   clock tree.
4198 *
4199 * @param[out] freq
4200 *   The frequency.
4201 *
4202 * @param[out] sel
4203 *   The selected oscillator.
4204 ******************************************************************************/
em01GrpcClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4205 static void em01GrpcClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4206 {
4207   uint32_t f = 0U;
4208   CMU_Select_TypeDef s;
4209 
4210   switch (CMU->EM01GRPCCLKCTRL & _CMU_EM01GRPCCLKCTRL_CLKSEL_MASK) {
4211     case CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCODPLL:
4212       f = SystemHFRCODPLLClockGet();
4213       s = cmuSelect_HFRCODPLL;
4214       break;
4215 
4216 #if defined(CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCODPLLRT)
4217     case CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCODPLLRT:
4218       f = SystemHFRCODPLLClockGet();
4219       s = cmuSelect_HFRCODPLLRT;
4220       break;
4221 #endif
4222 
4223 #if defined(_CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCOEM23)
4224     case _CMU_EM01GRPCCLKCTRL_CLKSEL_HFRCOEM23:
4225       f = SystemHFRCOEM23ClockGet();
4226       s = cmuSelect_HFRCOEM23;
4227       break;
4228 #endif
4229 
4230     case CMU_EM01GRPCCLKCTRL_CLKSEL_HFXO:
4231       f = SystemHFXOClockGet();
4232       s = cmuSelect_HFXO;
4233       break;
4234 
4235 #if defined(CMU_EM01GRPCCLKCTRL_CLKSEL_HFXORT)
4236     case CMU_EM01GRPCCLKCTRL_CLKSEL_HFXORT:
4237       f = SystemHFXOClockGet();
4238       s = cmuSelect_HFXORT;
4239       break;
4240 #endif
4241 
4242     case _CMU_EM01GRPCCLKCTRL_CLKSEL_FSRCO:
4243       f = SystemFSRCOClockGet();
4244       s = cmuSelect_FSRCO;
4245       break;
4246 
4247     default:
4248       s = cmuSelect_Error;
4249       EFM_ASSERT(false);
4250       break;
4251   }
4252   if (freq != NULL) {
4253     *freq = f;
4254   }
4255   if (sel != NULL) {
4256     *sel = s;
4257   }
4258 }
4259 #endif // defined(_CMU_EM01GRPCCLKCTRL_MASK)
4260 #endif // defined(EUSART_PRESENT)
4261 
4262 #if defined(LCD_PRESENT)
4263 /***************************************************************************//**
4264  * @brief
4265  *   Get selected oscillator and frequency for @ref cmuClock_LCDCLK
4266  *   clock tree.
4267  *
4268  * @param[out] freq
4269  *   The frequency.
4270  *
4271  * @param[out] sel
4272  *   The selected oscillator.
4273  ******************************************************************************/
lcdClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4274 static void lcdClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4275 {
4276   uint32_t f = 0U;
4277   CMU_Select_TypeDef s;
4278 
4279   switch (CMU->LCDCLKCTRL & _CMU_LCDCLKCTRL_CLKSEL_MASK) {
4280     case CMU_LCDCLKCTRL_CLKSEL_ULFRCO:
4281       f = SystemULFRCOClockGet();
4282       s = cmuSelect_ULFRCO;
4283       break;
4284 
4285     case CMU_LCDCLKCTRL_CLKSEL_LFRCO:
4286       f = SystemLFRCOClockGet();
4287       s = cmuSelect_LFRCO;
4288       break;
4289 
4290     case CMU_LCDCLKCTRL_CLKSEL_LFXO:
4291       f = SystemLFXOClockGet();
4292       s = cmuSelect_LFXO;
4293       break;
4294 
4295     default:
4296       s = cmuSelect_Error;
4297       EFM_ASSERT(false);
4298       break;
4299   }
4300   if (freq != NULL) {
4301     *freq = f;
4302   }
4303   if (sel != NULL) {
4304     *sel = s;
4305   }
4306 }
4307 #endif // defined(LCD_PRESENT)
4308 
4309 #if defined(VDAC_PRESENT)
4310 /***************************************************************************//**
4311  * @brief
4312  *   Get selected oscillator and frequency for @ref cmuClock_VDAC0CLK
4313  *   clock tree.
4314  *
4315  * @param[out] freq
4316  *   The frequency.
4317  *
4318  * @param[out] sel
4319  *   The selected oscillator.
4320  ******************************************************************************/
vdac0ClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4321 static void vdac0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4322 {
4323   uint32_t f = 0U;
4324   CMU_Select_TypeDef s;
4325 
4326   switch (CMU->VDAC0CLKCTRL & _CMU_VDAC0CLKCTRL_CLKSEL_MASK) {
4327     case CMU_VDAC0CLKCTRL_CLKSEL_EM01GRPACLK:
4328       em01GrpaClkGet(&f, NULL);
4329       s = cmuSelect_EM01GRPACLK;
4330       break;
4331 
4332     case CMU_VDAC0CLKCTRL_CLKSEL_EM23GRPACLK:
4333       em23GrpaClkGet(&f, NULL);
4334       s = cmuSelect_EM23GRPACLK;
4335       break;
4336 
4337     case CMU_VDAC0CLKCTRL_CLKSEL_HFRCOEM23:
4338       f = SystemHFRCOEM23ClockGet();
4339       s = cmuSelect_HFRCOEM23;
4340       break;
4341 
4342     case CMU_VDAC0CLKCTRL_CLKSEL_FSRCO:
4343       f = SystemFSRCOClockGet();
4344       s = cmuSelect_FSRCO;
4345       break;
4346 
4347     default:
4348       s = cmuSelect_Error;
4349       EFM_ASSERT(false);
4350       break;
4351   }
4352   if (freq != NULL) {
4353     *freq = f;
4354   }
4355   if (sel != NULL) {
4356     *sel = s;
4357   }
4358 }
4359 
4360 #if (VDAC_COUNT > 1)
4361 /***************************************************************************//**
4362  * @brief
4363  *   Get selected oscillator and frequency for @ref cmuClock_VDAC1CLK
4364  *   clock tree.
4365  *
4366  * @param[out] freq
4367  *   The frequency.
4368  *
4369  * @param[out] sel
4370  *   The selected oscillator.
4371  ******************************************************************************/
vdac1ClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4372 static void vdac1ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4373 {
4374   uint32_t f = 0U;
4375   CMU_Select_TypeDef s;
4376 
4377   switch (CMU->VDAC1CLKCTRL & _CMU_VDAC1CLKCTRL_CLKSEL_MASK) {
4378     case CMU_VDAC1CLKCTRL_CLKSEL_EM01GRPACLK:
4379       em01GrpaClkGet(&f, NULL);
4380       s = cmuSelect_EM01GRPACLK;
4381       break;
4382 
4383     case CMU_VDAC1CLKCTRL_CLKSEL_EM23GRPACLK:
4384       em23GrpaClkGet(&f, NULL);
4385       s = cmuSelect_EM23GRPACLK;
4386       break;
4387 
4388     case CMU_VDAC1CLKCTRL_CLKSEL_HFRCOEM23:
4389       f = SystemHFRCOEM23ClockGet();
4390       s = cmuSelect_HFRCOEM23;
4391       break;
4392 
4393     case CMU_VDAC1CLKCTRL_CLKSEL_FSRCO:
4394       f = SystemFSRCOClockGet();
4395       s = cmuSelect_FSRCO;
4396       break;
4397 
4398     default:
4399       s = cmuSelect_Error;
4400       EFM_ASSERT(false);
4401       break;
4402   }
4403   if (freq != NULL) {
4404     *freq = f;
4405   }
4406   if (sel != NULL) {
4407     *sel = s;
4408   }
4409 }
4410 #endif
4411 #endif /* VDAC_PRESENT */
4412 
4413 #if defined(PCNT_PRESENT)
4414 /***************************************************************************//**
4415  * @brief
4416  *   Get selected oscillator and frequency for @ref cmuClock_PCNT0CLK
4417  *   clock tree.
4418  *
4419  * @param[out] freq
4420  *   The frequency.
4421  *
4422  * @param[out] sel
4423  *   The selected oscillator.
4424  ******************************************************************************/
pcnt0ClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4425 static void pcnt0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4426 {
4427   uint32_t f = 0U;
4428   CMU_Select_TypeDef s;
4429 
4430   switch (CMU->PCNT0CLKCTRL & _CMU_PCNT0CLKCTRL_CLKSEL_MASK) {
4431     case CMU_PCNT0CLKCTRL_CLKSEL_EM23GRPACLK:
4432       em23GrpaClkGet(&f, NULL);
4433       s = cmuSelect_EM23GRPACLK;
4434       break;
4435 
4436     case CMU_PCNT0CLKCTRL_CLKSEL_PCNTS0:
4437       f = 0U; // external or PRS source so the frequency is undefined.
4438       s = cmuSelect_PCNTEXTCLK;
4439       break;
4440 
4441     default:
4442       s = cmuSelect_Error;
4443       EFM_ASSERT(false);
4444       break;
4445   }
4446   if (freq != NULL) {
4447     *freq = f;
4448   }
4449   if (sel != NULL) {
4450     *sel = s;
4451   }
4452 }
4453 #endif
4454 
4455 #if defined(LESENSE_PRESENT)
4456 /***************************************************************************//**
4457  * @brief
4458  *   Get selected oscillator and frequency for @ref cmuClock_LESENSEHFCLK
4459  *   clock tree.
4460  *
4461  * @param[out] freq
4462  *   The frequency.
4463  *
4464  * @param[out] sel
4465  *   The selected oscillator.
4466  ******************************************************************************/
lesenseHFClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4467 static void lesenseHFClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4468 {
4469   uint32_t f = 0U;
4470   CMU_Select_TypeDef s;
4471 
4472   switch (CMU->LESENSEHFCLKCTRL & _CMU_LESENSEHFCLKCTRL_CLKSEL_MASK) {
4473     case CMU_LESENSEHFCLKCTRL_CLKSEL_HFRCOEM23:
4474       f = SystemHFRCOEM23ClockGet();
4475       s = cmuSelect_HFRCOEM23;
4476       break;
4477 
4478     case CMU_LESENSEHFCLKCTRL_CLKSEL_FSRCO:
4479       f = SystemFSRCOClockGet();
4480       s = cmuSelect_FSRCO;
4481       break;
4482 
4483     default:
4484       s = cmuSelect_Error;
4485       EFM_ASSERT(false);
4486       break;
4487   }
4488   if (freq != NULL) {
4489     *freq = f;
4490   }
4491   if (sel != NULL) {
4492     *sel = s;
4493   }
4494 }
4495 #endif
4496 
4497 #if ((defined(CMU_SYSCLKCTRL_RHCLKPRESC)) \
4498   && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
4499 /***************************************************************************//**
4500  * @brief
4501  *   Set maximum allowed prescaler for radio clock tree (RHCLK).
4502  ******************************************************************************/
rhclkPrescMax(void)4503 static void rhclkPrescMax(void)
4504 {
4505   // Set largest prescaler (DIV2).
4506   CMU->SYSCLKCTRL_SET = CMU_SYSCLKCTRL_RHCLKPRESC;
4507 }
4508 
4509 /***************************************************************************//**
4510  * @brief
4511  *   Set radio clock tree prescaler to achieve highest possible frequency
4512  *   and still be within spec.
4513  ******************************************************************************/
rhclkPrescOptimize(void)4514 static void rhclkPrescOptimize(void)
4515 {
4516   if (CMU_ClockFreqGet(cmuClock_SYSCLK) <= CMU_MAX_RHCLK_FREQ) {
4517     // Set smallest prescaler (DIV1).
4518     CMU->SYSCLKCTRL_CLR = CMU_SYSCLKCTRL_RHCLKPRESC;
4519   }
4520 }
4521 #endif // ((defined(CMU_SYSCLKCTRL_RHCLKPRESC)) && (_SILICON_LABS_EFR32_RADIO_TYPE != _SILICON_LABS_EFR32_RADIO_NONE))
4522 #endif // #if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
4523 
4524 #if defined(HFRCOEM23_PRESENT)
4525 /***************************************************************************//**
4526  * @brief
4527  *   Get calibrated HFRCOEM23 tuning value from Device information (DI) page
4528  *   for a given frequency. Calibration value is not available for all frequency
4529  *   bands.
4530  *
4531  * @param[in] freq
4532  *   HFRCOEM23 frequency band
4533  ******************************************************************************/
HFRCOEM23DevinfoGet(CMU_HFRCOEM23Freq_TypeDef freq)4534 static uint32_t HFRCOEM23DevinfoGet(CMU_HFRCOEM23Freq_TypeDef freq)
4535 {
4536   uint32_t ret = 0U;
4537 
4538   switch (freq) {
4539     // 1, 2 and 4MHz share the same calibration word
4540     case cmuHFRCOEM23Freq_1M0Hz:
4541     case cmuHFRCOEM23Freq_2M0Hz:
4542     case cmuHFRCOEM23Freq_4M0Hz:
4543       ret = DEVINFO->HFRCOEM23CAL[0].HFRCOEM23CAL;
4544       break;
4545 
4546     case cmuHFRCOEM23Freq_13M0Hz:
4547       ret = DEVINFO->HFRCOEM23CAL[6].HFRCOEM23CAL;
4548       break;
4549 
4550     case cmuHFRCOEM23Freq_16M0Hz:
4551       ret = DEVINFO->HFRCOEM23CAL[7].HFRCOEM23CAL;
4552       break;
4553 
4554     case cmuHFRCOEM23Freq_19M0Hz:
4555       ret = DEVINFO->HFRCOEM23CAL[8].HFRCOEM23CAL;
4556       break;
4557 
4558     case cmuHFRCOEM23Freq_26M0Hz:
4559       ret = DEVINFO->HFRCOEM23CAL[10].HFRCOEM23CAL;
4560       break;
4561 
4562     case cmuHFRCOEM23Freq_32M0Hz:
4563       ret = DEVINFO->HFRCOEM23CAL[11].HFRCOEM23CAL;
4564       break;
4565 
4566     case cmuHFRCOEM23Freq_40M0Hz:
4567       ret = DEVINFO->HFRCOEM23CAL[12].HFRCOEM23CAL;
4568       break;
4569 
4570     case cmuHFRCOEM23Freq_UserDefined:
4571       break;
4572 
4573     default:
4574       EFM_ASSERT(false);
4575       break;
4576   }
4577   return ret;
4578 }
4579 #endif // defined(HFRCOEM23_PRESENT)
4580 
4581 /***************************************************************************//**
4582  * @brief
4583  *   Get selected oscillator and frequency for @ref cmuClock_TRACECLK
4584  *   clock tree.
4585  *
4586  * @param[out] freq
4587  *   The frequency.
4588  *
4589  * @param[out] sel
4590  *   The selected oscillator.
4591  ******************************************************************************/
traceClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4592 static void traceClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4593 {
4594   uint32_t f = 0U;
4595   CMU_Select_TypeDef s;
4596 
4597 #if defined(_CMU_TRACECLKCTRL_CLKSEL_MASK)
4598   switch (CMU->TRACECLKCTRL & _CMU_TRACECLKCTRL_CLKSEL_MASK) {
4599 #if defined(_CMU_TRACECLKCTRL_CLKSEL_HCLK)
4600     case CMU_TRACECLKCTRL_CLKSEL_HCLK:
4601       f = SystemHCLKGet();
4602       s = cmuSelect_HCLK;
4603       break;
4604 #endif
4605 #if defined(_CMU_TRACECLKCTRL_CLKSEL_SYSCLK)
4606     case CMU_TRACECLKCTRL_CLKSEL_SYSCLK:
4607       f = SystemSYSCLKGet();
4608       s = cmuSelect_SYSCLK;
4609       break;
4610 #endif
4611 
4612 #if defined(CMU_TRACECLKCTRL_CLKSEL_HFRCOEM23)
4613     case CMU_TRACECLKCTRL_CLKSEL_HFRCOEM23:
4614       f = SystemHFRCOEM23ClockGet();
4615       s = cmuSelect_HFRCOEM23;
4616       break;
4617 #endif
4618 
4619 #if defined(CMU_TRACECLKCTRL_CLKSEL_HFRCODPLLRT)
4620     case CMU_TRACECLKCTRL_CLKSEL_HFRCODPLLRT:
4621       f = SystemHFRCODPLLClockGet();
4622       s = cmuSelect_HFRCODPLLRT;
4623       break;
4624 #endif
4625 
4626     default:
4627       s = cmuSelect_Error;
4628       EFM_ASSERT(false);
4629       break;
4630   }
4631 #else
4632   f = SystemSYSCLKGet();
4633   s = cmuSelect_SYSCLK;
4634 #endif
4635 
4636   if (freq != NULL) {
4637     *freq = f;
4638   }
4639   if (sel != NULL) {
4640     *sel = s;
4641   }
4642 }
4643 
4644 /***************************************************************************//**
4645  * @brief
4646  *   Get selected oscillator and frequency for @ref cmuClock_DPLLREFCLK
4647  *   clock tree.
4648  *
4649  * @param[out] freq
4650  *   The frequency.
4651  *
4652  * @param[out] sel
4653  *   The selected oscillator.
4654  ******************************************************************************/
dpllRefClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4655 static void dpllRefClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4656 {
4657   uint32_t f = 0U;
4658   CMU_Select_TypeDef s;
4659 
4660   switch (CMU->DPLLREFCLKCTRL & _CMU_DPLLREFCLKCTRL_CLKSEL_MASK) {
4661     case CMU_DPLLREFCLKCTRL_CLKSEL_HFXO:
4662       f = SystemHFXOClockGet();
4663       s = cmuSelect_HFXO;
4664       break;
4665 
4666     case CMU_DPLLREFCLKCTRL_CLKSEL_LFXO:
4667       f = SystemLFXOClockGet();
4668       s = cmuSelect_LFXO;
4669       break;
4670 
4671     case CMU_DPLLREFCLKCTRL_CLKSEL_CLKIN0:
4672       f = SystemCLKIN0Get();
4673       s = cmuSelect_CLKIN0;
4674       break;
4675 
4676     case CMU_DPLLREFCLKCTRL_CLKSEL_DISABLED:
4677       s = cmuSelect_Disabled;
4678       break;
4679 
4680     default:
4681       s = cmuSelect_Error;
4682       EFM_ASSERT(false);
4683       break;
4684   }
4685 
4686   if (freq != NULL) {
4687     *freq = f;
4688   }
4689   if (sel != NULL) {
4690     *sel = s;
4691   }
4692 }
4693 
4694 /***************************************************************************//**
4695  * @brief
4696  *   Get selected oscillator and frequency for @ref cmuClock_EM01GRPACLK
4697  *   clock tree.
4698  *
4699  * @param[out] freq
4700  *   The frequency.
4701  *
4702  * @param[out] sel
4703  *   The selected oscillator.
4704  ******************************************************************************/
em01GrpaClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4705 static void em01GrpaClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4706 {
4707   uint32_t f = 0U;
4708   CMU_Select_TypeDef s;
4709 
4710   switch (CMU->EM01GRPACLKCTRL & _CMU_EM01GRPACLKCTRL_CLKSEL_MASK) {
4711     case CMU_EM01GRPACLKCTRL_CLKSEL_HFRCODPLL:
4712       f = SystemHFRCODPLLClockGet();
4713       s = cmuSelect_HFRCODPLL;
4714       break;
4715 
4716     case CMU_EM01GRPACLKCTRL_CLKSEL_HFXO:
4717       f = SystemHFXOClockGet();
4718       s = cmuSelect_HFXO;
4719       break;
4720 
4721 #if defined(HFRCOEM23_PRESENT)
4722     case CMU_EM01GRPACLKCTRL_CLKSEL_HFRCOEM23:
4723       f = SystemHFRCOEM23ClockGet();
4724       s = cmuSelect_HFRCOEM23;
4725       break;
4726 #endif
4727 
4728     case CMU_EM01GRPACLKCTRL_CLKSEL_FSRCO:
4729       f = SystemFSRCOClockGet();
4730       s = cmuSelect_FSRCO;
4731       break;
4732 
4733     case CMU_EM01GRPACLKCTRL_CLKSEL_DISABLED:
4734       s = cmuSelect_Disabled;
4735       break;
4736 
4737 #if defined(CMU_EM01GRPACLKCTRL_CLKSEL_HFRCODPLLRT)
4738     case CMU_EM01GRPACLKCTRL_CLKSEL_HFRCODPLLRT:
4739       f = SystemHFRCODPLLClockGet();
4740       s = cmuSelect_HFRCODPLLRT;
4741       break;
4742 #endif
4743 
4744 #if defined(CMU_EM01GRPACLKCTRL_CLKSEL_HFXORT)
4745     case CMU_EM01GRPACLKCTRL_CLKSEL_HFXORT:
4746       f = SystemHFXOClockGet();
4747       s = cmuSelect_HFXORT;
4748       break;
4749 #endif
4750 
4751     default:
4752       s = cmuSelect_Error;
4753       EFM_ASSERT(false);
4754       break;
4755   }
4756 
4757   if (freq != NULL) {
4758     *freq = f;
4759   }
4760   if (sel != NULL) {
4761     *sel = s;
4762   }
4763 }
4764 
4765 /***************************************************************************//**
4766  * @brief
4767  *   Get selected oscillator and frequency for @ref cmuClock_EM23GRPACLK
4768  *   clock tree.
4769  *
4770  * @param[out] freq
4771  *   The frequency.
4772  *
4773  * @param[out] sel
4774  *   The selected oscillator.
4775  ******************************************************************************/
em23GrpaClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4776 static void em23GrpaClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4777 {
4778   uint32_t f = 0U;
4779   CMU_Select_TypeDef s;
4780 
4781   switch (CMU->EM23GRPACLKCTRL & _CMU_EM23GRPACLKCTRL_CLKSEL_MASK) {
4782     case CMU_EM23GRPACLKCTRL_CLKSEL_LFRCO:
4783       f = SystemLFRCOClockGet();
4784       s = cmuSelect_LFRCO;
4785       break;
4786 
4787     case CMU_EM23GRPACLKCTRL_CLKSEL_LFXO:
4788       f = SystemLFXOClockGet();
4789       s = cmuSelect_LFXO;
4790       break;
4791 
4792     case CMU_EM23GRPACLKCTRL_CLKSEL_ULFRCO:
4793       f = SystemULFRCOClockGet();
4794       s = cmuSelect_ULFRCO;
4795       break;
4796 
4797     case CMU_EM23GRPACLKCTRL_CLKSEL_DISABLED:
4798       s = cmuSelect_Disabled;
4799       break;
4800 
4801     default:
4802       s = cmuSelect_Error;
4803       EFM_ASSERT(false);
4804       break;
4805   }
4806 
4807   if (freq != NULL) {
4808     *freq = f;
4809   }
4810   if (sel != NULL) {
4811     *sel = s;
4812   }
4813 }
4814 
4815 /***************************************************************************//**
4816  * @brief
4817  *   Get selected oscillator and frequency for @ref cmuClock_EM4GRPACLK
4818  *   clock tree.
4819  *
4820  * @param[out] freq
4821  *   The frequency.
4822  *
4823  * @param[out] sel
4824  *   The selected oscillator.
4825  ******************************************************************************/
em4GrpaClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)4826 static void em4GrpaClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
4827 {
4828   uint32_t f = 0U;
4829   CMU_Select_TypeDef s;
4830 
4831   switch (CMU->EM4GRPACLKCTRL & _CMU_EM4GRPACLKCTRL_CLKSEL_MASK) {
4832     case CMU_EM4GRPACLKCTRL_CLKSEL_LFRCO:
4833       f = SystemLFRCOClockGet();
4834       s = cmuSelect_LFRCO;
4835       break;
4836 
4837     case CMU_EM4GRPACLKCTRL_CLKSEL_LFXO:
4838       f = SystemLFXOClockGet();
4839       s = cmuSelect_LFXO;
4840       break;
4841 
4842     case CMU_EM4GRPACLKCTRL_CLKSEL_ULFRCO:
4843       f = SystemULFRCOClockGet();
4844       s = cmuSelect_ULFRCO;
4845       break;
4846 
4847     case CMU_EM4GRPACLKCTRL_CLKSEL_DISABLED:
4848       s = cmuSelect_Disabled;
4849       break;
4850 
4851     default:
4852       s = cmuSelect_Error;
4853       EFM_ASSERT(false);
4854       break;
4855   }
4856 
4857   if (freq != NULL) {
4858     *freq = f;
4859   }
4860   if (sel != NULL) {
4861     *sel = s;
4862   }
4863 }
4864 
getWaitStatesByFrequencyAndVScale(uint32_t freq,int vscale)4865 __STATIC_INLINE uint32_t getWaitStatesByFrequencyAndVScale(uint32_t freq, int vscale)
4866 {
4867   uint32_t flashWs = MSC_READCTRL_MODE_WS3;
4868 
4869   if (vscale == 0) {
4870     // VScale 1.1V core frequency ranges for wait-states configurations.
4871     if (0) {
4872     }
4873 #if defined(CMU_MAX_FREQ_2WS_1V1)
4874     else if (freq > CMU_MAX_FREQ_2WS_1V1) {
4875       flashWs = MSC_READCTRL_MODE_WS3;
4876     }
4877 #endif
4878 #if defined(CMU_MAX_FREQ_1WS_1V1)
4879     else if (freq > CMU_MAX_FREQ_1WS_1V1) {
4880       flashWs = MSC_READCTRL_MODE_WS2;
4881     }
4882 #endif
4883 #if defined(CMU_MAX_FREQ_0WS_1V1)
4884     else if (freq > CMU_MAX_FREQ_0WS_1V1) {
4885       flashWs = MSC_READCTRL_MODE_WS1;
4886     }
4887 #endif
4888     else {
4889       flashWs = MSC_READCTRL_MODE_WS0;
4890     }
4891   } else if (vscale >= 1) {
4892     // VScale 1.0V core frequency ranges for wait-states configurations.
4893     if (0) {
4894     }
4895 #if defined(CMU_MAX_FREQ_2WS_1V0)
4896     else if (freq > CMU_MAX_FREQ_2WS_1V0) {
4897       flashWs = MSC_READCTRL_MODE_WS3;
4898     }
4899 #endif
4900 #if defined(CMU_MAX_FREQ_1WS_1V0)
4901     else if (freq > CMU_MAX_FREQ_1WS_1V0) {
4902       flashWs = MSC_READCTRL_MODE_WS2;
4903     }
4904 #endif
4905 #if defined(CMU_MAX_FREQ_0WS_1V0)
4906     else if (freq > CMU_MAX_FREQ_0WS_1V0) {
4907       flashWs = MSC_READCTRL_MODE_WS1;
4908     }
4909 #endif
4910     else {
4911       flashWs = MSC_READCTRL_MODE_WS0;
4912     }
4913   }
4914   return flashWs;
4915 }
4916 
4917 /***************************************************************************//**
4918  * @brief
4919  *   Configure flash access wait states to support the given core clock
4920  *   frequency and vscale level.
4921  *
4922  * @note Current implementation sets wait states depending on frequency only.
4923  *   This assumes that applications running on Vscale enabled microcontrollers
4924  *   never attemtps to set core frequency above 40MHz at VSCALE1 (1.0V).
4925  *   Series 2 Config 1 devices does not support vscale.
4926  *
4927  * @param[in] coreFreq
4928  *   The core clock frequency to configure flash wait-states.
4929  *
4930  * @param[in] vscale
4931  *   Voltage Scale level. Supported levels are 0 and 1 where 0 is the default.
4932  *   @li 0 = 1.1 V (VSCALE2)
4933  *   @li 1 = 1.0 V (VSCALE1)
4934  ******************************************************************************/
flashWaitStateControl(uint32_t coreFreq,int vscale)4935 static void flashWaitStateControl(uint32_t coreFreq, int vscale)
4936 {
4937   (void)vscale;
4938 
4939   uint32_t mode;
4940   bool mscLocked;
4941 
4942 #if defined(CMU_CLKEN1_MSC)
4943   CMU->CLKEN1_SET = CMU_CLKEN1_MSC;
4944 #endif
4945 
4946 #if (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
4947   coreFreq *= CMU_ClockDivGet(cmuClock_CORE);
4948 #endif
4949 
4950   // Make sure the MSC is unlocked
4951   mscLocked = MSC_LockGetLocked();
4952   MSC_LockSetUnlocked();
4953 
4954   // Get current flash read setting
4955   mode = MSC_ReadCTRLGet() & ~_MSC_READCTRL_MODE_MASK;
4956 
4957   // Set new mode based on the core clock frequency
4958   mode |= getWaitStatesByFrequencyAndVScale(coreFreq, vscale);
4959 
4960   MSC_ReadCTRLSet(mode);
4961 
4962   // Set sram wait states for config 1 mcu.
4963 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_1)
4964   // Set new mode based on the core clock frequency
4965   if (coreFreq > CMU_MAX_SRAM_FREQ_0WS) {
4966     SYSCFG_setDmem0RamCtrlRamwsenBit();
4967   } else {
4968     SYSCFG_clearDmem0RamCtrlRamwsenBit();
4969   }
4970 #endif
4971   if (mscLocked) {
4972     MSC_LockSetLocked();
4973   }
4974 }
4975 
4976 /***************************************************************************//**
4977  * @brief
4978  *   Get calibrated HFRCODPLL tuning value from Device information (DI) page
4979  *   for a given frequency. Calibration value is not available for all frequency
4980  *   bands.
4981  *
4982  * @param[in] freq
4983  *   HFRCODPLL frequency band
4984  ******************************************************************************/
HFRCODPLLDevinfoGet(CMU_HFRCODPLLFreq_TypeDef freq)4985 static uint32_t HFRCODPLLDevinfoGet(CMU_HFRCODPLLFreq_TypeDef freq)
4986 {
4987   uint32_t ret = 0U;
4988 
4989   switch (freq) {
4990     // 1, 2 and 4MHz share the same calibration word
4991     case cmuHFRCODPLLFreq_1M0Hz:
4992     case cmuHFRCODPLLFreq_2M0Hz:
4993     case cmuHFRCODPLLFreq_4M0Hz:
4994       ret = DEVINFO->HFRCODPLLCAL[0].HFRCODPLLCAL;
4995       break;
4996 
4997     case cmuHFRCODPLLFreq_7M0Hz:
4998       ret = DEVINFO->HFRCODPLLCAL[3].HFRCODPLLCAL;
4999       break;
5000 
5001     case cmuHFRCODPLLFreq_13M0Hz:
5002       ret = DEVINFO->HFRCODPLLCAL[6].HFRCODPLLCAL;
5003       break;
5004 
5005     case cmuHFRCODPLLFreq_16M0Hz:
5006       ret = DEVINFO->HFRCODPLLCAL[7].HFRCODPLLCAL;
5007       break;
5008 
5009     case cmuHFRCODPLLFreq_19M0Hz:
5010       ret = DEVINFO->HFRCODPLLCAL[8].HFRCODPLLCAL;
5011       break;
5012 
5013     case cmuHFRCODPLLFreq_26M0Hz:
5014       ret = DEVINFO->HFRCODPLLCAL[10].HFRCODPLLCAL;
5015       break;
5016 
5017     case cmuHFRCODPLLFreq_32M0Hz:
5018       ret = DEVINFO->HFRCODPLLCAL[11].HFRCODPLLCAL;
5019       break;
5020 
5021     case cmuHFRCODPLLFreq_38M0Hz:
5022       ret = DEVINFO->HFRCODPLLCAL[12].HFRCODPLLCAL;
5023       break;
5024 
5025     case cmuHFRCODPLLFreq_48M0Hz:
5026       ret = DEVINFO->HFRCODPLLCAL[13].HFRCODPLLCAL;
5027       break;
5028 
5029     case cmuHFRCODPLLFreq_56M0Hz:
5030       ret = DEVINFO->HFRCODPLLCAL[14].HFRCODPLLCAL;
5031       break;
5032 
5033     case cmuHFRCODPLLFreq_64M0Hz:
5034       ret = DEVINFO->HFRCODPLLCAL[15].HFRCODPLLCAL;
5035       break;
5036 
5037     case cmuHFRCODPLLFreq_80M0Hz:
5038       ret = DEVINFO->HFRCODPLLCAL[16].HFRCODPLLCAL;
5039       break;
5040 
5041 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG_5)
5042     case cmuHFRCODPLLFreq_100M0Hz:
5043       ret = DEVINFO->HFRCODPLLCAL[17].HFRCODPLLCAL;
5044       break;
5045 #endif
5046 
5047     case cmuHFRCODPLLFreq_UserDefined:
5048       break;
5049 
5050     default:
5051       EFM_ASSERT(false);
5052       break;
5053   }
5054   return ret;
5055 }
5056 
5057 #if defined(IADC_PRESENT)
5058 /***************************************************************************//**
5059  * @brief
5060  *   Get selected oscillator and frequency for @ref cmuClock_IADCCLK
5061  *   clock tree.
5062  *
5063  * @param[out] freq
5064  *   The frequency.
5065  *
5066  * @param[out] sel
5067  *   The selected oscillator.
5068  ******************************************************************************/
iadcClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)5069 static void iadcClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
5070 {
5071   uint32_t f = 0U;
5072   CMU_Select_TypeDef s;
5073 
5074   switch (CMU->IADCCLKCTRL & _CMU_IADCCLKCTRL_CLKSEL_MASK) {
5075     case CMU_IADCCLKCTRL_CLKSEL_EM01GRPACLK:
5076       em01GrpaClkGet(&f, NULL);
5077       s = cmuSelect_EM01GRPACLK;
5078       break;
5079 
5080 #if defined(HFRCOEM23_PRESENT)
5081     case CMU_IADCCLKCTRL_CLKSEL_HFRCOEM23:
5082       f = SystemHFRCOEM23ClockGet();
5083       s = cmuSelect_HFRCOEM23;
5084       break;
5085 #endif
5086 
5087     case CMU_IADCCLKCTRL_CLKSEL_FSRCO:
5088       f = SystemFSRCOClockGet();
5089       s = cmuSelect_FSRCO;
5090       break;
5091 
5092     default:
5093       s = cmuSelect_Error;
5094       EFM_ASSERT(false);
5095       break;
5096   }
5097 
5098   if (freq != NULL) {
5099     *freq = f;
5100   }
5101   if (sel != NULL) {
5102     *sel = s;
5103   }
5104 }
5105 #endif
5106 
5107 /***************************************************************************//**
5108  * @brief
5109  *   Set maximum allowed divisor for @ref cmuClock_PCLK clock tree.
5110  ******************************************************************************/
pclkDivMax(void)5111 static void pclkDivMax(void)
5112 {
5113   // Set largest divisor for PCLK clock tree.
5114   CMU_ClockDivSet(cmuClock_PCLK, 2U);
5115 }
5116 
5117 /***************************************************************************//**
5118  * @brief
5119  *   Set @ref cmuClock_PCLK clock tree divisor to achieve highest possible
5120  *  frequency and still be within spec.
5121  ******************************************************************************/
pclkDivOptimize(void)5122 static void pclkDivOptimize(void)
5123 {
5124   CMU_ClkDiv_TypeDef div = 2U;
5125 
5126   if (CMU_ClockFreqGet(cmuClock_HCLK) <= CMU_MAX_PCLK_FREQ) {
5127     div = 1U;
5128   }
5129   CMU_ClockDivSet(cmuClock_PCLK, div);
5130 }
5131 
5132 #if defined(RTCC_PRESENT)
5133 /***************************************************************************//**
5134  * @brief
5135  *   Get selected oscillator and frequency for @ref cmuClock_RTCCCLK
5136  *   clock tree.
5137  *
5138  * @param[out] freq
5139  *   The frequency.
5140  *
5141  * @param[out] sel
5142  *   The selected oscillator.
5143  ******************************************************************************/
rtccClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)5144 static void rtccClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
5145 {
5146   uint32_t f = 0U;
5147   CMU_Select_TypeDef s;
5148 
5149   switch (CMU->RTCCCLKCTRL & _CMU_RTCCCLKCTRL_CLKSEL_MASK) {
5150     case CMU_RTCCCLKCTRL_CLKSEL_LFRCO:
5151       f = SystemLFRCOClockGet();
5152       s = cmuSelect_LFRCO;
5153       break;
5154 
5155     case CMU_RTCCCLKCTRL_CLKSEL_LFXO:
5156       f = SystemLFXOClockGet();
5157       s = cmuSelect_LFXO;
5158       break;
5159 
5160     case CMU_RTCCCLKCTRL_CLKSEL_ULFRCO:
5161       f = SystemULFRCOClockGet();
5162       s = cmuSelect_ULFRCO;
5163       break;
5164 
5165     default:
5166       s = cmuSelect_Error;
5167       EFM_ASSERT(false);
5168       break;
5169   }
5170 
5171   if (freq != NULL) {
5172     *freq = f;
5173   }
5174   if (sel != NULL) {
5175     *sel = s;
5176   }
5177 }
5178 #endif
5179 
5180 #if defined(SYSRTC_PRESENT)
5181 /***************************************************************************//**
5182  * @brief
5183  *   Get selected oscillator and frequency for @ref cmuClock_SYSRTCCLK
5184  *   clock tree.
5185  *
5186  * @param[out] freq
5187  *   The frequency.
5188  *
5189  * @param[out] sel
5190  *   The selected oscillator.
5191  ******************************************************************************/
sysrtcClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)5192 static void sysrtcClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
5193 {
5194   uint32_t f = 0U;
5195   CMU_Select_TypeDef s;
5196 
5197   switch (CMU->SYSRTC0CLKCTRL & _CMU_SYSRTC0CLKCTRL_CLKSEL_MASK) {
5198     case CMU_SYSRTC0CLKCTRL_CLKSEL_LFRCO:
5199       f = SystemLFRCOClockGet();
5200       s = cmuSelect_LFRCO;
5201       break;
5202 
5203     case CMU_SYSRTC0CLKCTRL_CLKSEL_LFXO:
5204       f = SystemLFXOClockGet();
5205       s = cmuSelect_LFXO;
5206       break;
5207 
5208     case CMU_SYSRTC0CLKCTRL_CLKSEL_ULFRCO:
5209       f = SystemULFRCOClockGet();
5210       s = cmuSelect_ULFRCO;
5211       break;
5212 
5213     case CMU_SYSRTC0CLKCTRL_CLKSEL_DISABLED:
5214       s = cmuSelect_Disabled;
5215       break;
5216 
5217     default:
5218       s = cmuSelect_Error;
5219       EFM_ASSERT(false);
5220       break;
5221   }
5222 
5223   if (freq != NULL) {
5224     *freq = f;
5225   }
5226   if (sel != NULL) {
5227     *sel = s;
5228   }
5229 }
5230 #endif
5231 
5232 /***************************************************************************//**
5233  * @brief
5234  *   Set wait-states to values valid for maximum allowable core clock frequency.
5235  ******************************************************************************/
waitStateMax(void)5236 static void waitStateMax(void)
5237 {
5238   flashWaitStateControl(SystemMaxCoreClockGet(), 0);
5239 }
5240 
5241 /***************************************************************************//**
5242  * @brief
5243  *   Get selected oscillator and frequency for @ref cmuClock_WDOG0CLK
5244  *   clock tree.
5245  *
5246  * @param[out] freq
5247  *   The frequency.
5248  *
5249  * @param[out] sel
5250  *   The selected oscillator.
5251  ******************************************************************************/
wdog0ClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)5252 static void wdog0ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
5253 {
5254   uint32_t f = 0U;
5255   CMU_Select_TypeDef s;
5256 
5257   switch (CMU->WDOG0CLKCTRL & _CMU_WDOG0CLKCTRL_CLKSEL_MASK) {
5258     case CMU_WDOG0CLKCTRL_CLKSEL_LFRCO:
5259       f = SystemLFRCOClockGet();
5260       s = cmuSelect_LFRCO;
5261       break;
5262 
5263     case CMU_WDOG0CLKCTRL_CLKSEL_LFXO:
5264       f = SystemLFXOClockGet();
5265       s = cmuSelect_LFXO;
5266       break;
5267 
5268     case CMU_WDOG0CLKCTRL_CLKSEL_ULFRCO:
5269       f = SystemULFRCOClockGet();
5270       s = cmuSelect_ULFRCO;
5271       break;
5272 
5273     case CMU_WDOG0CLKCTRL_CLKSEL_HCLKDIV1024:
5274       f = SystemHCLKGet() / 1024U;
5275       s = cmuSelect_HCLKDIV1024;
5276       break;
5277 
5278     case CMU_WDOG0CLKCTRL_CLKSEL_DISABLED:
5279       s = cmuSelect_Disabled;
5280       break;
5281 
5282     default:
5283       s = cmuSelect_Error;
5284       EFM_ASSERT(false);
5285       break;
5286   }
5287 
5288   if (freq != NULL) {
5289     *freq = f;
5290   }
5291   if (sel != NULL) {
5292     *sel = s;
5293   }
5294 }
5295 
5296 #if defined(_SILICON_LABS_32B_SERIES_2) && WDOG_COUNT > 1
5297 /***************************************************************************//**
5298  * @brief
5299  *   Get selected oscillator and frequency for @ref cmuClock_WDOG1CLK
5300  *   clock tree.
5301  *
5302  * @param[out] freq
5303  *   The frequency.
5304  *
5305  * @param[out] sel
5306  *   The selected oscillator.
5307  ******************************************************************************/
wdog1ClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)5308 static void wdog1ClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
5309 {
5310   uint32_t f = 0U;
5311   CMU_Select_TypeDef s;
5312 
5313   switch (CMU->WDOG1CLKCTRL & _CMU_WDOG1CLKCTRL_CLKSEL_MASK) {
5314     case CMU_WDOG1CLKCTRL_CLKSEL_LFRCO:
5315       f = SystemLFRCOClockGet();
5316       s = cmuSelect_LFRCO;
5317       break;
5318 
5319     case CMU_WDOG1CLKCTRL_CLKSEL_LFXO:
5320       f = SystemLFXOClockGet();
5321       s = cmuSelect_LFXO;
5322       break;
5323 
5324     case CMU_WDOG1CLKCTRL_CLKSEL_ULFRCO:
5325       f = SystemULFRCOClockGet();
5326       s = cmuSelect_ULFRCO;
5327       break;
5328 
5329     case CMU_WDOG1CLKCTRL_CLKSEL_HCLKDIV1024:
5330       f = SystemHCLKGet() / 1024U;
5331       s = cmuSelect_HCLKDIV1024;
5332       break;
5333 
5334     case CMU_WDOG1CLKCTRL_CLKSEL_DISABLED:
5335       s = cmuSelect_Disabled;
5336       break;
5337 
5338     default:
5339       s = cmuSelect_Error;
5340       EFM_ASSERT(false);
5341       break;
5342   }
5343 
5344   if (freq != NULL) {
5345     *freq = f;
5346   }
5347   if (sel != NULL) {
5348     *sel = s;
5349   }
5350 }
5351 #endif // defined(_SILICON_LABS_32B_SERIES_2) && WDOG_COUNT > 1
5352 
5353 /***************************************************************************//**
5354  * @brief
5355  *   Get selected oscillator and frequency for @ref cmuClock_SYSTICK
5356  *   clock tree.
5357  *
5358  * @param[out] freq
5359  *   The frequency.
5360  *
5361  * @param[out] sel
5362  *   The selected oscillator.
5363  ******************************************************************************/
sysTickClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)5364 static void sysTickClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
5365 {
5366   uint32_t f = 0U;
5367   CMU_Select_TypeDef s;
5368 
5369   if (SysTick->CTRL & SysTick_CTRL_CLKSOURCE_Msk) {
5370     f = SystemHCLKGet();
5371     s = cmuSelect_HCLK;
5372   } else {
5373     em23GrpaClkGet(&f, &s);
5374   }
5375 
5376   if (freq != NULL) {
5377     *freq = f;
5378   }
5379   if (sel != NULL) {
5380     *sel = s;
5381   }
5382 }
5383 
5384 #if defined(USB_PRESENT)
5385 /***************************************************************************//**
5386  * @brief
5387  *   Get selected oscillator and frequency for @ref cmuClock_USB clock tree.
5388  *
5389  * @param[out] freq
5390  *   The frequency.
5391  *
5392  * @param[out] sel
5393  *   The selected oscillator.
5394  ******************************************************************************/
usbClkGet(uint32_t * freq,CMU_Select_TypeDef * sel)5395 static void usbClkGet(uint32_t *freq, CMU_Select_TypeDef *sel)
5396 {
5397   uint32_t f = 0U;
5398   CMU_Select_TypeDef s;
5399 
5400   switch (CMU->USB0CLKCTRL & _CMU_USB0CLKCTRL_CLKSEL_MASK) {
5401     case CMU_USB0CLKCTRL_CLKSEL_USBPLL0:
5402       f = PLL0_USB_OUTPUT_FREQ;
5403       s = cmuSelect_USBPLL0;
5404       break;
5405 
5406     case CMU_USB0CLKCTRL_CLKSEL_LFXO:
5407       f = SystemLFXOClockGet();
5408       s = cmuSelect_LFXO;
5409       break;
5410 
5411     case CMU_USB0CLKCTRL_CLKSEL_LFRCO:
5412       f = SystemLFRCOClockGet();
5413       s = cmuSelect_LFRCO;
5414       break;
5415 
5416     default:
5417       s = cmuSelect_Error;
5418       EFM_ASSERT(false);
5419       break;
5420   }
5421 
5422   if (freq != NULL) {
5423     *freq = f;
5424   }
5425   if (sel != NULL) {
5426     *sel = s;
5427   }
5428 }
5429 #endif
5430 
5431 /** @endcond */
5432 
5433 #else // defined(_SILICON_LABS_32B_SERIES_2)
5434 
5435 /*******************************************************************************
5436  ******************************   DEFINES   ************************************
5437  ******************************************************************************/
5438 
5439 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
5440 
5441 #if defined(_SILICON_LABS_32B_SERIES_0)
5442 /** The maximum allowed core frequency when using 0 wait-states on flash access. */
5443 #define CMU_MAX_FREQ_0WS        16000000
5444 /** The maximum allowed core frequency when using 1 wait-states on flash access */
5445 #define CMU_MAX_FREQ_1WS        32000000
5446 
5447 #elif (_SILICON_LABS_GECKO_INTERNAL_SDID == 80)
5448 // EFR32xG1x and EFM32xG1x
5449 #define CMU_MAX_FREQ_0WS_1V2    25000000
5450 #define CMU_MAX_FREQ_1WS_1V2    40000000
5451 
5452 #elif (_SILICON_LABS_GECKO_INTERNAL_SDID == 84)
5453 // EFR32xG12x and EFM32xG12x
5454 #define CMU_MAX_FREQ_0WS_1V2    25000000
5455 #define CMU_MAX_FREQ_1WS_1V2    40000000
5456 #define CMU_MAX_FREQ_0WS_1V1    21330000
5457 #define CMU_MAX_FREQ_1WS_1V1    32000000
5458 #define CMU_MAX_FREQ_0WS_1V0     7000000
5459 #define CMU_MAX_FREQ_1WS_1V0    14000000
5460 #define CMU_MAX_FREQ_2WS_1V0    20000000
5461 
5462 #elif (_SILICON_LABS_GECKO_INTERNAL_SDID == 89)
5463 // EFR32xG13x and EFM32xG13x
5464 #define CMU_MAX_FREQ_0WS_1V2    25000000
5465 #define CMU_MAX_FREQ_1WS_1V2    40000000
5466 #define CMU_MAX_FREQ_0WS_1V0     7000000
5467 #define CMU_MAX_FREQ_1WS_1V0    14000000
5468 #define CMU_MAX_FREQ_2WS_1V0    20000000
5469 
5470 #elif (_SILICON_LABS_GECKO_INTERNAL_SDID == 95)
5471 // EFR32xG14x and EFM32xG14x
5472 #define CMU_MAX_FREQ_0WS_1V2    25000000
5473 #define CMU_MAX_FREQ_1WS_1V2    40000000
5474 #define CMU_MAX_FREQ_0WS_1V0     7000000
5475 #define CMU_MAX_FREQ_1WS_1V0    14000000
5476 #define CMU_MAX_FREQ_2WS_1V0    20000000
5477 
5478 #elif (_SILICON_LABS_GECKO_INTERNAL_SDID == 100)
5479 // EFM32GG11x
5480 #define CMU_MAX_FREQ_0WS_1V2    18000000
5481 #define CMU_MAX_FREQ_1WS_1V2    36000000
5482 #define CMU_MAX_FREQ_2WS_1V2    54000000
5483 #define CMU_MAX_FREQ_3WS_1V2    72000000
5484 #define CMU_MAX_FREQ_0WS_1V0     7000000
5485 #define CMU_MAX_FREQ_1WS_1V0    14000000
5486 #define CMU_MAX_FREQ_2WS_1V0    20000000
5487 
5488 #elif (_SILICON_LABS_GECKO_INTERNAL_SDID == 103)
5489 // EFM32TG11x
5490 #define CMU_MAX_FREQ_0WS_1V2    25000000
5491 #define CMU_MAX_FREQ_1WS_1V2    48000000
5492 #define CMU_MAX_FREQ_0WS_1V0    10000000
5493 #define CMU_MAX_FREQ_1WS_1V0    21000000
5494 #define CMU_MAX_FREQ_2WS_1V0    20000000
5495 
5496 #elif (_SILICON_LABS_GECKO_INTERNAL_SDID == 106)
5497 // EFM32GG12x
5498 #define CMU_MAX_FREQ_0WS_1V2    18000000
5499 #define CMU_MAX_FREQ_1WS_1V2    36000000
5500 #define CMU_MAX_FREQ_2WS_1V2    54000000
5501 #define CMU_MAX_FREQ_3WS_1V2    72000000
5502 #define CMU_MAX_FREQ_0WS_1V0    7000000
5503 #define CMU_MAX_FREQ_1WS_1V0    14000000
5504 #define CMU_MAX_FREQ_2WS_1V0    20000000
5505 
5506 #else
5507 #error "Max Flash wait-state frequencies are not defined for this platform."
5508 #endif
5509 
5510 /** The maximum frequency for the HFLE interface. */
5511 #if defined(CMU_CTRL_HFLE)
5512 /** The maximum HFLE frequency for series 0 EFM32 and EZR32 Wonder Gecko. */
5513 #if defined(_SILICON_LABS_32B_SERIES_0) \
5514   && (defined(_EFM32_WONDER_FAMILY)     \
5515   || defined(_EZR32_WONDER_FAMILY))
5516 #define CMU_MAX_FREQ_HFLE                       24000000UL
5517 /** The maximum HFLE frequency for other series 0 parts with maximum core clock
5518     higher than 32 MHz. */
5519 #elif defined(_SILICON_LABS_32B_SERIES_0) \
5520   && (defined(_EFM32_GIANT_FAMILY)        \
5521   || defined(_EZR32_LEOPARD_FAMILY))
5522 #define CMU_MAX_FREQ_HFLE                       maxFreqHfle()
5523 #endif
5524 #elif defined(CMU_CTRL_WSHFLE)
5525 /** The maximum HFLE frequency for series 1 parts. */
5526 #define CMU_MAX_FREQ_HFLE                       32000000UL
5527 #endif
5528 
5529 #if defined(CMU_STATUS_HFXOSHUNTOPTRDY)
5530 #define HFXO_TUNING_READY_FLAGS  (CMU_STATUS_HFXOPEAKDETRDY | CMU_STATUS_HFXOSHUNTOPTRDY)
5531 #define HFXO_TUNING_MODE_AUTO    (_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_AUTOCMD)
5532 #define HFXO_TUNING_MODE_CMD     (_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_CMD)
5533 #elif defined(CMU_STATUS_HFXOPEAKDETRDY)
5534 #define HFXO_TUNING_READY_FLAGS  (CMU_STATUS_HFXOPEAKDETRDY)
5535 #define HFXO_TUNING_MODE_AUTO    (_CMU_HFXOCTRL_PEAKDETMODE_AUTOCMD)
5536 #define HFXO_TUNING_MODE_CMD     (_CMU_HFXOCTRL_PEAKDETMODE_CMD)
5537 #endif
5538 
5539 #if defined(CMU_HFXOCTRL_MODE_EXTCLK)
5540 /** HFXO external clock mode is renamed from EXTCLK to DIGEXTCLK. */
5541 #define CMU_HFXOCTRL_MODE_DIGEXTCLK     CMU_HFXOCTRL_MODE_EXTCLK
5542 #endif
5543 
5544 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
5545 #define VSCALE_DEFAULT    ((int)EMU_VScaleGet())
5546 #else
5547 #define VSCALE_DEFAULT    VSCALE_EM01_HIGH_PERFORMANCE
5548 #endif
5549 
5550 /*******************************************************************************
5551  **************************   LOCAL VARIABLES   ********************************
5552  ******************************************************************************/
5553 
5554 #if defined(_CMU_AUXHFRCOCTRL_FREQRANGE_MASK)
5555 static CMU_AUXHFRCOFreq_TypeDef auxHfrcoFreq = cmuAUXHFRCOFreq_19M0Hz;
5556 #endif
5557 #if defined(_CMU_STATUS_HFXOSHUNTOPTRDY_MASK)
5558 #define HFXO_INVALID_TRIM   (~_CMU_HFXOTRIMSTATUS_MASK)
5559 #endif
5560 
5561 #if defined(CMU_OSCENCMD_DPLLEN)
5562 /** A table of HFRCOCTRL values and their associated minimum/maximum frequencies and
5563     an optional band enumerator. */
5564 static const struct hfrcoCtrlTableElement{
5565   uint32_t              minFreq;
5566   uint32_t              maxFreq;
5567   uint32_t              value;
5568   CMU_HFRCOFreq_TypeDef band;
5569 } hfrcoCtrlTable[] =
5570 {
5571   // minFreq  maxFreq   HFRCOCTRL value  band
5572   {  860000UL, 1050000UL, 0xBC601F00UL, cmuHFRCOFreq_1M0Hz       },
5573   { 1050000UL, 1280000UL, 0xBC611F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5574   { 1280000UL, 1480000UL, 0xBCA21F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5575   { 1480000UL, 1800000UL, 0xAD231F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5576   { 1800000UL, 2110000UL, 0xBA601F00UL, cmuHFRCOFreq_2M0Hz       },
5577   { 2110000UL, 2560000UL, 0xBA611F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5578   { 2560000UL, 2970000UL, 0xBAA21F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5579   { 2970000UL, 3600000UL, 0xAB231F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5580   { 3600000UL, 4220000UL, 0xB8601F00UL, cmuHFRCOFreq_4M0Hz       },
5581   { 4220000UL, 5120000UL, 0xB8611F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5582   { 5120000UL, 5930000UL, 0xB8A21F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5583   { 5930000UL, 7520000UL, 0xA9231F00UL, cmuHFRCOFreq_7M0Hz       },
5584   { 7520000UL, 9520000UL, 0x99241F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5585   { 9520000UL, 11800000UL, 0x99251F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5586   { 11800000UL, 14400000UL, 0x99261F00UL, cmuHFRCOFreq_13M0Hz     },
5587   { 14400000UL, 17200000UL, 0x99271F00UL, cmuHFRCOFreq_16M0Hz     },
5588   { 17200000UL, 19700000UL, 0x99481F00UL, cmuHFRCOFreq_19M0Hz     },
5589   { 19700000UL, 23800000UL, 0x99491F35UL, (CMU_HFRCOFreq_TypeDef)0 },
5590   { 23800000UL, 28700000UL, 0x994A1F00UL, cmuHFRCOFreq_26M0Hz      },
5591   { 28700000UL, 34800000UL, 0x996B1F00UL, cmuHFRCOFreq_32M0Hz      },
5592 #if defined(_SILICON_LABS_GECKO_INTERNAL_SDID_84)  \
5593   || defined(_SILICON_LABS_GECKO_INTERNAL_SDID_89) \
5594   || defined(_SILICON_LABS_GECKO_INTERNAL_SDID_95)
5595   { 34800000UL, 40000000UL, 0x996C1F00UL, cmuHFRCOFreq_38M0Hz      }
5596 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_100) \
5597   || defined(_SILICON_LABS_GECKO_INTERNAL_SDID_106)
5598   { 34800000UL, 42800000UL, 0x996C1F00UL, cmuHFRCOFreq_38M0Hz      },
5599   { 42800000UL, 51600000UL, 0x996D1F00UL, cmuHFRCOFreq_48M0Hz      },
5600   { 51600000UL, 60500000UL, 0x998E1F00UL, cmuHFRCOFreq_56M0Hz      },
5601   { 60500000UL, 72000000UL, 0xA98F1F00UL, cmuHFRCOFreq_64M0Hz      }
5602 #elif defined(_SILICON_LABS_GECKO_INTERNAL_SDID_103)
5603   { 34800000UL, 42800000UL, 0x996C1F00UL, cmuHFRCOFreq_38M0Hz      },
5604   { 42800000UL, 48000000UL, 0x996D1F00UL, cmuHFRCOFreq_48M0Hz      }
5605 #else
5606   #error "HFRCOCTRL values not set for this platform."
5607 #endif
5608 };
5609 
5610 #define HFRCOCTRLTABLE_ENTRIES (sizeof(hfrcoCtrlTable) \
5611                                 / sizeof(struct hfrcoCtrlTableElement))
5612 #endif // CMU_OSCENCMD_DPLLEN
5613 
5614 #if defined(_SILICON_LABS_32B_SERIES_1) && defined(_EMU_STATUS_VSCALE_MASK)
5615 /* Devices with Voltage Scaling needs extra handling of wait states. */
5616 static const struct flashWsTableElement{
5617   uint32_t maxFreq;
5618   uint8_t  vscale;
5619   uint8_t  ws;
5620 } flashWsTable[] =
5621 {
5622 #if (_SILICON_LABS_GECKO_INTERNAL_SDID == 100 || _SILICON_LABS_GECKO_INTERNAL_SDID == 106)
5623   { CMU_MAX_FREQ_0WS_1V2, 0, 0 },  /* 0 wait states at max frequency 18 MHz and 1.2V */
5624   { CMU_MAX_FREQ_1WS_1V2, 0, 1 },  /* 1 wait states at max frequency 36 MHz and 1.2V */
5625   { CMU_MAX_FREQ_2WS_1V2, 0, 2 },  /* 2 wait states at max frequency 54 MHz and 1.2V */
5626   { CMU_MAX_FREQ_3WS_1V2, 0, 3 },  /* 3 wait states at max frequency 72 MHz and 1.2V */
5627   { CMU_MAX_FREQ_0WS_1V0, 2, 0 },  /* 0 wait states at max frequency 7 MHz and 1.0V */
5628   { CMU_MAX_FREQ_1WS_1V0, 2, 1 },  /* 1 wait states at max frequency 14 MHz and 1.0V */
5629   { CMU_MAX_FREQ_2WS_1V0, 2, 2 },  /* 2 wait states at max frequency 21 MHz and 1.0V */
5630 #else
5631   { CMU_MAX_FREQ_0WS_1V2, 0, 0 },  /* 0 wait states at 1.2V */
5632   { CMU_MAX_FREQ_1WS_1V2, 0, 1 },  /* 1 wait states at 1.2V */
5633   { CMU_MAX_FREQ_0WS_1V0, 2, 0 },  /* 0 wait states at 1.0V */
5634   { CMU_MAX_FREQ_1WS_1V0, 2, 1 },  /* 1 wait states at 1.0V */
5635   { CMU_MAX_FREQ_2WS_1V0, 2, 2 },  /* 2 wait states at 1.0V */
5636 #endif
5637 };
5638 
5639 #define FLASH_WS_TABLE_ENTRIES (sizeof(flashWsTable) / sizeof(flashWsTable[0]))
5640 #endif
5641 
5642 #if defined(_CMU_USHFRCOCTRL_FREQRANGE_MASK) \
5643   || defined(_CMU_USHFRCOTUNE_MASK)
5644 #ifndef EFM32_USHFRCO_STARTUP_FREQ
5645 #define EFM32_USHFRCO_STARTUP_FREQ        (48000000UL)
5646 #endif
5647 
5648 static uint32_t ushfrcoFreq = EFM32_USHFRCO_STARTUP_FREQ;
5649 #endif
5650 
5651 /*******************************************************************************
5652  **************************   LOCAL PROTOTYPES   *******************************
5653  ******************************************************************************/
5654 #if defined(_CMU_HFRCOCTRL_FREQRANGE_MASK)
5655 static uint32_t CMU_HFRCODevinfoGet(CMU_HFRCOFreq_TypeDef freq);
5656 #endif
5657 
5658 #if defined(_CMU_USHFRCOCTRL_FREQRANGE_MASK)
5659 static uint32_t CMU_USHFRCODevinfoGet(CMU_USHFRCOFreq_TypeDef freq);
5660 #endif
5661 
5662 static void hfperClkSafePrescaler(void);
5663 static void hfperClkOptimizedPrescaler(void);
5664 
5665 static uint16_t lfxo_precision = 0xFFFF;
5666 static uint16_t hfxo_precision = 0xFFFF;
5667 
5668 /** @endcond */
5669 
5670 /*******************************************************************************
5671  **************************   LOCAL FUNCTIONS   ********************************
5672  ******************************************************************************/
5673 
5674 #if defined(_SILICON_LABS_32B_SERIES_0) \
5675   && (defined(_EFM32_GIANT_FAMILY)      \
5676   || defined(_EZR32_LEOPARD_FAMILY))
5677 /***************************************************************************//**
5678  * @brief
5679  *   Return maximum allowed frequency for low energy peripherals.
5680  ******************************************************************************/
maxFreqHfle(void)5681 static uint32_t maxFreqHfle(void)
5682 {
5683   uint16_t majorMinorRev;
5684 
5685   switch (SYSTEM_GetFamily()) {
5686     case systemPartFamilyEfm32Leopard:
5687     case systemPartFamilyEzr32Leopard:
5688       /* CHIP MAJOR bit [5:0] */
5689       majorMinorRev = (((ROMTABLE->PID0 & _ROMTABLE_PID0_REVMAJOR_MASK)
5690                         >> _ROMTABLE_PID0_REVMAJOR_SHIFT) << 8);
5691       /* CHIP MINOR bit [7:4] */
5692       majorMinorRev |= (((ROMTABLE->PID2 & _ROMTABLE_PID2_REVMINORMSB_MASK)
5693                          >> _ROMTABLE_PID2_REVMINORMSB_SHIFT) << 4);
5694       /* CHIP MINOR bit [3:0] */
5695       majorMinorRev |=  ((ROMTABLE->PID3 & _ROMTABLE_PID3_REVMINORLSB_MASK)
5696                          >> _ROMTABLE_PID3_REVMINORLSB_SHIFT);
5697 
5698       if (majorMinorRev >= 0x0204) {
5699         return 24000000;
5700       } else {
5701         return 32000000;
5702       }
5703 
5704     case systemPartFamilyEfm32Giant:
5705       return 32000000;
5706 
5707     default:
5708       /* Invalid device family. */
5709       EFM_ASSERT(false);
5710       return 0;
5711   }
5712 }
5713 #endif
5714 
5715 #if defined(CMU_MAX_FREQ_HFLE)
5716 
5717 /** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
5718 /* Unified definitions for the HFLE wait-state and prescaler fields. */
5719 #if defined(CMU_CTRL_HFLE)
5720 #define _GENERIC_HFLE_WS_MASK           _CMU_CTRL_HFLE_MASK
5721 #define _GENERIC_HFLE_WS_SHIFT          _CMU_CTRL_HFLE_SHIFT
5722 #define GENERIC_HFLE_PRESC_REG          CMU->HFCORECLKDIV
5723 #define _GENERIC_HFLE_PRESC_MASK        _CMU_HFCORECLKDIV_HFCORECLKLEDIV_MASK
5724 #define _GENERIC_HFLE_PRESC_SHIFT       _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT
5725 #elif defined(CMU_CTRL_WSHFLE)
5726 #define _GENERIC_HFLE_WS_MASK           _CMU_CTRL_WSHFLE_MASK
5727 #define _GENERIC_HFLE_WS_SHIFT          _CMU_CTRL_WSHFLE_SHIFT
5728 #define GENERIC_HFLE_PRESC_REG          CMU->HFPRESC
5729 #define _GENERIC_HFLE_PRESC_MASK        _CMU_HFPRESC_HFCLKLEPRESC_MASK
5730 #define _GENERIC_HFLE_PRESC_SHIFT       _CMU_HFPRESC_HFCLKLEPRESC_SHIFT
5731 #endif
5732 /** @endcond */
5733 
5734 /***************************************************************************//**
5735  * @brief
5736  *   Set HFLE wait-states and HFCLKLE prescaler according to wanted HF clock.
5737  *
5738  * @param[in] hfFreq
5739  *   The HF clock frequency to use.
5740  *   This is:
5741  *     CORE clock on Series0 devices.
5742  *     HF clock on on Series1 devices.
5743  ******************************************************************************/
setHfLeConfig(uint32_t hfFreq)5744 static void setHfLeConfig(uint32_t hfFreq)
5745 {
5746   unsigned int hfleWs;
5747   uint32_t hflePresc;
5748 
5749   /* Check for 1 bit fields. @ref BUS_RegBitWrite() below are going to fail if the
5750      fields are changed to more than 1 bit. */
5751   EFM_ASSERT((_GENERIC_HFLE_WS_MASK >> _GENERIC_HFLE_WS_SHIFT) == 0x1U);
5752 
5753   /* - Enable HFLE wait-state to allow access to LE peripherals when HFBUSCLK is
5754        above maxLeFreq.
5755      - Set HFLE prescaler. Allowed HFLE clock frequency is maxLeFreq. */
5756 
5757   hfleWs = 1;
5758   if (hfFreq <= CMU_MAX_FREQ_HFLE) {
5759     hfleWs = 0;
5760     hflePresc = 0;
5761   } else if (hfFreq <= (2UL * CMU_MAX_FREQ_HFLE)) {
5762     hflePresc = 1;
5763   } else {
5764     hflePresc = 2;
5765   }
5766   BUS_RegBitWrite(&CMU->CTRL, _GENERIC_HFLE_WS_SHIFT, hfleWs);
5767   GENERIC_HFLE_PRESC_REG = (GENERIC_HFLE_PRESC_REG & ~_GENERIC_HFLE_PRESC_MASK)
5768                            | (hflePresc << _GENERIC_HFLE_PRESC_SHIFT);
5769 }
5770 
5771 #if defined(_CMU_CTRL_HFLE_MASK)
5772 /***************************************************************************//**
5773  * @brief
5774  *   Get HFLE wait-state configuration.
5775  *
5776  * @return
5777  *   The current wait-state configuration.
5778  ******************************************************************************/
getHfLeConfig(void)5779 static uint32_t getHfLeConfig(void)
5780 {
5781   uint32_t ws = BUS_RegBitRead(&CMU->CTRL, _GENERIC_HFLE_WS_SHIFT);
5782   return ws;
5783 }
5784 #endif
5785 #endif
5786 
5787 /***************************************************************************//**
5788  * @brief
5789  *   Get the AUX clock frequency. Used by MSC flash programming and LESENSE,
5790  *   by default also as a debug clock.
5791  *
5792  * @return
5793  *   AUX Frequency in Hz.
5794  ******************************************************************************/
auxClkGet(void)5795 static uint32_t auxClkGet(void)
5796 {
5797   uint32_t ret;
5798 
5799 #if defined(_CMU_AUXHFRCOCTRL_FREQRANGE_MASK)
5800   ret = (uint32_t)auxHfrcoFreq;
5801 
5802 #elif defined(_CMU_AUXHFRCOCTRL_BAND_MASK)
5803   /* All series 0 families except EFM32G */
5804   switch (CMU->AUXHFRCOCTRL & _CMU_AUXHFRCOCTRL_BAND_MASK) {
5805     case CMU_AUXHFRCOCTRL_BAND_1MHZ:
5806       if ( SYSTEM_GetProdRev() >= 19 ) {
5807         ret = 1200000;
5808       } else {
5809         ret = 1000000;
5810       }
5811       break;
5812 
5813     case CMU_AUXHFRCOCTRL_BAND_7MHZ:
5814       if ( SYSTEM_GetProdRev() >= 19 ) {
5815         ret = 6600000;
5816       } else {
5817         ret = 7000000;
5818       }
5819       break;
5820 
5821     case CMU_AUXHFRCOCTRL_BAND_11MHZ:
5822       ret = 11000000;
5823       break;
5824 
5825     case CMU_AUXHFRCOCTRL_BAND_14MHZ:
5826       ret = 14000000;
5827       break;
5828 
5829     case CMU_AUXHFRCOCTRL_BAND_21MHZ:
5830       ret = 21000000;
5831       break;
5832 
5833 #if defined(_CMU_AUXHFRCOCTRL_BAND_28MHZ)
5834     case CMU_AUXHFRCOCTRL_BAND_28MHZ:
5835       ret = 28000000;
5836       break;
5837 #endif
5838 
5839     default:
5840       ret = 0;
5841       EFM_ASSERT(false);
5842       break;
5843   }
5844 
5845 #else
5846   /* Gecko has a fixed 14 MHz AUXHFRCO clock. */
5847   ret = 14000000;
5848 
5849 #endif
5850 
5851   return ret;
5852 }
5853 
5854 #if defined (_CMU_ADCCTRL_ADC0CLKSEL_HFSRCCLK) \
5855   || defined (_CMU_ADCCTRL_ADC1CLKSEL_HFSRCCLK)
5856 /***************************************************************************//**
5857  * @brief
5858  *   Get the HFSRCCLK frequency.
5859  *
5860  * @return
5861  *   HFSRCCLK Frequency in Hz.
5862  ******************************************************************************/
hfSrcClkGet(void)5863 static uint32_t hfSrcClkGet(void)
5864 {
5865   uint32_t ret;
5866 
5867   ret = SystemHFClockGet();
5868   return ret * (1U + ((CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK)
5869                       >> _CMU_HFPRESC_PRESC_SHIFT));
5870 }
5871 #endif
5872 
5873 /***************************************************************************//**
5874  * @brief
5875  *   Get the Debug Trace clock frequency.
5876  *
5877  * @return
5878  *   Debug Trace frequency in Hz.
5879  ******************************************************************************/
dbgClkGet(void)5880 static uint32_t dbgClkGet(void)
5881 {
5882   uint32_t ret;
5883   CMU_Select_TypeDef clk;
5884 
5885   /* Get selected clock source */
5886   clk = CMU_ClockSelectGet(cmuClock_DBG);
5887 
5888   switch (clk) {
5889     case cmuSelect_HFCLK:
5890       ret = SystemHFClockGet();
5891       break;
5892 
5893     case cmuSelect_AUXHFRCO:
5894       ret = auxClkGet();
5895       break;
5896 
5897     default:
5898       ret = 0;
5899       EFM_ASSERT(false);
5900       break;
5901   }
5902   return ret;
5903 }
5904 
5905 #if defined(_CMU_ADCCTRL_ADC0CLKSEL_MASK)
5906 /***************************************************************************//**
5907  * @brief
5908  *   Get the ADC n asynchronous clock frequency.
5909  *
5910  * @return
5911  *   ADC n asynchronous frequency in Hz.
5912  ******************************************************************************/
adcAsyncClkGet(uint32_t adc)5913 static uint32_t adcAsyncClkGet(uint32_t adc)
5914 {
5915   uint32_t ret;
5916   CMU_Select_TypeDef clk;
5917 
5918   /* Get the selected clock source. */
5919   switch (adc) {
5920     case 0:
5921       clk = CMU_ClockSelectGet(cmuClock_ADC0ASYNC);
5922       break;
5923 
5924 #if defined(_CMU_ADCCTRL_ADC1CLKSEL_MASK)
5925     case 1:
5926       clk = CMU_ClockSelectGet(cmuClock_ADC1ASYNC);
5927       break;
5928 #endif
5929 
5930     default:
5931       EFM_ASSERT(false);
5932       return 0;
5933   }
5934 
5935   switch (clk) {
5936     case cmuSelect_Disabled:
5937       ret = 0;
5938       break;
5939 
5940     case cmuSelect_AUXHFRCO:
5941       ret = auxClkGet();
5942       break;
5943 
5944     case cmuSelect_HFXO:
5945       ret = SystemHFXOClockGet();
5946       break;
5947 
5948     case cmuSelect_HFSRCCLK:
5949       ret = hfSrcClkGet();
5950       break;
5951 
5952     default:
5953       ret = 0;
5954       EFM_ASSERT(false);
5955       break;
5956   }
5957   return ret;
5958 }
5959 #endif
5960 
5961 #if defined(_CMU_SDIOCTRL_MASK)
5962 /***************************************************************************//**
5963  * @brief
5964  *   Get the SDIO reference clock frequency.
5965  *
5966  * @return
5967  *   SDIO reference clock frequency in Hz.
5968  ******************************************************************************/
sdioRefClkGet(void)5969 static uint32_t sdioRefClkGet(void)
5970 {
5971   uint32_t ret;
5972   CMU_Select_TypeDef clk;
5973 
5974   /* Get the selected clock source. */
5975   clk = CMU_ClockSelectGet(cmuClock_SDIOREF);
5976 
5977   switch (clk) {
5978     case cmuSelect_HFRCO:
5979       ret = SystemHfrcoFreq;
5980       break;
5981 
5982     case cmuSelect_HFXO:
5983       ret = SystemHFXOClockGet();
5984       break;
5985 
5986     case cmuSelect_AUXHFRCO:
5987       ret = auxClkGet();
5988       break;
5989 
5990     case cmuSelect_USHFRCO:
5991       ret = ushfrcoFreq;
5992       break;
5993 
5994     default:
5995       ret = 0;
5996       EFM_ASSERT(false);
5997       break;
5998   }
5999   return ret;
6000 }
6001 #endif
6002 
6003 #if defined(_CMU_QSPICTRL_MASK)
6004 /***************************************************************************//**
6005  * @brief
6006  *   Get the QSPI n reference clock frequency.
6007  *
6008  * @return
6009  *   QSPI n reference clock frequency in Hz.
6010  ******************************************************************************/
qspiRefClkGet(uint32_t qspi)6011 static uint32_t qspiRefClkGet(uint32_t qspi)
6012 {
6013   uint32_t ret;
6014   CMU_Select_TypeDef clk;
6015 
6016   /* Get the selected clock source. */
6017   switch (qspi) {
6018     case 0:
6019       clk = CMU_ClockSelectGet(cmuClock_QSPI0REF);
6020       break;
6021 
6022     default:
6023       EFM_ASSERT(false);
6024       return 0;
6025   }
6026 
6027   switch (clk) {
6028     case cmuSelect_HFRCO:
6029       ret = SystemHfrcoFreq;
6030       break;
6031 
6032     case cmuSelect_HFXO:
6033       ret = SystemHFXOClockGet();
6034       break;
6035 
6036     case cmuSelect_AUXHFRCO:
6037       ret = auxClkGet();
6038       break;
6039 
6040     case cmuSelect_USHFRCO:
6041       ret = ushfrcoFreq;
6042       break;
6043 
6044     default:
6045       ret = 0;
6046       EFM_ASSERT(false);
6047       break;
6048   }
6049   return ret;
6050 }
6051 #endif
6052 
6053 #if defined(_CMU_PDMCTRL_MASK)
6054 /***************************************************************************//**
6055  * @brief
6056  *   Get the PDM reference clock frequency.
6057  *
6058  * @return
6059  *   PDM reference clock frequency in Hz.
6060  ******************************************************************************/
pdmRefClkGet(void)6061 static uint32_t pdmRefClkGet(void)
6062 {
6063   uint32_t ret;
6064   CMU_Select_TypeDef clk;
6065 
6066   /* Get the selected clock source. */
6067   clk = CMU_ClockSelectGet(cmuClock_PDMREF);
6068 
6069   switch (clk) {
6070     case cmuSelect_HFRCO:
6071       ret = SystemHfrcoFreq;
6072       break;
6073 
6074     case cmuSelect_HFXO:
6075       ret = SystemHFXOClockGet();
6076       break;
6077 
6078     case cmuSelect_USHFRCO:
6079       ret = ushfrcoFreq;
6080       break;
6081 
6082     default:
6083       ret = 0;
6084       EFM_ASSERT(false);
6085       break;
6086   }
6087   return ret;
6088 }
6089 #endif
6090 
6091 #if defined(USBR_CLOCK_PRESENT)
6092 /***************************************************************************//**
6093  * @brief
6094  *   Get the USB rate clock frequency.
6095  *
6096  * @return
6097  *   USB rate clock frequency in Hz.
6098  ******************************************************************************/
usbRateClkGet(void)6099 static uint32_t usbRateClkGet(void)
6100 {
6101   uint32_t ret;
6102   CMU_Select_TypeDef clk;
6103 
6104   clk = CMU_ClockSelectGet(cmuClock_USBR);
6105 
6106   switch (clk) {
6107     case cmuSelect_USHFRCO:
6108       ret = ushfrcoFreq;
6109       break;
6110 
6111     case cmuSelect_HFXO:
6112       ret = SystemHFXOClockGet();
6113       break;
6114 
6115     case cmuSelect_HFXOX2:
6116       ret = 2u * SystemHFXOClockGet();
6117       break;
6118 
6119     case cmuSelect_HFRCO:
6120       ret = SystemHfrcoFreq;
6121       break;
6122 
6123     case cmuSelect_LFXO:
6124       ret = SystemLFXOClockGet();
6125       break;
6126 
6127     case cmuSelect_LFRCO:
6128       ret = SystemLFRCOClockGet();
6129       break;
6130 
6131     default:
6132       ret = 0;
6133       EFM_ASSERT(false);
6134       break;
6135   }
6136   return ret;
6137 }
6138 #endif
6139 
6140 /***************************************************************************//**
6141  * @brief
6142  *   Configure flash access wait states to support the given core clock
6143  *   frequency.
6144  *
6145  * @param[in] coreFreq
6146  *   The core clock frequency to configure flash wait-states.
6147  *
6148  * @param[in] vscale
6149  *   Voltage Scale level. Supported levels are 0 and 2 where 0 is the default.
6150  ******************************************************************************/
flashWaitStateControl(uint32_t coreFreq,int vscale)6151 static void flashWaitStateControl(uint32_t coreFreq, int vscale)
6152 {
6153   uint32_t mode;
6154 #if defined(MSC_READCTRL_MODE_WS0SCBTP)
6155   bool scbtpEn;   /* Suppressed Conditional Branch Target Prefetch setting. */
6156 #endif
6157   (void) vscale;  /* vscale parameter is only used on some devices. */
6158 
6159   /* Get mode and SCBTP enable. */
6160   mode = MSC_ReadCTRLGet() & _MSC_READCTRL_MODE_MASK;
6161 
6162 #if defined(_SILICON_LABS_32B_SERIES_0)
6163 #if defined(MSC_READCTRL_MODE_WS0SCBTP)
6164   /* Devices with MODE and SCBTP in the same register field. */
6165   switch (mode) {
6166     case MSC_READCTRL_MODE_WS0:
6167     case MSC_READCTRL_MODE_WS1:
6168 #if defined(MSC_READCTRL_MODE_WS2)
6169     case MSC_READCTRL_MODE_WS2:
6170 #endif
6171       scbtpEn = false;
6172       break;
6173 
6174     default: /* WSxSCBTP */
6175       scbtpEn = true;
6176       break;
6177   }
6178 
6179   /* Set mode based on the core clock frequency and SCBTP enable. */
6180   if (false) {
6181   }
6182 #if defined(MSC_READCTRL_MODE_WS2)
6183   else if (coreFreq > CMU_MAX_FREQ_1WS) {
6184     mode = (scbtpEn ? MSC_READCTRL_MODE_WS2SCBTP : MSC_READCTRL_MODE_WS2);
6185   }
6186 #endif
6187   else if ((coreFreq <= CMU_MAX_FREQ_1WS) && (coreFreq > CMU_MAX_FREQ_0WS)) {
6188     mode = (scbtpEn ? MSC_READCTRL_MODE_WS1SCBTP : MSC_READCTRL_MODE_WS1);
6189   } else {
6190     mode = (scbtpEn ? MSC_READCTRL_MODE_WS0SCBTP : MSC_READCTRL_MODE_WS0);
6191   }
6192 #else /* defined(MSC_READCTRL_MODE_WS0SCBTP) */
6193 
6194   if (coreFreq <= CMU_MAX_FREQ_0WS) {
6195     mode = 0;
6196   } else if (coreFreq <= CMU_MAX_FREQ_1WS) {
6197     mode = 1;
6198   }
6199 #endif /* defined(MSC_READCTRL_MODE_WS0SCBTP) */
6200 // End defined(_SILICON_LABS_32B_SERIES_0)
6201 
6202 #elif defined(_SILICON_LABS_32B_SERIES_1)
6203 #if defined(_EMU_STATUS_VSCALE_MASK)
6204 
6205   /* These devices have specific requirements on the supported flash wait state
6206    * depending on the frequency and voltage scale level. */
6207   uint32_t i;
6208   for (i = 0; i < FLASH_WS_TABLE_ENTRIES; i++) {
6209     if ((flashWsTable[i].vscale == (uint8_t)vscale)
6210         && (coreFreq <= flashWsTable[i].maxFreq)) {
6211       break; // Found a matching entry.
6212     }
6213   }
6214 
6215   if (i == FLASH_WS_TABLE_ENTRIES) {
6216     mode = 3; // Worst case flash wait state for unsupported cases.
6217     EFM_ASSERT(false);
6218   } else {
6219     mode = flashWsTable[i].ws;
6220   }
6221   mode = mode << _MSC_READCTRL_MODE_SHIFT;
6222 
6223 #else
6224   /* Devices where MODE and SCBTP are in separate fields and where the device
6225    * either does not support voltage scale or where the voltage scale does
6226    * not impact the flash wait state configuration. */
6227   if (coreFreq <= CMU_MAX_FREQ_0WS_1V2) {
6228     mode = 0;
6229   } else if (coreFreq <= CMU_MAX_FREQ_1WS_1V2) {
6230     mode = 1;
6231   }
6232 #if defined(MSC_READCTRL_MODE_WS2)
6233   else if (coreFreq <= CMU_MAX_FREQ_2WS) {
6234     mode = 2;
6235   }
6236 #endif
6237 #if defined(MSC_READCTRL_MODE_WS3)
6238   else if (coreFreq <= CMU_MAX_FREQ_3WS) {
6239     mode = 3;
6240   }
6241 #endif
6242   mode = mode << _MSC_READCTRL_MODE_SHIFT;
6243 #endif
6244 // End defined(_SILICON_LABS_32B_SERIES_1)
6245 
6246 #else
6247 #error "Undefined 32B SERIES!"
6248 #endif
6249 
6250   mode = (MSC_ReadCTRLGet() & ~_MSC_READCTRL_MODE_MASK) | mode;
6251   MSC_ReadCTRLSet(mode);
6252 }
6253 
6254 /***************************************************************************//**
6255  * @brief
6256  *   Configure flash access wait states to the most conservative setting for
6257  *   this target. Retain SCBTP (Suppressed Conditional Branch Target Prefetch)
6258  *   setting.
6259  ******************************************************************************/
flashWaitStateMax(void)6260 static void flashWaitStateMax(void)
6261 {
6262   /* Make sure the MSC is unlocked */
6263   bool mscLocked = MSC_LockGetLocked();
6264   MSC_LockSetUnlocked();
6265 
6266   flashWaitStateControl(SystemMaxCoreClockGet(), 0);
6267 
6268   if (mscLocked) {
6269     MSC_LockSetLocked();
6270   }
6271 }
6272 
6273 #if defined(_MSC_RAMCTRL_RAMWSEN_MASK)
6274 /***************************************************************************//**
6275  * @brief
6276  *   Configure RAM access wait states to support the given core clock
6277  *   frequency.
6278  *
6279  * @param[in] coreFreq
6280  *   The core clock frequency to configure RAM wait-states.
6281  *
6282  * @param[in] vscale
6283  *   A voltage scale level. Supported levels are 0 and 2 where 0 is the default.
6284  ******************************************************************************/
setRamWaitState(uint32_t coreFreq,int vscale)6285 static void setRamWaitState(uint32_t coreFreq, int vscale)
6286 {
6287   uint32_t limit = 38000000;
6288   if (vscale == 2) {
6289     limit = 16000000;
6290   }
6291 
6292   if (coreFreq > limit) {
6293     BUS_RegMaskedSet(&MSC->RAMCTRL, (MSC_RAMCTRL_RAMWSEN
6294                                      | MSC_RAMCTRL_RAM1WSEN
6295                                      | MSC_RAMCTRL_RAM2WSEN));
6296   } else {
6297     BUS_RegMaskedClear(&MSC->RAMCTRL, (MSC_RAMCTRL_RAMWSEN
6298                                        | MSC_RAMCTRL_RAM1WSEN
6299                                        | MSC_RAMCTRL_RAM2WSEN));
6300   }
6301 }
6302 #endif
6303 
6304 #if defined(_MSC_CTRL_WAITMODE_MASK)
6305 /***************************************************************************//**
6306  * @brief
6307  *   Configure the wait state for peripheral accesses over the bus to support
6308  *   the given bus clock frequency.
6309  *
6310  * @param[in] busFreq
6311  *   A peripheral bus clock frequency to configure wait-states.
6312  *
6313  * @param[in] vscale
6314  *   The voltage scale to configure wait-states. Expected values are
6315  *   0 or 2.
6316  *
6317  *   @li 0 = 1.2 V (VSCALE2)
6318  *   @li 2 = 1.0 V (VSCALE0)
6319  * ******************************************************************************/
setBusWaitState(uint32_t busFreq,int vscale)6320 static void setBusWaitState(uint32_t busFreq, int vscale)
6321 {
6322   if ((busFreq > 50000000) && (vscale == 0)) {
6323     BUS_RegMaskedSet(&MSC->CTRL, MSC_CTRL_WAITMODE_WS1);
6324   } else {
6325     BUS_RegMaskedClear(&MSC->CTRL, MSC_CTRL_WAITMODE_WS1);
6326   }
6327 }
6328 #endif
6329 
6330 #if defined(PLFRCO_PRESENT)
deviceHasPlfrco(void)6331 static bool deviceHasPlfrco(void)
6332 {
6333   SYSTEM_ChipRevision_TypeDef rev;
6334 
6335   if (_SILICON_LABS_GECKO_INTERNAL_SDID == 89) {
6336     // check the xG13 rev and check if it's >= Rev A3
6337     SYSTEM_ChipRevisionGet(&rev);
6338     return (rev.major > 1) || (rev.minor >= 3);
6339   } else {
6340     return false;
6341   }
6342 }
6343 #endif
6344 
6345 /***************************************************************************//**
6346  * @brief
6347  *   Configure various wait states to switch to a certain frequency
6348  *   and a certain voltage scale.
6349  *
6350  * @details
6351  *   This function will set up the necessary flash, bus, and RAM wait states.
6352  *   Updating the wait state configuration must be done before
6353  *   increasing the clock frequency and it must be done after decreasing the
6354  *   clock frequency. Updating the wait state configuration must be done before
6355  *   core voltage is decreased and it must be done after a core voltage is
6356  *   increased.
6357  *
6358  * @param[in] freq
6359  *   The core clock frequency to configure wait-states.
6360  *
6361  * @param[in] vscale
6362  *   The voltage scale to configure wait-states. Expected values are
6363  *   0 or 2, higher number is lower voltage.
6364  *
6365  *   @li 0 = 1.2 V (VSCALE2)
6366  *   @li 2 = 1.0 V (VSCALE0)
6367  *
6368  ******************************************************************************/
CMU_UpdateWaitStates(uint32_t freq,int vscale)6369 void CMU_UpdateWaitStates(uint32_t freq, int vscale)
6370 {
6371   /* Make sure the MSC is unlocked */
6372   bool mscLocked = MSC_LockGetLocked();
6373   MSC_LockSetUnlocked();
6374 
6375   flashWaitStateControl(freq, vscale);
6376 #if defined(_MSC_RAMCTRL_RAMWSEN_MASK)
6377   setRamWaitState(freq, vscale);
6378 #endif
6379 #if defined(_MSC_CTRL_WAITMODE_MASK)
6380   setBusWaitState(freq, vscale);
6381 #endif
6382 
6383   if (mscLocked) {
6384     MSC_LockSetLocked();
6385   }
6386 }
6387 
6388 #if defined(_CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_MASK)
6389 /***************************************************************************//**
6390  * @brief
6391  *   Return the upper value for CMU_HFXOSTEADYSTATECTRL_REGISH.
6392  ******************************************************************************/
getRegIshUpperVal(uint32_t steadyStateRegIsh)6393 static uint32_t getRegIshUpperVal(uint32_t steadyStateRegIsh)
6394 {
6395   uint32_t regIshUpper;
6396   const uint32_t upperMax = _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_MASK
6397                             >> _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_SHIFT;
6398   /* Add 3 as specified in the register description for CMU_HFXOSTEADYSTATECTRL_REGISHUPPER. */
6399   regIshUpper = SL_MIN(steadyStateRegIsh + 3UL, upperMax);
6400   regIshUpper <<= _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_SHIFT;
6401   return regIshUpper;
6402 }
6403 #endif
6404 
6405 #if defined(_CMU_HFXOCTRL_MASK)
6406 /***************************************************************************//**
6407  * @brief
6408  *   Get the HFXO tuning mode.
6409  *
6410  * @return
6411  *   The current HFXO tuning mode from the HFXOCTRL register.
6412  ******************************************************************************/
getHfxoTuningMode(void)6413 __STATIC_INLINE uint32_t getHfxoTuningMode(void)
6414 {
6415 #if defined(_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
6416   return (CMU->HFXOCTRL & _CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
6417          >> _CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_SHIFT;
6418 #else
6419   return (CMU->HFXOCTRL & _CMU_HFXOCTRL_PEAKDETMODE_MASK)
6420          >> _CMU_HFXOCTRL_PEAKDETMODE_SHIFT;
6421 #endif
6422 }
6423 
6424 /***************************************************************************//**
6425  * @brief
6426  *   Set the HFXO tuning mode.
6427  *
6428  * @param[in] mode
6429  *   The new HFXO tuning mode. This can be HFXO_TUNING_MODE_AUTO or
6430  *   HFXO_TUNING_MODE_CMD.
6431  ******************************************************************************/
setHfxoTuningMode(uint32_t mode)6432 __STATIC_INLINE void setHfxoTuningMode(uint32_t mode)
6433 {
6434 #if defined(_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
6435   CMU->HFXOCTRL = (CMU->HFXOCTRL & ~_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
6436                   | (mode << _CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_SHIFT);
6437 #else
6438   CMU->HFXOCTRL = (CMU->HFXOCTRL & ~_CMU_HFXOCTRL_PEAKDETMODE_MASK)
6439                   | (mode << _CMU_HFXOCTRL_PEAKDETMODE_SHIFT);
6440 #endif
6441 }
6442 #endif
6443 
6444 /***************************************************************************//**
6445  * @brief
6446  *   Get the LFnCLK frequency based on the current configuration.
6447  *
6448  * @param[in] lfClkBranch
6449  *   Selected LF branch.
6450  *
6451  * @return
6452  *   The LFnCLK frequency in Hz. If no LFnCLK is selected (disabled), 0 is
6453  *   returned.
6454  ******************************************************************************/
lfClkGet(CMU_Clock_TypeDef lfClkBranch)6455 static uint32_t lfClkGet(CMU_Clock_TypeDef lfClkBranch)
6456 {
6457   uint32_t sel;
6458   uint32_t ret = 0;
6459 
6460   switch (lfClkBranch) {
6461     case cmuClock_LFA:
6462     case cmuClock_LFB:
6463 #if defined(_CMU_LFCCLKEN0_MASK)
6464     case cmuClock_LFC:
6465 #endif
6466 #if defined(_CMU_LFECLKSEL_MASK)
6467     case cmuClock_LFE:
6468 #endif
6469       break;
6470 
6471     default:
6472       EFM_ASSERT(false);
6473       break;
6474   }
6475 
6476   sel = (uint32_t)CMU_ClockSelectGet(lfClkBranch);
6477 
6478   /* Get clock select field */
6479   switch (lfClkBranch) {
6480     case cmuClock_LFA:
6481 #if defined(_CMU_LFCLKSEL_MASK)
6482       sel = (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFA_MASK) >> _CMU_LFCLKSEL_LFA_SHIFT;
6483 #elif defined(_CMU_LFACLKSEL_MASK)
6484       sel = (CMU->LFACLKSEL & _CMU_LFACLKSEL_LFA_MASK) >> _CMU_LFACLKSEL_LFA_SHIFT;
6485 #else
6486       EFM_ASSERT(false);
6487 #endif
6488       break;
6489 
6490     case cmuClock_LFB:
6491 #if defined(_CMU_LFCLKSEL_MASK)
6492       sel = (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFB_MASK) >> _CMU_LFCLKSEL_LFB_SHIFT;
6493 #elif defined(_CMU_LFBCLKSEL_MASK)
6494       sel = (CMU->LFBCLKSEL & _CMU_LFBCLKSEL_LFB_MASK) >> _CMU_LFBCLKSEL_LFB_SHIFT;
6495 #else
6496       EFM_ASSERT(false);
6497 #endif
6498       break;
6499 
6500 #if defined(_CMU_LFCCLKEN0_MASK)
6501     case cmuClock_LFC:
6502 #if defined(_CMU_LFCLKSEL_LFC_MASK)
6503       sel = (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFC_MASK) >> _CMU_LFCLKSEL_LFC_SHIFT;
6504 #elif defined(_CMU_LFCCLKSEL_LFC_MASK)
6505       sel = (CMU->LFCCLKSEL & _CMU_LFCCLKSEL_LFC_MASK) >> _CMU_LFCCLKSEL_LFC_SHIFT;
6506 #else
6507       EFM_ASSERT(false);
6508 #endif
6509       break;
6510 #endif
6511 
6512 #if defined(_CMU_LFECLKSEL_MASK)
6513     case cmuClock_LFE:
6514       sel = (CMU->LFECLKSEL & _CMU_LFECLKSEL_LFE_MASK) >> _CMU_LFECLKSEL_LFE_SHIFT;
6515       break;
6516 #endif
6517 
6518     default:
6519       EFM_ASSERT(false);
6520       break;
6521   }
6522 
6523   /* Get the clock frequency. */
6524 #if defined(_CMU_LFCLKSEL_MASK)
6525   switch (sel) {
6526     case _CMU_LFCLKSEL_LFA_LFRCO:
6527       ret = SystemLFRCOClockGet();
6528       break;
6529 
6530     case _CMU_LFCLKSEL_LFA_LFXO:
6531       ret = SystemLFXOClockGet();
6532       break;
6533 
6534 #if defined(_CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2)
6535     case _CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2:
6536 #if defined(CMU_MAX_FREQ_HFLE)
6537       /* HFLE bit is or'ed by hardware with HFCORECLKLEDIV to reduce the
6538        * frequency of CMU_HFCORECLKLEDIV2. */
6539       ret = SystemCoreClockGet() / (1U << (getHfLeConfig() + 1));
6540 #else
6541       ret = SystemCoreClockGet() / 2U;
6542 #endif
6543       break;
6544 #endif
6545 
6546     case _CMU_LFCLKSEL_LFA_DISABLED:
6547       ret = 0;
6548 #if defined(CMU_LFCLKSEL_LFAE)
6549       /* Check LF Extended bit setting for LFA or LFB ULFRCO clock. */
6550       if ((lfClkBranch == cmuClock_LFA) || (lfClkBranch == cmuClock_LFB)) {
6551         if (CMU->LFCLKSEL >> (lfClkBranch == cmuClock_LFA
6552                               ? _CMU_LFCLKSEL_LFAE_SHIFT
6553                               : _CMU_LFCLKSEL_LFBE_SHIFT)) {
6554           ret = SystemULFRCOClockGet();
6555         }
6556       }
6557 #endif
6558       break;
6559 
6560     default:
6561       ret = 0U;
6562       EFM_ASSERT(false);
6563       break;
6564   }
6565 #endif /* _CMU_LFCLKSEL_MASK */
6566 
6567 #if defined(_CMU_LFACLKSEL_MASK)
6568   switch (sel) {
6569     case _CMU_LFACLKSEL_LFA_LFRCO:
6570       ret = SystemLFRCOClockGet();
6571       break;
6572 
6573     case _CMU_LFACLKSEL_LFA_LFXO:
6574       ret = SystemLFXOClockGet();
6575       break;
6576 
6577     case _CMU_LFACLKSEL_LFA_ULFRCO:
6578       ret = SystemULFRCOClockGet();
6579       break;
6580 
6581 #if defined(PLFRCO_PRESENT)
6582     case _CMU_LFACLKSEL_LFA_PLFRCO:
6583       ret = SystemLFRCOClockGet();
6584       break;
6585 #endif
6586 
6587 #if defined(_CMU_LFBCLKSEL_LFB_HFCLKLE)
6588     case _CMU_LFBCLKSEL_LFB_HFCLKLE:
6589       ret = SystemHFClockGet()
6590             / SL_Log2ToDiv(((CMU->HFPRESC & _CMU_HFPRESC_HFCLKLEPRESC_MASK)
6591                             >> _CMU_HFPRESC_HFCLKLEPRESC_SHIFT) + 1UL);
6592       break;
6593 #endif
6594 
6595     case _CMU_LFACLKSEL_LFA_DISABLED:
6596       ret = 0;
6597       break;
6598 
6599     default:
6600       ret = 0U;
6601       EFM_ASSERT(false);
6602       break;
6603   }
6604 #endif
6605 
6606   return ret;
6607 }
6608 
6609 /***************************************************************************//**
6610  * @brief
6611  *   Wait for an ongoing sync of register(s) to low-frequency domain to complete.
6612  *
6613  * @param[in] mask
6614  *   A bitmask corresponding to SYNCBUSY register defined bits, indicating
6615  *   registers that must complete any ongoing synchronization.
6616  ******************************************************************************/
syncReg(uint32_t mask)6617 __STATIC_INLINE void syncReg(uint32_t mask)
6618 {
6619   /* Avoid a deadlock if modifying the same register twice when freeze mode is */
6620   /* activated. */
6621   if ((CMU->FREEZE & CMU_FREEZE_REGFREEZE) != 0UL) {
6622     return;
6623   }
6624 
6625   /* Wait for any pending previous write operation to complete */
6626   /* in low-frequency domain. */
6627   while ((CMU->SYNCBUSY & mask) != 0UL) {
6628   }
6629 }
6630 
6631 #if defined(USBC_CLOCK_PRESENT)
6632 /***************************************************************************//**
6633  * @brief
6634  *   Get the USBC frequency.
6635  *
6636  * @return
6637  *   USBC frequency in Hz.
6638  ******************************************************************************/
usbCClkGet(void)6639 static uint32_t usbCClkGet(void)
6640 {
6641   uint32_t ret;
6642   CMU_Select_TypeDef clk;
6643 
6644   /* Get the selected clock source. */
6645   clk = CMU_ClockSelectGet(cmuClock_USBC);
6646 
6647   switch (clk) {
6648     case cmuSelect_LFXO:
6649       ret = SystemLFXOClockGet();
6650       break;
6651     case cmuSelect_LFRCO:
6652       ret = SystemLFRCOClockGet();
6653       break;
6654 #if defined (_CMU_USHFRCOCTRL_MASK)
6655     case cmuSelect_USHFRCO:
6656       ret = ushfrcoFreq;
6657       break;
6658 #endif
6659     case cmuSelect_HFCLK:
6660       ret = SystemHFClockGet();
6661       break;
6662     default:
6663       /* Clock is not enabled */
6664       ret = 0;
6665       break;
6666   }
6667   return ret;
6668 }
6669 #endif
6670 
6671 /***************************************************************************//**
6672  * @brief
6673  *   Set HFPER clock tree prescalers to safe values.
6674  *
6675  * @note
6676  *   This function applies to EFM32GG11B. There are 3 HFPER clock trees with
6677  *   these frequency limits:
6678  *     HFPERCLK  (A-tree): 20MHz in VSCALE0 mode, 50MHz in VSCALE2 mode.
6679  *     HFPERBCLK (B-tree): 20MHz in VSCALE0 mode, 72MHz in VSCALE2 mode.
6680  *     HFPERCCLK (C-tree): 20MHz in VSCALE0 mode, 50MHz in VSCALE2 mode.
6681  ******************************************************************************/
hfperClkSafePrescaler(void)6682 static void hfperClkSafePrescaler(void)
6683 {
6684 #if defined(_CMU_HFPERPRESC_MASK) && defined(_CMU_HFPERPRESCB_MASK) \
6685   && defined(_CMU_HFPERPRESCC_MASK)
6686   // Assuming a maximum HFCLK of 72MHz, set prescalers to DIV4.
6687   CMU_ClockPrescSet(cmuClock_HFPER, 3U);
6688   CMU_ClockPrescSet(cmuClock_HFPERB, 3U);
6689   CMU_ClockPrescSet(cmuClock_HFPERC, 3U);
6690 #endif
6691 }
6692 
6693 /***************************************************************************//**
6694  * @brief
6695  *   Set HFPER clock tree prescalers to give highest possible clock node
6696  *   frequency while still beeing within spec.
6697  *
6698  * @note
6699  *   This function applies to EFM32GG11B. There are 3 HFPER clock trees with
6700  *   these frequency limits:
6701  *     HFPERCLK  (A-tree): 20MHz in VSCALE0 mode, 50MHz in VSCALE2 mode.
6702  *     HFPERBCLK (B-tree): 20MHz in VSCALE0 mode, 72MHz in VSCALE2 mode.
6703  *     HFPERCCLK (C-tree): 20MHz in VSCALE0 mode, 50MHz in VSCALE2 mode.
6704  ******************************************************************************/
hfperClkOptimizedPrescaler(void)6705 static void hfperClkOptimizedPrescaler(void)
6706 {
6707 #if defined(_CMU_HFPERPRESC_MASK) && defined(_CMU_HFPERPRESCB_MASK) \
6708   && defined(_CMU_HFPERPRESCC_MASK)
6709   uint32_t hfClkFreq, divisor;
6710 
6711   hfClkFreq = SystemHFClockGet();
6712 
6713   if ( EMU_VScaleGet() == emuVScaleEM01_LowPower) {
6714     divisor = (hfClkFreq + 20000000U - 1U) / 20000000U; // ceil(x)
6715     if (divisor > 0U) {
6716       divisor--;                                        // Convert to prescaler
6717     }
6718     CMU_ClockPrescSet(cmuClock_HFPER, divisor);
6719     CMU_ClockPrescSet(cmuClock_HFPERB, divisor);
6720     CMU_ClockPrescSet(cmuClock_HFPERC, divisor);
6721   } else {
6722     divisor = (hfClkFreq + 50000000U - 1U) / 50000000U;
6723     if (divisor > 0U) {
6724       divisor--;
6725     }
6726     CMU_ClockPrescSet(cmuClock_HFPER, divisor);
6727     CMU_ClockPrescSet(cmuClock_HFPERC, divisor);
6728 
6729     divisor = (hfClkFreq + 72000000U - 1U) / 72000000U;
6730     if (divisor > 0U) {
6731       divisor--;
6732     }
6733     CMU_ClockPrescSet(cmuClock_HFPERB, divisor);
6734   }
6735 #endif
6736 }
6737 
6738 /*******************************************************************************
6739  **************************   GLOBAL FUNCTIONS   *******************************
6740  ******************************************************************************/
6741 
6742 #if defined(_CMU_AUXHFRCOCTRL_BAND_MASK)
6743 /***************************************************************************//**
6744  * @brief
6745  *   Get the AUXHFRCO band in use.
6746  *
6747  * @return
6748  *   AUXHFRCO band in use.
6749  ******************************************************************************/
CMU_AUXHFRCOBandGet(void)6750 CMU_AUXHFRCOBand_TypeDef CMU_AUXHFRCOBandGet(void)
6751 {
6752   return (CMU_AUXHFRCOBand_TypeDef)((CMU->AUXHFRCOCTRL
6753                                      & _CMU_AUXHFRCOCTRL_BAND_MASK)
6754                                     >> _CMU_AUXHFRCOCTRL_BAND_SHIFT);
6755 }
6756 #endif /* _CMU_AUXHFRCOCTRL_BAND_MASK */
6757 
6758 #if defined(_CMU_AUXHFRCOCTRL_BAND_MASK)
6759 /***************************************************************************//**
6760  * @brief
6761  *   Set the AUXHFRCO band and the tuning value based on the value in the
6762  *   calibration table made during production.
6763  *
6764  * @param[in] band
6765  *   AUXHFRCO band to activate.
6766  ******************************************************************************/
CMU_AUXHFRCOBandSet(CMU_AUXHFRCOBand_TypeDef band)6767 void CMU_AUXHFRCOBandSet(CMU_AUXHFRCOBand_TypeDef band)
6768 {
6769   uint32_t tuning;
6770 
6771   /* Read a tuning value from the calibration table. */
6772   switch (band) {
6773     case cmuAUXHFRCOBand_1MHz:
6774       tuning = (DEVINFO->AUXHFRCOCAL0 & _DEVINFO_AUXHFRCOCAL0_BAND1_MASK)
6775                >> _DEVINFO_AUXHFRCOCAL0_BAND1_SHIFT;
6776       break;
6777 
6778     case cmuAUXHFRCOBand_7MHz:
6779       tuning = (DEVINFO->AUXHFRCOCAL0 & _DEVINFO_AUXHFRCOCAL0_BAND7_MASK)
6780                >> _DEVINFO_AUXHFRCOCAL0_BAND7_SHIFT;
6781       break;
6782 
6783     case cmuAUXHFRCOBand_11MHz:
6784       tuning = (DEVINFO->AUXHFRCOCAL0 & _DEVINFO_AUXHFRCOCAL0_BAND11_MASK)
6785                >> _DEVINFO_AUXHFRCOCAL0_BAND11_SHIFT;
6786       break;
6787 
6788     case cmuAUXHFRCOBand_14MHz:
6789       tuning = (DEVINFO->AUXHFRCOCAL0 & _DEVINFO_AUXHFRCOCAL0_BAND14_MASK)
6790                >> _DEVINFO_AUXHFRCOCAL0_BAND14_SHIFT;
6791       break;
6792 
6793     case cmuAUXHFRCOBand_21MHz:
6794       tuning = (DEVINFO->AUXHFRCOCAL1 & _DEVINFO_AUXHFRCOCAL1_BAND21_MASK)
6795                >> _DEVINFO_AUXHFRCOCAL1_BAND21_SHIFT;
6796       break;
6797 
6798 #if defined(_CMU_AUXHFRCOCTRL_BAND_28MHZ)
6799     case cmuAUXHFRCOBand_28MHz:
6800       tuning = (DEVINFO->AUXHFRCOCAL1 & _DEVINFO_AUXHFRCOCAL1_BAND28_MASK)
6801                >> _DEVINFO_AUXHFRCOCAL1_BAND28_SHIFT;
6802       break;
6803 #endif
6804 
6805     default:
6806       EFM_ASSERT(false);
6807       return;
6808   }
6809 
6810   /* Set band/tuning. */
6811   CMU->AUXHFRCOCTRL = (CMU->AUXHFRCOCTRL
6812                        & ~(_CMU_AUXHFRCOCTRL_BAND_MASK
6813                            | _CMU_AUXHFRCOCTRL_TUNING_MASK))
6814                       | (band << _CMU_AUXHFRCOCTRL_BAND_SHIFT)
6815                       | (tuning << _CMU_AUXHFRCOCTRL_TUNING_SHIFT);
6816 }
6817 #endif /* _CMU_AUXHFRCOCTRL_BAND_MASK */
6818 
6819 #if defined(_CMU_AUXHFRCOCTRL_FREQRANGE_MASK)
6820 /**************************************************************************//**
6821  * @brief
6822  *   Get the AUXHFRCO frequency calibration word in DEVINFO.
6823  *
6824  * @param[in] freq
6825  *   Frequency in Hz.
6826  *
6827  * @return
6828  *   AUXHFRCO calibration word for a given frequency.
6829  *****************************************************************************/
CMU_AUXHFRCODevinfoGet(CMU_AUXHFRCOFreq_TypeDef freq)6830 static uint32_t CMU_AUXHFRCODevinfoGet(CMU_AUXHFRCOFreq_TypeDef freq)
6831 {
6832   switch (freq) {
6833     /* 1, 2, and 4 MHz share the same calibration word. */
6834     case cmuAUXHFRCOFreq_1M0Hz:
6835     case cmuAUXHFRCOFreq_2M0Hz:
6836     case cmuAUXHFRCOFreq_4M0Hz:
6837       return DEVINFO->AUXHFRCOCAL0;
6838 
6839     case cmuAUXHFRCOFreq_7M0Hz:
6840       return DEVINFO->AUXHFRCOCAL3;
6841 
6842     case cmuAUXHFRCOFreq_13M0Hz:
6843       return DEVINFO->AUXHFRCOCAL6;
6844 
6845     case cmuAUXHFRCOFreq_16M0Hz:
6846       return DEVINFO->AUXHFRCOCAL7;
6847 
6848     case cmuAUXHFRCOFreq_19M0Hz:
6849       return DEVINFO->AUXHFRCOCAL8;
6850 
6851     case cmuAUXHFRCOFreq_26M0Hz:
6852       return DEVINFO->AUXHFRCOCAL10;
6853 
6854     case cmuAUXHFRCOFreq_32M0Hz:
6855       return DEVINFO->AUXHFRCOCAL11;
6856 
6857     case cmuAUXHFRCOFreq_38M0Hz:
6858       return DEVINFO->AUXHFRCOCAL12;
6859 
6860 #if defined(_DEVINFO_AUXHFRCOCAL13_MASK)
6861     case cmuAUXHFRCOFreq_48M0Hz:
6862       return DEVINFO->AUXHFRCOCAL13;
6863 #endif
6864 #if defined(_DEVINFO_AUXHFRCOCAL14_MASK)
6865     case cmuAUXHFRCOFreq_50M0Hz:
6866       return DEVINFO->AUXHFRCOCAL14;
6867 #endif
6868 
6869     default: /* cmuAUXHFRCOFreq_UserDefined */
6870       return 0;
6871   }
6872 }
6873 #endif /* _CMU_AUXHFRCOCTRL_FREQRANGE_MASK */
6874 
6875 #if defined(_CMU_AUXHFRCOCTRL_FREQRANGE_MASK)
6876 /***************************************************************************//**
6877  * @brief
6878  *   Get the current AUXHFRCO frequency.
6879  *
6880  * @return
6881  *   AUXHFRCO frequency.
6882  ******************************************************************************/
CMU_AUXHFRCOBandGet(void)6883 CMU_AUXHFRCOFreq_TypeDef CMU_AUXHFRCOBandGet(void)
6884 {
6885   return auxHfrcoFreq;
6886 }
6887 #endif /* _CMU_AUXHFRCOCTRL_FREQRANGE_MASK */
6888 
6889 #if defined(_CMU_AUXHFRCOCTRL_FREQRANGE_MASK)
6890 /***************************************************************************//**
6891  * @brief
6892  *   Set AUXHFRCO calibration for the selected target frequency.
6893  *
6894  * @param[in] setFreq
6895  *   AUXHFRCO frequency to set
6896  ******************************************************************************/
CMU_AUXHFRCOBandSet(CMU_AUXHFRCOFreq_TypeDef setFreq)6897 void CMU_AUXHFRCOBandSet(CMU_AUXHFRCOFreq_TypeDef setFreq)
6898 {
6899   uint32_t freqCal;
6900 
6901   /* Get DEVINFO index and set global auxHfrcoFreq. */
6902   freqCal = CMU_AUXHFRCODevinfoGet(setFreq);
6903   EFM_ASSERT((freqCal != 0UL) && (freqCal != UINT_MAX));
6904   auxHfrcoFreq = setFreq;
6905 
6906   /* Wait for any previous sync to complete, then set calibration data
6907      for the selected frequency.  */
6908   while (BUS_RegBitRead(&CMU->SYNCBUSY,
6909                         _CMU_SYNCBUSY_AUXHFRCOBSY_SHIFT) != 0UL) {
6910   }
6911 
6912   /* Set a divider in AUXHFRCOCTRL for 1, 2, and 4 MHz. */
6913   switch (setFreq) {
6914     case cmuAUXHFRCOFreq_1M0Hz:
6915       freqCal = (freqCal & ~_CMU_AUXHFRCOCTRL_CLKDIV_MASK)
6916                 | CMU_AUXHFRCOCTRL_CLKDIV_DIV4;
6917       break;
6918 
6919     case cmuAUXHFRCOFreq_2M0Hz:
6920       freqCal = (freqCal & ~_CMU_AUXHFRCOCTRL_CLKDIV_MASK)
6921                 | CMU_AUXHFRCOCTRL_CLKDIV_DIV2;
6922       break;
6923 
6924     case cmuAUXHFRCOFreq_4M0Hz:
6925       freqCal = (freqCal & ~_CMU_AUXHFRCOCTRL_CLKDIV_MASK)
6926                 | CMU_AUXHFRCOCTRL_CLKDIV_DIV1;
6927       break;
6928 
6929     default:
6930       break;
6931   }
6932   CMU->AUXHFRCOCTRL = freqCal;
6933 }
6934 #endif /* _CMU_AUXHFRCOCTRL_FREQRANGE_MASK */
6935 
6936 /***************************************************************************//**
6937  * @brief
6938  *   Calibrate the clock.
6939  *
6940  * @details
6941  *   Run a calibration for HFCLK against a selectable reference clock.
6942  *   See the reference manual, CMU chapter, for more details.
6943  *
6944  * @note
6945  *   This function will not return until the calibration measurement is completed.
6946  *
6947  * @param[in] HFCycles
6948  *   The number of HFCLK cycles to run the calibration. Increasing this number
6949  *   increases precision but the calibration will take more time.
6950  *
6951  * @param[in] reference
6952  *   The reference clock used to compare HFCLK.
6953  *
6954  * @return
6955  *   The number of ticks the reference clock after HFCycles ticks on the HF
6956  *   clock.
6957  ******************************************************************************/
CMU_Calibrate(uint32_t HFCycles,CMU_Osc_TypeDef reference)6958 uint32_t CMU_Calibrate(uint32_t HFCycles, CMU_Osc_TypeDef reference)
6959 {
6960   EFM_ASSERT(HFCycles <= (_CMU_CALCNT_CALCNT_MASK >> _CMU_CALCNT_CALCNT_SHIFT));
6961 
6962   /* Set the reference clock source. */
6963   switch (reference) {
6964     case cmuOsc_LFXO:
6965       CMU->CALCTRL = CMU_CALCTRL_UPSEL_LFXO;
6966       break;
6967 
6968     case cmuOsc_LFRCO:
6969       CMU->CALCTRL = CMU_CALCTRL_UPSEL_LFRCO;
6970       break;
6971 
6972 #if defined(PLFRCO_PRESENT)
6973     case cmuOsc_PLFRCO:
6974       CMU->CALCTRL = CMU_CALCTRL_UPSEL_PLFRCO;
6975       break;
6976 #endif
6977 
6978     case cmuOsc_HFXO:
6979       CMU->CALCTRL = CMU_CALCTRL_UPSEL_HFXO;
6980       break;
6981 
6982     case cmuOsc_HFRCO:
6983       CMU->CALCTRL = CMU_CALCTRL_UPSEL_HFRCO;
6984       break;
6985 
6986     case cmuOsc_AUXHFRCO:
6987       CMU->CALCTRL = CMU_CALCTRL_UPSEL_AUXHFRCO;
6988       break;
6989 
6990 #if defined (_CMU_USHFRCOCTRL_MASK)
6991     case cmuOsc_USHFRCO:
6992       CMU->CALCTRL = CMU_CALCTRL_UPSEL_USHFRCO;
6993       break;
6994 #endif
6995 
6996     default:
6997       EFM_ASSERT(false);
6998       return 0;
6999   }
7000 
7001   /* Set the top value. */
7002   CMU->CALCNT = HFCycles;
7003 
7004   /* Start the calibration. */
7005   CMU->CMD = CMU_CMD_CALSTART;
7006 
7007 #if defined(CMU_STATUS_CALRDY)
7008   /* Wait until calibration completes. */
7009   while (BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_CALRDY_SHIFT) == 0UL) {
7010   }
7011 #else
7012   /* Wait until calibration completes. */
7013   while (BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_CALBSY_SHIFT) != 0UL) {
7014   }
7015 #endif
7016 
7017   return CMU->CALCNT;
7018 }
7019 
7020 #if defined(_CMU_CALCTRL_UPSEL_MASK) && defined(_CMU_CALCTRL_DOWNSEL_MASK)
7021 /***************************************************************************//**
7022  * @brief
7023  *   Configure the clock calibration.
7024  *
7025  * @details
7026  *   Configure a calibration for a selectable clock source against another
7027  *   selectable reference clock.
7028  *   See the reference manual, CMU chapter, for more details.
7029  *
7030  * @note
7031  *   After configuration, a call to @ref CMU_CalibrateStart() is required and
7032  *   the resulting calibration value can be read out with the
7033  *   @ref CMU_CalibrateCountGet() function call.
7034  *
7035  * @param[in] downCycles
7036  *   The number of downSel clock cycles to run the calibration. Increasing this
7037  *   number increases precision but the calibration will take more time.
7038  *
7039  * @param[in] downSel
7040  *   The clock, which will be counted down downCycles.
7041  *
7042  * @param[in] upSel
7043  *   The reference clock; the number of cycles generated by this clock will
7044  *   be counted and added up and the result can be given with the
7045  *   @ref CMU_CalibrateCountGet() function call.
7046  ******************************************************************************/
CMU_CalibrateConfig(uint32_t downCycles,CMU_Osc_TypeDef downSel,CMU_Osc_TypeDef upSel)7047 void CMU_CalibrateConfig(uint32_t downCycles, CMU_Osc_TypeDef downSel,
7048                          CMU_Osc_TypeDef upSel)
7049 {
7050   /* Keep configuration settings untouched. */
7051   uint32_t calCtrl = CMU->CALCTRL
7052                      & ~(_CMU_CALCTRL_UPSEL_MASK | _CMU_CALCTRL_DOWNSEL_MASK);
7053 
7054   /* 20 bits of precision to calibration count register. */
7055   EFM_ASSERT(downCycles <= (_CMU_CALCNT_CALCNT_MASK >> _CMU_CALCNT_CALCNT_SHIFT));
7056 
7057   /* Set down counting clock source - down counter. */
7058   switch (downSel) {
7059     case cmuOsc_LFXO:
7060       calCtrl |= CMU_CALCTRL_DOWNSEL_LFXO;
7061       break;
7062 
7063     case cmuOsc_LFRCO:
7064       calCtrl |= CMU_CALCTRL_DOWNSEL_LFRCO;
7065       break;
7066 
7067 #if defined(PLFRCO_PRESENT)
7068     case cmuOsc_PLFRCO:
7069       calCtrl |= CMU_CALCTRL_DOWNSEL_PLFRCO;
7070       break;
7071 #endif
7072 
7073     case cmuOsc_HFXO:
7074       calCtrl |= CMU_CALCTRL_DOWNSEL_HFXO;
7075       break;
7076 
7077     case cmuOsc_HFRCO:
7078       calCtrl |= CMU_CALCTRL_DOWNSEL_HFRCO;
7079       break;
7080 
7081     case cmuOsc_AUXHFRCO:
7082       calCtrl |= CMU_CALCTRL_DOWNSEL_AUXHFRCO;
7083       break;
7084 
7085 #if defined (_CMU_USHFRCOCTRL_MASK)
7086     case cmuOsc_USHFRCO:
7087       calCtrl |= CMU_CALCTRL_DOWNSEL_USHFRCO;
7088       break;
7089 #endif
7090 
7091     default:
7092       EFM_ASSERT(false);
7093       break;
7094   }
7095 
7096   /* Set the top value to be counted down by the downSel clock. */
7097   CMU->CALCNT = downCycles;
7098 
7099   /* Set the reference clock source - up counter. */
7100   switch (upSel) {
7101     case cmuOsc_LFXO:
7102       calCtrl |= CMU_CALCTRL_UPSEL_LFXO;
7103       break;
7104 
7105     case cmuOsc_LFRCO:
7106       calCtrl |= CMU_CALCTRL_UPSEL_LFRCO;
7107       break;
7108 
7109 #if defined(PLFRCO_PRESENT)
7110     case cmuOsc_PLFRCO:
7111       calCtrl |= CMU_CALCTRL_UPSEL_PLFRCO;
7112       break;
7113 #endif
7114 
7115     case cmuOsc_HFXO:
7116       calCtrl |= CMU_CALCTRL_UPSEL_HFXO;
7117       break;
7118 
7119     case cmuOsc_HFRCO:
7120       calCtrl |= CMU_CALCTRL_UPSEL_HFRCO;
7121       break;
7122 
7123     case cmuOsc_AUXHFRCO:
7124       calCtrl |= CMU_CALCTRL_UPSEL_AUXHFRCO;
7125       break;
7126 
7127 #if defined (_CMU_USHFRCOCTRL_MASK)
7128     case cmuOsc_USHFRCO:
7129       calCtrl |= CMU_CALCTRL_UPSEL_USHFRCO;
7130       break;
7131 #endif
7132 
7133     default:
7134       EFM_ASSERT(false);
7135       break;
7136   }
7137 
7138   CMU->CALCTRL = calCtrl;
7139 }
7140 #endif
7141 
7142 /***************************************************************************//**
7143  * @brief
7144  *    Get the calibration count register.
7145  * @note
7146  *    If continuous calibration mode is active, calibration busy will almost
7147  *    always be off and only the value needs to be read. In a normal case,
7148  *    this function call is triggered by the CALRDY
7149  *    interrupt flag.
7150  * @return
7151  *    The calibration count, the number of UPSEL clocks
7152  *    in the period of DOWNSEL oscillator clock cycles configured by a previous
7153  *    write operation to CMU->CALCNT.
7154  ******************************************************************************/
CMU_CalibrateCountGet(void)7155 uint32_t CMU_CalibrateCountGet(void)
7156 {
7157   /* Wait until calibration completes, UNLESS continuous calibration mode is  */
7158   /* active. */
7159 #if defined(CMU_CALCTRL_CONT)
7160   if (BUS_RegBitRead(&CMU->CALCTRL, _CMU_CALCTRL_CONT_SHIFT) == 0UL) {
7161 #if defined(CMU_STATUS_CALRDY)
7162     /* Wait until calibration completes */
7163     while (BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_CALRDY_SHIFT) == 0UL) {
7164     }
7165 #else
7166     /* Wait until calibration completes */
7167     while (BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_CALBSY_SHIFT) != 0UL) {
7168     }
7169 #endif
7170   }
7171 #else
7172   while (BUS_RegBitRead(&CMU->STATUS, _CMU_STATUS_CALBSY_SHIFT) != 0UL) {
7173   }
7174 #endif
7175   return CMU->CALCNT;
7176 }
7177 
7178 /***************************************************************************//**
7179  * @brief
7180  *   Get the clock divisor/prescaler.
7181  *
7182  * @param[in] clock
7183  *   A clock point to get the divisor/prescaler for. Notice that not all clock points
7184  *   have a divisor/prescaler. See the CMU overview in the reference manual.
7185  *
7186  * @return
7187  *   The current clock point divisor/prescaler. 1 is returned
7188  *   if @p clock specifies a clock point without a divisor/prescaler.
7189  ******************************************************************************/
CMU_ClockDivGet(CMU_Clock_TypeDef clock)7190 CMU_ClkDiv_TypeDef CMU_ClockDivGet(CMU_Clock_TypeDef clock)
7191 {
7192 #if defined(_SILICON_LABS_32B_SERIES_1)
7193   return 1UL + (uint32_t)CMU_ClockPrescGet(clock);
7194 
7195 #elif defined(_SILICON_LABS_32B_SERIES_0)
7196   uint32_t           divReg;
7197   CMU_ClkDiv_TypeDef ret;
7198 
7199   /* Get divisor reg ID. */
7200   divReg = (clock >> CMU_DIV_REG_POS) & CMU_DIV_REG_MASK;
7201 
7202   switch (divReg) {
7203 #if defined(_CMU_CTRL_HFCLKDIV_MASK)
7204     case CMU_HFCLKDIV_REG:
7205       ret = 1 + ((CMU->CTRL & _CMU_CTRL_HFCLKDIV_MASK)
7206                  >> _CMU_CTRL_HFCLKDIV_SHIFT);
7207       break;
7208 #endif
7209 
7210     case CMU_HFPERCLKDIV_REG:
7211       ret = (CMU_ClkDiv_TypeDef)((CMU->HFPERCLKDIV
7212                                   & _CMU_HFPERCLKDIV_HFPERCLKDIV_MASK)
7213                                  >> _CMU_HFPERCLKDIV_HFPERCLKDIV_SHIFT);
7214       ret = SL_Log2ToDiv(ret);
7215       break;
7216 
7217     case CMU_HFCORECLKDIV_REG:
7218       ret = (CMU_ClkDiv_TypeDef)((CMU->HFCORECLKDIV
7219                                   & _CMU_HFCORECLKDIV_HFCORECLKDIV_MASK)
7220                                  >> _CMU_HFCORECLKDIV_HFCORECLKDIV_SHIFT);
7221       ret = SL_Log2ToDiv(ret);
7222       break;
7223 
7224 #if defined(_CMU_HFCORECLKDIV_HFCORECLKLEDIV_MASK)
7225     case CMU_HFCORECLKLEDIV_REG:
7226       ret = (CMU_ClkDiv_TypeDef)((CMU->HFCORECLKDIV
7227                                   & _CMU_HFCORECLKDIV_HFCORECLKLEDIV_MASK)
7228                                  >> _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT);
7229       ret = SL_Log2ToDiv(ret + 1U);
7230       break;
7231 #endif
7232 
7233     case CMU_LFAPRESC0_REG:
7234       switch (clock) {
7235         case cmuClock_RTC:
7236           ret = (CMU_ClkDiv_TypeDef)((CMU->LFAPRESC0 & _CMU_LFAPRESC0_RTC_MASK)
7237                                      >> _CMU_LFAPRESC0_RTC_SHIFT);
7238           ret = SL_Log2ToDiv(ret);
7239           break;
7240 
7241 #if defined(_CMU_LFAPRESC0_LETIMER0_MASK)
7242         case cmuClock_LETIMER0:
7243           ret = (CMU_ClkDiv_TypeDef)((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER0_MASK)
7244                                      >> _CMU_LFAPRESC0_LETIMER0_SHIFT);
7245           ret = SL_Log2ToDiv(ret);
7246           break;
7247 #endif
7248 
7249 #if defined(_CMU_LFAPRESC0_LCD_MASK)
7250         case cmuClock_LCDpre:
7251           ret = (CMU_ClkDiv_TypeDef)(((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK)
7252                                       >> _CMU_LFAPRESC0_LCD_SHIFT)
7253                                      + CMU_DivToLog2(cmuClkDiv_16));
7254           ret = SL_Log2ToDiv(ret);
7255           break;
7256 #endif
7257 
7258 #if defined(_CMU_LFAPRESC0_LESENSE_MASK)
7259         case cmuClock_LESENSE:
7260           ret = (CMU_ClkDiv_TypeDef)((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LESENSE_MASK)
7261                                      >> _CMU_LFAPRESC0_LESENSE_SHIFT);
7262           ret = SL_Log2ToDiv(ret);
7263           break;
7264 #endif
7265 
7266         default:
7267           ret = cmuClkDiv_1;
7268           EFM_ASSERT(false);
7269           break;
7270       }
7271       break;
7272 
7273     case CMU_LFBPRESC0_REG:
7274       switch (clock) {
7275 #if defined(_CMU_LFBPRESC0_LEUART0_MASK)
7276         case cmuClock_LEUART0:
7277           ret = (CMU_ClkDiv_TypeDef)((CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART0_MASK)
7278                                      >> _CMU_LFBPRESC0_LEUART0_SHIFT);
7279           ret = SL_Log2ToDiv(ret);
7280           break;
7281 #endif
7282 
7283 #if defined(_CMU_LFBPRESC0_LEUART1_MASK)
7284         case cmuClock_LEUART1:
7285           ret = (CMU_ClkDiv_TypeDef)((CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART1_MASK)
7286                                      >> _CMU_LFBPRESC0_LEUART1_SHIFT);
7287           ret = SL_Log2ToDiv(ret);
7288           break;
7289 #endif
7290 
7291         default:
7292           ret = cmuClkDiv_1;
7293           EFM_ASSERT(false);
7294           break;
7295       }
7296       break;
7297 
7298     default:
7299       ret = cmuClkDiv_1;
7300       EFM_ASSERT(false);
7301       break;
7302   }
7303 
7304   return ret;
7305 #endif
7306 }
7307 
7308 /***************************************************************************//**
7309  * @brief
7310  *   Set the clock divisor/prescaler.
7311  *
7312  * @note
7313  *   If setting an LF clock prescaler, synchronization into the low-frequency
7314  *   domain is required. If the same register is modified before a previous
7315  *   update has completed, this function will stall until the previous
7316  *   synchronization has completed. See @ref CMU_FreezeEnable() for
7317  *   a suggestion on how to reduce the stalling time in some use cases.
7318  *
7319  *   HFCLKLE prescaler is automatically modified when peripherals with clock
7320  *   domain HFBUSCLK is chosen based on the maximum HFLE frequency allowed.
7321  *
7322  * @param[in] clock
7323  *   Clock point to set divisor/prescaler for. Notice that not all clock points
7324  *   have a divisor/prescaler. See the CMU overview in the reference
7325  *   manual.
7326  *
7327  * @param[in] div
7328  *   The clock divisor to use (<= cmuClkDiv_512).
7329  ******************************************************************************/
CMU_ClockDivSet(CMU_Clock_TypeDef clock,CMU_ClkDiv_TypeDef div)7330 void CMU_ClockDivSet(CMU_Clock_TypeDef clock, CMU_ClkDiv_TypeDef div)
7331 {
7332 #if defined(_SILICON_LABS_32B_SERIES_1)
7333   CMU_ClockPrescSet(clock, (CMU_ClkPresc_TypeDef)(div - 1U));
7334 
7335 #elif defined(_SILICON_LABS_32B_SERIES_0)
7336   uint32_t freq;
7337   uint32_t divReg;
7338 
7339   /* Get the divisor reg ID. */
7340   divReg = (clock >> CMU_DIV_REG_POS) & CMU_DIV_REG_MASK;
7341 
7342   switch (divReg) {
7343 #if defined(_CMU_CTRL_HFCLKDIV_MASK)
7344     case CMU_HFCLKDIV_REG:
7345       EFM_ASSERT((div >= cmuClkDiv_1) && (div <= cmuClkDiv_8));
7346 
7347       /* Configure worst case wait states for flash access before setting divisor. */
7348       flashWaitStateMax();
7349 
7350       /* Set the divider. */
7351       CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFCLKDIV_MASK)
7352                   | ((div - 1) << _CMU_CTRL_HFCLKDIV_SHIFT);
7353 
7354       /* Update the CMSIS core clock variable. */
7355       /* (The function will update the global variable). */
7356       freq = SystemCoreClockGet();
7357 
7358       /* Optimize flash access wait state setting for the current core clk. */
7359       CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
7360       break;
7361 #endif
7362 
7363     case CMU_HFPERCLKDIV_REG:
7364       EFM_ASSERT((div >= cmuClkDiv_1) && (div <= cmuClkDiv_512));
7365       /* Convert to the correct scale. */
7366       div = CMU_DivToLog2(div);
7367       CMU->HFPERCLKDIV = (CMU->HFPERCLKDIV & ~_CMU_HFPERCLKDIV_HFPERCLKDIV_MASK)
7368                          | (div << _CMU_HFPERCLKDIV_HFPERCLKDIV_SHIFT);
7369       break;
7370 
7371 #if defined(_CMU_HFCORECLKDIV_HFCORECLKLEDIV_MASK)
7372     case CMU_HFCORECLKLEDIV_REG:
7373       /*
7374          This divisor is usually set when changing HF clock to keep HFLE clock
7375          within safe bounds. This code path ignore these constraints.
7376        */
7377       /* Convert to the correct scale. */
7378       div = CMU_DivToLog2(div) - 1U;
7379       CMU->HFCORECLKDIV = (CMU->HFCORECLKDIV
7380                            & ~_CMU_HFCORECLKDIV_HFCORECLKLEDIV_MASK)
7381                           | (div << _CMU_HFCORECLKDIV_HFCORECLKLEDIV_SHIFT);
7382       break;
7383 #endif
7384 
7385     case CMU_HFCORECLKDIV_REG:
7386       EFM_ASSERT((div >= cmuClkDiv_1) && (div <= cmuClkDiv_512));
7387 
7388       /* Configure worst case wait states for flash access before setting the divisor. */
7389       flashWaitStateMax();
7390 
7391 #if defined(CMU_MAX_FREQ_HFLE)
7392       setHfLeConfig(SystemCoreClockGet() / div);
7393 #endif
7394 
7395       /* Convert to the correct scale. */
7396       div = CMU_DivToLog2(div);
7397 
7398       CMU->HFCORECLKDIV = (CMU->HFCORECLKDIV
7399                            & ~_CMU_HFCORECLKDIV_HFCORECLKDIV_MASK)
7400                           | (div << _CMU_HFCORECLKDIV_HFCORECLKDIV_SHIFT);
7401 
7402       /* Update the CMSIS core clock variable. */
7403       /* (The function will update the global variable). */
7404       freq = SystemCoreClockGet();
7405 
7406       /* Optimize wait state setting for the current core clk. */
7407       CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
7408 #if defined(CMU_MAX_FREQ_HFLE)
7409       setHfLeConfig(freq);
7410 #endif
7411       break;
7412 
7413     case CMU_LFAPRESC0_REG:
7414       switch (clock) {
7415         case cmuClock_RTC:
7416           EFM_ASSERT(div <= cmuClkDiv_32768);
7417 
7418           /* LF register about to be modified requires sync. busy check. */
7419           syncReg(CMU_SYNCBUSY_LFAPRESC0);
7420 
7421           /* Convert to the correct scale. */
7422           div = CMU_DivToLog2(div);
7423 
7424           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_RTC_MASK)
7425                            | (div << _CMU_LFAPRESC0_RTC_SHIFT);
7426           break;
7427 
7428 #if defined(_CMU_LFAPRESC0_LETIMER0_MASK)
7429         case cmuClock_LETIMER0:
7430           EFM_ASSERT(div <= cmuClkDiv_32768);
7431 
7432           /* LF register about to be modified requires sync. busy check. */
7433           syncReg(CMU_SYNCBUSY_LFAPRESC0);
7434 
7435           /* Convert to the correct scale. */
7436           div = CMU_DivToLog2(div);
7437 
7438           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LETIMER0_MASK)
7439                            | (div << _CMU_LFAPRESC0_LETIMER0_SHIFT);
7440           break;
7441 #endif
7442 
7443 #if defined(LCD_PRESENT)
7444         case cmuClock_LCDpre:
7445           EFM_ASSERT((div >= cmuClkDiv_16) && (div <= cmuClkDiv_128));
7446 
7447           /* LF register about to be modified requires sync. busy check. */
7448           syncReg(CMU_SYNCBUSY_LFAPRESC0);
7449 
7450           /* Convert to the correct scale. */
7451           div = CMU_DivToLog2(div);
7452 
7453           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LCD_MASK)
7454                            | ((div - CMU_DivToLog2(cmuClkDiv_16))
7455                               << _CMU_LFAPRESC0_LCD_SHIFT);
7456           break;
7457 #endif /* defined(LCD_PRESENT) */
7458 
7459 #if defined(LESENSE_PRESENT)
7460         case cmuClock_LESENSE:
7461           EFM_ASSERT(div <= cmuClkDiv_8);
7462 
7463           /* LF register about to be modified requires sync. busy check. */
7464           syncReg(CMU_SYNCBUSY_LFAPRESC0);
7465 
7466           /* Convert to the correct scale. */
7467           div = CMU_DivToLog2(div);
7468 
7469           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LESENSE_MASK)
7470                            | (div << _CMU_LFAPRESC0_LESENSE_SHIFT);
7471           break;
7472 #endif /* defined(LESENSE_PRESENT) */
7473 
7474         default:
7475           EFM_ASSERT(false);
7476           break;
7477       }
7478       break;
7479 
7480     case CMU_LFBPRESC0_REG:
7481       switch (clock) {
7482 #if defined(_CMU_LFBPRESC0_LEUART0_MASK)
7483         case cmuClock_LEUART0:
7484           EFM_ASSERT(div <= cmuClkDiv_8);
7485 
7486           /* LF register about to be modified requires sync. busy check. */
7487           syncReg(CMU_SYNCBUSY_LFBPRESC0);
7488 
7489           /* Convert to the correct scale. */
7490           div = CMU_DivToLog2(div);
7491 
7492           CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_LEUART0_MASK)
7493                            | (((uint32_t)div) << _CMU_LFBPRESC0_LEUART0_SHIFT);
7494           break;
7495 #endif
7496 
7497 #if defined(_CMU_LFBPRESC0_LEUART1_MASK)
7498         case cmuClock_LEUART1:
7499           EFM_ASSERT(div <= cmuClkDiv_8);
7500 
7501           /* LF register about to be modified requires sync. busy check. */
7502           syncReg(CMU_SYNCBUSY_LFBPRESC0);
7503 
7504           /* Convert to the correct scale. */
7505           div = CMU_DivToLog2(div);
7506 
7507           CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_LEUART1_MASK)
7508                            | (((uint32_t)div) << _CMU_LFBPRESC0_LEUART1_SHIFT);
7509           break;
7510 #endif
7511 
7512         default:
7513           EFM_ASSERT(false);
7514           break;
7515       }
7516       break;
7517 
7518     default:
7519       EFM_ASSERT(false);
7520       break;
7521   }
7522 #endif
7523 }
7524 
7525 /***************************************************************************//**
7526  * @brief
7527  *   Enable/disable a clock.
7528  *
7529  * @details
7530  *   In general, module clocking is disabled after a reset. If a module
7531  *   clock is disabled, the registers of that module are not accessible and
7532  *   reading from such registers may return undefined values. Writing to
7533  *   registers of clock-disabled modules has no effect.
7534  *   Avoid accessing module registers of a module with a disabled clock.
7535  *
7536  * @note
7537  *   If enabling/disabling an LF clock, synchronization into the low-frequency
7538  *   domain is required. If the same register is modified before a previous
7539  *   update has completed, this function will stall until the previous
7540  *   synchronization has completed. See @ref CMU_FreezeEnable() for
7541  *   a suggestion on how to reduce the stalling time in some use cases.
7542  *
7543  *   HFCLKLE prescaler is automatically modified when peripherals with clock
7544  *   domain HFBUSCLK is chosen based on the maximum HFLE frequency allowed.
7545  *
7546  * @param[in] clock
7547  *   The clock to enable/disable. Notice that not all defined clock
7548  *   points have separate enable/disable control. See the CMU overview
7549  *   in the reference manual.
7550  *
7551  * @param[in] enable
7552  *   @li true - enable specified clock.
7553  *   @li false - disable specified clock.
7554  ******************************************************************************/
CMU_ClockEnable(CMU_Clock_TypeDef clock,bool enable)7555 void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
7556 {
7557   volatile uint32_t *reg;
7558   uint32_t          bit;
7559   uint32_t          sync = 0;
7560 
7561   /* Identify enable register */
7562   switch (((unsigned)clock >> CMU_EN_REG_POS) & CMU_EN_REG_MASK) {
7563 #if defined(_CMU_CTRL_HFPERCLKEN_MASK)
7564     case CMU_CTRL_EN_REG:
7565       reg = &CMU->CTRL;
7566       break;
7567 #endif
7568 
7569 #if defined(_CMU_HFCORECLKEN0_MASK)
7570     case CMU_HFCORECLKEN0_EN_REG:
7571       reg = &CMU->HFCORECLKEN0;
7572 #if defined(CMU_MAX_FREQ_HFLE)
7573       setHfLeConfig(SystemCoreClockGet());
7574 #endif
7575       break;
7576 #endif
7577 
7578 #if defined(_CMU_HFBUSCLKEN0_MASK)
7579     case CMU_HFBUSCLKEN0_EN_REG:
7580       reg = &CMU->HFBUSCLKEN0;
7581       break;
7582 #endif
7583 
7584 #if defined(_CMU_HFPERCLKDIV_MASK)
7585     case CMU_HFPERCLKDIV_EN_REG:
7586       reg = &CMU->HFPERCLKDIV;
7587       break;
7588 #endif
7589 
7590     case CMU_HFPERCLKEN0_EN_REG:
7591       reg = &CMU->HFPERCLKEN0;
7592       break;
7593 
7594 #if defined(_CMU_HFPERCLKEN1_MASK)
7595     case CMU_HFPERCLKEN1_EN_REG:
7596       reg = &CMU->HFPERCLKEN1;
7597       break;
7598 #endif
7599 
7600     case CMU_LFACLKEN0_EN_REG:
7601       reg  = &CMU->LFACLKEN0;
7602       sync = CMU_SYNCBUSY_LFACLKEN0;
7603       break;
7604 
7605     case CMU_LFBCLKEN0_EN_REG:
7606       reg  = &CMU->LFBCLKEN0;
7607       sync = CMU_SYNCBUSY_LFBCLKEN0;
7608       break;
7609 
7610 #if defined(_CMU_LFCCLKEN0_MASK)
7611     case CMU_LFCCLKEN0_EN_REG:
7612       reg = &CMU->LFCCLKEN0;
7613       sync = CMU_SYNCBUSY_LFCCLKEN0;
7614       break;
7615 #endif
7616 
7617 #if defined(_CMU_LFECLKEN0_MASK)
7618     case CMU_LFECLKEN0_EN_REG:
7619       reg  = &CMU->LFECLKEN0;
7620       sync = CMU_SYNCBUSY_LFECLKEN0;
7621       break;
7622 #endif
7623 
7624 #if defined(_CMU_SDIOCTRL_MASK)
7625     case CMU_SDIOREF_EN_REG:
7626       reg = &CMU->SDIOCTRL;
7627       enable = !enable;
7628       break;
7629 #endif
7630 
7631 #if defined(_CMU_QSPICTRL_MASK)
7632     case CMU_QSPI0REF_EN_REG:
7633       reg = &CMU->QSPICTRL;
7634       enable = !enable;
7635       break;
7636 #endif
7637 #if defined(_CMU_USBCTRL_MASK)
7638     case CMU_USBRCLK_EN_REG:
7639       reg = &CMU->USBCTRL;
7640       break;
7641 #endif
7642 #if defined(_CMU_PDMCTRL_MASK)
7643     case CMU_PDMREF_EN_REG:
7644       reg = &CMU->PDMCTRL;
7645       break;
7646 #endif
7647 
7648     case CMU_PCNT_EN_REG:
7649       reg = &CMU->PCNTCTRL;
7650       break;
7651 
7652     default: /* Cannot enable/disable a clock point. */
7653       EFM_ASSERT(false);
7654       return;
7655   }
7656 
7657   /* Get the bit position used to enable/disable. */
7658   bit = ((unsigned)clock >> CMU_EN_BIT_POS) & CMU_EN_BIT_MASK;
7659 
7660   /* LF synchronization required. */
7661   if (sync > 0UL) {
7662     syncReg(sync);
7663   }
7664 
7665   /* Set/clear bit as requested. */
7666   BUS_RegBitWrite(reg, bit, (uint32_t)enable);
7667 }
7668 
7669 /***************************************************************************//**
7670  * @brief
7671  *   Get the clock frequency for a clock point.
7672  *
7673  * @param[in] clock
7674  *   A clock point to fetch the frequency for.
7675  *
7676  * @return
7677  *   The current frequency in Hz.
7678  ******************************************************************************/
CMU_ClockFreqGet(CMU_Clock_TypeDef clock)7679 uint32_t CMU_ClockFreqGet(CMU_Clock_TypeDef clock)
7680 {
7681   uint32_t ret;
7682 
7683   switch ((unsigned)clock & (CMU_CLK_BRANCH_MASK << CMU_CLK_BRANCH_POS)) {
7684     case (CMU_HF_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7685       ret = SystemHFClockGet();
7686       break;
7687 
7688     case (CMU_HFPER_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7689       ret = SystemHFClockGet();
7690       /* Calculate frequency after HFPER divider. */
7691 #if defined(_CMU_HFPERCLKDIV_HFPERCLKDIV_MASK)
7692       ret >>= (CMU->HFPERCLKDIV & _CMU_HFPERCLKDIV_HFPERCLKDIV_MASK)
7693               >> _CMU_HFPERCLKDIV_HFPERCLKDIV_SHIFT;
7694 #endif
7695 #if defined(_CMU_HFPERPRESC_PRESC_MASK)
7696       ret /= 1U + ((CMU->HFPERPRESC & _CMU_HFPERPRESC_PRESC_MASK)
7697                    >> _CMU_HFPERPRESC_PRESC_SHIFT);
7698 #endif
7699       break;
7700 
7701 #if defined(_CMU_HFPERPRESCB_MASK)
7702     case (CMU_HFPERB_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7703       ret = SystemHFClockGet();
7704       /* Calculate frequency after HFPERB prescaler. */
7705       ret /= 1U + ((CMU->HFPERPRESCB & _CMU_HFPERPRESCB_PRESC_MASK)
7706                    >> _CMU_HFPERPRESCB_PRESC_SHIFT);
7707       break;
7708 #endif
7709 
7710 #if defined(_CMU_HFPERPRESCC_MASK)
7711     case (CMU_HFPERC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7712       ret = SystemHFClockGet();
7713       /* Calculate frequency after HFPERC prescaler. */
7714       ret /= 1U + ((CMU->HFPERPRESCC & _CMU_HFPERPRESCC_PRESC_MASK)
7715                    >> _CMU_HFPERPRESCC_PRESC_SHIFT);
7716       break;
7717 #endif
7718 
7719 #if defined(_SILICON_LABS_32B_SERIES_1)
7720 #if defined(CRYPTO_PRESENT)     \
7721       || defined(LDMA_PRESENT)  \
7722       || defined(GPCRC_PRESENT) \
7723       || defined(PRS_PRESENT)   \
7724       || defined(GPIO_PRESENT)
7725     case (CMU_HFBUS_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7726       ret = SystemHFClockGet();
7727 #if defined(_CMU_HFBUSPRESC_MASK)
7728       ret /= 1U + ((CMU->HFBUSPRESC & _CMU_HFBUSPRESC_MASK)
7729                    >> _CMU_HFBUSPRESC_PRESC_SHIFT);
7730 #endif
7731       break;
7732 #endif
7733 
7734     case (CMU_HFCORE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7735       ret = SystemHFClockGet();
7736       ret /= 1U + ((CMU->HFCOREPRESC & _CMU_HFCOREPRESC_PRESC_MASK)
7737                    >> _CMU_HFCOREPRESC_PRESC_SHIFT);
7738       break;
7739 
7740     case (CMU_HFEXP_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7741       ret = SystemHFClockGet();
7742       ret /= 1U + ((CMU->HFEXPPRESC & _CMU_HFEXPPRESC_PRESC_MASK)
7743                    >> _CMU_HFEXPPRESC_PRESC_SHIFT);
7744       break;
7745 #endif
7746 
7747 #if defined(_SILICON_LABS_32B_SERIES_0)
7748 #if defined(AES_PRESENT)      \
7749       || defined(DMA_PRESENT) \
7750       || defined(EBI_PRESENT) \
7751       || defined(USB_PRESENT)
7752     case (CMU_HFCORE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7753     {
7754       ret = SystemCoreClockGet();
7755     } break;
7756 #endif
7757 #endif
7758 
7759     case (CMU_LFA_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7760       ret = lfClkGet(cmuClock_LFA);
7761       break;
7762 
7763 #if defined(_CMU_LFACLKEN0_RTC_MASK)
7764     case (CMU_RTC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7765       ret = lfClkGet(cmuClock_LFA);
7766       ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_RTC_MASK)
7767               >> _CMU_LFAPRESC0_RTC_SHIFT;
7768       break;
7769 #endif
7770 
7771 #if defined(_CMU_LFECLKEN0_RTCC_MASK)
7772     case (CMU_RTCC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7773       ret = lfClkGet(cmuClock_LFE);
7774       ret >>= (CMU->LFEPRESC0 & _CMU_LFEPRESC0_RTCC_MASK)
7775               >> _CMU_LFEPRESC0_RTCC_SHIFT;
7776       break;
7777 #endif
7778 
7779 #if defined(_CMU_LFACLKEN0_LETIMER0_MASK)
7780     case (CMU_LETIMER0_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7781       ret = lfClkGet(cmuClock_LFA);
7782 #if defined(_SILICON_LABS_32B_SERIES_0)
7783       ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER0_MASK)
7784               >> _CMU_LFAPRESC0_LETIMER0_SHIFT;
7785 #else
7786       ret /= SL_Log2ToDiv((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER0_MASK)
7787                           >> _CMU_LFAPRESC0_LETIMER0_SHIFT);
7788 #endif
7789       break;
7790 #endif
7791 
7792 #if defined(_CMU_LFACLKEN0_LETIMER1_MASK)
7793     case (CMU_LETIMER1_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7794       ret = lfClkGet(cmuClock_LFA);
7795 #if defined(_SILICON_LABS_32B_SERIES_0)
7796       ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER1_MASK)
7797               >> _CMU_LFAPRESC0_LETIMER1_SHIFT;
7798 #else
7799       ret /= SL_Log2ToDiv((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER1_MASK)
7800                           >> _CMU_LFAPRESC0_LETIMER1_SHIFT);
7801 #endif
7802       break;
7803 #endif
7804 
7805 #if defined(_CMU_LFACLKEN0_LCD_MASK)
7806     case (CMU_LCDPRE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7807       ret = lfClkGet(cmuClock_LFA);
7808 #if defined(_SILICON_LABS_32B_SERIES_0)
7809       ret >>= ((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK)
7810                >> _CMU_LFAPRESC0_LCD_SHIFT)
7811               + CMU_DivToLog2(cmuClkDiv_16);
7812 #else
7813       ret /= SL_Log2ToDiv((CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK)
7814                           >> _CMU_LFAPRESC0_LCD_SHIFT);
7815 #endif
7816       break;
7817 
7818 #if defined(_CMU_LCDCTRL_MASK)
7819     case (CMU_LCD_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7820       ret = lfClkGet(cmuClock_LFA);
7821       ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK)
7822               >> _CMU_LFAPRESC0_LCD_SHIFT;
7823       ret /= 1U + ((CMU->LCDCTRL & _CMU_LCDCTRL_FDIV_MASK)
7824                    >> _CMU_LCDCTRL_FDIV_SHIFT);
7825       break;
7826 #endif
7827 #endif
7828 
7829 #if defined(_CMU_LFACLKEN0_LESENSE_MASK)
7830     case (CMU_LESENSE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7831       ret = lfClkGet(cmuClock_LFA);
7832       ret >>= (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LESENSE_MASK)
7833               >> _CMU_LFAPRESC0_LESENSE_SHIFT;
7834       break;
7835 #endif
7836 
7837     case (CMU_LFB_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7838       ret = lfClkGet(cmuClock_LFB);
7839       break;
7840 
7841 #if defined(_CMU_LFBCLKEN0_LEUART0_MASK)
7842     case (CMU_LEUART0_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7843       ret = lfClkGet(cmuClock_LFB);
7844 #if defined(_SILICON_LABS_32B_SERIES_0)
7845       ret >>= (CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART0_MASK)
7846               >> _CMU_LFBPRESC0_LEUART0_SHIFT;
7847 #else
7848       ret /= SL_Log2ToDiv((CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART0_MASK)
7849                           >> _CMU_LFBPRESC0_LEUART0_SHIFT);
7850 #endif
7851       break;
7852 #endif
7853 
7854 #if defined(_CMU_LFBCLKEN0_LEUART1_MASK)
7855     case (CMU_LEUART1_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7856       ret = lfClkGet(cmuClock_LFB);
7857 #if defined(_SILICON_LABS_32B_SERIES_0)
7858       ret >>= (CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART1_MASK)
7859               >> _CMU_LFBPRESC0_LEUART1_SHIFT;
7860 #else
7861       ret /= SL_Log2ToDiv((CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART1_MASK)
7862                           >> _CMU_LFBPRESC0_LEUART1_SHIFT);
7863 #endif
7864       break;
7865 #endif
7866 
7867 #if defined(_CMU_LFBCLKEN0_CSEN_MASK)
7868     case (CMU_CSEN_LF_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7869       ret = lfClkGet(cmuClock_LFB);
7870       ret /= SL_Log2ToDiv(((CMU->LFBPRESC0 & _CMU_LFBPRESC0_CSEN_MASK)
7871                            >> _CMU_LFBPRESC0_CSEN_SHIFT) + 4UL);
7872       break;
7873 #endif
7874 
7875 #if defined(CMU_LFCCLKEN0_USB)
7876     case (CMU_USBLE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7877       ret = lfClkGet(cmuClock_LFC);
7878       break;
7879 #endif
7880 
7881 #if defined(_SILICON_LABS_32B_SERIES_1)
7882     case (CMU_LFE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7883       ret = lfClkGet(cmuClock_LFE);
7884       break;
7885 #endif
7886 
7887     case (CMU_DBG_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7888       ret = dbgClkGet();
7889       break;
7890 
7891     case (CMU_AUX_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7892       ret = auxClkGet();
7893       break;
7894 
7895 #if defined(USBC_CLOCK_PRESENT)
7896     case (CMU_USBC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7897       ret = usbCClkGet();
7898       break;
7899 #endif
7900 
7901 #if defined(_CMU_ADCCTRL_ADC0CLKSEL_MASK)
7902     case (CMU_ADC0ASYNC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7903       ret = adcAsyncClkGet(0);
7904 #if defined(_CMU_ADCCTRL_ADC0CLKDIV_MASK)
7905       ret /= 1U + ((CMU->ADCCTRL & _CMU_ADCCTRL_ADC0CLKDIV_MASK)
7906                    >> _CMU_ADCCTRL_ADC0CLKDIV_SHIFT);
7907 #endif
7908       break;
7909 #endif
7910 
7911 #if defined(_CMU_ADCCTRL_ADC1CLKSEL_MASK)
7912     case (CMU_ADC1ASYNC_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7913       ret = adcAsyncClkGet(1);
7914 #if defined(_CMU_ADCCTRL_ADC1CLKDIV_MASK)
7915       ret /= 1U + ((CMU->ADCCTRL & _CMU_ADCCTRL_ADC1CLKDIV_MASK)
7916                    >> _CMU_ADCCTRL_ADC1CLKDIV_SHIFT);
7917 #endif
7918       break;
7919 #endif
7920 
7921 #if defined(_CMU_SDIOCTRL_SDIOCLKSEL_MASK)
7922     case (CMU_SDIOREF_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7923       ret = sdioRefClkGet();
7924       break;
7925 #endif
7926 
7927 #if defined(_CMU_QSPICTRL_QSPI0CLKSEL_MASK)
7928     case (CMU_QSPI0REF_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7929       ret = qspiRefClkGet(0);
7930       break;
7931 #endif
7932 
7933 #if defined(USBR_CLOCK_PRESENT)
7934     case (CMU_USBR_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7935       ret = usbRateClkGet();
7936       break;
7937 #endif
7938 
7939 #if defined(_CMU_PDMCTRL_PDMCLKSEL_MASK)
7940     case (CMU_PDMREF_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7941       ret = pdmRefClkGet();
7942       break;
7943 #endif
7944 
7945     case (CMU_HFLE_CLK_BRANCH << CMU_CLK_BRANCH_POS):
7946 #if defined(_CMU_HFCORECLKDIV_HFCORECLKLEDIV_MASK)
7947       ret = SystemCoreClockGet() / CMU_ClockDivGet(clock);
7948 #elif defined(_CMU_HFPRESC_HFCLKLEPRESC_MASK)
7949       ret = SystemHFClockGet() / CMU_ClockDivGet(clock);
7950 #else
7951       ret = SystemCoreClockGet() / 2;
7952 #endif
7953       break;
7954 
7955     default:
7956       ret = 0;
7957       EFM_ASSERT(false);
7958       break;
7959   }
7960 
7961   return ret;
7962 }
7963 
7964 #if defined(_SILICON_LABS_32B_SERIES_1)
7965 /***************************************************************************//**
7966  * @brief
7967  *   Get the clock prescaler.
7968  *
7969  * @param[in] clock
7970  *   A clock point to get the prescaler for. Notice that not all clock points
7971  *   have a prescaler. See the CMU overview in the reference manual.
7972  *
7973  * @return
7974  *   The prescaler value of the current clock point. 0 is returned
7975  *   if @p clock specifies a clock point without a prescaler.
7976  ******************************************************************************/
CMU_ClockPrescGet(CMU_Clock_TypeDef clock)7977 uint32_t CMU_ClockPrescGet(CMU_Clock_TypeDef clock)
7978 {
7979   uint32_t  prescReg;
7980   uint32_t  ret;
7981 
7982   /* Get the prescaler register ID. */
7983   prescReg = ((unsigned)clock >> CMU_PRESC_REG_POS) & CMU_PRESC_REG_MASK;
7984 
7985   switch (prescReg) {
7986     case CMU_HFPRESC_REG:
7987       ret = (CMU->HFPRESC & _CMU_HFPRESC_PRESC_MASK)
7988             >> _CMU_HFPRESC_PRESC_SHIFT;
7989       break;
7990 
7991     case CMU_HFEXPPRESC_REG:
7992       ret = (CMU->HFEXPPRESC & _CMU_HFEXPPRESC_PRESC_MASK)
7993             >> _CMU_HFEXPPRESC_PRESC_SHIFT;
7994       break;
7995 
7996     case CMU_HFCLKLEPRESC_REG:
7997       ret = (CMU->HFPRESC & _CMU_HFPRESC_HFCLKLEPRESC_MASK)
7998             >> _CMU_HFPRESC_HFCLKLEPRESC_SHIFT;
7999       ret = SL_Log2ToDiv(ret + 1U) - 1U;
8000       break;
8001 
8002     case CMU_HFPERPRESC_REG:
8003       ret = (CMU->HFPERPRESC & _CMU_HFPERPRESC_PRESC_MASK)
8004             >> _CMU_HFPERPRESC_PRESC_SHIFT;
8005       break;
8006 
8007 #if defined(_CMU_HFPERPRESCB_MASK)
8008     case CMU_HFPERPRESCB_REG:
8009       ret = (CMU->HFPERPRESCB & _CMU_HFPERPRESCB_PRESC_MASK)
8010             >> _CMU_HFPERPRESCB_PRESC_SHIFT;
8011       break;
8012 #endif
8013 
8014 #if defined(_CMU_HFPERPRESCC_MASK)
8015     case CMU_HFPERPRESCC_REG:
8016       ret = (CMU->HFPERPRESCC & _CMU_HFPERPRESCC_PRESC_MASK)
8017             >> _CMU_HFPERPRESCC_PRESC_SHIFT;
8018       break;
8019 #endif
8020 
8021     case CMU_HFCOREPRESC_REG:
8022       ret = (CMU->HFCOREPRESC & _CMU_HFCOREPRESC_PRESC_MASK)
8023             >> _CMU_HFCOREPRESC_PRESC_SHIFT;
8024       break;
8025 
8026     case CMU_LFAPRESC0_REG:
8027       switch (clock) {
8028 #if defined(_CMU_LFAPRESC0_LETIMER0_MASK)
8029         case cmuClock_LETIMER0:
8030           ret = (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER0_MASK)
8031                 >> _CMU_LFAPRESC0_LETIMER0_SHIFT;
8032           /* Convert the exponent to a prescaler value. */
8033           ret = SL_Log2ToDiv(ret) - 1U;
8034           break;
8035 #endif
8036 
8037 #if defined(_CMU_LFAPRESC0_LESENSE_MASK)
8038         case cmuClock_LESENSE:
8039           ret = (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LESENSE_MASK)
8040                 >> _CMU_LFAPRESC0_LESENSE_SHIFT;
8041           /* Convert the exponent to a prescaler value. */
8042           ret = SL_Log2ToDiv(ret) - 1U;
8043           break;
8044 #endif
8045 
8046 #if defined(_CMU_LFAPRESC0_LETIMER1_MASK)
8047         case cmuClock_LETIMER1:
8048           ret = (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LETIMER1_MASK)
8049                 >> _CMU_LFAPRESC0_LETIMER1_SHIFT;
8050           ret = SL_Log2ToDiv(ret) - 1U;
8051           break;
8052 #endif
8053 
8054 #if defined(_CMU_LFAPRESC0_LCD_MASK)
8055         case cmuClock_LCD:
8056         case cmuClock_LCDpre:
8057           ret = (CMU->LFAPRESC0 & _CMU_LFAPRESC0_LCD_MASK)
8058                 >> _CMU_LFAPRESC0_LCD_SHIFT;
8059           ret = SL_Log2ToDiv(ret) - 1U;
8060           break;
8061 #endif
8062 
8063 #if defined(_CMU_LFAPRESC0_RTC_MASK)
8064         case cmuClock_RTC:
8065           ret = (CMU->LFAPRESC0 & _CMU_LFAPRESC0_RTC_MASK)
8066                 >> _CMU_LFAPRESC0_RTC_SHIFT;
8067           ret = SL_Log2ToDiv(ret) - 1U;
8068           break;
8069 #endif
8070 
8071         default:
8072           ret = 0U;
8073           EFM_ASSERT(false);
8074           break;
8075       }
8076       break;
8077 
8078     case CMU_LFBPRESC0_REG:
8079       switch (clock) {
8080 #if defined(_CMU_LFBPRESC0_LEUART0_MASK)
8081         case cmuClock_LEUART0:
8082           ret = (CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART0_MASK)
8083                 >> _CMU_LFBPRESC0_LEUART0_SHIFT;
8084           /* Convert the exponent to a prescaler value. */
8085           ret = SL_Log2ToDiv(ret) - 1U;
8086           break;
8087 #endif
8088 
8089 #if defined(_CMU_LFBPRESC0_LEUART1_MASK)
8090         case cmuClock_LEUART1:
8091           ret = (CMU->LFBPRESC0 & _CMU_LFBPRESC0_LEUART1_MASK)
8092                 >> _CMU_LFBPRESC0_LEUART1_SHIFT;
8093           /* Convert the exponent to a prescaler value. */
8094           ret = SL_Log2ToDiv(ret) - 1U;
8095           break;
8096 #endif
8097 
8098 #if defined(_CMU_LFBPRESC0_CSEN_MASK)
8099         case cmuClock_CSEN_LF:
8100           ret = (CMU->LFBPRESC0 & _CMU_LFBPRESC0_CSEN_MASK)
8101                 >> _CMU_LFBPRESC0_CSEN_SHIFT;
8102           /* Convert the exponent to a prescaler value. */
8103           ret = SL_Log2ToDiv(ret + 4U) - 1U;
8104           break;
8105 #endif
8106 
8107         default:
8108           ret = 0U;
8109           EFM_ASSERT(false);
8110           break;
8111       }
8112       break;
8113 
8114     case CMU_LFEPRESC0_REG:
8115       switch (clock) {
8116 #if defined(RTCC_PRESENT)
8117         case cmuClock_RTCC:
8118           ret = (CMU->LFEPRESC0 & _CMU_LFEPRESC0_RTCC_MASK)
8119                 >> _CMU_LFEPRESC0_RTCC_SHIFT;
8120           break;
8121 
8122         default:
8123           ret = 0U;
8124           EFM_ASSERT(false);
8125           break;
8126 #endif
8127       }
8128       break;
8129 
8130 #if defined(_CMU_ADCCTRL_ADC0CLKDIV_MASK) \
8131       || defined(_CMU_ADCCTRL_ADC1CLKDIV_MASK)
8132     case CMU_ADCASYNCDIV_REG:
8133       switch (clock) {
8134 #if defined(_CMU_ADCCTRL_ADC0CLKDIV_MASK)
8135         case cmuClock_ADC0ASYNC:
8136           ret = (CMU->ADCCTRL & _CMU_ADCCTRL_ADC0CLKDIV_MASK)
8137                 >> _CMU_ADCCTRL_ADC0CLKDIV_SHIFT;
8138           break;
8139 #endif
8140 #if defined(_CMU_ADCCTRL_ADC1CLKDIV_MASK)
8141         case cmuClock_ADC1ASYNC:
8142           ret = (CMU->ADCCTRL & _CMU_ADCCTRL_ADC1CLKDIV_MASK)
8143                 >> _CMU_ADCCTRL_ADC1CLKDIV_SHIFT;
8144           break;
8145 #endif
8146         default:
8147           ret = 0U;
8148           EFM_ASSERT(false);
8149           break;
8150       }
8151       break;
8152 #endif
8153 #if defined(_CMU_HFBUSPRESC_MASK)
8154     case CMU_HFBUSPRESC_REG:
8155       ret = (CMU->HFBUSPRESC & _CMU_HFBUSPRESC_MASK)
8156             >> _CMU_HFBUSPRESC_PRESC_SHIFT;
8157       break;
8158 #endif
8159     default:
8160       ret = 0U;
8161       EFM_ASSERT(false);
8162       break;
8163   }
8164 
8165   return ret;
8166 }
8167 #endif
8168 
8169 #if defined(_SILICON_LABS_32B_SERIES_1)
8170 /***************************************************************************//**
8171  * @brief
8172  *   Set the clock prescaler.
8173  *
8174  * @note
8175  *   If setting an LF clock prescaler, synchronization into the low-frequency
8176  *   domain is required. If the same register is modified before a previous
8177  *   update has completed, this function will stall until the previous
8178  *   synchronization has completed. See @ref CMU_FreezeEnable() for
8179  *   a suggestion on how to reduce the stalling time in some use cases.
8180  *
8181  *   HFCLKLE prescaler is automatically modified when peripherals with clock
8182  *   domain HFBUSCLK is chosen based on the maximum HFLE frequency allowed.
8183  *
8184  * @param[in] clock
8185  *   A clock point to set the prescaler for. Notice that not all clock points
8186  *   have a prescaler. See the CMU overview in the reference manual.
8187  *
8188  * @param[in] presc
8189  *   The clock prescaler. The prescaler value is linked to the clock divider by:
8190  *   divider = 'presc' + 1.
8191  ******************************************************************************/
CMU_ClockPrescSet(CMU_Clock_TypeDef clock,CMU_ClkPresc_TypeDef presc)8192 void CMU_ClockPrescSet(CMU_Clock_TypeDef clock, CMU_ClkPresc_TypeDef presc)
8193 {
8194   uint32_t freq;
8195   uint32_t prescReg;
8196 
8197   /* Get the divisor reg ID. */
8198   prescReg = ((unsigned)clock >> CMU_PRESC_REG_POS) & CMU_PRESC_REG_MASK;
8199 
8200   switch (prescReg) {
8201     case CMU_HFPRESC_REG:
8202       EFM_ASSERT(presc < 32U);
8203 
8204       /* Configure worst case wait-states for flash and HFLE, set safe HFPER
8205          clock-tree prescalers. */
8206       flashWaitStateMax();
8207       setHfLeConfig(CMU_MAX_FREQ_HFLE + 1UL);
8208       hfperClkSafePrescaler();
8209 
8210       CMU->HFPRESC = (CMU->HFPRESC & ~_CMU_HFPRESC_PRESC_MASK)
8211                      | (presc << _CMU_HFPRESC_PRESC_SHIFT);
8212 
8213       /* Update the CMSIS core clock variable (this function updates the global
8214          variable). */
8215       freq = SystemCoreClockGet();
8216       /* Optimize flash and HFLE wait states and set optimized HFPER clock-tree
8217          prescalers. */
8218       CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
8219       setHfLeConfig(SystemHFClockGet());
8220       hfperClkOptimizedPrescaler();
8221       break;
8222 
8223     case CMU_HFEXPPRESC_REG:
8224       EFM_ASSERT(presc < 32U);
8225 
8226       CMU->HFEXPPRESC = (CMU->HFEXPPRESC & ~_CMU_HFEXPPRESC_PRESC_MASK)
8227                         | (presc << _CMU_HFEXPPRESC_PRESC_SHIFT);
8228       break;
8229 
8230     case CMU_HFCLKLEPRESC_REG:
8231       presc = CMU_DivToLog2(presc);
8232       CMU->HFPRESC = (CMU->HFPRESC & ~_CMU_HFPRESC_HFCLKLEPRESC_MASK)
8233                      | (presc << _CMU_HFPRESC_HFCLKLEPRESC_SHIFT);
8234       break;
8235 
8236     case CMU_HFPERPRESC_REG:
8237       EFM_ASSERT(presc < 512U);
8238       CMU->HFPERPRESC = (CMU->HFPERPRESC & ~_CMU_HFPERPRESC_PRESC_MASK)
8239                         | (presc << _CMU_HFPERPRESC_PRESC_SHIFT);
8240       break;
8241 
8242 #if defined(_CMU_HFPERPRESCB_MASK)
8243     case CMU_HFPERPRESCB_REG:
8244       EFM_ASSERT(presc < 512U);
8245       CMU->HFPERPRESCB = (CMU->HFPERPRESCB & ~_CMU_HFPERPRESCB_PRESC_MASK)
8246                          | (presc << _CMU_HFPERPRESCB_PRESC_SHIFT);
8247       break;
8248 #endif
8249 
8250 #if defined(_CMU_HFPERPRESCC_MASK)
8251     case CMU_HFPERPRESCC_REG:
8252       EFM_ASSERT(presc < 512U);
8253       CMU->HFPERPRESCC = (CMU->HFPERPRESCC & ~_CMU_HFPERPRESCC_PRESC_MASK)
8254                          | (presc << _CMU_HFPERPRESCC_PRESC_SHIFT);
8255       break;
8256 #endif
8257 
8258     case CMU_HFCOREPRESC_REG:
8259       EFM_ASSERT(presc < 512U);
8260 
8261       /* Configure worst case wait-states for flash. */
8262       flashWaitStateMax();
8263 
8264       CMU->HFCOREPRESC = (CMU->HFCOREPRESC & ~_CMU_HFCOREPRESC_PRESC_MASK)
8265                          | (presc << _CMU_HFCOREPRESC_PRESC_SHIFT);
8266 
8267       /* Update the CMSIS core clock variable (this function updates the global variable).
8268          Optimize flash and HFLE wait states. */
8269       freq = SystemCoreClockGet();
8270       CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
8271       break;
8272 
8273     case CMU_LFAPRESC0_REG:
8274       switch (clock) {
8275 #if defined(RTC_PRESENT)
8276         case cmuClock_RTC:
8277           EFM_ASSERT(presc <= 32768U);
8278 
8279           /* Convert the prescaler value to a DIV exponent scale. */
8280           presc = CMU_PrescToLog2(presc);
8281 
8282           /* LF register about to be modified requires sync. Busy check. */
8283           syncReg(CMU_SYNCBUSY_LFAPRESC0);
8284 
8285           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_RTC_MASK)
8286                            | (presc << _CMU_LFAPRESC0_RTC_SHIFT);
8287           break;
8288 #endif
8289 
8290 #if defined(RTCC_PRESENT)
8291         case cmuClock_RTCC:
8292 #if defined(_CMU_LFEPRESC0_RTCC_MASK)
8293 #if defined(_CMU_LFEPRESC0_RTCC_DIV4)
8294           EFM_ASSERT(presc <= _CMU_LFEPRESC0_RTCC_DIV4);
8295 #elif defined(_CMU_LFEPRESC0_RTCC_DIV2)
8296           EFM_ASSERT(presc <= _CMU_LFEPRESC0_RTCC_DIV2);
8297 #else
8298           EFM_ASSERT(presc <= 0U);
8299 #endif
8300 
8301           /* LF register about to be modified requires sync. Busy check. */
8302           syncReg(CMU_SYNCBUSY_LFEPRESC0);
8303 
8304           CMU->LFEPRESC0 = (CMU->LFEPRESC0 & ~_CMU_LFEPRESC0_RTCC_MASK)
8305                            | (presc << _CMU_LFEPRESC0_RTCC_SHIFT);
8306 #else
8307           EFM_ASSERT(presc <= 32768U);
8308 
8309           /* Convert the prescaler value to a DIV exponent scale. */
8310           presc = CMU_PrescToLog2(presc);
8311 
8312           /* LF register about to be modified requires sync. Busy check. */
8313           syncReg(CMU_SYNCBUSY_LFAPRESC0);
8314 
8315           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_RTCC_MASK)
8316                            | (presc << _CMU_LFAPRESC0_RTCC_SHIFT);
8317 #endif
8318           break;
8319 #endif
8320 
8321 #if defined(_CMU_LFAPRESC0_LETIMER0_MASK)
8322         case cmuClock_LETIMER0:
8323           EFM_ASSERT(presc <= 32768U);
8324 
8325           /* Convert the prescaler value to a DIV exponent scale. */
8326           presc = CMU_PrescToLog2(presc);
8327 
8328           /* LF register about to be modified requires sync. Busy check. */
8329           syncReg(CMU_SYNCBUSY_LFAPRESC0);
8330 
8331           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LETIMER0_MASK)
8332                            | (presc << _CMU_LFAPRESC0_LETIMER0_SHIFT);
8333           break;
8334 #endif
8335 
8336 #if defined(_CMU_LFAPRESC0_LETIMER1_MASK)
8337         case cmuClock_LETIMER1:
8338           EFM_ASSERT(presc <= 32768U);
8339 
8340           /* Convert the prescaler value to a DIV exponent scale. */
8341           presc = CMU_PrescToLog2(presc);
8342 
8343           /* LF register about to be modified requires sync. Busy check. */
8344           syncReg(CMU_SYNCBUSY_LFAPRESC0);
8345 
8346           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LETIMER1_MASK)
8347                            | (presc << _CMU_LFAPRESC0_LETIMER1_SHIFT);
8348           break;
8349 #endif
8350 
8351 #if defined(_CMU_LFAPRESC0_LESENSE_MASK)
8352         case cmuClock_LESENSE:
8353           EFM_ASSERT(presc <= 8U);
8354 
8355           /* Convert the prescaler value to a DIV exponent scale. */
8356           presc = CMU_PrescToLog2(presc);
8357 
8358           /* LF register about to be modified requires sync. Busy check. */
8359           syncReg(CMU_SYNCBUSY_LFAPRESC0);
8360 
8361           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LESENSE_MASK)
8362                            | (presc << _CMU_LFAPRESC0_LESENSE_SHIFT);
8363           break;
8364 #endif
8365 
8366 #if defined(_CMU_LFAPRESC0_LCD_MASK)
8367         case cmuClock_LCDpre:
8368         case cmuClock_LCD:
8369           EFM_ASSERT(presc <= 32768U);
8370 
8371           /* Convert the prescaler value to a DIV exponent scale. */
8372           presc = CMU_PrescToLog2(presc);
8373 
8374           /* LF register about to be modified requires sync. Busy check. */
8375           syncReg(CMU_SYNCBUSY_LFAPRESC0);
8376 
8377           CMU->LFAPRESC0 = (CMU->LFAPRESC0 & ~_CMU_LFAPRESC0_LCD_MASK)
8378                            | (presc << _CMU_LFAPRESC0_LCD_SHIFT);
8379           break;
8380 #endif
8381 
8382         default:
8383           EFM_ASSERT(false);
8384           break;
8385       }
8386       break;
8387 
8388     case CMU_LFBPRESC0_REG:
8389       switch (clock) {
8390 #if defined(_CMU_LFBPRESC0_LEUART0_MASK)
8391         case cmuClock_LEUART0:
8392           EFM_ASSERT(presc <= 8U);
8393 
8394           /* Convert the prescaler value to a DIV exponent scale. */
8395           presc = CMU_PrescToLog2(presc);
8396 
8397           /* LF register about to be modified requires sync. Busy check. */
8398           syncReg(CMU_SYNCBUSY_LFBPRESC0);
8399 
8400           CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_LEUART0_MASK)
8401                            | (presc << _CMU_LFBPRESC0_LEUART0_SHIFT);
8402           break;
8403 #endif
8404 
8405 #if defined(_CMU_LFBPRESC0_LEUART1_MASK)
8406         case cmuClock_LEUART1:
8407           EFM_ASSERT(presc <= 8U);
8408 
8409           /* Convert the prescaler value to a DIV exponent scale. */
8410           presc = CMU_PrescToLog2(presc);
8411 
8412           /* LF register about to be modified requires sync. Busy check. */
8413           syncReg(CMU_SYNCBUSY_LFBPRESC0);
8414 
8415           CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_LEUART1_MASK)
8416                            | (presc << _CMU_LFBPRESC0_LEUART1_SHIFT);
8417           break;
8418 #endif
8419 
8420 #if defined(_CMU_LFBPRESC0_CSEN_MASK)
8421         case cmuClock_CSEN_LF:
8422           EFM_ASSERT((presc <= 127U) && (presc >= 15U));
8423 
8424           /* Convert the prescaler value to a DIV exponent scale.
8425            * DIV16 is the lowest supported prescaler. */
8426           presc = CMU_PrescToLog2(presc) - 4U;
8427 
8428           /* LF register about to be modified requires sync. Busy check. */
8429           syncReg(CMU_SYNCBUSY_LFBPRESC0);
8430 
8431           CMU->LFBPRESC0 = (CMU->LFBPRESC0 & ~_CMU_LFBPRESC0_CSEN_MASK)
8432                            | (presc << _CMU_LFBPRESC0_CSEN_SHIFT);
8433           break;
8434 #endif
8435 
8436         default:
8437           EFM_ASSERT(false);
8438           break;
8439       }
8440       break;
8441 
8442     case CMU_LFEPRESC0_REG:
8443       switch (clock) {
8444 #if defined(_CMU_LFEPRESC0_RTCC_MASK)
8445         case cmuClock_RTCC:
8446 #if defined(_CMU_LFEPRESC0_RTCC_DIV4)
8447           EFM_ASSERT(presc <= _CMU_LFEPRESC0_RTCC_DIV4);
8448 #elif defined(_CMU_LFEPRESC0_RTCC_DIV2)
8449           EFM_ASSERT(presc <= _CMU_LFEPRESC0_RTCC_DIV2);
8450 #else
8451           EFM_ASSERT(presc <= 0U);
8452 #endif
8453 
8454           /* LF register about to be modified requires sync. Busy check. */
8455           syncReg(CMU_SYNCBUSY_LFEPRESC0);
8456 
8457           CMU->LFEPRESC0 = (CMU->LFEPRESC0 & ~_CMU_LFEPRESC0_RTCC_MASK)
8458                            | (presc << _CMU_LFEPRESC0_RTCC_SHIFT);
8459           break;
8460 #endif
8461 
8462         default:
8463           EFM_ASSERT(false);
8464           break;
8465       }
8466       break;
8467 
8468 #if defined(_CMU_ADCCTRL_ADC0CLKDIV_MASK) \
8469       ||  defined(_CMU_ADCCTRL_ADC1CLKDIV_MASK)
8470     case CMU_ADCASYNCDIV_REG:
8471       switch (clock) {
8472 #if defined(_CMU_ADCCTRL_ADC0CLKDIV_MASK)
8473         case cmuClock_ADC0ASYNC:
8474           EFM_ASSERT(presc <= 3);
8475           CMU->ADCCTRL = (CMU->ADCCTRL & ~_CMU_ADCCTRL_ADC0CLKDIV_MASK)
8476                          | (presc << _CMU_ADCCTRL_ADC0CLKDIV_SHIFT);
8477           break;
8478 #endif
8479 
8480 #if defined(_CMU_ADCCTRL_ADC1CLKDIV_MASK)
8481         case cmuClock_ADC1ASYNC:
8482           EFM_ASSERT(presc <= 3);
8483           CMU->ADCCTRL = (CMU->ADCCTRL & ~_CMU_ADCCTRL_ADC1CLKDIV_MASK)
8484                          | (presc << _CMU_ADCCTRL_ADC1CLKDIV_SHIFT);
8485           break;
8486 #endif
8487         default:
8488           EFM_ASSERT(false);
8489           break;
8490       }
8491       break;
8492 #endif
8493 
8494 #if defined(_CMU_HFBUSPRESC_MASK)
8495     case CMU_HFBUSPRESC_REG:
8496       EFM_ASSERT(presc <= _CMU_HFBUSPRESC_MASK >> _CMU_HFBUSPRESC_PRESC_SHIFT);
8497       CMU->HFBUSPRESC = (CMU->HFBUSPRESC & ~_CMU_HFBUSPRESC_MASK)
8498                         | (presc << _CMU_HFBUSPRESC_PRESC_SHIFT);
8499       break;
8500 #endif
8501 
8502     default:
8503       EFM_ASSERT(false);
8504       break;
8505   }
8506 }
8507 #endif
8508 
8509 /***************************************************************************//**
8510  * @brief
8511  *   Get the currently selected reference clock used for a clock branch.
8512  *
8513  * @param[in] clock
8514  *   Clock branch to fetch selected ref. clock for. One of:
8515  *   @li #cmuClock_HF
8516  *   @li #cmuClock_LFA
8517  *   @li #cmuClock_LFB @if _CMU_LFCLKSEL_LFAE_ULFRCO
8518  *   @li #cmuClock_LFC
8519  *   @endif            @if _SILICON_LABS_32B_SERIES_1
8520  *   @li #cmuClock_LFE
8521  *   @endif
8522  *   @li #cmuClock_DBG @if DOXYDOC_USB_PRESENT
8523  *   @li #cmuClock_USBC
8524  *   @endif
8525  *
8526  * @return
8527  *   The reference clock used for clocking the selected branch, #cmuSelect_Error if
8528  *   invalid @p clock provided.
8529  ******************************************************************************/
CMU_ClockSelectGet(CMU_Clock_TypeDef clock)8530 CMU_Select_TypeDef CMU_ClockSelectGet(CMU_Clock_TypeDef clock)
8531 {
8532   CMU_Select_TypeDef ret = cmuSelect_Disabled;
8533   uint32_t selReg;
8534 
8535   selReg = ((unsigned)clock >> CMU_SEL_REG_POS) & CMU_SEL_REG_MASK;
8536 
8537   switch (selReg) {
8538     case CMU_HFCLKSEL_REG:
8539 #if defined(_CMU_HFCLKSTATUS_MASK)
8540       switch (CMU->HFCLKSTATUS & _CMU_HFCLKSTATUS_SELECTED_MASK) {
8541         case CMU_HFCLKSTATUS_SELECTED_LFXO:
8542           ret = cmuSelect_LFXO;
8543           break;
8544 
8545         case CMU_HFCLKSTATUS_SELECTED_LFRCO:
8546           ret = cmuSelect_LFRCO;
8547           break;
8548 
8549         case CMU_HFCLKSTATUS_SELECTED_HFXO:
8550           ret = cmuSelect_HFXO;
8551           break;
8552 
8553 #if defined(CMU_HFCLKSTATUS_SELECTED_HFRCODIV2)
8554         case CMU_HFCLKSTATUS_SELECTED_HFRCODIV2:
8555           ret = cmuSelect_HFRCODIV2;
8556           break;
8557 #endif
8558 
8559 #if defined(CMU_HFCLKSTATUS_SELECTED_CLKIN0)
8560         case CMU_HFCLKSTATUS_SELECTED_CLKIN0:
8561           ret = cmuSelect_CLKIN0;
8562           break;
8563 #endif
8564 
8565 #if defined(CMU_HFCLKSTATUS_SELECTED_USHFRCO)
8566         case CMU_HFCLKSTATUS_SELECTED_USHFRCO:
8567           ret = cmuSelect_USHFRCO;
8568           break;
8569 #endif
8570 
8571         default:
8572           ret = cmuSelect_HFRCO;
8573           break;
8574       }
8575 #else
8576       switch (CMU->STATUS
8577               & (CMU_STATUS_HFRCOSEL
8578                  | CMU_STATUS_HFXOSEL
8579                  | CMU_STATUS_LFRCOSEL
8580 #if defined(CMU_STATUS_USHFRCODIV2SEL)
8581                  | CMU_STATUS_USHFRCODIV2SEL
8582 #endif
8583                  | CMU_STATUS_LFXOSEL)) {
8584         case CMU_STATUS_LFXOSEL:
8585           ret = cmuSelect_LFXO;
8586           break;
8587 
8588         case CMU_STATUS_LFRCOSEL:
8589           ret = cmuSelect_LFRCO;
8590           break;
8591 
8592         case CMU_STATUS_HFXOSEL:
8593           ret = cmuSelect_HFXO;
8594           break;
8595 
8596 #if defined(CMU_STATUS_USHFRCODIV2SEL)
8597         case CMU_STATUS_USHFRCODIV2SEL:
8598           ret = cmuSelect_USHFRCODIV2;
8599           break;
8600 #endif
8601 
8602         default:
8603           ret = cmuSelect_HFRCO;
8604           break;
8605       }
8606 #endif
8607       break;
8608 
8609 #if defined(_CMU_LFCLKSEL_MASK) || defined(_CMU_LFACLKSEL_MASK)
8610     case CMU_LFACLKSEL_REG:
8611 #if defined(_CMU_LFCLKSEL_MASK)
8612       switch (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFA_MASK) {
8613         case CMU_LFCLKSEL_LFA_LFRCO:
8614           ret = cmuSelect_LFRCO;
8615           break;
8616 
8617         case CMU_LFCLKSEL_LFA_LFXO:
8618           ret = cmuSelect_LFXO;
8619           break;
8620 
8621 #if defined(CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2)
8622         case CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2:
8623           ret = cmuSelect_HFCLKLE;
8624           break;
8625 #endif
8626 
8627         default:
8628 #if defined(CMU_LFCLKSEL_LFAE)
8629           if (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFAE_MASK) {
8630             ret = cmuSelect_ULFRCO;
8631             break;
8632           }
8633 #else
8634           ret = cmuSelect_Disabled;
8635 #endif
8636           break;
8637       }
8638 
8639 #elif defined(_CMU_LFACLKSEL_MASK)
8640       switch (CMU->LFACLKSEL & _CMU_LFACLKSEL_LFA_MASK) {
8641         case CMU_LFACLKSEL_LFA_LFRCO:
8642           ret = cmuSelect_LFRCO;
8643           break;
8644 
8645         case CMU_LFACLKSEL_LFA_LFXO:
8646           ret = cmuSelect_LFXO;
8647           break;
8648 
8649         case CMU_LFACLKSEL_LFA_ULFRCO:
8650           ret = cmuSelect_ULFRCO;
8651           break;
8652 
8653 #if defined(PLFRCO_PRESENT)
8654         case CMU_LFACLKSEL_LFA_PLFRCO:
8655           ret = cmuSelect_PLFRCO;
8656           break;
8657 #endif
8658 
8659         default:
8660           ret = cmuSelect_Disabled;
8661           break;
8662       }
8663 #endif
8664       break;
8665 #endif /* _CMU_LFCLKSEL_MASK || _CMU_LFACLKSEL_MASK */
8666 
8667 #if defined(_CMU_LFCLKSEL_MASK) || defined(_CMU_LFBCLKSEL_MASK)
8668     case CMU_LFBCLKSEL_REG:
8669 #if defined(_CMU_LFCLKSEL_MASK)
8670       switch (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFB_MASK) {
8671         case CMU_LFCLKSEL_LFB_LFRCO:
8672           ret = cmuSelect_LFRCO;
8673           break;
8674 
8675         case CMU_LFCLKSEL_LFB_LFXO:
8676           ret = cmuSelect_LFXO;
8677           break;
8678 
8679 #if defined(CMU_LFCLKSEL_LFB_HFCORECLKLEDIV2)
8680         case CMU_LFCLKSEL_LFB_HFCORECLKLEDIV2:
8681           ret = cmuSelect_HFCLKLE;
8682           break;
8683 #endif
8684 
8685 #if defined(CMU_LFCLKSEL_LFB_HFCLKLE)
8686         case CMU_LFCLKSEL_LFB_HFCLKLE:
8687           ret = cmuSelect_HFCLKLE;
8688           break;
8689 #endif
8690 
8691         default:
8692 #if defined(CMU_LFCLKSEL_LFBE)
8693           if (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFBE_MASK) {
8694             ret = cmuSelect_ULFRCO;
8695             break;
8696           }
8697 #else
8698           ret = cmuSelect_Disabled;
8699 #endif
8700           break;
8701       }
8702 
8703 #elif defined(_CMU_LFBCLKSEL_MASK)
8704       switch (CMU->LFBCLKSEL & _CMU_LFBCLKSEL_LFB_MASK) {
8705         case CMU_LFBCLKSEL_LFB_LFRCO:
8706           ret = cmuSelect_LFRCO;
8707           break;
8708 
8709         case CMU_LFBCLKSEL_LFB_LFXO:
8710           ret = cmuSelect_LFXO;
8711           break;
8712 
8713         case CMU_LFBCLKSEL_LFB_ULFRCO:
8714           ret = cmuSelect_ULFRCO;
8715           break;
8716 
8717         case CMU_LFBCLKSEL_LFB_HFCLKLE:
8718           ret = cmuSelect_HFCLKLE;
8719           break;
8720 
8721 #if defined(PLFRCO_PRESENT)
8722         case CMU_LFBCLKSEL_LFB_PLFRCO:
8723           ret = cmuSelect_PLFRCO;
8724           break;
8725 #endif
8726 
8727         default:
8728           ret = cmuSelect_Disabled;
8729           break;
8730       }
8731 #endif
8732       break;
8733 #endif /* _CMU_LFCLKSEL_MASK || _CMU_LFBCLKSEL_MASK */
8734 
8735 #if defined(_CMU_LFCLKSEL_LFC_MASK)
8736     case CMU_LFCCLKSEL_REG:
8737       switch (CMU->LFCLKSEL & _CMU_LFCLKSEL_LFC_MASK) {
8738         case CMU_LFCLKSEL_LFC_LFRCO:
8739           ret = cmuSelect_LFRCO;
8740           break;
8741 
8742         case CMU_LFCLKSEL_LFC_LFXO:
8743           ret = cmuSelect_LFXO;
8744           break;
8745 
8746         default:
8747           ret = cmuSelect_Disabled;
8748           break;
8749       }
8750       break;
8751 #endif
8752 
8753 #if defined(_CMU_LFECLKSEL_LFE_MASK)
8754     case CMU_LFECLKSEL_REG:
8755       switch (CMU->LFECLKSEL & _CMU_LFECLKSEL_LFE_MASK) {
8756         case CMU_LFECLKSEL_LFE_LFRCO:
8757           ret = cmuSelect_LFRCO;
8758           break;
8759 
8760         case CMU_LFECLKSEL_LFE_LFXO:
8761           ret = cmuSelect_LFXO;
8762           break;
8763 
8764         case CMU_LFECLKSEL_LFE_ULFRCO:
8765           ret = cmuSelect_ULFRCO;
8766           break;
8767 
8768 #if defined(PLFRCO_PRESENT)
8769         case CMU_LFECLKSEL_LFE_PLFRCO:
8770           ret = cmuSelect_PLFRCO;
8771           break;
8772 #endif
8773 
8774         default:
8775           ret = cmuSelect_Disabled;
8776           break;
8777       }
8778       break;
8779 #endif /* CMU_LFECLKSEL_REG */
8780 
8781 #if defined(_CMU_LFCCLKSEL_LFC_MASK)
8782     case CMU_LFCCLKSEL_REG:
8783       switch (CMU->LFCCLKSEL & _CMU_LFCCLKSEL_LFC_MASK) {
8784         case CMU_LFCCLKSEL_LFC_LFRCO:
8785           ret = cmuSelect_LFRCO;
8786           break;
8787 
8788         case CMU_LFCCLKSEL_LFC_LFXO:
8789           ret = cmuSelect_LFXO;
8790           break;
8791 
8792         case CMU_LFCCLKSEL_LFC_ULFRCO:
8793           ret = cmuSelect_ULFRCO;
8794           break;
8795 
8796         default:
8797           ret = cmuSelect_Disabled;
8798           break;
8799       }
8800       break;
8801 #endif /* CMU_LFCCLKSEL_REG */
8802 
8803     case CMU_DBGCLKSEL_REG:
8804 #if defined(_CMU_DBGCLKSEL_DBG_MASK)
8805       switch (CMU->DBGCLKSEL & _CMU_DBGCLKSEL_DBG_MASK) {
8806         case CMU_DBGCLKSEL_DBG_HFCLK:
8807           ret = cmuSelect_HFCLK;
8808           break;
8809 
8810         case CMU_DBGCLKSEL_DBG_AUXHFRCO:
8811           ret = cmuSelect_AUXHFRCO;
8812           break;
8813 
8814         default:
8815           ret = cmuSelect_Disabled;
8816           break;
8817       }
8818 
8819 #elif defined(_CMU_CTRL_DBGCLK_MASK)
8820       switch (CMU->CTRL & _CMU_CTRL_DBGCLK_MASK) {
8821         case CMU_CTRL_DBGCLK_AUXHFRCO:
8822           ret = cmuSelect_AUXHFRCO;
8823           break;
8824 
8825         case CMU_CTRL_DBGCLK_HFCLK:
8826           ret = cmuSelect_HFCLK;
8827           break;
8828       }
8829 #else
8830       ret = cmuSelect_AUXHFRCO;
8831 #endif
8832       break;
8833 
8834 #if defined(USBC_CLOCK_PRESENT)
8835     case CMU_USBCCLKSEL_REG:
8836       switch (CMU->STATUS
8837               & (CMU_STATUS_USBCLFXOSEL
8838 #if defined(_CMU_STATUS_USBCHFCLKSEL_MASK)
8839                  | CMU_STATUS_USBCHFCLKSEL
8840 #endif
8841 #if defined(_CMU_STATUS_USBCUSHFRCOSEL_MASK)
8842                  | CMU_STATUS_USBCUSHFRCOSEL
8843 #endif
8844                  | CMU_STATUS_USBCLFRCOSEL)) {
8845 #if defined(_CMU_STATUS_USBCHFCLKSEL_MASK)
8846         case CMU_STATUS_USBCHFCLKSEL:
8847           ret = cmuSelect_HFCLK;
8848           break;
8849 #endif
8850 
8851 #if defined(_CMU_STATUS_USBCUSHFRCOSEL_MASK)
8852         case CMU_STATUS_USBCUSHFRCOSEL:
8853           ret = cmuSelect_USHFRCO;
8854           break;
8855 #endif
8856 
8857         case CMU_STATUS_USBCLFXOSEL:
8858           ret = cmuSelect_LFXO;
8859           break;
8860 
8861         case CMU_STATUS_USBCLFRCOSEL:
8862           ret = cmuSelect_LFRCO;
8863           break;
8864 
8865         default:
8866           ret = cmuSelect_Disabled;
8867           break;
8868       }
8869       break;
8870 #endif
8871 
8872 #if defined(_CMU_ADCCTRL_ADC0CLKSEL_MASK)
8873     case CMU_ADC0ASYNCSEL_REG:
8874       switch (CMU->ADCCTRL & _CMU_ADCCTRL_ADC0CLKSEL_MASK) {
8875         case CMU_ADCCTRL_ADC0CLKSEL_DISABLED:
8876           ret = cmuSelect_Disabled;
8877           break;
8878 
8879         case CMU_ADCCTRL_ADC0CLKSEL_AUXHFRCO:
8880           ret = cmuSelect_AUXHFRCO;
8881           break;
8882 
8883         case CMU_ADCCTRL_ADC0CLKSEL_HFXO:
8884           ret = cmuSelect_HFXO;
8885           break;
8886 
8887         case CMU_ADCCTRL_ADC0CLKSEL_HFSRCCLK:
8888           ret = cmuSelect_HFSRCCLK;
8889           break;
8890 
8891         default:
8892           ret = cmuSelect_Disabled;
8893           break;
8894       }
8895       break;
8896 #endif
8897 
8898 #if defined(_CMU_ADCCTRL_ADC1CLKSEL_MASK)
8899     case CMU_ADC1ASYNCSEL_REG:
8900       switch (CMU->ADCCTRL & _CMU_ADCCTRL_ADC1CLKSEL_MASK) {
8901         case CMU_ADCCTRL_ADC1CLKSEL_DISABLED:
8902           ret = cmuSelect_Disabled;
8903           break;
8904 
8905         case CMU_ADCCTRL_ADC1CLKSEL_AUXHFRCO:
8906           ret = cmuSelect_AUXHFRCO;
8907           break;
8908 
8909         case CMU_ADCCTRL_ADC1CLKSEL_HFXO:
8910           ret = cmuSelect_HFXO;
8911           break;
8912 
8913         case CMU_ADCCTRL_ADC1CLKSEL_HFSRCCLK:
8914           ret = cmuSelect_HFSRCCLK;
8915           break;
8916       }
8917       break;
8918 #endif
8919 
8920 #if defined(_CMU_SDIOCTRL_SDIOCLKSEL_MASK)
8921     case CMU_SDIOREFSEL_REG:
8922       switch (CMU->SDIOCTRL & _CMU_SDIOCTRL_SDIOCLKSEL_MASK) {
8923         case CMU_SDIOCTRL_SDIOCLKSEL_HFRCO:
8924           ret = cmuSelect_HFRCO;
8925           break;
8926 
8927         case CMU_SDIOCTRL_SDIOCLKSEL_HFXO:
8928           ret = cmuSelect_HFXO;
8929           break;
8930 
8931         case CMU_SDIOCTRL_SDIOCLKSEL_AUXHFRCO:
8932           ret = cmuSelect_AUXHFRCO;
8933           break;
8934 
8935         case CMU_SDIOCTRL_SDIOCLKSEL_USHFRCO:
8936           ret = cmuSelect_USHFRCO;
8937           break;
8938       }
8939       break;
8940 #endif
8941 
8942 #if defined(_CMU_QSPICTRL_QSPI0CLKSEL_MASK)
8943     case CMU_QSPI0REFSEL_REG:
8944       switch (CMU->QSPICTRL & _CMU_QSPICTRL_QSPI0CLKSEL_MASK) {
8945         case CMU_QSPICTRL_QSPI0CLKSEL_HFRCO:
8946           ret = cmuSelect_HFRCO;
8947           break;
8948 
8949         case CMU_QSPICTRL_QSPI0CLKSEL_HFXO:
8950           ret = cmuSelect_HFXO;
8951           break;
8952 
8953         case CMU_QSPICTRL_QSPI0CLKSEL_AUXHFRCO:
8954           ret = cmuSelect_AUXHFRCO;
8955           break;
8956 
8957         case CMU_QSPICTRL_QSPI0CLKSEL_USHFRCO:
8958           ret = cmuSelect_USHFRCO;
8959           break;
8960       }
8961       break;
8962 #endif
8963 
8964 #if defined(_CMU_USBCTRL_USBCLKSEL_MASK)
8965     case CMU_USBRCLKSEL_REG:
8966       switch (CMU->USBCTRL & _CMU_USBCTRL_USBCLKSEL_MASK) {
8967         case CMU_USBCTRL_USBCLKSEL_USHFRCO:
8968           ret = cmuSelect_USHFRCO;
8969           break;
8970 
8971         case CMU_USBCTRL_USBCLKSEL_HFXO:
8972           ret = cmuSelect_HFXO;
8973           break;
8974 
8975         case CMU_USBCTRL_USBCLKSEL_HFXOX2:
8976           ret = cmuSelect_HFXOX2;
8977           break;
8978 
8979         case CMU_USBCTRL_USBCLKSEL_HFRCO:
8980           ret = cmuSelect_HFRCO;
8981           break;
8982 
8983         case CMU_USBCTRL_USBCLKSEL_LFXO:
8984           ret = cmuSelect_LFXO;
8985           break;
8986 
8987         case CMU_USBCTRL_USBCLKSEL_LFRCO:
8988           ret = cmuSelect_LFRCO;
8989           break;
8990       }
8991       break;
8992 #endif
8993 
8994 #if defined(_CMU_PDMCTRL_PDMCLKSEL_MASK)
8995     case CMU_PDMREFSEL_REG:
8996       switch (CMU->PDMCTRL & _CMU_PDMCTRL_PDMCLKSEL_MASK) {
8997         case CMU_PDMCTRL_PDMCLKSEL_USHFRCO:
8998           ret = cmuSelect_USHFRCO;
8999           break;
9000 
9001         case CMU_PDMCTRL_PDMCLKSEL_HFXO:
9002           ret = cmuSelect_HFXO;
9003           break;
9004 
9005         case CMU_PDMCTRL_PDMCLKSEL_HFRCO:
9006           ret = cmuSelect_HFRCO;
9007           break;
9008       }
9009       break;
9010 #endif
9011 
9012     default:
9013       ret = cmuSelect_Error;
9014       EFM_ASSERT(false);
9015       break;
9016   }
9017 
9018   return ret;
9019 }
9020 
9021 /***************************************************************************//**
9022  * @brief This function configures the HFLE wait-states and divider suitable
9023  *        for the System Core Clock.
9024  *
9025  * @note FOR INTERNAL USE ONLY.
9026  *
9027  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
9028  *       the clock source is HFCLKLE.
9029  ******************************************************************************/
sli_em_cmu_SetHFLEConfigSystemCoreClock(void)9030 void sli_em_cmu_SetHFLEConfigSystemCoreClock(void)
9031 {
9032 #if defined(CMU_MAX_FREQ_HFLE)
9033   setHfLeConfig(SystemCoreClockGet());
9034 #endif
9035 }
9036 
9037 /***************************************************************************//**
9038  * @brief This function configures the HFLE wait-states and divider suitable
9039  *        for the HF Clock.
9040  *
9041  * @note FOR INTERNAL USE ONLY.
9042  *
9043  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
9044  *       the clock source is HFCLKLE.
9045  ******************************************************************************/
sli_em_cmu_SetHFLEConfigHFClock(void)9046 void sli_em_cmu_SetHFLEConfigHFClock(void)
9047 {
9048 #if defined(CMU_MAX_FREQ_HFLE)
9049   setHfLeConfig(SystemHFClockGet());
9050 #endif
9051 }
9052 
9053 /***************************************************************************//**
9054  * @brief This function is used to initialize the HF clock and selecting
9055  *        an LF clock source.
9056  *
9057  * @note FOR INTERNAL USE ONLY.
9058  *
9059  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
9060  *       the clock is HF and LFXO or LFRCO is selected as the clock source.
9061  ******************************************************************************/
sli_em_cmu_HFClockSelectLFOsc(uint8_t osc)9062 void sli_em_cmu_HFClockSelectLFOsc(uint8_t osc)
9063 {
9064   if (osc == (uint8_t)cmuOsc_LFXO) {
9065     // Enable LFXO oscillator
9066     CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
9067   } else if (osc == (uint8_t)cmuOsc_LFRCO) {
9068     // Enable LFRCO oscillator
9069     CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
9070   } else {
9071     EFM_ASSERT(false);
9072   }
9073 
9074   // Configure worst case wait-states for flash and set safe HFPER
9075   // clock-tree prescalers.
9076   flashWaitStateMax();
9077   hfperClkSafePrescaler();
9078 
9079 #if defined(_SILICON_LABS_32B_SERIES_1)
9080   // Select HF clock source.
9081   if (osc == (uint8_t)cmuOsc_LFXO) {
9082     CMU->HFCLKSEL = CMU_HFCLKSEL_HF_LFXO;
9083   } else if (osc == (uint8_t)cmuOsc_LFRCO) {
9084     CMU->HFCLKSEL = CMU_HFCLKSEL_HF_LFRCO;
9085   }
9086 #if defined(CMU_MAX_FREQ_HFLE)
9087   // Set HFLE clock.
9088   setHfLeConfig(SystemHFClockGet());
9089 #endif
9090 #elif defined(_SILICON_LABS_32B_SERIES_0)
9091   // Select HF clock source.
9092   if (osc == (uint8_t)cmuOsc_LFXO) {
9093     CMU->CMD = CMU_CMD_HFCLKSEL_LFXO;
9094   } else if (osc == (uint8_t)cmuOsc_LFRCO) {
9095     CMU->CMD = CMU_CMD_HFCLKSEL_LFRCO;
9096   }
9097 #if defined(CMU_MAX_FREQ_HFLE)
9098   // Set HFLE clock.
9099   setHfLeConfig(SystemCoreClockGet());
9100 #endif
9101 #endif
9102 
9103   // Optimize flash access wait state setting for the currently selected core clk.
9104   CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
9105   // Set optimized HFPER clock-tree prescalers.
9106   hfperClkOptimizedPrescaler();
9107 }
9108 
9109 /***************************************************************************//**
9110  * @brief This function is used to initialize the HF clock and selecting
9111  *        HFXO as the clock source.
9112  *
9113  * @note FOR INTERNAL USE ONLY.
9114  *
9115  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
9116  *       the clock is HF and HFXO is selected as the clock source.
9117  ******************************************************************************/
sli_em_cmu_HFClockSelectHFXO(void)9118 void sli_em_cmu_HFClockSelectHFXO(void)
9119 {
9120 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
9121   uint32_t vScaleFrequency = SystemHFXOClockGet();
9122   EMU_VScaleEM01ByClock(vScaleFrequency, false);
9123 #endif
9124 
9125 #if defined(CMU_MAX_FREQ_HFLE)
9126   // Set 1 HFLE wait-state until the new HFCLKLE frequency is known.
9127   // This is known after 'select' is written below.
9128   setHfLeConfig(CMU_MAX_FREQ_HFLE + 1UL);
9129 #endif
9130 #if defined(CMU_CTRL_HFXOBUFCUR_BOOSTABOVE32MHZ)
9131   // Adjust HFXO buffer current for frequencies above 32 MHz.
9132   if (SystemHFXOClockGet() > 32000000) {
9133     CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFXOBUFCUR_MASK)
9134                 | CMU_CTRL_HFXOBUFCUR_BOOSTABOVE32MHZ;
9135   } else {
9136     CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFXOBUFCUR_MASK)
9137                 | CMU_CTRL_HFXOBUFCUR_BOOSTUPTO32MHZ;
9138   }
9139 #endif
9140 
9141   // Enable HFXO oscillator
9142   CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
9143 
9144   // Configure worst case wait-states for flash and set safe HFPER
9145   // clock-tree prescalers.
9146   flashWaitStateMax();
9147   hfperClkSafePrescaler();
9148 
9149 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
9150   // Wait for voltage upscaling to complete before the clock is set.
9151   if (vScaleFrequency != 0UL) {
9152     EMU_VScaleWait();
9153   }
9154 #endif
9155 
9156 #if defined(CMU_HFCLKSEL_HF_HFXO)
9157   // Select HF clock source.
9158   CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFXO;
9159 #if defined(CMU_MAX_FREQ_HFLE)
9160   // Set HFLE clock.
9161   setHfLeConfig(SystemHFClockGet());
9162 #endif
9163 #elif defined(CMU_CMD_HFCLKSEL_HFXO)
9164   // Select HF clock source.
9165   CMU->CMD = CMU_CMD_HFCLKSEL_HFXO;
9166 #if defined(CMU_MAX_FREQ_HFLE)
9167   // Set HFLE clock.
9168   setHfLeConfig(SystemCoreClockGet());
9169 #endif
9170 #endif
9171 
9172   // Optimize flash access wait state setting for the currently selected core clk.
9173   CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
9174 
9175 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
9176   // Keep EMU module informed on the source HF clock frequency. This will apply voltage
9177   // downscaling after clock is set if downscaling is configured.
9178   if (vScaleFrequency == 0UL) {
9179     EMU_VScaleEM01ByClock(0, true);
9180   }
9181 #endif
9182 
9183   // Set optimized HFPER clock-tree prescalers.
9184   hfperClkOptimizedPrescaler();
9185 }
9186 
9187 /***************************************************************************//**
9188  * @brief This function is used to initialize the HF clock and selecting
9189  *        HFRCO as the clock source.
9190  *
9191  * @note FOR INTERNAL USE ONLY.
9192  *
9193  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
9194  *       the clock is HF and HFRCO is selected as the clock source.
9195  ******************************************************************************/
sli_em_cmu_HFClockSelectHFRCO(void)9196 void sli_em_cmu_HFClockSelectHFRCO(void)
9197 {
9198 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
9199   uint32_t vScaleFrequency = 0;    /* Use default. */
9200   if (((uint32_t)CMU_HFRCOBandGet() > CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX)) {
9201     vScaleFrequency = (uint32_t)CMU_HFRCOBandGet();
9202   }
9203   if (vScaleFrequency != 0UL) {
9204     EMU_VScaleEM01ByClock(vScaleFrequency, false);
9205   }
9206 #endif
9207 
9208 #if defined(CMU_MAX_FREQ_HFLE)
9209   // Set 1 HFLE wait-state until the new HFCLKLE frequency is known.
9210   // This is known after 'select' is written below.
9211   setHfLeConfig(CMU_MAX_FREQ_HFLE + 1UL);
9212 #endif
9213 
9214   // Enable HFRCO oscillator
9215   CMU_OscillatorEnable(cmuOsc_HFRCO, true, true);
9216 
9217   // Configure worst case wait-states for flash and set safe HFPER
9218   // clock-tree prescalers.
9219   flashWaitStateMax();
9220   hfperClkSafePrescaler();
9221 
9222 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
9223   // Wait for voltage upscaling to complete before the clock is set.
9224   if (vScaleFrequency != 0UL) {
9225     EMU_VScaleWait();
9226   }
9227 #endif
9228 
9229 #if defined(_SILICON_LABS_32B_SERIES_1)
9230   // Select HF clock source.
9231   CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFRCO;
9232 #if defined(CMU_MAX_FREQ_HFLE)
9233   // Set HFLE clock.
9234   setHfLeConfig(SystemHFClockGet());
9235 #endif
9236 #elif defined(_SILICON_LABS_32B_SERIES_0)
9237   // Select HF clock source.
9238   CMU->CMD = CMU_CMD_HFCLKSEL_HFRCO;
9239 #if defined(CMU_MAX_FREQ_HFLE)
9240   // Set HFLE clock.
9241   setHfLeConfig(SystemCoreClockGet());
9242 #endif
9243 #endif
9244 
9245   // Optimize flash access wait state setting for the currently selected core clk.
9246   CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
9247 
9248 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
9249   // Keep EMU module informed on the source HF clock frequency. This will apply voltage
9250   // downscaling after clock is set if downscaling is configured.
9251   if (vScaleFrequency == 0UL) {
9252     EMU_VScaleEM01ByClock(0, true);
9253   }
9254 #endif
9255 
9256   // Set optimized HFPER clock-tree prescalers.
9257   hfperClkOptimizedPrescaler();
9258 }
9259 
9260 #if defined(CMU_CMD_HFCLKSEL_USHFRCODIV2)
9261 /***************************************************************************//**
9262  * @brief This function is used to initialize the HF clock and selecting
9263  *        USHFRCODIV2 as the clock source.
9264  *
9265  * @note FOR INTERNAL USE ONLY.
9266  *
9267  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
9268  *       the clock is HF and USHFRCODIV2 is selected as the clock source.
9269  ******************************************************************************/
sli_em_cmu_HFClockSelectUSHFRCODIV2(void)9270 void sli_em_cmu_HFClockSelectUSHFRCODIV2(void)
9271 {
9272   // Enable USHFRCO oscillator
9273   CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
9274   // Configure worst case wait-states for flash and set safe HFPER
9275   // clock-tree prescalers.
9276   flashWaitStateMax();
9277   hfperClkSafePrescaler();
9278 
9279   // Select HF clock source.
9280   CMU->CMD = CMU_CMD_HFCLKSEL_USHFRCODIV2;
9281 #if defined(CMU_MAX_FREQ_HFLE)
9282   setHfLeConfig(SystemCoreClockGet());
9283 #endif
9284 
9285   // Optimize flash access wait state setting for the currently selected core clk.
9286   CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
9287   // Set optimized HFPER clock-tree prescalers.
9288   hfperClkOptimizedPrescaler();
9289 }
9290 #endif
9291 
9292 #if defined(CMU_HFCLKSTATUS_SELECTED_HFRCODIV2)
9293 /***************************************************************************//**
9294  * @brief This function is used to initialize the HF clock and selecting
9295  *        HFRCODIV2 as the clock source.
9296  *
9297  * @note FOR INTERNAL USE ONLY.
9298  *
9299  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
9300  *       the clock is HF and HFRCODIV2 is selected as the clock source.
9301  ******************************************************************************/
sli_em_cmu_HFClockSelectHFRCODIV2(void)9302 void sli_em_cmu_HFClockSelectHFRCODIV2(void)
9303 {
9304   // Enable HFRCO oscillator
9305   CMU_OscillatorEnable(cmuOsc_HFRCO, true, true);
9306   // Configure worst case wait-states for flash and set safe HFPER
9307   // clock-tree prescalers.
9308   flashWaitStateMax();
9309   hfperClkSafePrescaler();
9310 
9311   // Select HF clock source.
9312   CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFRCODIV2;
9313 #if defined(CMU_MAX_FREQ_HFLE)
9314   setHfLeConfig(SystemHFClockGet());
9315 #endif
9316 
9317   // Optimize flash access wait state setting for the currently selected core clk.
9318   CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
9319   // Set optimized HFPER clock-tree prescalers.
9320   hfperClkOptimizedPrescaler();
9321 }
9322 #endif
9323 
9324 #if defined(CMU_HFCLKSTATUS_SELECTED_CLKIN0)
9325 /***************************************************************************//**
9326  * @brief This function is used to initialize the HF clock and selecting
9327  *        CLKIN0 as the clock source.
9328  *
9329  * @note FOR INTERNAL USE ONLY.
9330  *
9331  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
9332  *       the clock is HF and CLKIN0 is selected as the clock source.
9333  ******************************************************************************/
sli_em_cmu_HFClockSelectCLKIN0(void)9334 void sli_em_cmu_HFClockSelectCLKIN0(void)
9335 {
9336   // Configure worst case wait-states for flash and set safe HFPER
9337   // clock-tree prescalers.
9338   flashWaitStateMax();
9339   hfperClkSafePrescaler();
9340 
9341   // Select HF clock source.
9342   CMU->HFCLKSEL = CMU_HFCLKSEL_HF_CLKIN0;
9343 #if defined(CMU_MAX_FREQ_HFLE)
9344   setHfLeConfig(SystemHFClockGet());
9345 #endif
9346 
9347   // Optimize flash access wait state setting for the currently selected core clk.
9348   CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
9349   // Set optimized HFPER clock-tree prescalers.
9350   hfperClkOptimizedPrescaler();
9351 }
9352 #endif
9353 
9354 #if defined(CMU_HFCLKSTATUS_SELECTED_USHFRCO)
9355 /***************************************************************************//**
9356  * @brief This function is used to initialize the HF clock and selecting
9357  *        USHFRCO as the clock source.
9358  *
9359  * @note FOR INTERNAL USE ONLY.
9360  *
9361  * @note This function is needed for macro expansion of CMU_CLOCK_SELECT_SET when
9362  *       the clock is HF and USHFRCO is selected as the clock source.
9363  ******************************************************************************/
sli_em_cmu_HFClockSelectUSHFRCO(void)9364 void sli_em_cmu_HFClockSelectUSHFRCO(void)
9365 {
9366   // Enable USHFRCO oscillator
9367   CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
9368   // Configure worst case wait-states for flash and set safe HFPER
9369   // clock-tree prescalers.
9370   flashWaitStateMax();
9371   hfperClkSafePrescaler();
9372 
9373   // Select HF clock source.
9374   CMU->HFCLKSEL = CMU_HFCLKSEL_HF_USHFRCO;
9375 #if defined(CMU_MAX_FREQ_HFLE)
9376   setHfLeConfig(SystemHFClockGet());
9377 #endif
9378 
9379   // Optimize flash access wait state setting for the currently selected core clk.
9380   CMU_UpdateWaitStates(SystemCoreClockGet(), VSCALE_DEFAULT);
9381   // Set optimized HFPER clock-tree prescalers.
9382   hfperClkOptimizedPrescaler();
9383 }
9384 #endif
9385 
9386 /***************************************************************************//**
9387  * @brief
9388  *   Select the reference clock/oscillator used for a clock branch.
9389  *
9390  * @details
9391  *   Notice that if a selected reference is not enabled prior to selecting its
9392  *   use, it will be enabled and this function will wait for the selected
9393  *   oscillator to be stable. It will however NOT be disabled if another
9394  *   reference clock is selected later.
9395  *
9396  *   This feature is particularly important if selecting a new reference
9397  *   clock for the clock branch clocking the core. Otherwise, the system
9398  *   may halt.
9399  *
9400  * @note
9401  *   HFCLKLE prescaler is automatically modified when peripherals with clock
9402  *   domain HFBUSCLK is chosen based on the maximum HFLE frequency allowed.
9403  *
9404  * @param[in] clock
9405  *   A clock branch to select reference clock for. One of:
9406  *   @li #cmuClock_HF
9407  *   @li #cmuClock_LFA
9408  *   @li #cmuClock_LFB
9409  *   @if _CMU_LFCCLKEN0_MASK
9410  *   @li #cmuClock_LFC
9411  *   @endif
9412  *   @if _CMU_LFECLKEN0_MASK
9413  *   @li #cmuClock_LFE
9414  *   @endif
9415  *   @li #cmuClock_DBG
9416  *   @if _CMU_CMD_USBCLKSEL_MASK
9417  *   @li #cmuClock_USBC
9418  *   @endif
9419  *   @if _CMU_USBCTRL_MASK
9420  *   @li #cmuClock_USBR
9421  *   @endif
9422  *
9423  * @param[in] ref
9424  *   A reference selected for clocking. See the reference manual
9425  *   for details about references available for a specific clock branch.
9426  *   @li #cmuSelect_HFRCO
9427  *   @li #cmuSelect_LFRCO
9428  *   @li #cmuSelect_HFXO
9429  *   @if _CMU_HFXOCTRL_HFXOX2EN_MASK
9430  *   @li #cmuSelect_HFXOX2
9431  *   @endif
9432  *   @li #cmuSelect_LFXO
9433  *   @li #cmuSelect_HFCLKLE
9434  *   @li #cmuSelect_AUXHFRCO
9435  *   @if _CMU_USHFRCOCTRL_MASK
9436  *   @li #cmuSelect_USHFRCO
9437  *   @endif
9438  *   @li #cmuSelect_HFCLK
9439  *   @ifnot DOXYDOC_EFM32_GECKO_FAMILY
9440  *   @li #cmuSelect_ULFRCO
9441  *   @endif
9442  *   @if CMU_OSCENCMD_PLFRCOEN
9443  *   @li #cmuSelect_PLFRCO
9444  *   @endif
9445  ******************************************************************************/
CMU_ClockSelectSet(CMU_Clock_TypeDef clock,CMU_Select_TypeDef ref)9446 void CMU_ClockSelectSet(CMU_Clock_TypeDef clock, CMU_Select_TypeDef ref)
9447 {
9448   uint32_t              select = (uint32_t)cmuOsc_HFRCO;
9449   CMU_Osc_TypeDef       osc    = cmuOsc_HFRCO;
9450   uint32_t              freq;
9451   uint32_t              tmp;
9452   uint32_t              selRegId;
9453 #if defined(_SILICON_LABS_32B_SERIES_1)
9454   volatile uint32_t     *selReg = NULL;
9455 #endif
9456 #if defined(CMU_LFCLKSEL_LFAE_ULFRCO)
9457   uint32_t              lfExtended = 0;
9458 #endif
9459 
9460 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
9461   uint32_t              vScaleFrequency = 0; /* Use default. */
9462 
9463   /* Start voltage upscaling before the clock is set. */
9464   if (clock == cmuClock_HF) {
9465     if (ref == cmuSelect_HFXO) {
9466       vScaleFrequency = SystemHFXOClockGet();
9467     } else if ((ref == cmuSelect_HFRCO)
9468                && ((uint32_t)CMU_HFRCOBandGet()
9469                    > CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX)) {
9470       vScaleFrequency = (uint32_t)CMU_HFRCOBandGet();
9471     } else {
9472       /* Use the default frequency. */
9473     }
9474     if (vScaleFrequency != 0UL) {
9475       EMU_VScaleEM01ByClock(vScaleFrequency, false);
9476     }
9477   }
9478 #endif
9479 
9480   selRegId = ((unsigned)clock >> CMU_SEL_REG_POS) & CMU_SEL_REG_MASK;
9481 
9482   switch (selRegId) {
9483     case CMU_HFCLKSEL_REG:
9484       switch (ref) {
9485         case cmuSelect_LFXO:
9486 #if defined(_SILICON_LABS_32B_SERIES_1)
9487           select = CMU_HFCLKSEL_HF_LFXO;
9488 #elif defined(_SILICON_LABS_32B_SERIES_0)
9489           select = CMU_CMD_HFCLKSEL_LFXO;
9490 #endif
9491           osc = cmuOsc_LFXO;
9492           break;
9493 
9494         case cmuSelect_LFRCO:
9495 #if defined(_SILICON_LABS_32B_SERIES_1)
9496           select = CMU_HFCLKSEL_HF_LFRCO;
9497 #elif defined(_SILICON_LABS_32B_SERIES_0)
9498           select = CMU_CMD_HFCLKSEL_LFRCO;
9499 #endif
9500           osc = cmuOsc_LFRCO;
9501           break;
9502 
9503         case cmuSelect_HFXO:
9504 #if defined(CMU_HFCLKSEL_HF_HFXO)
9505           select = CMU_HFCLKSEL_HF_HFXO;
9506 #elif defined(CMU_CMD_HFCLKSEL_HFXO)
9507           select = CMU_CMD_HFCLKSEL_HFXO;
9508 #endif
9509           osc = cmuOsc_HFXO;
9510 #if defined(CMU_MAX_FREQ_HFLE)
9511           /* Set 1 HFLE wait-state until the new HFCLKLE frequency is known.
9512              This is known after 'select' is written below. */
9513           setHfLeConfig(CMU_MAX_FREQ_HFLE + 1UL);
9514 #endif
9515 #if defined(CMU_CTRL_HFXOBUFCUR_BOOSTABOVE32MHZ)
9516           /* Adjust HFXO buffer current for frequencies above 32 MHz. */
9517           if (SystemHFXOClockGet() > 32000000) {
9518             CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFXOBUFCUR_MASK)
9519                         | CMU_CTRL_HFXOBUFCUR_BOOSTABOVE32MHZ;
9520           } else {
9521             CMU->CTRL = (CMU->CTRL & ~_CMU_CTRL_HFXOBUFCUR_MASK)
9522                         | CMU_CTRL_HFXOBUFCUR_BOOSTUPTO32MHZ;
9523           }
9524 #endif
9525           break;
9526 
9527         case cmuSelect_HFRCO:
9528 #if defined(_SILICON_LABS_32B_SERIES_1)
9529           select = CMU_HFCLKSEL_HF_HFRCO;
9530 #elif defined(_SILICON_LABS_32B_SERIES_0)
9531           select = CMU_CMD_HFCLKSEL_HFRCO;
9532 #endif
9533           osc = cmuOsc_HFRCO;
9534 #if defined(CMU_MAX_FREQ_HFLE)
9535           /* Set 1 HFLE wait-state until the new HFCLKLE frequency is known.
9536              This is known after 'select' is written below. */
9537           setHfLeConfig(CMU_MAX_FREQ_HFLE + 1UL);
9538 #endif
9539           break;
9540 
9541 #if defined(CMU_CMD_HFCLKSEL_USHFRCODIV2)
9542         case cmuSelect_USHFRCODIV2:
9543           select = CMU_CMD_HFCLKSEL_USHFRCODIV2;
9544           osc = cmuOsc_USHFRCO;
9545           break;
9546 #endif
9547 
9548 #if defined(CMU_HFCLKSTATUS_SELECTED_HFRCODIV2)
9549         case cmuSelect_HFRCODIV2:
9550           select = CMU_HFCLKSEL_HF_HFRCODIV2;
9551           osc = cmuOsc_HFRCO;
9552           break;
9553 #endif
9554 
9555 #if defined(CMU_HFCLKSTATUS_SELECTED_CLKIN0)
9556         case cmuSelect_CLKIN0:
9557           select = CMU_HFCLKSEL_HF_CLKIN0;
9558           osc = cmuOsc_CLKIN0;
9559           break;
9560 #endif
9561 
9562 #if defined(CMU_HFCLKSTATUS_SELECTED_USHFRCO)
9563         case cmuSelect_USHFRCO:
9564           select = CMU_HFCLKSEL_HF_USHFRCO;
9565           osc = cmuOsc_USHFRCO;
9566           break;
9567 #endif
9568 
9569 #if defined(CMU_LFCLKSEL_LFAE_ULFRCO) || defined(CMU_LFACLKSEL_LFA_ULFRCO)
9570         case cmuSelect_ULFRCO:
9571           /* ULFRCO cannot be used as HFCLK.  */
9572           EFM_ASSERT(false);
9573           return;
9574 #endif
9575 
9576         default:
9577           EFM_ASSERT(false);
9578           return;
9579       }
9580 
9581       /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9582 #if defined(CMU_HFCLKSTATUS_SELECTED_CLKIN0)
9583       if (osc != cmuOsc_CLKIN0) {
9584         CMU_OscillatorEnable(osc, true, true);
9585       }
9586 #else
9587       CMU_OscillatorEnable(osc, true, true);
9588 #endif
9589 
9590       /* Configure worst case wait-states for flash and set safe HFPER
9591          clock-tree prescalers. */
9592       flashWaitStateMax();
9593       hfperClkSafePrescaler();
9594 
9595 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
9596       /* Wait for voltage upscaling to complete before the clock is set. */
9597       if (vScaleFrequency != 0UL) {
9598         EMU_VScaleWait();
9599       }
9600 #endif
9601 
9602       /* Switch to the selected oscillator. */
9603 #if defined(_CMU_HFCLKSEL_MASK)
9604       CMU->HFCLKSEL = select;
9605 #else
9606       CMU->CMD = select;
9607 #endif
9608       /* Update the CMSIS core clock variable. */
9609       /* (The function will update the global variable). */
9610       freq = SystemCoreClockGet();
9611 
9612 #if defined(CMU_MAX_FREQ_HFLE)
9613       /* Update the HFLE configuration after 'select' is set.
9614          Note that the HFCLKLE clock is connected differently on platforms 1 and 2. */
9615 #if defined(_SILICON_LABS_32B_SERIES_0)
9616       setHfLeConfig(freq);
9617 #else
9618       setHfLeConfig(SystemHFClockGet());
9619 #endif
9620 #endif
9621 
9622       /* Optimize flash access wait state setting for the currently selected core clk. */
9623       CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
9624 
9625 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
9626       /* Keep EMU module informed on the source HF clock frequency. This will apply voltage
9627          downscaling after clock is set if downscaling is configured. */
9628       if (vScaleFrequency == 0UL) {
9629         EMU_VScaleEM01ByClock(0, true);
9630       }
9631 #endif
9632       /* Set optimized HFPER clock-tree prescalers. */
9633       hfperClkOptimizedPrescaler();
9634       break;
9635 
9636 #if defined(_SILICON_LABS_32B_SERIES_1)
9637     case CMU_LFACLKSEL_REG:
9638       selReg = &CMU->LFACLKSEL;
9639       /* HFCLKCLE can't be used as LFACLK. */
9640       EFM_ASSERT(ref != cmuSelect_HFCLKLE);
9641       SL_FALLTHROUGH
9642       /* Fall through and select the clock source. */
9643 
9644 #if defined(_CMU_LFCCLKSEL_MASK)
9645     case CMU_LFCCLKSEL_REG:
9646       selReg = (selReg == NULL) ? &CMU->LFCCLKSEL : selReg;
9647       /* HFCLKCLE can't be used as LFCCLK. */
9648       EFM_ASSERT(ref != cmuSelect_HFCLKLE);
9649       SL_FALLTHROUGH
9650 #endif
9651     /* Fall through and select the clock source. */
9652 
9653     case CMU_LFECLKSEL_REG:
9654       selReg = (selReg == NULL) ? &CMU->LFECLKSEL : selReg;
9655       /* HFCLKCLE can't be used as LFECLK. */
9656       EFM_ASSERT(ref != cmuSelect_HFCLKLE);
9657       SL_FALLTHROUGH
9658     /* Fall through and select the clock source. */
9659 
9660     case CMU_LFBCLKSEL_REG:
9661       selReg = (selReg == NULL) ? &CMU->LFBCLKSEL : selReg;
9662       switch (ref) {
9663         case cmuSelect_Disabled:
9664           tmp = _CMU_LFACLKSEL_LFA_DISABLED;
9665           break;
9666 
9667         case cmuSelect_LFXO:
9668           /* Ensure that thes elected oscillator is enabled, waiting for it to stabilize. */
9669           CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
9670           tmp = _CMU_LFACLKSEL_LFA_LFXO;
9671           break;
9672 
9673         case cmuSelect_LFRCO:
9674           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9675           CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
9676           tmp = _CMU_LFACLKSEL_LFA_LFRCO;
9677           break;
9678 
9679         case cmuSelect_HFCLKLE:
9680           /* Ensure the correct HFLE wait-states and enable HFCLK to LE.*/
9681           setHfLeConfig(SystemHFClockGet());
9682           BUS_RegBitWrite(&CMU->HFBUSCLKEN0, _CMU_HFBUSCLKEN0_LE_SHIFT, 1);
9683           tmp = _CMU_LFBCLKSEL_LFB_HFCLKLE;
9684           break;
9685 
9686         case cmuSelect_ULFRCO:
9687           /* ULFRCO is always on, there is no need to enable it. */
9688           tmp = _CMU_LFACLKSEL_LFA_ULFRCO;
9689           break;
9690 
9691 #if defined(PLFRCO_PRESENT)
9692         case cmuSelect_PLFRCO:
9693           CMU_OscillatorEnable(cmuOsc_PLFRCO, true, true);
9694           tmp = _CMU_LFACLKSEL_LFA_PLFRCO;
9695           break;
9696 #endif
9697 
9698         default:
9699           EFM_ASSERT(false);
9700           return;
9701       }
9702       *selReg = tmp;
9703       break;
9704 
9705 #elif defined(_SILICON_LABS_32B_SERIES_0)
9706     case CMU_LFACLKSEL_REG:
9707     case CMU_LFBCLKSEL_REG:
9708       switch (ref) {
9709         case cmuSelect_Disabled:
9710           tmp = _CMU_LFCLKSEL_LFA_DISABLED;
9711           break;
9712 
9713         case cmuSelect_LFXO:
9714           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9715           CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
9716           tmp = _CMU_LFCLKSEL_LFA_LFXO;
9717           break;
9718 
9719         case cmuSelect_LFRCO:
9720           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9721           CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
9722           tmp = _CMU_LFCLKSEL_LFA_LFRCO;
9723           break;
9724 
9725         case cmuSelect_HFCLKLE:
9726 #if defined(CMU_MAX_FREQ_HFLE)
9727           /* Set the HFLE wait-state and divider. */
9728           freq = SystemCoreClockGet();
9729           setHfLeConfig(freq);
9730 #endif
9731           /* Ensure HFCORE to LE clocking is enabled. */
9732           BUS_RegBitWrite(&CMU->HFCORECLKEN0, _CMU_HFCORECLKEN0_LE_SHIFT, 1);
9733           tmp = _CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2;
9734           break;
9735 
9736 #if defined(CMU_LFCLKSEL_LFAE_ULFRCO)
9737         case cmuSelect_ULFRCO:
9738           /* ULFRCO is always enabled. */
9739           tmp = _CMU_LFCLKSEL_LFA_DISABLED;
9740           lfExtended = 1;
9741           break;
9742 #endif
9743 
9744         default:
9745           /* An illegal clock source for LFA/LFB selected. */
9746           EFM_ASSERT(false);
9747           return;
9748       }
9749 
9750       /* Apply select. */
9751       if (selRegId == CMU_LFACLKSEL_REG) {
9752 #if defined(_CMU_LFCLKSEL_LFAE_MASK)
9753         CMU->LFCLKSEL = (CMU->LFCLKSEL
9754                          & ~(_CMU_LFCLKSEL_LFA_MASK | _CMU_LFCLKSEL_LFAE_MASK))
9755                         | (tmp << _CMU_LFCLKSEL_LFA_SHIFT)
9756                         | (lfExtended << _CMU_LFCLKSEL_LFAE_SHIFT);
9757 #else
9758         CMU->LFCLKSEL = (CMU->LFCLKSEL & ~_CMU_LFCLKSEL_LFA_MASK)
9759                         | (tmp << _CMU_LFCLKSEL_LFA_SHIFT);
9760 #endif
9761       } else {
9762 #if defined(_CMU_LFCLKSEL_LFBE_MASK)
9763         CMU->LFCLKSEL = (CMU->LFCLKSEL
9764                          & ~(_CMU_LFCLKSEL_LFB_MASK | _CMU_LFCLKSEL_LFBE_MASK))
9765                         | (tmp << _CMU_LFCLKSEL_LFB_SHIFT)
9766                         | (lfExtended << _CMU_LFCLKSEL_LFBE_SHIFT);
9767 #else
9768         CMU->LFCLKSEL = (CMU->LFCLKSEL & ~_CMU_LFCLKSEL_LFB_MASK)
9769                         | (tmp << _CMU_LFCLKSEL_LFB_SHIFT);
9770 #endif
9771       }
9772       break;
9773 
9774 #if defined(_CMU_LFCLKSEL_LFC_MASK)
9775     case CMU_LFCCLKSEL_REG:
9776       switch (ref) {
9777         case cmuSelect_Disabled:
9778           tmp = _CMU_LFCLKSEL_LFA_DISABLED;
9779           break;
9780 
9781         case cmuSelect_LFXO:
9782           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9783           CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
9784           tmp = _CMU_LFCLKSEL_LFC_LFXO;
9785           break;
9786 
9787         case cmuSelect_LFRCO:
9788           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9789           CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
9790           tmp = _CMU_LFCLKSEL_LFC_LFRCO;
9791           break;
9792 
9793         default:
9794           /* An illegal clock source for LFC selected. */
9795           EFM_ASSERT(false);
9796           return;
9797       }
9798 
9799       /* Apply select. */
9800       CMU->LFCLKSEL = (CMU->LFCLKSEL & ~_CMU_LFCLKSEL_LFC_MASK)
9801                       | (tmp << _CMU_LFCLKSEL_LFC_SHIFT);
9802       break;
9803 #endif
9804 #endif
9805 
9806 #if defined(_CMU_DBGCLKSEL_DBG_MASK) || defined(CMU_CTRL_DBGCLK)
9807     case CMU_DBGCLKSEL_REG:
9808       switch (ref) {
9809 #if defined(_CMU_DBGCLKSEL_DBG_MASK)
9810         case cmuSelect_AUXHFRCO:
9811           /* Select AUXHFRCO as a debug clock. */
9812           CMU->DBGCLKSEL = CMU_DBGCLKSEL_DBG_AUXHFRCO;
9813           break;
9814 
9815         case cmuSelect_HFCLK:
9816           /* Select divided HFCLK as a debug clock. */
9817           CMU->DBGCLKSEL = CMU_DBGCLKSEL_DBG_HFCLK;
9818           break;
9819 #endif
9820 
9821 #if defined(CMU_CTRL_DBGCLK)
9822         case cmuSelect_AUXHFRCO:
9823           /* Select AUXHFRCO as a debug clock. */
9824           CMU->CTRL = (CMU->CTRL & ~(_CMU_CTRL_DBGCLK_MASK))
9825                       | CMU_CTRL_DBGCLK_AUXHFRCO;
9826           break;
9827 
9828         case cmuSelect_HFCLK:
9829           /* Select divided HFCLK as a debug clock. */
9830           CMU->CTRL = (CMU->CTRL & ~(_CMU_CTRL_DBGCLK_MASK))
9831                       | CMU_CTRL_DBGCLK_HFCLK;
9832           break;
9833 #endif
9834 
9835         default:
9836           /* An illegal clock source for debug selected. */
9837           EFM_ASSERT(false);
9838           return;
9839       }
9840       break;
9841 #endif
9842 
9843 #if defined(USBC_CLOCK_PRESENT)
9844     case CMU_USBCCLKSEL_REG:
9845       switch (ref) {
9846         case cmuSelect_LFXO:
9847           /* Select LFXO as a clock source for USB. It can only be used in sleep mode. */
9848           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9849           CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
9850 
9851           /* Switch the oscillator. */
9852           CMU->CMD = CMU_CMD_USBCCLKSEL_LFXO;
9853 
9854           /* Wait until the clock is activated. */
9855           while ((CMU->STATUS & CMU_STATUS_USBCLFXOSEL) == 0) {
9856           }
9857           break;
9858 
9859         case cmuSelect_LFRCO:
9860           /* Select LFRCO as a clock source for USB. It can only be used in sleep mode. */
9861           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9862           CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
9863 
9864           /* Switch the oscillator. */
9865           CMU->CMD = CMU_CMD_USBCCLKSEL_LFRCO;
9866 
9867           /* Wait until the clock is activated. */
9868           while ((CMU->STATUS & CMU_STATUS_USBCLFRCOSEL) == 0) {
9869           }
9870           break;
9871 
9872 #if defined(CMU_STATUS_USBCHFCLKSEL)
9873         case cmuSelect_HFCLK:
9874           /* Select undivided HFCLK as a clock source for USB. */
9875           /* The oscillator must already be enabled to avoid a core lockup. */
9876           CMU->CMD = CMU_CMD_USBCCLKSEL_HFCLKNODIV;
9877           /* Wait until the clock is activated. */
9878           while ((CMU->STATUS & CMU_STATUS_USBCHFCLKSEL) == 0) {
9879           }
9880           break;
9881 #endif
9882 
9883 #if defined(CMU_CMD_USBCCLKSEL_USHFRCO)
9884         case cmuSelect_USHFRCO:
9885           /* Select USHFRCO as a clock source for USB. */
9886           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9887           CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
9888 
9889           /* Switch the oscillator. */
9890           CMU->CMD = CMU_CMD_USBCCLKSEL_USHFRCO;
9891 
9892           /* Wait until the clock is activated. */
9893           while ((CMU->STATUS & CMU_STATUS_USBCUSHFRCOSEL) == 0) {
9894           }
9895           break;
9896 #endif
9897 
9898         default:
9899           /* An illegal clock source for USB. */
9900           EFM_ASSERT(false);
9901           return;
9902       }
9903       break;
9904 #endif
9905 
9906 #if defined(_CMU_ADCCTRL_ADC0CLKSEL_MASK)
9907     case CMU_ADC0ASYNCSEL_REG:
9908       switch (ref) {
9909         case cmuSelect_Disabled:
9910           tmp = _CMU_ADCCTRL_ADC0CLKSEL_DISABLED;
9911           break;
9912 
9913         case cmuSelect_AUXHFRCO:
9914           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9915           CMU_OscillatorEnable(cmuOsc_AUXHFRCO, true, true);
9916           tmp = _CMU_ADCCTRL_ADC0CLKSEL_AUXHFRCO;
9917           break;
9918 
9919         case cmuSelect_HFXO:
9920           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9921           CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
9922           tmp = _CMU_ADCCTRL_ADC0CLKSEL_HFXO;
9923           break;
9924 
9925         case cmuSelect_HFSRCCLK:
9926           tmp = _CMU_ADCCTRL_ADC0CLKSEL_HFSRCCLK;
9927           break;
9928 
9929         default:
9930           /* An illegal clock source for ADC0ASYNC selected. */
9931           EFM_ASSERT(false);
9932           return;
9933       }
9934 
9935       /* Apply select. */
9936       CMU->ADCCTRL = (CMU->ADCCTRL & ~_CMU_ADCCTRL_ADC0CLKSEL_MASK)
9937                      | (tmp << _CMU_ADCCTRL_ADC0CLKSEL_SHIFT);
9938       break;
9939 #endif
9940 
9941 #if defined(_CMU_ADCCTRL_ADC1CLKSEL_MASK)
9942     case CMU_ADC1ASYNCSEL_REG:
9943       switch (ref) {
9944         case cmuSelect_Disabled:
9945           tmp = _CMU_ADCCTRL_ADC1CLKSEL_DISABLED;
9946           break;
9947 
9948         case cmuSelect_AUXHFRCO:
9949           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9950           CMU_OscillatorEnable(cmuOsc_AUXHFRCO, true, true);
9951           tmp = _CMU_ADCCTRL_ADC1CLKSEL_AUXHFRCO;
9952           break;
9953 
9954         case cmuSelect_HFXO:
9955           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9956           CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
9957           tmp = _CMU_ADCCTRL_ADC1CLKSEL_HFXO;
9958           break;
9959 
9960         case cmuSelect_HFSRCCLK:
9961           tmp = _CMU_ADCCTRL_ADC1CLKSEL_HFSRCCLK;
9962           break;
9963 
9964         default:
9965           /* An illegal clock source for ADC1ASYNC selected. */
9966           EFM_ASSERT(false);
9967           return;
9968       }
9969 
9970       /* Apply select. */
9971       CMU->ADCCTRL = (CMU->ADCCTRL & ~_CMU_ADCCTRL_ADC1CLKSEL_MASK)
9972                      | (tmp << _CMU_ADCCTRL_ADC1CLKSEL_SHIFT);
9973       break;
9974 #endif
9975 
9976 #if defined(_CMU_SDIOCTRL_SDIOCLKSEL_MASK)
9977     case CMU_SDIOREFSEL_REG:
9978       switch (ref) {
9979         case cmuSelect_HFRCO:
9980           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9981           CMU_OscillatorEnable(cmuOsc_HFRCO, true, true);
9982           tmp = _CMU_SDIOCTRL_SDIOCLKSEL_HFRCO;
9983           break;
9984 
9985         case cmuSelect_HFXO:
9986           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9987           CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
9988           tmp = _CMU_SDIOCTRL_SDIOCLKSEL_HFXO;
9989           break;
9990 
9991         case cmuSelect_AUXHFRCO:
9992           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9993           CMU_OscillatorEnable(cmuOsc_AUXHFRCO, true, true);
9994           tmp = _CMU_SDIOCTRL_SDIOCLKSEL_AUXHFRCO;
9995           break;
9996 
9997         case cmuSelect_USHFRCO:
9998           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
9999           CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
10000           tmp = _CMU_SDIOCTRL_SDIOCLKSEL_USHFRCO;
10001           break;
10002 
10003         default:
10004           /* An illegal clock source for SDIOREF selected. */
10005           EFM_ASSERT(false);
10006           return;
10007       }
10008 
10009       /* Apply select. */
10010       CMU->SDIOCTRL = (CMU->SDIOCTRL & ~_CMU_SDIOCTRL_SDIOCLKSEL_MASK)
10011                       | (tmp << _CMU_SDIOCTRL_SDIOCLKSEL_SHIFT);
10012       break;
10013 #endif
10014 
10015 #if defined(_CMU_QSPICTRL_QSPI0CLKSEL_MASK)
10016     case CMU_QSPI0REFSEL_REG:
10017       switch (ref) {
10018         case cmuSelect_HFRCO:
10019           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
10020           CMU_OscillatorEnable(cmuOsc_HFRCO, true, true);
10021           tmp = _CMU_QSPICTRL_QSPI0CLKSEL_HFRCO;
10022           break;
10023 
10024         case cmuSelect_HFXO:
10025           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
10026           CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
10027           tmp = _CMU_QSPICTRL_QSPI0CLKSEL_HFXO;
10028           break;
10029 
10030         case cmuSelect_AUXHFRCO:
10031           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
10032           CMU_OscillatorEnable(cmuOsc_AUXHFRCO, true, true);
10033           tmp = _CMU_QSPICTRL_QSPI0CLKSEL_AUXHFRCO;
10034           break;
10035 
10036         case cmuSelect_USHFRCO:
10037           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
10038           CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
10039           tmp = _CMU_QSPICTRL_QSPI0CLKSEL_USHFRCO;
10040           break;
10041 
10042         default:
10043           /* An illegal clock source for QSPI0REF selected. */
10044           EFM_ASSERT(false);
10045           return;
10046       }
10047 
10048       /* Apply select. */
10049       CMU->QSPICTRL = (CMU->QSPICTRL & ~_CMU_QSPICTRL_QSPI0CLKSEL_MASK)
10050                       | (tmp << _CMU_QSPICTRL_QSPI0CLKSEL_SHIFT);
10051       break;
10052 #endif
10053 
10054 #if defined(_CMU_USBCTRL_USBCLKSEL_MASK)
10055     case CMU_USBRCLKSEL_REG:
10056       switch (ref) {
10057         case cmuSelect_USHFRCO:
10058           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
10059           CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
10060           tmp = _CMU_USBCTRL_USBCLKSEL_USHFRCO;
10061           break;
10062 
10063         case cmuSelect_HFXO:
10064           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
10065           CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
10066           tmp = _CMU_USBCTRL_USBCLKSEL_HFXO;
10067           break;
10068 
10069         case cmuSelect_HFXOX2:
10070           /* Only allowed for HFXO frequencies up to 25 MHz. */
10071           EFM_ASSERT(SystemHFXOClockGet() <= 25000000u);
10072 
10073           /* Enable HFXO X2. */
10074           CMU->HFXOCTRL |= CMU_HFXOCTRL_HFXOX2EN;
10075 
10076           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
10077           CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
10078 
10079           tmp = _CMU_USBCTRL_USBCLKSEL_HFXOX2;
10080           break;
10081 
10082         case cmuSelect_HFRCO:
10083           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
10084           CMU_OscillatorEnable(cmuOsc_HFRCO, true, true);
10085           tmp = _CMU_USBCTRL_USBCLKSEL_HFRCO;
10086           break;
10087 
10088         case cmuSelect_LFXO:
10089           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
10090           CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
10091           tmp = _CMU_USBCTRL_USBCLKSEL_LFXO;
10092           break;
10093 
10094         case cmuSelect_LFRCO:
10095           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
10096           CMU_OscillatorEnable(cmuOsc_LFRCO, true, true);
10097           tmp = _CMU_USBCTRL_USBCLKSEL_LFRCO;
10098           break;
10099 
10100         default:
10101           /* An illegal clock source for USBR selected. */
10102           EFM_ASSERT(false);
10103           return;
10104       }
10105 
10106       /* Apply select. */
10107       CMU->USBCTRL = (CMU->USBCTRL & ~_CMU_USBCTRL_USBCLKSEL_MASK)
10108                      | (tmp << _CMU_USBCTRL_USBCLKSEL_SHIFT);
10109       break;
10110 #endif
10111 
10112 #if defined(_CMU_PDMCTRL_PDMCLKSEL_MASK)
10113     case CMU_PDMREFSEL_REG:
10114       switch (ref) {
10115         case cmuSelect_USHFRCO:
10116           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
10117           CMU_OscillatorEnable(cmuOsc_USHFRCO, true, true);
10118           tmp = _CMU_PDMCTRL_PDMCLKSEL_USHFRCO;
10119           break;
10120 
10121         case cmuSelect_HFXO:
10122           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
10123           CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
10124           tmp = _CMU_PDMCTRL_PDMCLKSEL_HFXO;
10125           break;
10126 
10127         case cmuSelect_HFRCO:
10128           /* Ensure that the selected oscillator is enabled, waiting for it to stabilize. */
10129           CMU_OscillatorEnable(cmuOsc_HFRCO, true, true);
10130           tmp = _CMU_PDMCTRL_PDMCLKSEL_HFRCO;
10131           break;
10132 
10133         default:
10134           /* An illegal clock source for PDMREF selected. */
10135           EFM_ASSERT(false);
10136           return;
10137       }
10138 
10139       /* Apply select. */
10140       CMU->PDMCTRL = (CMU->PDMCTRL & ~_CMU_PDMCTRL_PDMCLKSEL_MASK)
10141                      | (tmp << _CMU_PDMCTRL_PDMCLKSEL_SHIFT);
10142       break;
10143 #endif
10144 
10145     default:
10146       EFM_ASSERT(false);
10147       break;
10148   }
10149 }
10150 
10151 /***************************************************************************//**
10152  * @brief
10153  *   Gets the precision (in PPM) of the specified low frequency clock branch.
10154  *
10155  * @param[in] clock
10156  *   Clock branch.
10157  *
10158  * @return
10159  *   Precision, in PPM, of the specified clock branch.
10160  *
10161  * @note
10162  *   This function is only for internal usage.
10163  *
10164  * @note
10165  *   The current implementation of this function is used to determine if the
10166  *   clock has a precision <= 500 ppm or not (which is the minimum required
10167  *   for BLE). Future version of this function should provide more accurate
10168  *   precision numbers to allow for further optimizations from the stacks.
10169  ******************************************************************************/
CMU_LF_ClockPrecisionGet(CMU_Clock_TypeDef clock)10170 uint16_t CMU_LF_ClockPrecisionGet(CMU_Clock_TypeDef clock)
10171 {
10172   CMU_Select_TypeDef src = CMU_ClockSelectGet(clock);
10173   uint16_t precision;
10174 
10175   switch (src) {
10176     case cmuSelect_LFXO:
10177       precision = lfxo_precision;
10178       break;
10179 
10180 #if defined(_SILICON_LABS_32B_SERIES_1) && defined(PLFRCO_PRESENT)
10181     case cmuSelect_PLFRCO:
10182       precision = 500;
10183       break;
10184 #endif
10185 
10186     default:
10187       precision = 0xFFFF;
10188       break;
10189   }
10190 
10191   return precision;
10192 }
10193 
10194 /***************************************************************************//**
10195  * @brief
10196  *   Gets the precision (in PPM) of the specified high frequency clock branch.
10197  *
10198  * @param[in] clock
10199  *   Clock branch.
10200  *
10201  * @return
10202  *   Precision, in PPM, of the specified clock branch.
10203  *
10204  * @note
10205  *   This function is only for internal usage.
10206  *
10207  * @note
10208  *   The current implementation of this function is used to determine if the
10209  *   clock has a precision <= 500 ppm or not (which is the minimum required
10210  *   for BLE). Future version of this function should provide more accurate
10211  *   precision numbers to allow for further optimizations from the stacks.
10212  ******************************************************************************/
CMU_HF_ClockPrecisionGet(CMU_Clock_TypeDef clock)10213 uint16_t CMU_HF_ClockPrecisionGet(CMU_Clock_TypeDef clock)
10214 {
10215   CMU_Select_TypeDef src = CMU_ClockSelectGet(clock);
10216   uint16_t precision;
10217 
10218   switch (src) {
10219     case cmuSelect_HFXO:
10220       precision = hfxo_precision;
10221       break;
10222 
10223     case cmuSelect_HFRCO:
10224       precision = 0xFFFF;
10225       break;
10226 
10227     default:
10228       precision = 0xFFFF;
10229       break;
10230   }
10231 
10232   return precision;
10233 }
10234 
10235 #if defined(CMU_OSCENCMD_DPLLEN)
10236 /**************************************************************************//**
10237  * @brief
10238  *   Lock the DPLL to a given frequency.
10239  *
10240  *   The frequency is given by: Fout = Fref * (N+1) / (M+1).
10241  *
10242  * @note
10243  *   This function does not check if the given N & M values will actually
10244  *   produce the desired target frequency. @n
10245  *   N & M limitations: @n
10246  *     300 < N <= 4095 @n
10247  *     0 <= M <= 4095 @n
10248  *   Any peripheral running off HFRCO should be switched to HFRCODIV2 prior to
10249  *   calling this function to avoid over-clocking.
10250  *
10251  *   HFCLKLE prescaler is automatically modified before updating HFRCO
10252  *   based on the maximum HFLE frequency allowed.
10253  *
10254  * @param[in] init
10255  *    DPLL setup parameters.
10256  *
10257  * @return
10258  *   Returns false on invalid target frequency or DPLL locking error.
10259  *****************************************************************************/
CMU_DPLLLock(const CMU_DPLLInit_TypeDef * init)10260 bool CMU_DPLLLock(const CMU_DPLLInit_TypeDef *init)
10261 {
10262   int index = 0;
10263   unsigned int i;
10264   bool hfrcoDiv2override = false;
10265   uint32_t hfrcoCtrlVal, lockStatus, sysFreq;
10266 
10267   EFM_ASSERT(init->frequency >= hfrcoCtrlTable[0].minFreq);
10268   EFM_ASSERT(init->frequency
10269              <= hfrcoCtrlTable[HFRCOCTRLTABLE_ENTRIES - 1U].maxFreq);
10270   EFM_ASSERT(init->n > 300U);
10271   EFM_ASSERT(init->n <= (_CMU_DPLLCTRL1_N_MASK >> _CMU_DPLLCTRL1_N_SHIFT));
10272   EFM_ASSERT(init->m <= (_CMU_DPLLCTRL1_M_MASK >> _CMU_DPLLCTRL1_M_SHIFT));
10273   EFM_ASSERT(init->ssInterval  <= (_CMU_HFRCOSS_SSINV_MASK
10274                                    >> _CMU_HFRCOSS_SSINV_SHIFT));
10275   EFM_ASSERT(init->ssAmplitude <= (_CMU_HFRCOSS_SSAMP_MASK
10276                                    >> _CMU_HFRCOSS_SSAMP_SHIFT));
10277 
10278 #if defined(_EMU_STATUS_VSCALE_MASK)
10279   if ((EMU_VScaleGet() == emuVScaleEM01_LowPower)
10280       && (init->frequency > CMU_VSCALEEM01_LOWPOWER_VOLTAGE_CLOCK_MAX)) {
10281     EFM_ASSERT(false);
10282     return false;
10283   }
10284 #endif
10285 
10286   // Find the correct HFRCO band and retrieve a HFRCOCTRL value.
10287   for (i = 0; i < HFRCOCTRLTABLE_ENTRIES; i++) {
10288     if ((init->frequency    >= hfrcoCtrlTable[i].minFreq)
10289         && (init->frequency <= hfrcoCtrlTable[i].maxFreq)) {
10290       index = (int)i;                       // Correct band found
10291       break;
10292     }
10293   }
10294   if ((uint32_t)index == HFRCOCTRLTABLE_ENTRIES) {
10295     EFM_ASSERT(false);
10296     return false;                           // Target frequency out of spec.
10297   }
10298   hfrcoCtrlVal = hfrcoCtrlTable[index].value;
10299 
10300   // Check if a calibrated HFRCOCTRL.TUNING value is in device DI page.
10301   if (hfrcoCtrlTable[index].band != (CMU_HFRCOFreq_TypeDef)0) {
10302     uint32_t tuning;
10303 
10304     tuning = (CMU_HFRCODevinfoGet(hfrcoCtrlTable[index].band)
10305               & _CMU_HFRCOCTRL_TUNING_MASK)
10306              >> _CMU_HFRCOCTRL_TUNING_SHIFT;
10307 
10308     // When HFRCOCTRL.FINETUNINGEN is enabled, the center frequency
10309     // of the band shifts down by 5.8%. 9 is subtracted to compensate.
10310     if (tuning > 9UL) {
10311       tuning -= 9UL;
10312     } else {
10313       tuning = 0UL;
10314     }
10315 
10316     hfrcoCtrlVal |= tuning << _CMU_HFRCOCTRL_TUNING_SHIFT;
10317   }
10318 
10319   // Update the CMSIS frequency SystemHfrcoFreq value.
10320   SystemHfrcoFreq = init->frequency;
10321 
10322   // Set maximum wait-states while changing the core clock.
10323   if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
10324     flashWaitStateMax();
10325   }
10326 
10327   // Update the HFLE configuration before updating HFRCO, use new DPLL frequency.
10328   if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
10329     setHfLeConfig(init->frequency);
10330 
10331     // Switch to HFRCO/2 before setting DPLL to avoid over-clocking.
10332     hfrcoDiv2override = true;
10333     CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFRCODIV2;
10334   }
10335 
10336   CMU->OSCENCMD  = CMU_OSCENCMD_DPLLDIS;
10337   while ((CMU->STATUS & (CMU_STATUS_DPLLENS | CMU_STATUS_DPLLRDY)) != 0UL) {
10338   }
10339   CMU->IFC       = CMU_IFC_DPLLRDY | CMU_IFC_DPLLLOCKFAILLOW
10340                    | CMU_IFC_DPLLLOCKFAILHIGH;
10341   CMU->DPLLCTRL1 = ((uint32_t)init->n   << _CMU_DPLLCTRL1_N_SHIFT)
10342                    | ((uint32_t)init->m << _CMU_DPLLCTRL1_M_SHIFT);
10343   CMU->HFRCOCTRL = hfrcoCtrlVal;
10344   CMU->DPLLCTRL  = ((uint32_t)init->refClk << _CMU_DPLLCTRL_REFSEL_SHIFT)
10345                    | ((init->autoRecover ? 1UL : 0UL)
10346                       << _CMU_DPLLCTRL_AUTORECOVER_SHIFT)
10347                    | ((uint32_t)init->edgeSel << _CMU_DPLLCTRL_EDGESEL_SHIFT)
10348                    | ((uint32_t)init->lockMode << _CMU_DPLLCTRL_MODE_SHIFT);
10349   CMU->OSCENCMD  = CMU_OSCENCMD_DPLLEN;
10350   while ((lockStatus = (CMU->IF & (CMU_IF_DPLLRDY
10351                                    | CMU_IF_DPLLLOCKFAILLOW
10352                                    | CMU_IF_DPLLLOCKFAILHIGH))) == 0UL) {
10353   }
10354 
10355   // Restore to HFRCO
10356   if ((CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCODIV2)
10357       && (hfrcoDiv2override == true)) {
10358     CMU->HFCLKSEL = CMU_HFCLKSEL_HF_HFRCO;
10359   }
10360 
10361   // If HFRCO is selected as an HF clock, optimize the flash access wait-state
10362   // configuration for this frequency and update the CMSIS core clock variable.
10363   if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
10364     // Call @ref SystemCoreClockGet() to update the CMSIS core clock variable.
10365     sysFreq = SystemCoreClockGet();
10366     EFM_ASSERT(sysFreq <= init->frequency);
10367     EFM_ASSERT(sysFreq <= SystemHfrcoFreq);
10368     EFM_ASSERT(init->frequency == SystemHfrcoFreq);
10369     CMU_UpdateWaitStates(sysFreq, VSCALE_DEFAULT);
10370   }
10371 
10372   // Reduce HFLE frequency if possible.
10373   setHfLeConfig(SystemHFClockGet());
10374 
10375 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
10376   // Update voltage scaling.
10377   EMU_VScaleEM01ByClock(0, true);
10378 #endif
10379 
10380   if (lockStatus == CMU_IF_DPLLRDY) {
10381     return true;
10382   }
10383   return false;
10384 }
10385 #endif // CMU_OSCENCMD_DPLLEN
10386 
10387 /**************************************************************************//**
10388  * @brief
10389  *   CMU low frequency register synchronization freeze control.
10390  *
10391  * @details
10392  *   Some CMU registers require synchronization into the low-frequency (LF)
10393  *   domain. The freeze feature allows for several such registers to be
10394  *   modified before passing them to the LF domain simultaneously (which
10395  *   takes place when the freeze mode is disabled).
10396  *
10397  *   Another use case for this feature is using an API (such
10398  *   as the CMU API) for modifying several bit fields consecutively in the
10399  *   same register. If freeze mode is enabled during this sequence, stalling
10400  *   can be avoided.
10401  *
10402  * @note
10403  *   When enabling freeze mode, this function will wait for all current
10404  *   ongoing CMU synchronization to LF domain to complete (normally
10405  *   synchronization will not be in progress.) However, for this reason, when
10406  *   using freeze mode, modifications of registers requiring LF synchronization
10407  *   should be done within one freeze enable/disable block to avoid unnecessary
10408  *   stalling.
10409  *
10410  * @param[in] enable
10411  *   @li true - enable freeze, modified registers are not propagated to the
10412  *       LF domain
10413  *   @li false - disable freeze, modified registers are propagated to the LF
10414  *       domain
10415  *****************************************************************************/
CMU_FreezeEnable(bool enable)10416 void CMU_FreezeEnable(bool enable)
10417 {
10418   if (enable) {
10419     /* Wait for any ongoing LF synchronizations to complete. This */
10420     /* protects against the rare case when a user                            */
10421     /* - modifies a register requiring LF sync                              */
10422     /* - then enables freeze before LF sync completed                       */
10423     /* - then modifies the same register again                              */
10424     /* since modifying a register while it is in sync progress should be    */
10425     /* avoided.                                                             */
10426     while (CMU->SYNCBUSY != 0UL) {
10427     }
10428 
10429     CMU->FREEZE = CMU_FREEZE_REGFREEZE;
10430   } else {
10431     CMU->FREEZE = 0;
10432   }
10433 }
10434 
10435 #if defined(_CMU_HFRCOCTRL_BAND_MASK)
10436 /***************************************************************************//**
10437  * @brief
10438  *   Get HFRCO band in use.
10439  *
10440  * @return
10441  *   HFRCO band in use.
10442  ******************************************************************************/
CMU_HFRCOBandGet(void)10443 CMU_HFRCOBand_TypeDef CMU_HFRCOBandGet(void)
10444 {
10445   return (CMU_HFRCOBand_TypeDef)((CMU->HFRCOCTRL & _CMU_HFRCOCTRL_BAND_MASK)
10446                                  >> _CMU_HFRCOCTRL_BAND_SHIFT);
10447 }
10448 #endif /* _CMU_HFRCOCTRL_BAND_MASK */
10449 
10450 #if defined(_CMU_HFRCOCTRL_BAND_MASK)
10451 /***************************************************************************//**
10452  * @brief
10453  *   Set HFRCO band and the tuning value based on the value in the calibration
10454  *   table made during production.
10455  *
10456  * @note
10457  *   HFCLKLE prescaler is automatically modified based on the maximum
10458  *   HFLE frequency allowed.
10459  *
10460  * @param[in] band
10461  *   HFRCO band to activate.
10462  ******************************************************************************/
CMU_HFRCOBandSet(CMU_HFRCOBand_TypeDef band)10463 void CMU_HFRCOBandSet(CMU_HFRCOBand_TypeDef band)
10464 {
10465   uint32_t           tuning;
10466   uint32_t           freq;
10467   CMU_Select_TypeDef osc;
10468 
10469   /* Read the tuning value from the calibration table. */
10470   switch (band) {
10471     case cmuHFRCOBand_1MHz:
10472       tuning = (DEVINFO->HFRCOCAL0 & _DEVINFO_HFRCOCAL0_BAND1_MASK)
10473                >> _DEVINFO_HFRCOCAL0_BAND1_SHIFT;
10474       break;
10475 
10476     case cmuHFRCOBand_7MHz:
10477       tuning = (DEVINFO->HFRCOCAL0 & _DEVINFO_HFRCOCAL0_BAND7_MASK)
10478                >> _DEVINFO_HFRCOCAL0_BAND7_SHIFT;
10479       break;
10480 
10481     case cmuHFRCOBand_11MHz:
10482       tuning = (DEVINFO->HFRCOCAL0 & _DEVINFO_HFRCOCAL0_BAND11_MASK)
10483                >> _DEVINFO_HFRCOCAL0_BAND11_SHIFT;
10484       break;
10485 
10486     case cmuHFRCOBand_14MHz:
10487       tuning = (DEVINFO->HFRCOCAL0 & _DEVINFO_HFRCOCAL0_BAND14_MASK)
10488                >> _DEVINFO_HFRCOCAL0_BAND14_SHIFT;
10489       break;
10490 
10491     case cmuHFRCOBand_21MHz:
10492       tuning = (DEVINFO->HFRCOCAL1 & _DEVINFO_HFRCOCAL1_BAND21_MASK)
10493                >> _DEVINFO_HFRCOCAL1_BAND21_SHIFT;
10494       break;
10495 
10496 #if defined(_CMU_HFRCOCTRL_BAND_28MHZ)
10497     case cmuHFRCOBand_28MHz:
10498       tuning = (DEVINFO->HFRCOCAL1 & _DEVINFO_HFRCOCAL1_BAND28_MASK)
10499                >> _DEVINFO_HFRCOCAL1_BAND28_SHIFT;
10500       break;
10501 #endif
10502 
10503     default:
10504       EFM_ASSERT(false);
10505       return;
10506   }
10507 
10508   /* If HFRCO is used for the core clock, flash access WS has to be considered. */
10509   osc = CMU_ClockSelectGet(cmuClock_HF);
10510   if (osc == cmuSelect_HFRCO) {
10511     /* Configure worst case wait states for flash access before setting the divider. */
10512     flashWaitStateMax();
10513   }
10514 
10515   /* Set band/tuning. */
10516   CMU->HFRCOCTRL = (CMU->HFRCOCTRL
10517                     & ~(_CMU_HFRCOCTRL_BAND_MASK | _CMU_HFRCOCTRL_TUNING_MASK))
10518                    | (band << _CMU_HFRCOCTRL_BAND_SHIFT)
10519                    | (tuning << _CMU_HFRCOCTRL_TUNING_SHIFT);
10520 
10521   /* If HFRCO is used for the core clock, optimize flash WS. */
10522   if (osc == cmuSelect_HFRCO) {
10523     /* Call @ref SystemCoreClockGet() to update the CMSIS core clock variable. */
10524     freq = SystemCoreClockGet();
10525     CMU_UpdateWaitStates(freq, VSCALE_DEFAULT);
10526   }
10527 
10528 #if defined(CMU_MAX_FREQ_HFLE)
10529   /* Reduce HFLE frequency if possible. */
10530   setHfLeConfig(SystemCoreClockGet());
10531 #endif
10532 }
10533 #endif /* _CMU_HFRCOCTRL_BAND_MASK */
10534 
10535 #if defined(_CMU_HFRCOCTRL_FREQRANGE_MASK)
10536 /**************************************************************************//**
10537  * @brief
10538  *   Get the HFRCO frequency calibration word in DEVINFO.
10539  *
10540  * @param[in] freq
10541  *   Frequency in Hz.
10542  *
10543  * @return
10544  *   HFRCO calibration word for a given frequency.
10545  *****************************************************************************/
CMU_HFRCODevinfoGet(CMU_HFRCOFreq_TypeDef freq)10546 static uint32_t CMU_HFRCODevinfoGet(CMU_HFRCOFreq_TypeDef freq)
10547 {
10548   switch (freq) {
10549     /* 1, 2, and 4 MHz share the same calibration word. */
10550     case cmuHFRCOFreq_1M0Hz:
10551     case cmuHFRCOFreq_2M0Hz:
10552     case cmuHFRCOFreq_4M0Hz:
10553       return DEVINFO->HFRCOCAL0;
10554 
10555     case cmuHFRCOFreq_7M0Hz:
10556       return DEVINFO->HFRCOCAL3;
10557 
10558     case cmuHFRCOFreq_13M0Hz:
10559       return DEVINFO->HFRCOCAL6;
10560 
10561     case cmuHFRCOFreq_16M0Hz:
10562       return DEVINFO->HFRCOCAL7;
10563 
10564     case cmuHFRCOFreq_19M0Hz:
10565       return DEVINFO->HFRCOCAL8;
10566 
10567     case cmuHFRCOFreq_26M0Hz:
10568       return DEVINFO->HFRCOCAL10;
10569 
10570     case cmuHFRCOFreq_32M0Hz:
10571       return DEVINFO->HFRCOCAL11;
10572 
10573     case cmuHFRCOFreq_38M0Hz:
10574       return DEVINFO->HFRCOCAL12;
10575 
10576 #if defined(_DEVINFO_HFRCOCAL13_MASK)
10577     case cmuHFRCOFreq_48M0Hz:
10578       return DEVINFO->HFRCOCAL13;
10579 #endif
10580 
10581 #if defined(_DEVINFO_HFRCOCAL14_MASK)
10582     case cmuHFRCOFreq_56M0Hz:
10583       return DEVINFO->HFRCOCAL14;
10584 #endif
10585 
10586 #if defined(_DEVINFO_HFRCOCAL15_MASK)
10587     case cmuHFRCOFreq_64M0Hz:
10588       return DEVINFO->HFRCOCAL15;
10589 #endif
10590 
10591 #if defined(_DEVINFO_HFRCOCAL16_MASK)
10592     case cmuHFRCOFreq_72M0Hz:
10593       return DEVINFO->HFRCOCAL16;
10594 #endif
10595 
10596     default: /* cmuHFRCOFreq_UserDefined */
10597       return 0;
10598   }
10599 }
10600 
10601 /***************************************************************************//**
10602  * @brief
10603  *   Get the current HFRCO frequency.
10604  *
10605  * @return
10606  *   HFRCO frequency.
10607  ******************************************************************************/
CMU_HFRCOBandGet(void)10608 CMU_HFRCOFreq_TypeDef CMU_HFRCOBandGet(void)
10609 {
10610   return (CMU_HFRCOFreq_TypeDef)SystemHfrcoFreq;
10611 }
10612 
10613 /***************************************************************************//**
10614  * @brief
10615  *   Set the HFRCO calibration for the selected target frequency.
10616  *
10617  * @note
10618  *   HFCLKLE prescaler is automatically modified based on the maximum
10619  *   HFLE frequency allowed.
10620  *
10621  * @param[in] setFreq
10622  *   HFRCO frequency to set.
10623  ******************************************************************************/
CMU_HFRCOBandSet(CMU_HFRCOFreq_TypeDef setFreq)10624 void CMU_HFRCOBandSet(CMU_HFRCOFreq_TypeDef setFreq)
10625 {
10626   uint32_t freqCal;
10627   uint32_t sysFreq;
10628   uint32_t prevFreq;
10629 
10630   /* Get the DEVINFO index and set the CMSIS frequency SystemHfrcoFreq. */
10631   freqCal = CMU_HFRCODevinfoGet(setFreq);
10632   EFM_ASSERT((freqCal != 0UL) && (freqCal != UINT_MAX));
10633   prevFreq = SystemHfrcoFreq;
10634   SystemHfrcoFreq = (uint32_t)setFreq;
10635 
10636   /* Set maximum wait-states and set safe HFPER clock-tree prescalers while
10637      changing the core clock. */
10638   if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
10639     flashWaitStateMax();
10640     hfperClkSafePrescaler();
10641   }
10642 
10643   /* Wait for any previous sync to complete and set calibration data
10644      for the selected frequency.  */
10645   while (BUS_RegBitRead(&CMU->SYNCBUSY, _CMU_SYNCBUSY_HFRCOBSY_SHIFT) != 0UL) {
10646   }
10647 
10648   /* Check for valid calibration data. */
10649   EFM_ASSERT(freqCal != UINT_MAX);
10650 
10651   /* Set divider in HFRCOCTRL for 1, 2, and 4 MHz. */
10652   switch (setFreq) {
10653     case cmuHFRCOFreq_1M0Hz:
10654       freqCal = (freqCal & ~_CMU_HFRCOCTRL_CLKDIV_MASK)
10655                 | CMU_HFRCOCTRL_CLKDIV_DIV4;
10656       break;
10657 
10658     case cmuHFRCOFreq_2M0Hz:
10659       freqCal = (freqCal & ~_CMU_HFRCOCTRL_CLKDIV_MASK)
10660                 | CMU_HFRCOCTRL_CLKDIV_DIV2;
10661       break;
10662 
10663     case cmuHFRCOFreq_4M0Hz:
10664       freqCal = (freqCal & ~_CMU_HFRCOCTRL_CLKDIV_MASK)
10665                 | CMU_HFRCOCTRL_CLKDIV_DIV1;
10666       break;
10667 
10668     default:
10669       break;
10670   }
10671 
10672   /* Update HFLE configuration before updating HFRCO.
10673      Use the new set frequency. */
10674   if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
10675     /* setFreq is worst-case as dividers may reduce the HFLE frequency. */
10676     setHfLeConfig((uint32_t)setFreq);
10677   }
10678 
10679   if ((uint32_t)setFreq > prevFreq) {
10680 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
10681     /* When increasing frequency voltage scale must be done before the change. */
10682     EMU_VScaleEM01ByClock((uint32_t)setFreq, true);
10683 #endif
10684   }
10685 
10686   CMU->HFRCOCTRL = freqCal;
10687 
10688   /* If HFRCO is selected as an HF clock, optimize the flash access wait-state configuration
10689      for this frequency and update the CMSIS core clock variable. */
10690   if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
10691     /* Call @ref SystemCoreClockGet() to update the CMSIS core clock variable. */
10692     sysFreq = SystemCoreClockGet();
10693     EFM_ASSERT(sysFreq <= (uint32_t)setFreq);
10694     EFM_ASSERT(sysFreq <= SystemHfrcoFreq);
10695     EFM_ASSERT((uint32_t)setFreq == SystemHfrcoFreq);
10696     CMU_UpdateWaitStates(sysFreq, VSCALE_DEFAULT);
10697   }
10698 
10699   /* Reduce HFLE frequency if possible. */
10700   setHfLeConfig(SystemHFClockGet());
10701 
10702   if ((uint32_t)setFreq <= prevFreq) {
10703 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
10704     /* When decreasing frequency voltage scale must be done after the change */
10705     EMU_VScaleEM01ByClock(0, true);
10706 #endif
10707   }
10708   if (CMU_ClockSelectGet(cmuClock_HF) == cmuSelect_HFRCO) {
10709     /* Set optimized HFPER clock-tree prescalers. */
10710     hfperClkOptimizedPrescaler();
10711   }
10712 }
10713 #endif /* _CMU_HFRCOCTRL_FREQRANGE_MASK */
10714 
10715 #if defined(_CMU_HFRCOCTRL_SUDELAY_MASK)
10716 /***************************************************************************//**
10717  * @brief
10718  *   Get the HFRCO startup delay.
10719  *
10720  * @details
10721  *   See the reference manual for more details.
10722  *
10723  * @return
10724  *   The startup delay in use.
10725  ******************************************************************************/
CMU_HFRCOStartupDelayGet(void)10726 uint32_t CMU_HFRCOStartupDelayGet(void)
10727 {
10728   return (CMU->HFRCOCTRL & _CMU_HFRCOCTRL_SUDELAY_MASK)
10729          >> _CMU_HFRCOCTRL_SUDELAY_SHIFT;
10730 }
10731 
10732 /***************************************************************************//**
10733  * @brief
10734  *   Set the HFRCO startup delay.
10735  *
10736  * @details
10737  *   See the reference manual for more details.
10738  *
10739  * @param[in] delay
10740  *   The startup delay to set (<= 31).
10741  ******************************************************************************/
CMU_HFRCOStartupDelaySet(uint32_t delay)10742 void CMU_HFRCOStartupDelaySet(uint32_t delay)
10743 {
10744   EFM_ASSERT(delay <= 31);
10745 
10746   delay &= _CMU_HFRCOCTRL_SUDELAY_MASK >> _CMU_HFRCOCTRL_SUDELAY_SHIFT;
10747   CMU->HFRCOCTRL = (CMU->HFRCOCTRL & ~(_CMU_HFRCOCTRL_SUDELAY_MASK))
10748                    | (delay << _CMU_HFRCOCTRL_SUDELAY_SHIFT);
10749 }
10750 #endif
10751 
10752 #if defined(_CMU_USHFRCOCTRL_FREQRANGE_MASK)
10753 /**************************************************************************//**
10754  * @brief
10755  *   Get the USHFRCO frequency calibration word in DEVINFO.
10756  *
10757  * @param[in] freq
10758  *   Frequency in Hz.
10759  *
10760  * @return
10761  *   USHFRCO calibration word for a given frequency.
10762  *****************************************************************************/
CMU_USHFRCODevinfoGet(CMU_USHFRCOFreq_TypeDef freq)10763 static uint32_t CMU_USHFRCODevinfoGet(CMU_USHFRCOFreq_TypeDef freq)
10764 {
10765   switch (freq) {
10766     case cmuUSHFRCOFreq_16M0Hz:
10767       return DEVINFO->USHFRCOCAL7;
10768 
10769     case cmuUSHFRCOFreq_32M0Hz:
10770       return DEVINFO->USHFRCOCAL11;
10771 
10772     case cmuUSHFRCOFreq_48M0Hz:
10773       return DEVINFO->USHFRCOCAL13;
10774 
10775     case cmuUSHFRCOFreq_50M0Hz:
10776       return DEVINFO->USHFRCOCAL14;
10777 
10778     default: /* cmuUSHFRCOFreq_UserDefined */
10779       return 0;
10780   }
10781 }
10782 
10783 /***************************************************************************//**
10784  * @brief
10785  *   Get the current USHFRCO frequency.
10786  *
10787  * @return
10788  *   HFRCO frequency.
10789  ******************************************************************************/
CMU_USHFRCOBandGet(void)10790 CMU_USHFRCOFreq_TypeDef CMU_USHFRCOBandGet(void)
10791 {
10792   return (CMU_USHFRCOFreq_TypeDef) ushfrcoFreq;
10793 }
10794 
10795 /***************************************************************************//**
10796  * @brief
10797  *   Get USHFRCO frequency.
10798  *
10799  * @return
10800  *   USHFRCO frequency.
10801  ******************************************************************************/
CMU_USHFRCOFreqGet(void)10802 uint32_t CMU_USHFRCOFreqGet(void)
10803 {
10804   return ushfrcoFreq;
10805 }
10806 
10807 /***************************************************************************//**
10808  * @brief
10809  *   Set the USHFRCO calibration for the selected target frequency.
10810  *
10811  * @param[in] setFreq
10812  *   USHFRCO frequency to set.
10813  ******************************************************************************/
CMU_USHFRCOBandSet(CMU_USHFRCOFreq_TypeDef setFreq)10814 void CMU_USHFRCOBandSet(CMU_USHFRCOFreq_TypeDef setFreq)
10815 {
10816   uint32_t freqCal;
10817 
10818   /* Get DEVINFO calibration values. */
10819   freqCal = CMU_USHFRCODevinfoGet(setFreq);
10820   EFM_ASSERT((freqCal != 0) && (freqCal != UINT_MAX));
10821   ushfrcoFreq = (uint32_t)setFreq;
10822 
10823   /* Wait for any previous sync to complete and set calibration data
10824      for the selected frequency.  */
10825   while (BUS_RegBitRead(&CMU->SYNCBUSY, _CMU_SYNCBUSY_USHFRCOBSY_SHIFT)) ;
10826 
10827   CMU->USHFRCOCTRL = freqCal;
10828 }
10829 #endif /* _CMU_USHFRCOCTRL_FREQRANGE_MASK  */
10830 
10831 #if defined(_CMU_HFXOCTRL_AUTOSTARTEM0EM1_MASK)
10832 /***************************************************************************//**
10833  * @brief
10834  *   Enable or disable HFXO autostart.
10835  *
10836  * @param[in] userSel
10837  *   Additional user specified enable bit.
10838  *
10839  * @param[in] enEM0EM1Start
10840  *   If true, HFXO is automatically started upon entering EM0/EM1 entry from
10841  *   EM2/EM3. HFXO selection has to be handled by the user.
10842  *   If false, HFXO is not started automatically when entering EM0/EM1.
10843  *
10844  * @param[in] enEM0EM1StartSel
10845  *   If true, HFXO is automatically started and immediately selected upon
10846  *   entering EM0/EM1 entry from EM2/EM3. Note that this option stalls the use of
10847  *   HFSRCCLK until HFXO becomes ready. HFCLKLE prescaler is also automatically
10848  *   modified if userSel is specified.
10849  *   If false, HFXO is not started or selected automatically when entering
10850  *   EM0/EM1.
10851  ******************************************************************************/
CMU_HFXOAutostartEnable(uint32_t userSel,bool enEM0EM1Start,bool enEM0EM1StartSel)10852 void CMU_HFXOAutostartEnable(uint32_t userSel,
10853                              bool enEM0EM1Start,
10854                              bool enEM0EM1StartSel)
10855 {
10856   uint32_t hfxoFreq;
10857   uint32_t hfxoCtrl;
10858 
10859 #if defined(_EMU_CTRL_EM23VSCALE_MASK)
10860   if (enEM0EM1StartSel) {
10861     /* Voltage scaling is not compatible with HFXO auto start and select. */
10862     EFM_ASSERT((EMU->CTRL & _EMU_CTRL_EM23VSCALE_MASK) == EMU_CTRL_EM23VSCALE_VSCALE2);
10863   }
10864 #endif
10865 
10866   /* Mask supported enable bits. */
10867 #if defined(_CMU_HFXOCTRL_AUTOSTARTRDYSELRAC_MASK)
10868   userSel &= _CMU_HFXOCTRL_AUTOSTARTRDYSELRAC_MASK;
10869 #else
10870   userSel = 0;
10871 #endif
10872 
10873   hfxoFreq = SystemHFXOClockGet();
10874 #if defined(_EMU_CMD_EM01VSCALE0_MASK)
10875   // Update voltage scaling.
10876   EMU_VScaleEM01ByClock(hfxoFreq, true);
10877 #endif
10878   /* Set wait-states for HFXO if automatic start and select is configured. */
10879   if ((userSel > 0UL) || enEM0EM1StartSel) {
10880     CMU_UpdateWaitStates(hfxoFreq, VSCALE_DEFAULT);
10881     setHfLeConfig(hfxoFreq / CMU_ClockDivGet(cmuClock_HF));
10882   }
10883 
10884   if (enEM0EM1Start || enEM0EM1StartSel) {
10885     /* Enable the HFXO once in order to finish first time calibrations. */
10886     CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
10887   }
10888 
10889   /* Since call to CMU_OscillatorEnable() can change the CMU->HFXOCTRL register,
10890    * it's important to read the CMU->HFXOCTRL register after the call to CMU_OscillatorEnable(). */
10891   hfxoCtrl = CMU->HFXOCTRL & ~(userSel
10892                                | _CMU_HFXOCTRL_AUTOSTARTEM0EM1_MASK
10893                                | _CMU_HFXOCTRL_AUTOSTARTSELEM0EM1_MASK);
10894 
10895   hfxoCtrl |= userSel
10896               | (enEM0EM1Start ? CMU_HFXOCTRL_AUTOSTARTEM0EM1 : 0UL)
10897               | (enEM0EM1StartSel ? CMU_HFXOCTRL_AUTOSTARTSELEM0EM1 : 0UL);
10898 
10899   /* Update HFXOCTRL after wait-states are updated as HF may automatically switch
10900      to HFXO when automatic select is enabled . */
10901   CMU->HFXOCTRL = hfxoCtrl;
10902 }
10903 #endif
10904 
10905 /**************************************************************************//**
10906  * @brief
10907  *   Set HFXO control registers.
10908  *
10909  * @note
10910  *   HFXO configuration should be obtained from a configuration tool,
10911  *   app note, or crystal data sheet. This function disables the HFXO to
10912  *   ensure a valid state before update.
10913  *
10914  * @param[in] hfxoInit
10915  *    HFXO setup parameters.
10916  *****************************************************************************/
CMU_HFXOInit(const CMU_HFXOInit_TypeDef * hfxoInit)10917 void CMU_HFXOInit(const CMU_HFXOInit_TypeDef *hfxoInit)
10918 {
10919   /* Do not disable HFXO if it is currently selected as the HF/Core clock. */
10920   EFM_ASSERT(CMU_ClockSelectGet(cmuClock_HF) != cmuSelect_HFXO);
10921 
10922   /* HFXO must be disabled before reconfiguration. */
10923   CMU_OscillatorEnable(cmuOsc_HFXO, false, true);
10924 
10925 #if defined(_SILICON_LABS_32B_SERIES_1) \
10926   && (_SILICON_LABS_GECKO_INTERNAL_SDID >= 100)
10927   uint32_t tmp = CMU_HFXOCTRL_MODE_XTAL;
10928 
10929   switch (hfxoInit->mode) {
10930     case cmuOscMode_Crystal:
10931       tmp = CMU_HFXOCTRL_MODE_XTAL;
10932       break;
10933     case cmuOscMode_External:
10934       tmp = CMU_HFXOCTRL_MODE_DIGEXTCLK;
10935       break;
10936     case cmuOscMode_AcCoupled:
10937       tmp = CMU_HFXOCTRL_MODE_ACBUFEXTCLK;
10938       break;
10939     default:
10940       EFM_ASSERT(false); /* Unsupported configuration */
10941       break;
10942   }
10943   CMU->HFXOCTRL = (CMU->HFXOCTRL & ~_CMU_HFXOCTRL_MODE_MASK) | tmp;
10944 
10945 #if defined(CMU_HFXOCTRL_HFXOX2EN)
10946   /* HFXO Doubler can only be enabled on crystals up to max 25 MHz. */
10947   tmp = 0;
10948   if (SystemHFXOClockGet() <= 25000000) {
10949     tmp |= CMU_HFXOCTRL_HFXOX2EN;
10950   }
10951 
10952   CMU->HFXOCTRL = (CMU->HFXOCTRL & ~_CMU_HFXOCTRL_HFXOX2EN_MASK) | tmp;
10953 #endif
10954 
10955   /* Set tuning for startup and steady state. */
10956   CMU->HFXOSTARTUPCTRL = (hfxoInit->ctuneStartup
10957                           << _CMU_HFXOSTARTUPCTRL_CTUNE_SHIFT)
10958                          | (hfxoInit->xoCoreBiasTrimStartup
10959                             << _CMU_HFXOSTARTUPCTRL_IBTRIMXOCORE_SHIFT);
10960 
10961   CMU->HFXOSTEADYSTATECTRL = (CMU->HFXOSTEADYSTATECTRL
10962                               & ~(_CMU_HFXOSTEADYSTATECTRL_CTUNE_MASK
10963                                   | _CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_MASK))
10964                              | (hfxoInit->ctuneSteadyState
10965                                 << _CMU_HFXOSTEADYSTATECTRL_CTUNE_SHIFT)
10966                              | (hfxoInit->xoCoreBiasTrimSteadyState
10967                                 << _CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_SHIFT);
10968 
10969   /* Set timeouts */
10970   CMU->HFXOTIMEOUTCTRL = (hfxoInit->timeoutPeakDetect
10971                           << _CMU_HFXOTIMEOUTCTRL_PEAKDETTIMEOUT_SHIFT)
10972                          | (hfxoInit->timeoutSteady
10973                             << _CMU_HFXOTIMEOUTCTRL_STEADYTIMEOUT_SHIFT)
10974                          | (hfxoInit->timeoutStartup
10975                             << _CMU_HFXOTIMEOUTCTRL_STARTUPTIMEOUT_SHIFT);
10976 
10977 #elif defined(_CMU_HFXOCTRL_MASK)
10978   uint32_t tmp = CMU_HFXOCTRL_MODE_XTAL;
10979 
10980   /* AC coupled external clock not supported. */
10981   EFM_ASSERT(hfxoInit->mode != cmuOscMode_AcCoupled);
10982   if (hfxoInit->mode == cmuOscMode_External) {
10983     tmp = CMU_HFXOCTRL_MODE_DIGEXTCLK;
10984   }
10985 
10986   /* Apply control settings. */
10987   CMU->HFXOCTRL = (CMU->HFXOCTRL & ~_CMU_HFXOCTRL_MODE_MASK)
10988                   | tmp;
10989   BUS_RegBitWrite(&CMU->HFXOCTRL,
10990                   _CMU_HFXOCTRL_LOWPOWER_SHIFT,
10991                   (unsigned)hfxoInit->lowPowerMode);
10992 
10993   /* Set XTAL tuning parameters. */
10994 
10995 #if defined(_CMU_HFXOCTRL1_PEAKDETTHR_MASK)
10996   /* Set peak detection threshold. */
10997   CMU->HFXOCTRL1 = (CMU->HFXOCTRL1 & ~_CMU_HFXOCTRL1_PEAKDETTHR_MASK)
10998                    | (hfxoInit->thresholdPeakDetect
10999                       << _CMU_HFXOCTRL1_PEAKDETTHR_SHIFT);
11000 #endif
11001   /* Set tuning for startup and steady state. */
11002   CMU->HFXOSTARTUPCTRL = ((uint32_t)hfxoInit->ctuneStartup
11003                           << _CMU_HFXOSTARTUPCTRL_CTUNE_SHIFT)
11004                          | ((uint32_t)hfxoInit->xoCoreBiasTrimStartup
11005                             << _CMU_HFXOSTARTUPCTRL_IBTRIMXOCORE_SHIFT);
11006 
11007   CMU->HFXOSTEADYSTATECTRL = (CMU->HFXOSTEADYSTATECTRL
11008                               & ~(_CMU_HFXOSTEADYSTATECTRL_CTUNE_MASK
11009                                   | _CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_MASK
11010                                   | _CMU_HFXOSTEADYSTATECTRL_REGISH_MASK
11011                                   | _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_MASK))
11012                              | ((uint32_t)hfxoInit->ctuneSteadyState
11013                                 << _CMU_HFXOSTEADYSTATECTRL_CTUNE_SHIFT)
11014                              | ((uint32_t)hfxoInit->xoCoreBiasTrimSteadyState
11015                                 << _CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_SHIFT)
11016                              | ((uint32_t)hfxoInit->regIshSteadyState
11017                                 << _CMU_HFXOSTEADYSTATECTRL_REGISH_SHIFT)
11018                              | getRegIshUpperVal(hfxoInit->regIshSteadyState);
11019 
11020   /* Set timeouts. */
11021   CMU->HFXOTIMEOUTCTRL = ((uint32_t)hfxoInit->timeoutPeakDetect
11022                           << _CMU_HFXOTIMEOUTCTRL_PEAKDETTIMEOUT_SHIFT)
11023                          | ((uint32_t)hfxoInit->timeoutSteady
11024                             << _CMU_HFXOTIMEOUTCTRL_STEADYTIMEOUT_SHIFT)
11025                          | ((uint32_t)hfxoInit->timeoutStartup
11026                             << _CMU_HFXOTIMEOUTCTRL_STARTUPTIMEOUT_SHIFT)
11027                          | ((uint32_t)hfxoInit->timeoutShuntOptimization
11028                             << _CMU_HFXOTIMEOUTCTRL_SHUNTOPTTIMEOUT_SHIFT);
11029 
11030 #else
11031   CMU->CTRL = (CMU->CTRL & ~(_CMU_CTRL_HFXOTIMEOUT_MASK
11032                              | _CMU_CTRL_HFXOBOOST_MASK
11033                              | _CMU_CTRL_HFXOMODE_MASK
11034                              | _CMU_CTRL_HFXOGLITCHDETEN_MASK))
11035               | (hfxoInit->timeout << _CMU_CTRL_HFXOTIMEOUT_SHIFT)
11036               | (hfxoInit->boost << _CMU_CTRL_HFXOBOOST_SHIFT)
11037               | (hfxoInit->mode << _CMU_CTRL_HFXOMODE_SHIFT)
11038               | (hfxoInit->glitchDetector ? CMU_CTRL_HFXOGLITCHDETEN : 0);
11039 #endif
11040 }
11041 
11042 /***************************************************************************//**
11043  * @brief
11044  *   Get the LCD framerate divisor (FDIV) setting.
11045  *
11046  * @return
11047  *   The LCD framerate divisor.
11048  ******************************************************************************/
CMU_LCDClkFDIVGet(void)11049 uint32_t CMU_LCDClkFDIVGet(void)
11050 {
11051 #if defined(LCD_PRESENT) && defined(_CMU_LCDCTRL_MASK)
11052   return (CMU->LCDCTRL & _CMU_LCDCTRL_FDIV_MASK) >> _CMU_LCDCTRL_FDIV_SHIFT;
11053 #else
11054   return 0;
11055 #endif /* defined(LCD_PRESENT) */
11056 }
11057 
11058 /***************************************************************************//**
11059  * @brief
11060  *   Set the LCD framerate divisor (FDIV) setting.
11061  *
11062  * @note
11063  *   The FDIV field (CMU LCDCTRL register) should only be modified while the
11064  *   LCD module is clock disabled (CMU LFACLKEN0.LCD bit is 0). This function
11065  *   will NOT modify FDIV if the LCD module clock is enabled. See
11066  *   @ref CMU_ClockEnable() for disabling/enabling LCD clock.
11067  *
11068  * @param[in] div
11069  *   The FDIV setting to use.
11070  ******************************************************************************/
CMU_LCDClkFDIVSet(uint32_t div)11071 void CMU_LCDClkFDIVSet(uint32_t div)
11072 {
11073 #if defined(LCD_PRESENT) && defined(_CMU_LCDCTRL_MASK)
11074   EFM_ASSERT(div <= cmuClkDiv_128);
11075 
11076   /* Do not allow modification if LCD clock enabled. */
11077   if (CMU->LFACLKEN0 & CMU_LFACLKEN0_LCD) {
11078     return;
11079   }
11080 
11081   div        <<= _CMU_LCDCTRL_FDIV_SHIFT;
11082   div         &= _CMU_LCDCTRL_FDIV_MASK;
11083   CMU->LCDCTRL = (CMU->LCDCTRL & ~_CMU_LCDCTRL_FDIV_MASK) | div;
11084 #else
11085   (void)div; /* Unused parameter. */
11086 #endif /* defined(LCD_PRESENT) */
11087 }
11088 
11089 /**************************************************************************//**
11090  * @brief
11091  *   Set LFXO control registers.
11092  *
11093  * @note
11094  *   LFXO configuration should be obtained from a configuration tool,
11095  *   app note, or crystal data sheet. This function disables the LFXO when
11096  *   necessary to ensure a valid state before update.
11097  *
11098  * @param[in] lfxoInit
11099  *    LFXO setup parameters.
11100  *****************************************************************************/
CMU_LFXOInit(const CMU_LFXOInit_TypeDef * lfxoInit)11101 void CMU_LFXOInit(const CMU_LFXOInit_TypeDef *lfxoInit)
11102 {
11103   /* Do not disable LFXO if it is currently selected as the HF/Core clock. */
11104   EFM_ASSERT(CMU_ClockSelectGet(cmuClock_HF) != cmuSelect_LFXO);
11105 
11106 #if defined(_SILICON_LABS_32B_SERIES_1)
11107   uint32_t reg = (CMU->LFXOCTRL & ~(_CMU_LFXOCTRL_TUNING_MASK
11108                                     | _CMU_LFXOCTRL_GAIN_MASK
11109                                     | _CMU_LFXOCTRL_TIMEOUT_MASK
11110                                     | _CMU_LFXOCTRL_MODE_MASK))
11111                  | ((uint32_t)lfxoInit->ctune << _CMU_LFXOCTRL_TUNING_SHIFT)
11112                  | ((uint32_t)lfxoInit->gain << _CMU_LFXOCTRL_GAIN_SHIFT)
11113                  | ((uint32_t)lfxoInit->timeout << _CMU_LFXOCTRL_TIMEOUT_SHIFT)
11114                  | ((uint32_t)lfxoInit->mode << _CMU_LFXOCTRL_MODE_SHIFT);
11115 
11116   /* If LFXO already contains the correct configuration then there is no need
11117    * to stop the oscillator and apply new settings. The LFXO can be running out
11118    * of reset, in which case there is no need to disable it unless necessary. */
11119   if (reg != CMU->LFXOCTRL) {
11120     CMU_OscillatorEnable(cmuOsc_LFXO, false, true);
11121     CMU->LFXOCTRL = reg;
11122   }
11123 #elif defined(_SILICON_LABS_32B_SERIES_0)
11124   /* LFXO must be disabled before reconfiguration. */
11125   CMU_OscillatorEnable(cmuOsc_LFXO, false, true);
11126 
11127   bool cmuBoost  = (lfxoInit->boost & 0x2);
11128   BUS_RegMaskedWrite(&CMU->CTRL,
11129                      _CMU_CTRL_LFXOTIMEOUT_MASK
11130                      | _CMU_CTRL_LFXOBOOST_MASK
11131                      | _CMU_CTRL_LFXOMODE_MASK,
11132                      ((uint32_t)lfxoInit->timeout
11133                       << _CMU_CTRL_LFXOTIMEOUT_SHIFT)
11134                      | ((cmuBoost ? 1 : 0) << _CMU_CTRL_LFXOBOOST_SHIFT)
11135                      | ((uint32_t)lfxoInit->mode << _CMU_CTRL_LFXOMODE_SHIFT));
11136 #if defined(_EMU_AUXCTRL_REDLFXOBOOST_MASK)
11137   /* EFM32GG has a "reduce startup boost" field in the EMU */
11138   bool emuReduce = (lfxoInit->boost & 0x1);
11139   BUS_RegBitWrite(&EMU->AUXCTRL, _EMU_AUXCTRL_REDLFXOBOOST_SHIFT, emuReduce ? 1 : 0);
11140 #endif
11141 #endif
11142 }
11143 
11144 /**************************************************************************//**
11145  * @brief
11146  *   Sets LFXO's crystal precision, in PPM.
11147  *
11148  * @note
11149  *   LFXO precision should be obtained from a crystal datasheet.
11150  *
11151  * @param[in] precision
11152  *    LFXO's crystal precision, in PPM.
11153  *****************************************************************************/
CMU_LFXOPrecisionSet(uint16_t precision)11154 void CMU_LFXOPrecisionSet(uint16_t precision)
11155 {
11156   lfxo_precision = precision;
11157 }
11158 
11159 /**************************************************************************//**
11160  * @brief
11161  *   Gets LFXO's crystal precision, in PPM.
11162  *
11163  * @param[in] precision
11164  *    LFXO's crystal precision, in PPM.
11165  *****************************************************************************/
CMU_LFXOPrecisionGet(void)11166 uint16_t CMU_LFXOPrecisionGet(void)
11167 {
11168   return lfxo_precision;
11169 }
11170 
11171 /**************************************************************************//**
11172  * @brief
11173  *   Sets HFXO's crystal precision, in PPM.
11174  *
11175  * @note
11176  *   HFXO precision should be obtained from a crystal datasheet.
11177  *
11178  * @param[in] precision
11179  *    HFXO's crystal precision, in PPM.
11180  *****************************************************************************/
CMU_HFXOPrecisionSet(uint16_t precision)11181 void CMU_HFXOPrecisionSet(uint16_t precision)
11182 {
11183   hfxo_precision = precision;
11184 }
11185 
11186 /**************************************************************************//**
11187  * @brief
11188  *   Gets HFXO's crystal precision, in PPM.
11189  *
11190  * @param[in] precision
11191  *    HFXO's crystal precision, in PPM.
11192  *****************************************************************************/
CMU_HFXOPrecisionGet(void)11193 uint16_t CMU_HFXOPrecisionGet(void)
11194 {
11195   return hfxo_precision;
11196 }
11197 
11198 /***************************************************************************//**
11199  * @brief
11200  *   Enable/disable oscillator.
11201  *
11202  * @note
11203  *   WARNING: When this function is called to disable either cmuOsc_LFXO or
11204  *   cmuOsc_HFXO, the LFXOMODE or HFXOMODE fields of the CMU_CTRL register
11205  *   are reset to the reset value. In other words, if external clock sources are selected
11206  *   in either LFXOMODE or HFXOMODE fields, the configuration will be cleared
11207  *   and needs to be reconfigured if needed later.
11208  *
11209  * @param[in] osc
11210  *   The oscillator to enable/disable.
11211  *
11212  * @param[in] enable
11213  *   @li true - enable specified oscillator.
11214  *   @li false - disable specified oscillator.
11215  *
11216  * @param[in] wait
11217  *   Only used if @p enable is true.
11218  *   @li true - wait for oscillator start-up time to timeout before returning.
11219  *   @li false - do not wait for oscillator start-up time to timeout before
11220  *     returning.
11221  ******************************************************************************/
CMU_OscillatorEnable(CMU_Osc_TypeDef osc,bool enable,bool wait)11222 void CMU_OscillatorEnable(CMU_Osc_TypeDef osc, bool enable, bool wait)
11223 {
11224   uint32_t rdyBitPos;
11225 #if defined(_SILICON_LABS_32B_SERIES_1)
11226   uint32_t ensBitPos;
11227 #endif
11228 #if defined(_CMU_STATUS_HFXOPEAKDETRDY_MASK)
11229   uint32_t hfxoTrimStatus;
11230 #endif
11231 
11232   uint32_t enBit;
11233   uint32_t disBit;
11234 
11235   switch (osc) {
11236     case cmuOsc_HFRCO:
11237       enBit  = CMU_OSCENCMD_HFRCOEN;
11238       disBit = CMU_OSCENCMD_HFRCODIS;
11239       rdyBitPos = _CMU_STATUS_HFRCORDY_SHIFT;
11240 #if defined(_SILICON_LABS_32B_SERIES_1)
11241       ensBitPos = _CMU_STATUS_HFRCOENS_SHIFT;
11242 #endif
11243       break;
11244 
11245     case cmuOsc_HFXO:
11246       enBit  = CMU_OSCENCMD_HFXOEN;
11247       disBit = CMU_OSCENCMD_HFXODIS;
11248       rdyBitPos = _CMU_STATUS_HFXORDY_SHIFT;
11249 #if defined(_SILICON_LABS_32B_SERIES_1)
11250       ensBitPos = _CMU_STATUS_HFXOENS_SHIFT;
11251 #endif
11252       break;
11253 
11254     case cmuOsc_AUXHFRCO:
11255       enBit  = CMU_OSCENCMD_AUXHFRCOEN;
11256       disBit = CMU_OSCENCMD_AUXHFRCODIS;
11257       rdyBitPos = _CMU_STATUS_AUXHFRCORDY_SHIFT;
11258 #if defined(_SILICON_LABS_32B_SERIES_1)
11259       ensBitPos = _CMU_STATUS_AUXHFRCOENS_SHIFT;
11260 #endif
11261       break;
11262 
11263     case cmuOsc_LFRCO:
11264       enBit  = CMU_OSCENCMD_LFRCOEN;
11265       disBit = CMU_OSCENCMD_LFRCODIS;
11266       rdyBitPos = _CMU_STATUS_LFRCORDY_SHIFT;
11267 #if defined(_SILICON_LABS_32B_SERIES_1)
11268       ensBitPos = _CMU_STATUS_LFRCOENS_SHIFT;
11269 #endif
11270       break;
11271 
11272     case cmuOsc_LFXO:
11273       enBit  = CMU_OSCENCMD_LFXOEN;
11274       disBit = CMU_OSCENCMD_LFXODIS;
11275       rdyBitPos = _CMU_STATUS_LFXORDY_SHIFT;
11276 #if defined(_SILICON_LABS_32B_SERIES_1)
11277       ensBitPos = _CMU_STATUS_LFXOENS_SHIFT;
11278 #endif
11279       break;
11280 
11281 #if defined(_CMU_STATUS_USHFRCOENS_MASK)
11282     case cmuOsc_USHFRCO:
11283       enBit  = CMU_OSCENCMD_USHFRCOEN;
11284       disBit = CMU_OSCENCMD_USHFRCODIS;
11285       rdyBitPos = _CMU_STATUS_USHFRCORDY_SHIFT;
11286 #if defined(_SILICON_LABS_32B_SERIES_1)
11287       ensBitPos = _CMU_STATUS_USHFRCOENS_SHIFT;
11288 #endif
11289       break;
11290 #endif
11291 
11292 #if defined(PLFRCO_PRESENT)
11293     case cmuOsc_PLFRCO:
11294       if (!deviceHasPlfrco()) {
11295         while (true) { // PLFRCO is not available
11296           EFM_ASSERT(false);
11297         }
11298       }
11299       enBit = CMU_OSCENCMD_PLFRCOEN;
11300       disBit = CMU_OSCENCMD_PLFRCODIS;
11301       rdyBitPos = _CMU_STATUS_PLFRCORDY_SHIFT;
11302       ensBitPos = _CMU_STATUS_PLFRCOENS_SHIFT;
11303       break;
11304 #endif
11305 
11306     default:
11307       /* Undefined clock source, cmuOsc_CLKIN0 or cmuOsc_ULFRCO. ULFRCO is always enabled
11308          and cannot be disabled. In other words,the definition of cmuOsc_ULFRCO is primarily
11309          intended for information: the ULFRCO is always on.  */
11310       EFM_ASSERT(false);
11311       return;
11312   }
11313 
11314   if (enable) {
11315  #if defined(_CMU_HFXOCTRL_MASK)
11316     bool firstHfxoEnable = false;
11317 
11318     /* Enabling the HFXO for the first time requires special handling.
11319      * PEAKDETSHUTOPTMODE field of the HFXOCTRL register is used to see if this is the
11320      * first time the HFXO is enabled. */
11321     if (osc == cmuOsc_HFXO) {
11322       if (getHfxoTuningMode() == HFXO_TUNING_MODE_AUTO) {
11323         /* REGPWRSEL must be set to DVDD before the HFXO can be enabled. */
11324 #if defined(_EMU_PWRCTRL_REGPWRSEL_MASK)
11325         EFM_ASSERT((EMU->PWRCTRL & EMU_PWRCTRL_REGPWRSEL_DVDD) != 0UL);
11326 #endif
11327 
11328         firstHfxoEnable = true;
11329         /* The first time that an external clock is enabled, switch to CMD mode to make sure that
11330          * only SCO and not PDA tuning is performed. */
11331         if ((CMU->HFXOCTRL & (_CMU_HFXOCTRL_MODE_MASK)) == CMU_HFXOCTRL_MODE_DIGEXTCLK) {
11332           setHfxoTuningMode(HFXO_TUNING_MODE_CMD);
11333         }
11334       }
11335     }
11336 #endif
11337     CMU->OSCENCMD = enBit;
11338 
11339 #if defined(_SILICON_LABS_32B_SERIES_1)
11340     /* Always wait for ENS to go high. */
11341     while (BUS_RegBitRead(&CMU->STATUS, ensBitPos) == 0UL) {
11342     }
11343 #endif
11344 
11345     /* Wait for the clock to become ready after enable. */
11346     if (wait) {
11347       while (BUS_RegBitRead(&CMU->STATUS, rdyBitPos) == 0UL) {
11348       }
11349 #if defined(_SILICON_LABS_32B_SERIES_1)
11350       if ((osc == cmuOsc_HFXO) && firstHfxoEnable) {
11351         if ((CMU->HFXOCTRL & _CMU_HFXOCTRL_MODE_MASK)
11352             == CMU_HFXOCTRL_MODE_DIGEXTCLK) {
11353 #if defined(CMU_CMD_HFXOSHUNTOPTSTART)
11354           /* External clock mode should only do shunt current optimization. */
11355           (void)CMU_OscillatorTuningOptimize(cmuOsc_HFXO,
11356                                              cmuHFXOTuningMode_ShuntCommand,
11357                                              true);
11358 #endif
11359         } else {
11360           /* Wait for the peak detection and shunt current optimization
11361              to complete. */
11362           (void)CMU_OscillatorTuningWait(cmuOsc_HFXO, cmuHFXOTuningMode_Auto);
11363         }
11364 
11365         /* Disable the HFXO again to apply the trims. Apply trim from
11366            HFXOTRIMSTATUS when disabled. */
11367         hfxoTrimStatus = CMU_OscillatorTuningGet(cmuOsc_HFXO);
11368         CMU_OscillatorEnable(cmuOsc_HFXO, false, true);
11369         CMU_OscillatorTuningSet(cmuOsc_HFXO, hfxoTrimStatus);
11370 
11371         /* Restart in CMD mode. */
11372         CMU->OSCENCMD = enBit;
11373         while (BUS_RegBitRead(&CMU->STATUS, rdyBitPos) == 0UL) {
11374         }
11375       }
11376 #endif
11377     }
11378   } else {
11379     CMU->OSCENCMD = disBit;
11380 
11381 #if defined(_SILICON_LABS_32B_SERIES_1)
11382     /* Always wait for ENS to go low. */
11383     while ((CMU->STATUS & (0x1 << ensBitPos)) != 0U) {
11384     }
11385 
11386     if (wait) {
11387       /* Wait for RDY to go low as well. */
11388       while ((CMU->STATUS & (0x1 << rdyBitPos)) != 0U) {
11389       }
11390     }
11391 #endif
11392   }
11393 }
11394 
11395 /***************************************************************************//**
11396  * @brief
11397  *   Get the oscillator frequency tuning setting.
11398  *
11399  * @param[in] osc
11400  *   An oscillator to get tuning value for, one of the following:
11401  *   @li #cmuOsc_LFRCO
11402  *   @li #cmuOsc_HFRCO @if _CMU_USHFRCOCTRL_TUNING_MASK
11403  *   @li #cmuOsc_USHFRCO
11404  *   @endif
11405  *   @li #cmuOsc_AUXHFRCO
11406  *   @li #cmuOsc_HFXO if CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE is defined
11407  *
11408  * @return
11409  *   The oscillator frequency tuning setting in use.
11410  ******************************************************************************/
CMU_OscillatorTuningGet(CMU_Osc_TypeDef osc)11411 uint32_t CMU_OscillatorTuningGet(CMU_Osc_TypeDef osc)
11412 {
11413   uint32_t ret;
11414 
11415   switch (osc) {
11416     case cmuOsc_LFRCO:
11417       ret = (CMU->LFRCOCTRL & _CMU_LFRCOCTRL_TUNING_MASK)
11418             >> _CMU_LFRCOCTRL_TUNING_SHIFT;
11419       break;
11420 
11421     case cmuOsc_HFRCO:
11422       ret = (CMU->HFRCOCTRL & _CMU_HFRCOCTRL_TUNING_MASK)
11423             >> _CMU_HFRCOCTRL_TUNING_SHIFT;
11424       break;
11425 
11426 #if defined (_CMU_USHFRCOCTRL_TUNING_MASK)
11427     case cmuOsc_USHFRCO:
11428       ret = (CMU->USHFRCOCTRL & _CMU_USHFRCOCTRL_TUNING_MASK)
11429             >> _CMU_USHFRCOCTRL_TUNING_SHIFT;
11430       break;
11431 #endif
11432 
11433     case cmuOsc_AUXHFRCO:
11434       ret = (CMU->AUXHFRCOCTRL & _CMU_AUXHFRCOCTRL_TUNING_MASK)
11435             >> _CMU_AUXHFRCOCTRL_TUNING_SHIFT;
11436       break;
11437 
11438 #if defined(_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
11439     case cmuOsc_HFXO:
11440       ret = CMU->HFXOTRIMSTATUS & (_CMU_HFXOTRIMSTATUS_IBTRIMXOCORE_MASK
11441 #if defined(_CMU_HFXOTRIMSTATUS_REGISH_MASK)
11442                                    | _CMU_HFXOTRIMSTATUS_REGISH_MASK
11443 #endif
11444                                    );
11445       break;
11446 #endif
11447 
11448 #if defined(_SILICON_LABS_32B_SERIES_1) && !defined(_EFR32_ZEN_FAMILY)
11449     case cmuOsc_LFXO:
11450       ret = (CMU->LFXOCTRL & _CMU_LFXOCTRL_TUNING_MASK) >> _CMU_LFXOCTRL_TUNING_SHIFT;
11451       break;
11452 #endif
11453 
11454     default:
11455       ret = 0;
11456       EFM_ASSERT(false);
11457       break;
11458   }
11459 
11460   return ret;
11461 }
11462 
11463 /***************************************************************************//**
11464  * @brief
11465  *   Set the oscillator frequency tuning control.
11466  *
11467  * @note
11468  *   Oscillator tuning is done during production and the tuning value is
11469  *   automatically loaded after reset. Changing the tuning value from the
11470  *   calibrated value is for more advanced use. Certain oscillators also have
11471  *   build-in tuning optimization.
11472  *
11473  * @param[in] osc
11474  *   An oscillator to set tuning value for, one of the following:
11475  *   @li #cmuOsc_LFRCO
11476  *   @li #cmuOsc_HFRCO @if _CMU_USHFRCOCTRL_TUNING_MASK
11477  *   @li #cmuOsc_USHFRCO
11478  *   @endif
11479  *   @li #cmuOsc_AUXHFRCO
11480  *   @li #cmuOsc_HFXO if PEAKDETSHUNTOPTMODE is available. Note that CMD mode is set.
11481  *
11482  * @param[in] val
11483  *   The oscillator frequency tuning setting to use.
11484  ******************************************************************************/
CMU_OscillatorTuningSet(CMU_Osc_TypeDef osc,uint32_t val)11485 void CMU_OscillatorTuningSet(CMU_Osc_TypeDef osc, uint32_t val)
11486 {
11487 #if defined(_SILICON_LABS_32B_SERIES_1) && !defined(_EFR32_ZEN_FAMILY)
11488   uint8_t ctune = 0;
11489 #endif
11490 
11491 #if defined(_CMU_HFXOSTEADYSTATECTRL_REGISH_MASK)
11492   uint32_t regIshUpper;
11493 #endif
11494 
11495   switch (osc) {
11496     case cmuOsc_LFRCO:
11497       EFM_ASSERT(val <= (_CMU_LFRCOCTRL_TUNING_MASK
11498                          >> _CMU_LFRCOCTRL_TUNING_SHIFT));
11499       val &= (_CMU_LFRCOCTRL_TUNING_MASK >> _CMU_LFRCOCTRL_TUNING_SHIFT);
11500 #if defined(_SILICON_LABS_32B_SERIES_1)
11501       while (BUS_RegBitRead(&CMU->SYNCBUSY,
11502                             _CMU_SYNCBUSY_LFRCOBSY_SHIFT) != 0UL) {
11503       }
11504 #endif
11505       CMU->LFRCOCTRL = (CMU->LFRCOCTRL & ~(_CMU_LFRCOCTRL_TUNING_MASK))
11506                        | (val << _CMU_LFRCOCTRL_TUNING_SHIFT);
11507       break;
11508 
11509     case cmuOsc_HFRCO:
11510       EFM_ASSERT(val <= (_CMU_HFRCOCTRL_TUNING_MASK
11511                          >> _CMU_HFRCOCTRL_TUNING_SHIFT));
11512       val &= (_CMU_HFRCOCTRL_TUNING_MASK >> _CMU_HFRCOCTRL_TUNING_SHIFT);
11513 #if defined(_SILICON_LABS_32B_SERIES_1)
11514       while (BUS_RegBitRead(&CMU->SYNCBUSY,
11515                             _CMU_SYNCBUSY_HFRCOBSY_SHIFT) != 0UL) {
11516       }
11517 #endif
11518       CMU->HFRCOCTRL = (CMU->HFRCOCTRL & ~(_CMU_HFRCOCTRL_TUNING_MASK))
11519                        | (val << _CMU_HFRCOCTRL_TUNING_SHIFT);
11520       break;
11521 
11522 #if defined (_CMU_USHFRCOCTRL_TUNING_MASK)
11523     case cmuOsc_USHFRCO:
11524       EFM_ASSERT(val <= (_CMU_USHFRCOCTRL_TUNING_MASK
11525                          >> _CMU_USHFRCOCTRL_TUNING_SHIFT));
11526       val &= (_CMU_USHFRCOCTRL_TUNING_MASK >> _CMU_USHFRCOCTRL_TUNING_SHIFT);
11527 #if defined(_SILICON_LABS_32B_SERIES_1)
11528       while (BUS_RegBitRead(&CMU->SYNCBUSY, _CMU_SYNCBUSY_USHFRCOBSY_SHIFT)) {
11529       }
11530 #endif
11531       CMU->USHFRCOCTRL = (CMU->USHFRCOCTRL & ~(_CMU_USHFRCOCTRL_TUNING_MASK))
11532                          | (val << _CMU_USHFRCOCTRL_TUNING_SHIFT);
11533       break;
11534 #endif
11535 
11536     case cmuOsc_AUXHFRCO:
11537       EFM_ASSERT(val <= (_CMU_AUXHFRCOCTRL_TUNING_MASK
11538                          >> _CMU_AUXHFRCOCTRL_TUNING_SHIFT));
11539       val &= (_CMU_AUXHFRCOCTRL_TUNING_MASK >> _CMU_AUXHFRCOCTRL_TUNING_SHIFT);
11540 #if defined(_SILICON_LABS_32B_SERIES_1)
11541       while (BUS_RegBitRead(&CMU->SYNCBUSY,
11542                             _CMU_SYNCBUSY_AUXHFRCOBSY_SHIFT) != 0UL) {
11543       }
11544 #endif
11545       CMU->AUXHFRCOCTRL = (CMU->AUXHFRCOCTRL & ~(_CMU_AUXHFRCOCTRL_TUNING_MASK))
11546                           | (val << _CMU_AUXHFRCOCTRL_TUNING_SHIFT);
11547       break;
11548 
11549 #if defined(_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
11550     case cmuOsc_HFXO:
11551 
11552       /* Do set PEAKDETSHUNTOPTMODE or HFXOSTEADYSTATECTRL if HFXO is enabled. */
11553       EFM_ASSERT((CMU->STATUS & CMU_STATUS_HFXOENS) == 0UL);
11554 
11555       /* Switch to command mode. Automatic SCO and PDA calibration is not done
11556          at the next enable. Set user REGISH, REGISHUPPER, and IBTRIMXOCORE. */
11557       CMU->HFXOCTRL = (CMU->HFXOCTRL & ~_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK)
11558                       | CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_CMD;
11559 
11560 #if defined(_CMU_HFXOSTEADYSTATECTRL_REGISH_MASK)
11561       regIshUpper = getRegIshUpperVal((val & _CMU_HFXOSTEADYSTATECTRL_REGISH_MASK)
11562                                       >> _CMU_HFXOSTEADYSTATECTRL_REGISH_SHIFT);
11563       CMU->HFXOSTEADYSTATECTRL = (CMU->HFXOSTEADYSTATECTRL
11564                                   & ~(_CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_MASK
11565                                       | _CMU_HFXOSTEADYSTATECTRL_REGISH_MASK
11566                                       | _CMU_HFXOSTEADYSTATECTRL_REGISHUPPER_MASK))
11567                                  | val
11568                                  | regIshUpper;
11569 #else
11570       CMU->HFXOSTEADYSTATECTRL = (CMU->HFXOSTEADYSTATECTRL
11571                                   & ~_CMU_HFXOSTEADYSTATECTRL_IBTRIMXOCORE_MASK)
11572                                  | val;
11573 #endif
11574 
11575       break;
11576 #endif
11577 
11578 #if defined(_SILICON_LABS_32B_SERIES_1) && !defined(_EFR32_ZEN_FAMILY)
11579     case cmuOsc_LFXO:
11580       EFM_ASSERT(val <= (_CMU_LFXOCTRL_TUNING_MASK >> _CMU_LFXOCTRL_TUNING_SHIFT));
11581       // Max internal capacitance tuning value is 0x4F (20 pF)
11582       ctune = (uint8_t) SL_MIN(0x4FU, val);
11583 
11584       // Wait for the CMU_LFXOCTRL is ready for update
11585       while (BUS_RegBitRead(&CMU->SYNCBUSY,
11586                             _CMU_SYNCBUSY_LFXOBSY_SHIFT) != 0UL) {
11587       }
11588       CMU->LFXOCTRL = (CMU->LFXOCTRL & ~(_CMU_LFXOCTRL_TUNING_MASK))
11589                       | ((uint32_t)ctune << _CMU_LFXOCTRL_TUNING_SHIFT);
11590       break;
11591 #endif
11592 
11593     default:
11594       EFM_ASSERT(false);
11595       break;
11596   }
11597 }
11598 
11599 #if defined(_CMU_HFXOCTRL_PEAKDETSHUNTOPTMODE_MASK) || defined(_CMU_HFXOCTRL_PEAKDETMODE_MASK)
11600 /***************************************************************************//**
11601  * @brief
11602  *   Wait for the oscillator tuning optimization.
11603  *
11604  * @param[in] osc
11605  *   An oscillator to set tuning value for, one of the following:
11606  *   @li #cmuOsc_HFXO
11607  *
11608  * @param[in] mode
11609  *   Tuning optimization mode.
11610  *
11611  * @return
11612  *   Returns false on invalid parameters or oscillator error status.
11613  ******************************************************************************/
CMU_OscillatorTuningWait(CMU_Osc_TypeDef osc,CMU_HFXOTuningMode_TypeDef mode)11614 bool CMU_OscillatorTuningWait(CMU_Osc_TypeDef osc,
11615                               CMU_HFXOTuningMode_TypeDef mode)
11616 {
11617   uint32_t waitFlags;
11618   EFM_ASSERT(osc == cmuOsc_HFXO);
11619 
11620   /* Currently implemented for HFXO with PEAKDETSHUNTOPTMODE only. */
11621   (void)osc;
11622 
11623   if (getHfxoTuningMode() == HFXO_TUNING_MODE_AUTO) {
11624     waitFlags = HFXO_TUNING_READY_FLAGS;
11625   } else {
11626     /* Set wait flags for each command and wait. */
11627     switch (mode) {
11628 #if defined(_CMU_STATUS_HFXOSHUNTOPTRDY_MASK)
11629       case cmuHFXOTuningMode_ShuntCommand:
11630         waitFlags = CMU_STATUS_HFXOSHUNTOPTRDY;
11631         break;
11632 #endif
11633       case cmuHFXOTuningMode_Auto:
11634         waitFlags = HFXO_TUNING_READY_FLAGS;
11635         break;
11636 
11637 #if defined(CMU_CMD_HFXOSHUNTOPTSTART)
11638       case cmuHFXOTuningMode_PeakShuntCommand:
11639         waitFlags = HFXO_TUNING_READY_FLAGS;
11640         break;
11641 #endif
11642 
11643       default:
11644         waitFlags = _CMU_STATUS_MASK;
11645         EFM_ASSERT(false);
11646         break;
11647     }
11648   }
11649   while ((CMU->STATUS & waitFlags) != waitFlags) {
11650   }
11651 
11652 #if defined(CMU_IF_HFXOPEAKDETERR)
11653   /* Check error flags. */
11654   if ((waitFlags & CMU_STATUS_HFXOPEAKDETRDY) != 0UL) {
11655     return (CMU->IF & CMU_IF_HFXOPEAKDETERR) != 0UL ? true : false;
11656   }
11657 #endif
11658   return true;
11659 }
11660 
11661 /***************************************************************************//**
11662  * @brief
11663  *   Start and optionally wait for the oscillator tuning optimization.
11664  *
11665  * @param[in] osc
11666  *   An oscillator to set tuning value for, one of the following:
11667  *   @li #cmuOsc_HFXO
11668  *
11669  * @param[in] mode
11670  *   Tuning optimization mode.
11671  *
11672  * @param[in] wait
11673  *   Wait for tuning optimization to complete.
11674  *   true - wait for tuning optimization to complete.
11675  *   false - return without waiting.
11676  *
11677  * @return
11678  *   Returns false on invalid parameters or oscillator error status.
11679  ******************************************************************************/
CMU_OscillatorTuningOptimize(CMU_Osc_TypeDef osc,CMU_HFXOTuningMode_TypeDef mode,bool wait)11680 bool CMU_OscillatorTuningOptimize(CMU_Osc_TypeDef osc,
11681                                   CMU_HFXOTuningMode_TypeDef mode,
11682                                   bool wait)
11683 {
11684   switch (osc) {
11685     case cmuOsc_HFXO:
11686       if ((unsigned)mode != 0U) {
11687 #if defined(CMU_IF_HFXOPEAKDETERR)
11688         /* Clear the error flag before command write. */
11689         CMU->IFC = CMU_IFC_HFXOPEAKDETERR;
11690 #endif
11691         CMU->CMD = (uint32_t)mode;
11692       }
11693       if (wait) {
11694         return CMU_OscillatorTuningWait(osc, mode);
11695       }
11696       break;
11697 
11698     default:
11699       EFM_ASSERT(false);
11700       break;
11701   }
11702   return true;
11703 }
11704 #endif
11705 
11706 /**************************************************************************//**
11707  * @brief
11708  *   Determine if the currently selected PCNTn clock used is external or LFBCLK.
11709  *
11710  * @param[in] instance
11711  *   PCNT instance number to get currently selected clock source for.
11712  *
11713  * @return
11714  *   @li true - selected clock is external clock.
11715  *   @li false - selected clock is LFBCLK.
11716  *****************************************************************************/
CMU_PCNTClockExternalGet(unsigned int instance)11717 bool CMU_PCNTClockExternalGet(unsigned int instance)
11718 {
11719   uint32_t setting;
11720 
11721   switch (instance) {
11722 #if defined(_CMU_PCNTCTRL_PCNT0CLKEN_MASK)
11723     case 0:
11724       setting = CMU->PCNTCTRL & CMU_PCNTCTRL_PCNT0CLKSEL_PCNT0S0;
11725       break;
11726 
11727 #if defined(_CMU_PCNTCTRL_PCNT1CLKEN_MASK)
11728     case 1:
11729       setting = CMU->PCNTCTRL & CMU_PCNTCTRL_PCNT1CLKSEL_PCNT1S0;
11730       break;
11731 
11732 #if defined(_CMU_PCNTCTRL_PCNT2CLKEN_MASK)
11733     case 2:
11734       setting = CMU->PCNTCTRL & CMU_PCNTCTRL_PCNT2CLKSEL_PCNT2S0;
11735       break;
11736 #endif
11737 #endif
11738 #endif
11739 
11740     default:
11741       setting = 0;
11742       break;
11743   }
11744   return setting > 0UL ? true : false;
11745 }
11746 
11747 /**************************************************************************//**
11748  * @brief
11749  *   Select the PCNTn clock.
11750  *
11751  * @param[in] instance
11752  *   PCNT instance number to set selected clock source for.
11753  *
11754  * @param[in] external
11755  *   Set to true to select the external clock, false to select LFBCLK.
11756  *****************************************************************************/
CMU_PCNTClockExternalSet(unsigned int instance,bool external)11757 void CMU_PCNTClockExternalSet(unsigned int instance, bool external)
11758 {
11759 #if defined(PCNT_PRESENT)
11760   uint32_t setting = 0;
11761 
11762   EFM_ASSERT(instance < (unsigned)PCNT_COUNT);
11763 
11764   if (external) {
11765     setting = 1;
11766   }
11767 
11768   BUS_RegBitWrite(&(CMU->PCNTCTRL), (instance * 2U) + 1U, setting);
11769 
11770 #else
11771   (void)instance; /* An unused parameter */
11772   (void)external; /* An unused parameter */
11773 #endif
11774 }
11775 
11776 #if defined(_CMU_USHFRCOCONF_BAND_MASK)
11777 /***************************************************************************//**
11778  * @brief
11779  *   Get USHFRCO band in use.
11780  *
11781  * @return
11782  *   USHFRCO band in use.
11783  ******************************************************************************/
CMU_USHFRCOBandGet(void)11784 CMU_USHFRCOBand_TypeDef CMU_USHFRCOBandGet(void)
11785 {
11786   return (CMU_USHFRCOBand_TypeDef)((CMU->USHFRCOCONF
11787                                     & _CMU_USHFRCOCONF_BAND_MASK)
11788                                    >> _CMU_USHFRCOCONF_BAND_SHIFT);
11789 }
11790 
11791 /***************************************************************************//**
11792  * @brief
11793  *   Get USHFRCO frequency.
11794  *
11795  * @return
11796  *   USHFRCO frequency.
11797  ******************************************************************************/
CMU_USHFRCOFreqGet(void)11798 uint32_t CMU_USHFRCOFreqGet(void)
11799 {
11800   return ushfrcoFreq;
11801 }
11802 #endif
11803 
11804 #if defined(_CMU_USHFRCOCONF_BAND_MASK)
11805 /***************************************************************************//**
11806  * @brief
11807  *   Set the USHFRCO band to use.
11808  *
11809  * @param[in] band
11810  *   USHFRCO band to activate.
11811  ******************************************************************************/
CMU_USHFRCOBandSet(CMU_USHFRCOBand_TypeDef band)11812 void CMU_USHFRCOBandSet(CMU_USHFRCOBand_TypeDef band)
11813 {
11814   uint32_t           tuning;
11815   uint32_t           fineTuning;
11816 
11817   /* Cannot switch band if USHFRCO is already selected as HF clock. */
11818   EFM_ASSERT(CMU_ClockSelectGet(cmuClock_HF) != cmuSelect_USHFRCODIV2);
11819 
11820   /* Read tuning value from calibration table. */
11821   switch (band) {
11822     case cmuUSHFRCOBand_24MHz:
11823       tuning = (DEVINFO->USHFRCOCAL0 & _DEVINFO_USHFRCOCAL0_BAND24_TUNING_MASK)
11824                >> _DEVINFO_USHFRCOCAL0_BAND24_TUNING_SHIFT;
11825       fineTuning = (DEVINFO->USHFRCOCAL0
11826                     & _DEVINFO_USHFRCOCAL0_BAND24_FINETUNING_MASK)
11827                    >> _DEVINFO_USHFRCOCAL0_BAND24_FINETUNING_SHIFT;
11828       ushfrcoFreq = 24000000UL;
11829       break;
11830 
11831     case cmuUSHFRCOBand_48MHz:
11832       tuning = (DEVINFO->USHFRCOCAL0 & _DEVINFO_USHFRCOCAL0_BAND48_TUNING_MASK)
11833                >> _DEVINFO_USHFRCOCAL0_BAND48_TUNING_SHIFT;
11834       fineTuning = (DEVINFO->USHFRCOCAL0
11835                     & _DEVINFO_USHFRCOCAL0_BAND48_FINETUNING_MASK)
11836                    >> _DEVINFO_USHFRCOCAL0_BAND48_FINETUNING_SHIFT;
11837       /* Enable the clock divider before switching the band from 24 to 48 MHz */
11838       BUS_RegBitWrite(&CMU->USHFRCOCONF, _CMU_USHFRCOCONF_USHFRCODIV2DIS_SHIFT, 0);
11839       ushfrcoFreq = 48000000UL;
11840       break;
11841 
11842     default:
11843       EFM_ASSERT(false);
11844       return;
11845   }
11846 
11847   /* Set band and tuning. */
11848   CMU->USHFRCOCONF = (CMU->USHFRCOCONF & ~_CMU_USHFRCOCONF_BAND_MASK)
11849                      | (band << _CMU_USHFRCOCONF_BAND_SHIFT);
11850   CMU->USHFRCOCTRL = (CMU->USHFRCOCTRL & ~_CMU_USHFRCOCTRL_TUNING_MASK)
11851                      | (tuning << _CMU_USHFRCOCTRL_TUNING_SHIFT);
11852   CMU->USHFRCOTUNE = (CMU->USHFRCOTUNE & ~_CMU_USHFRCOTUNE_FINETUNING_MASK)
11853                      | (fineTuning << _CMU_USHFRCOTUNE_FINETUNING_SHIFT);
11854 
11855   /* Disable the clock divider after switching the band from 48 to 24 MHz. */
11856   if (band == cmuUSHFRCOBand_24MHz) {
11857     BUS_RegBitWrite(&CMU->USHFRCOCONF, _CMU_USHFRCOCONF_USHFRCODIV2DIS_SHIFT, 1);
11858   }
11859 }
11860 #endif
11861 
11862 #endif // defined(_SILICON_LABS_32B_SERIES_2)
11863 /** @} (end addtogroup cmu) */
11864 #endif /* defined(CMU_PRESENT) */
11865