1 /***************************************************************************//**
2  * @file
3  * @brief Clock Manager HAL API implementations.
4  *******************************************************************************
5  * # License
6  * <b>Copyright 2023 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 
31 #include <stddef.h>
32 #include "sl_core.h"
33 #include "sl_clock_manager.h"
34 #include "sli_clock_manager.h"
35 #include "sli_clock_manager_hal.h"
36 #include "em_cmu.h"
37 #include "em_bus.h"
38 #include "em_device.h"
39 #include "em_gpio.h"
40 
41 /***************************************************************************//**
42  * Performs Clock Manager runtime initialization.
43  ******************************************************************************/
sli_clock_manager_hal_runtime_init(void)44 sl_status_t sli_clock_manager_hal_runtime_init(void)
45 {
46   return SL_STATUS_OK;
47 }
48 
49 /***************************************************************************//**
50  * Gets frequency of given oscillator.
51  ******************************************************************************/
sli_clock_manager_hal_get_oscillator_frequency(sl_oscillator_t oscillator,uint32_t * frequency)52 sl_status_t sli_clock_manager_hal_get_oscillator_frequency(sl_oscillator_t oscillator,
53                                                            uint32_t *frequency)
54 {
55   switch (oscillator) {
56     case SL_OSCILLATOR_FSRCO:
57       *frequency = SystemFSRCOClockGet();
58       break;
59 
60     case SL_OSCILLATOR_HFXO:
61       *frequency = SystemHFXOClockGet();
62       break;
63 
64     case SL_OSCILLATOR_HFRCODPLL:
65       *frequency = SystemHFRCODPLLClockGet();
66       break;
67 
68 #if defined(HFRCOEM23_PRESENT)
69     case SL_OSCILLATOR_HFRCOEM23:
70       *frequency = SystemHFRCOEM23ClockGet();
71       break;
72 #endif
73 
74 #if defined(RFFPLL_PRESENT)
75     case SL_OSCILLATOR_RFFPLL:
76       *frequency = SystemRFFPLLClockGet();
77       break;
78 #endif
79 
80 #if defined(USBPLL_PRESENT)
81     case SL_OSCILLATOR_USBPLL:
82       *frequency = CMU_ClockFreqGet(cmuClock_USB);
83       break;
84 #endif
85 
86     case SL_OSCILLATOR_LFXO:
87       *frequency = SystemLFXOClockGet();
88       break;
89 
90     case SL_OSCILLATOR_LFRCO:
91       *frequency = SystemLFRCOClockGet();
92       break;
93 
94     case SL_OSCILLATOR_ULFRCO:
95       *frequency = SystemULFRCOClockGet();
96       break;
97 
98     default:
99       *frequency = 0U;
100       return SL_STATUS_INVALID_PARAMETER;
101   }
102 
103   return SL_STATUS_OK;
104 }
105 
106 /***************************************************************************//**
107  * Gets precision of given oscillator.
108  ******************************************************************************/
sli_clock_manager_hal_get_oscillator_precision(sl_oscillator_t oscillator,uint16_t * precision)109 sl_status_t sli_clock_manager_hal_get_oscillator_precision(sl_oscillator_t oscillator,
110                                                            uint16_t *precision)
111 {
112   switch (oscillator) {
113     case SL_OSCILLATOR_HFXO:
114       *precision = CMU_HFXOPrecisionGet();
115       break;
116 
117     case SL_OSCILLATOR_LFXO:
118       *precision = CMU_LFXOPrecisionGet();
119       break;
120 
121     case SL_OSCILLATOR_LFRCO:
122 #if defined(LFRCO_CFG_HIGHPRECEN)
123       if (LFRCO->CFG & _LFRCO_CFG_HIGHPRECEN_MASK) {
124         *precision = 500;
125       } else {
126         *precision = 0xFFFF;
127         return SL_STATUS_NOT_AVAILABLE;
128       }
129 #else
130       *precision = 0xFFFF;
131       return SL_STATUS_NOT_AVAILABLE;
132 #endif
133       break;
134 
135     case SL_OSCILLATOR_FSRCO:
136     case SL_OSCILLATOR_HFRCODPLL:
137     case SL_OSCILLATOR_ULFRCO:
138 #if defined(HFRCOEM23_PRESENT)
139     case SL_OSCILLATOR_HFRCOEM23:
140 #endif
141       *precision = 0xFFFF;
142       return SL_STATUS_NOT_AVAILABLE;
143 
144 #if defined(RFFPLL_PRESENT)
145     case SL_OSCILLATOR_RFFPLL:
146       *precision = 0xFFFF;
147       return SL_STATUS_NOT_AVAILABLE;
148 #endif
149 
150 #if defined(USBPLL_PRESENT)
151     case SL_OSCILLATOR_USBPLL:
152       *precision = 0xFFFF;
153       return SL_STATUS_NOT_AVAILABLE;
154 #endif
155 
156     default:
157       *precision = 0;
158       return SL_STATUS_INVALID_PARAMETER;
159   }
160 
161   return SL_STATUS_OK;
162 }
163 
164 /***************************************************************************//**
165  * Gets frequency of given clock branch.
166  ******************************************************************************/
sli_clock_manager_hal_get_clock_branch_frequency(sl_clock_branch_t clock_branch,uint32_t * frequency)167 sl_status_t sli_clock_manager_hal_get_clock_branch_frequency(sl_clock_branch_t clock_branch,
168                                                              uint32_t *frequency)
169 {
170   CORE_DECLARE_IRQ_STATE;
171 
172   sl_status_t return_status = SL_STATUS_OK;
173 
174   CORE_ENTER_ATOMIC();
175 
176   switch (clock_branch) {
177     case SL_CLOCK_BRANCH_SYSCLK:
178       *frequency = SystemSYSCLKGet();
179       break;
180 
181     case SL_CLOCK_BRANCH_HCLK:
182       *frequency = CMU_ClockFreqGet(cmuClock_HCLK);
183       break;
184 
185     case SL_CLOCK_BRANCH_PCLK:
186       *frequency = CMU_ClockFreqGet(cmuClock_PCLK);
187       break;
188 
189     case SL_CLOCK_BRANCH_LSPCLK:
190       *frequency = CMU_ClockFreqGet(cmuClock_LSPCLK);
191       break;
192 
193 #if defined(_CMU_TRACECLKCTRL_MASK)
194     case SL_CLOCK_BRANCH_TRACECLK:
195       *frequency = CMU_ClockFreqGet(cmuClock_TRACECLK);
196       break;
197 #endif
198 #if defined(_CMU_EXPORTCLKCTRL_MASK)
199     case SL_CLOCK_BRANCH_EXPORTCLK:
200       *frequency = CMU_ClockFreqGet(cmuClock_EXPCLK);
201       break;
202 #endif
203 #if defined(_CMU_EM01GRPACLKCTRL_MASK)
204     case SL_CLOCK_BRANCH_EM01GRPACLK:
205       *frequency = CMU_ClockFreqGet(cmuClock_EM01GRPACLK);
206       break;
207 #endif
208 #if defined(_CMU_EM01GRPBCLKCTRL_MASK)
209     case SL_CLOCK_BRANCH_EM01GRPBCLK:
210       *frequency = CMU_ClockFreqGet(cmuClock_EM01GRPBCLK);
211       break;
212 #endif
213 #if defined(_CMU_EM01GRPCCLKCTRL_MASK)
214     case SL_CLOCK_BRANCH_EM01GRPCCLK:
215       *frequency = CMU_ClockFreqGet(cmuClock_EM01GRPCCLK);
216       break;
217 #endif
218 #if defined(_CMU_EM23GRPACLKCTRL_MASK)
219     case SL_CLOCK_BRANCH_EM23GRPACLK:
220       *frequency = CMU_ClockFreqGet(cmuClock_EM23GRPACLK);
221       break;
222 #endif
223 #if defined(_CMU_EM4GRPACLKCTRL_MASK)
224     case SL_CLOCK_BRANCH_EM4GRPACLK:
225       *frequency = CMU_ClockFreqGet(cmuClock_EM4GRPACLK);
226       break;
227 #endif
228 #if defined(_CMU_IADCCLKCTRL_MASK)
229     case SL_CLOCK_BRANCH_IADCCLK:
230       *frequency = CMU_ClockFreqGet(cmuClock_IADCCLK);
231       break;
232 #endif
233 #if defined(_CMU_WDOG0CLKCTRL_MASK)
234     case SL_CLOCK_BRANCH_WDOG0CLK:
235       *frequency = CMU_ClockFreqGet(cmuClock_WDOG0CLK);
236       break;
237 #endif
238 #if defined(_CMU_WDOG1CLKCTRL_MASK)
239     case SL_CLOCK_BRANCH_WDOG1CLK:
240       *frequency = CMU_ClockFreqGet(cmuClock_WDOG1CLK);
241       break;
242 #endif
243 #if defined(_CMU_RTCCCLKCTRL_MASK)
244     case SL_CLOCK_BRANCH_RTCCCLK:
245       *frequency = CMU_ClockFreqGet(cmuClock_RTCCCLK);
246       break;
247 #endif
248 #if defined(_CMU_SYSRTC0CLKCTRL_MASK)
249     case SL_CLOCK_BRANCH_SYSRTCCLK:
250       *frequency = CMU_ClockFreqGet(cmuClock_SYSRTCCLK);
251       break;
252 #endif
253 #if defined(_CMU_EUART0CLKCTRL_MASK)
254     case SL_CLOCK_BRANCH_EUART0CLK:
255       *frequency = CMU_ClockFreqGet(cmuClock_EUART0CLK);
256       break;
257 #endif
258 #if defined(_CMU_EUSART0CLKCTRL_MASK)
259     case SL_CLOCK_BRANCH_EUSART0CLK:
260       *frequency = CMU_ClockFreqGet(cmuClock_EUSART0CLK);
261       break;
262 #endif
263 #if defined(LCD_PRESENT) && defined(_CMU_LCDCLKCTRL_MASK)
264     case SL_CLOCK_BRANCH_LCDCLK:
265       *frequency = CMU_ClockFreqGet(cmuClock_LCDCLK);
266       break;
267 #endif
268 #if defined(_CMU_PCNT0CLKCTRL_MASK)
269     case SL_CLOCK_BRANCH_PCNT0CLK:
270       *frequency = CMU_ClockFreqGet(cmuClock_PCNT0CLK);
271       break;
272 #endif
273 
274     case SL_CLOCK_BRANCH_SYSTICKCLK:
275       *frequency = CMU_ClockFreqGet(cmuClock_SYSTICK);
276       break;
277 
278 #if defined(_CMU_LESENSEHFCLKCTRL_MASK)
279     case SL_CLOCK_BRANCH_LESENSEHFCLK:
280       *frequency = CMU_ClockFreqGet(cmuClock_LESENSEHFCLK);
281       break;
282 #endif
283 #if defined(_CMU_VDAC0CLKCTRL_MASK)
284     case SL_CLOCK_BRANCH_VDAC0CLK:
285       *frequency = CMU_ClockFreqGet(cmuClock_VDAC0CLK);
286       break;
287 #endif
288 #if defined(_CMU_VDAC1CLKCTRL_MASK)
289     case SL_CLOCK_BRANCH_VDAC1CLK:
290       *frequency = CMU_ClockFreqGet(cmuClock_VDAC1CLK);
291       break;
292 #endif
293 #if defined(_CMU_USB0CLKCTRL_MASK)
294     case SL_CLOCK_BRANCH_USB0CLK:
295       *frequency = CMU_ClockFreqGet(cmuClock_USB);
296       break;
297 #endif
298 #if defined(_CMU_DPLLREFCLKCTRL_MASK)
299     case SL_CLOCK_BRANCH_DPLLREFCLK:
300       *frequency = CMU_ClockFreqGet(cmuClock_DPLLREFCLK);
301       break;
302 #endif
303 
304     default:
305       *frequency = 0U;
306       return_status = SL_STATUS_INVALID_PARAMETER;
307       break;
308   }
309 
310   CORE_EXIT_ATOMIC();
311 
312   return return_status;
313 }
314 
315 /***************************************************************************//**
316  * Gets precision of given clock branch.
317  ******************************************************************************/
sli_clock_manager_hal_get_clock_branch_precision(sl_clock_branch_t clock_branch,uint16_t * precision)318 sl_status_t sli_clock_manager_hal_get_clock_branch_precision(sl_clock_branch_t clock_branch,
319                                                              uint16_t *precision)
320 {
321   CORE_DECLARE_IRQ_STATE;
322   sl_status_t return_status = SL_STATUS_OK;
323 
324   CORE_ENTER_ATOMIC();
325 
326   switch (clock_branch) {
327     case SL_CLOCK_BRANCH_SYSCLK:
328     case SL_CLOCK_BRANCH_HCLK:
329     case SL_CLOCK_BRANCH_PCLK:
330     case SL_CLOCK_BRANCH_LSPCLK:
331     case SL_CLOCK_BRANCH_EXPORTCLK:
332       *precision = CMU_HF_ClockPrecisionGet(cmuClock_SYSCLK);
333       if (*precision == 0xFFFF) {
334         return_status = SL_STATUS_NOT_AVAILABLE;
335       }
336       break;
337 
338 #if defined(_CMU_TRACECLKCTRL_MASK)
339     case SL_CLOCK_BRANCH_TRACECLK:
340 #if defined(_CMU_TRACECLKCTRL_CLKSEL_MASK)
341       *precision = 0U;
342       return_status = SL_STATUS_NOT_SUPPORTED;
343 #else
344       *precision = CMU_HF_ClockPrecisionGet(cmuClock_SYSCLK);
345       if (*precision == 0xFFFF) {
346         return_status = SL_STATUS_NOT_AVAILABLE;
347       }
348 #endif
349       break;
350 
351 #endif
352 #if defined(_CMU_EM01GRPACLKCTRL_MASK)
353     case SL_CLOCK_BRANCH_EM01GRPACLK:
354       *precision = CMU_HF_ClockPrecisionGet(cmuClock_EM01GRPACLK);
355       if (*precision == 0xFFFF) {
356         return_status = SL_STATUS_NOT_AVAILABLE;
357       }
358       break;
359 #endif
360 #if defined(_CMU_EM01GRPBCLKCTRL_MASK)
361     case SL_CLOCK_BRANCH_EM01GRPBCLK:
362       *precision = CMU_HF_ClockPrecisionGet(cmuClock_EM01GRPBCLK);
363       if (*precision == 0xFFFF) {
364         return_status =  SL_STATUS_NOT_AVAILABLE;
365       }
366       break;
367 #endif
368 #if defined(_CMU_EM01GRPCCLKCTRL_MASK)
369     case SL_CLOCK_BRANCH_EM01GRPCCLK:
370       *precision = CMU_HF_ClockPrecisionGet(cmuClock_EM01GRPCCLK);
371       if (*precision == 0xFFFF) {
372         return_status =  SL_STATUS_NOT_AVAILABLE;
373       }
374       break;
375 #endif
376 #if defined(_CMU_EM23GRPACLKCTRL_MASK)
377     case SL_CLOCK_BRANCH_EM23GRPACLK:
378       *precision = CMU_LF_ClockPrecisionGet(cmuClock_EM23GRPACLK);
379       if (*precision == 0xFFFF) {
380         return_status =  SL_STATUS_NOT_AVAILABLE;
381       }
382       break;
383 #endif
384 #if defined(_CMU_EM4GRPACLKCTRL_MASK)
385     case SL_CLOCK_BRANCH_EM4GRPACLK:
386       *precision = CMU_LF_ClockPrecisionGet(cmuClock_EM4GRPACLK);
387       if (*precision == 0xFFFF) {
388         return_status =  SL_STATUS_NOT_AVAILABLE;
389       }
390       break;
391 #endif
392 #if defined(_CMU_IADCCLKCTRL_MASK)
393     case SL_CLOCK_BRANCH_IADCCLK:
394       *precision = 0U;
395       return_status =  SL_STATUS_NOT_SUPPORTED;
396       break;
397 #endif
398 #if defined(_CMU_WDOG0CLKCTRL_MASK)
399     case SL_CLOCK_BRANCH_WDOG0CLK:
400       *precision = 0U;
401       return_status =  SL_STATUS_NOT_SUPPORTED;
402       break;
403 #endif
404 #if defined(_CMU_WDOG1CLKCTRL_MASK)
405     case SL_CLOCK_BRANCH_WDOG1CLK:
406       *precision = 0U;
407       return_status =  SL_STATUS_NOT_SUPPORTED;
408       break;
409 #endif
410 #if defined(_CMU_RTCCCLKCTRL_MASK)
411     case SL_CLOCK_BRANCH_RTCCCLK:
412       *precision = CMU_LF_ClockPrecisionGet(cmuClock_RTCCCLK);
413       if (*precision == 0xFFFF) {
414         return_status =  SL_STATUS_NOT_AVAILABLE;
415       }
416       break;
417 #endif
418 #if defined(_CMU_SYSRTC0CLKCTRL_MASK)
419     case SL_CLOCK_BRANCH_SYSRTCCLK:
420       *precision = CMU_LF_ClockPrecisionGet(cmuClock_SYSRTCCLK);
421       if (*precision == 0xFFFF) {
422         return_status =  SL_STATUS_NOT_AVAILABLE;
423       }
424       break;
425 #endif
426 #if defined(_CMU_EUART0CLKCTRL_MASK)
427     case SL_CLOCK_BRANCH_EUART0CLK:
428       *precision = 0U;
429       return_status =  SL_STATUS_NOT_SUPPORTED;
430       break;
431 #endif
432 #if defined(_CMU_EUSART0CLKCTRL_MASK)
433     case SL_CLOCK_BRANCH_EUSART0CLK:
434       *precision = 0U;
435       return_status =  SL_STATUS_NOT_SUPPORTED;
436       break;
437 #endif
438 #if defined(LCD_PRESENT) && defined(_CMU_LCDCLKCTRL_MASK)
439     case SL_CLOCK_BRANCH_LCDCLK:
440       *precision = CMU_LF_ClockPrecisionGet(cmuClock_LCDCLK);
441       if (*precision == 0xFFFF) {
442         return_status =  SL_STATUS_NOT_AVAILABLE;
443       }
444       break;
445 #endif
446 #if defined(_CMU_PCNT0CLKCTRL_MASK)
447     case SL_CLOCK_BRANCH_PCNT0CLK:
448       *precision = 0U;
449       return_status =  SL_STATUS_NOT_SUPPORTED;
450       break;
451 #endif
452 
453     case SL_CLOCK_BRANCH_SYSTICKCLK:
454       *precision = 0U;
455       return_status =  SL_STATUS_NOT_SUPPORTED;
456       break;
457 
458 #if defined(_CMU_LESENSEHFCLKCTRL_MASK)
459     case SL_CLOCK_BRANCH_LESENSEHFCLK:
460       *precision = CMU_HF_ClockPrecisionGet(cmuClock_LESENSEHFCLK);
461       if (*precision == 0xFFFF) {
462         return_status =  SL_STATUS_NOT_AVAILABLE;
463       }
464       break;
465 #endif
466 #if defined(_CMU_VDAC0CLKCTRL_MASK)
467     case SL_CLOCK_BRANCH_VDAC0CLK:
468       *precision = 0U;
469       return_status =  SL_STATUS_NOT_SUPPORTED;
470       break;
471 #endif
472 #if defined(_CMU_VDAC1CLKCTRL_MASK)
473     case SL_CLOCK_BRANCH_VDAC1CLK:
474       *precision = 0U;
475       return_status =  SL_STATUS_NOT_SUPPORTED;
476       break;
477 #endif
478 #if defined(_CMU_USB0CLKCTRL_MASK)
479     case SL_CLOCK_BRANCH_USB0CLK:
480       *precision = 0U;
481       return_status =  SL_STATUS_NOT_SUPPORTED;
482       break;
483 #endif
484 
485 #if defined(_CMU_DPLLREFCLKCTRL_MASK)
486     case SL_CLOCK_BRANCH_DPLLREFCLK:
487       *precision = 0U;
488       return_status =  SL_STATUS_NOT_SUPPORTED;
489       break;
490 #endif
491 
492     default:
493       *precision = 0U;
494       return_status =  SL_STATUS_INVALID_PARAMETER;
495       break;
496   }
497 
498   CORE_EXIT_ATOMIC();
499 
500   return return_status;
501 }
502 
503 /***************************************************************************//**
504  * Enables/Disables the given module's bus clock.
505  ******************************************************************************/
sli_clock_manager_hal_enable_bus_clock(sl_bus_clock_t module_bus_clock,bool enable)506 sl_status_t sli_clock_manager_hal_enable_bus_clock(sl_bus_clock_t module_bus_clock, bool enable)
507 {
508 #if defined(_SILICON_LABS_32B_SERIES_2_CONFIG) && (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
509   volatile uint32_t *reg = NULL;
510   uint32_t bit;
511   uint32_t clken_index;
512 
513   if (module_bus_clock == SL_BUS_CLOCK_INVALID) {
514     return SL_STATUS_NOT_AVAILABLE;
515   }
516 
517   bit = (*module_bus_clock & _BUS_CLOCK_CLKEN_BIT_MASK) >> _BUS_CLOCK_CLKEN_BIT_SHIFT;
518   clken_index = (*module_bus_clock & _BUS_CLOCK_CLKENX_MASK) >> _BUS_CLOCK_CLKENX_SHIFT;
519 
520   if (clken_index == BUS_CLOCK_CLKEN0) {
521     reg = &CMU->CLKEN0;
522   } else if (clken_index == BUS_CLOCK_CLKEN1) {
523     reg = &CMU->CLKEN1;
524 #if defined(_CMU_CLKEN2_MASK)
525   } else if (clken_index == BUS_CLOCK_CLKEN2) {
526     reg = &CMU->CLKEN2;
527 #endif
528   } else {
529     return SL_STATUS_NOT_AVAILABLE;
530   }
531 
532   // Enable/disable bus clock.
533   BUS_RegBitWrite(reg, bit, (uint32_t)enable);
534 #else // defined(_SILICON_LABS_32B_SERIES_2_CONFIG) && (_SILICON_LABS_32B_SERIES_2_CONFIG > 1)
535   (void)enable;
536   (void)module_bus_clock;
537 #endif
538 
539   return SL_STATUS_OK;
540 }
541 
542 /***************************************************************************//**
543  * Configures the exported clock feature on CMU to output user selected
544  * clock source specified GPIO pin.
545  ******************************************************************************/
sli_clock_manager_hal_set_gpio_clock_output(sl_clock_manager_export_clock_source_t export_clock_source,sl_clock_manager_export_clock_output_select_t output_select,uint16_t divider,uint32_t port,uint32_t pin)546 sl_status_t sli_clock_manager_hal_set_gpio_clock_output(sl_clock_manager_export_clock_source_t export_clock_source,
547                                                         sl_clock_manager_export_clock_output_select_t output_select,
548                                                         uint16_t divider,
549                                                         uint32_t port,
550                                                         uint32_t pin)
551 {
552   CMU_Select_TypeDef cmu_clock_select;
553   CORE_DECLARE_IRQ_STATE;
554 
555   switch (export_clock_source) {
556     case SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_DISABLED:
557       cmu_clock_select = cmuSelect_Disabled;
558       break;
559 #if defined(FSRCO_PRESENT)
560     case SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_FSRCO:
561       cmu_clock_select = cmuSelect_FSRCO;
562       break;
563 #endif
564 #if defined(HFXO_PRESENT)
565     case SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_HFXO:
566       cmu_clock_select = cmuSelect_HFXO;
567       break;
568 #endif
569 #if defined(DPLL_PRESENT)
570     case SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_HFRCODPLL:
571       cmu_clock_select = cmuSelect_HFRCODPLL;
572       break;
573 #endif
574 #if defined(HFRCOEM23_PRESENT)
575     case SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_HFRCOEM23:
576       cmu_clock_select = cmuSelect_HFRCOEM23;
577       break;
578 #endif
579     case SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_HFEXPCLK:
580       cmu_clock_select  = cmuSelect_EXPCLK;
581       break;
582 #if defined(LFXO_PRESENT)
583     case SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_LFXO:
584       cmu_clock_select = cmuSelect_LFXO;
585       break;
586 #endif
587 #if defined(PLFRCO_PRESENT)
588     case SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_PLFRCO:
589       cmu_clock_select = cmuSelect_PLFRCO;
590       break;
591 #endif
592 #if defined(LFRCO)
593     case SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_LFRCO:
594       cmu_clock_select = cmuSelect_LFRCO;
595       break;
596 #endif
597 #if defined(ULFRCO)
598     case SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_ULFRCO:
599       cmu_clock_select = cmuSelect_ULFRCO;
600       break;
601 #endif
602     case SL_CLOCK_MANAGER_EXPORT_CLOCK_SOURCE_HCLK:
603       cmu_clock_select = cmuSelect_HCLK;
604       break;
605 
606     default:
607       return SL_STATUS_NOT_SUPPORTED;
608   }
609 
610   CORE_ENTER_ATOMIC();
611 
612   CMU_ClkOutPinConfig((uint32_t)output_select, cmu_clock_select, (CMU_ClkDiv_TypeDef)divider, port, pin);
613 
614   CORE_EXIT_ATOMIC();
615 
616   return SL_STATUS_OK;
617 }
618 
619 /***************************************************************************//**
620  * Sets the RC oscillator frequency tuning control.
621  ******************************************************************************/
sli_clock_manager_hal_set_rc_oscillator_calibration(sl_oscillator_t oscillator,uint32_t val)622 sl_status_t sli_clock_manager_hal_set_rc_oscillator_calibration(sl_oscillator_t oscillator,
623                                                                 uint32_t val)
624 {
625   switch (oscillator) {
626     case SL_OSCILLATOR_HFRCODPLL:
627       CMU_OscillatorTuningSet(cmuOsc_HFRCODPLL, val);
628       break;
629 
630 #if defined(HFRCOEM23_PRESENT)
631     case SL_OSCILLATOR_HFRCOEM23:
632       CMU_OscillatorTuningSet(cmuOsc_HFRCOEM23, val);
633       break;
634 #endif
635 
636     case SL_OSCILLATOR_LFRCO:
637       CMU_OscillatorTuningSet(cmuOsc_LFRCO, val);
638       break;
639 
640     default:
641       return SL_STATUS_NOT_SUPPORTED;
642   }
643 
644   return SL_STATUS_OK;
645 }
646 
647 /***************************************************************************//**
648  * Gets the RC oscillator frequency tuning setting.
649  ******************************************************************************/
sli_clock_manager_hal_get_rc_oscillator_calibration(sl_oscillator_t oscillator,uint32_t * val)650 sl_status_t sli_clock_manager_hal_get_rc_oscillator_calibration(sl_oscillator_t oscillator,
651                                                                 uint32_t *val)
652 {
653   switch (oscillator) {
654     case SL_OSCILLATOR_HFRCODPLL:
655       *val = CMU_OscillatorTuningGet(cmuOsc_HFRCODPLL);
656       break;
657 
658 #if defined(HFRCOEM23_PRESENT)
659     case SL_OSCILLATOR_HFRCOEM23:
660       *val = CMU_OscillatorTuningGet(cmuOsc_HFRCOEM23);
661       break;
662 #endif
663 
664     case SL_OSCILLATOR_LFRCO:
665       *val = CMU_OscillatorTuningGet(cmuOsc_LFRCO);
666       break;
667 
668     default:
669       *val = 0;
670       return SL_STATUS_NOT_SUPPORTED;
671   }
672 
673   return SL_STATUS_OK;
674 }
675 
676 /***************************************************************************//**
677  * Sets HFXO calibration value.
678  ******************************************************************************/
sli_clock_manager_hal_set_hfxo_calibration(uint32_t val)679 sl_status_t sli_clock_manager_hal_set_hfxo_calibration(uint32_t val)
680 {
681   CORE_DECLARE_IRQ_STATE;
682 
683   CORE_ENTER_ATOMIC();
684 
685   CMU_OscillatorTuningSet(cmuOsc_HFXO, val);
686 
687   CORE_EXIT_ATOMIC();
688 
689   return SL_STATUS_OK;
690 }
691 
692 /***************************************************************************//**
693  * Gets the HFXO calibration value.
694  ******************************************************************************/
sli_clock_manager_hal_get_hfxo_calibration(uint32_t * val)695 sl_status_t sli_clock_manager_hal_get_hfxo_calibration(uint32_t *val)
696 {
697   *val = CMU_OscillatorTuningGet(cmuOsc_HFXO);
698 
699   return SL_STATUS_OK;
700 }
701 
702 /***************************************************************************//**
703  * Sets the HFXO CTUNE setting.
704  ******************************************************************************/
sli_clock_manager_hal_hfxo_set_ctune(uint32_t ctune)705 sl_status_t sli_clock_manager_hal_hfxo_set_ctune(uint32_t ctune)
706 {
707   CORE_DECLARE_IRQ_STATE;
708   sl_status_t return_status = SL_STATUS_OK;
709 
710   CORE_ENTER_ATOMIC();
711   return_status = CMU_HFXOCTuneSet(ctune);
712   CORE_EXIT_ATOMIC();
713 
714   return return_status;
715 }
716 
717 /***************************************************************************//**
718  * Gets the HFXO CTUNE setting.
719  ******************************************************************************/
sli_clock_manager_hal_hfxo_get_ctune(uint32_t * ctune)720 sl_status_t sli_clock_manager_hal_hfxo_get_ctune(uint32_t *ctune)
721 {
722   *ctune = CMU_HFXOCTuneGet();
723 
724   return SL_STATUS_OK;
725 }
726 
727 /***************************************************************************//**
728  * Updates the tuning capacitances and calibrate the Core Bias Current.
729  ******************************************************************************/
sli_clock_manager_hal_hfxo_calibrate_ctune(uint32_t ctune)730 sl_status_t sli_clock_manager_hal_hfxo_calibrate_ctune(uint32_t ctune)
731 {
732   uint32_t hfxo_ctrl_backup = HFXO0->CTRL;
733 
734   // Having the FORCEEN here prevents the enabling and disabling of HFXO in
735   // each function calls.
736   HFXO0->CTRL_SET = HFXO_CTRL_FORCEEN;
737   while ((HFXO0->STATUS & (HFXO_STATUS_COREBIASOPTRDY | HFXO_STATUS_RDY | HFXO_STATUS_ENS))
738          != (HFXO_STATUS_COREBIASOPTRDY | HFXO_STATUS_RDY | HFXO_STATUS_ENS)) {
739     // Wait for crystal to startup
740   }
741 
742   sl_status_t status = CMU_HFXOCTuneSet(ctune);
743 
744   if (status == SL_STATUS_OK) {
745     CMU_HFXOCoreBiasCurrentCalibrate();
746   }
747 
748   BUS_RegMaskedWrite(&HFXO0->CTRL, _HFXO_CTRL_FORCEEN_MASK, hfxo_ctrl_backup);
749 
750   return status;
751 }
752 
753 /***************************************************************************//**
754  * Sets LFXO frequency tuning control.
755  ******************************************************************************/
sli_clock_manager_hal_set_lfxo_calibration(uint32_t val)756 sl_status_t sli_clock_manager_hal_set_lfxo_calibration(uint32_t val)
757 {
758   CORE_DECLARE_IRQ_STATE;
759 
760   CORE_ENTER_ATOMIC();
761 
762   CMU_OscillatorTuningSet(cmuOsc_LFXO, val);
763 
764   CORE_EXIT_ATOMIC();
765 
766   return SL_STATUS_OK;
767 }
768 
769 /***************************************************************************//**
770  * Gets the LFXO frequency tuning setting.
771  ******************************************************************************/
sli_clock_manager_hal_get_lfxo_calibration(uint32_t * val)772 sl_status_t sli_clock_manager_hal_get_lfxo_calibration(uint32_t *val)
773 {
774   *val = CMU_OscillatorTuningGet(cmuOsc_LFXO);
775 
776   return SL_STATUS_OK;
777 }
778 
779 /***************************************************************************//**
780  * Configures the RCO calibration.
781  ******************************************************************************/
sli_clock_manager_hal_configure_rco_calibration(uint32_t cycles,sl_clock_manager_clock_calibration_t down_counter_selection,sl_clock_manager_clock_calibration_t up_counter_selection,bool continuous_calibration)782 sl_status_t sli_clock_manager_hal_configure_rco_calibration(uint32_t cycles,
783                                                             sl_clock_manager_clock_calibration_t down_counter_selection,
784                                                             sl_clock_manager_clock_calibration_t up_counter_selection,
785                                                             bool continuous_calibration)
786 {
787   CMU_Select_TypeDef down_selection;
788   CMU_Select_TypeDef up_selection;
789 
790   switch (down_counter_selection) {
791     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_HFXO:
792       down_selection = cmuSelect_HFXO;
793       break;
794 
795     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_LFXO:
796       down_selection = cmuSelect_LFXO;
797       break;
798 
799     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_HFRCODPLL:
800       down_selection = cmuSelect_HFRCODPLL;
801       break;
802 
803 #if defined(HFRCOEM23_PRESENT)
804     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_HFRCOEM23:
805       down_selection = cmuSelect_HFRCOEM23;
806       break;
807 #endif
808 
809     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_FSRCO:
810       down_selection = cmuSelect_FSRCO;
811       break;
812 
813     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_LFRCO:
814       down_selection = cmuSelect_LFRCO;
815       break;
816 
817     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_ULFRCO:
818       down_selection = cmuSelect_ULFRCO;
819       break;
820 
821     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_PRS:
822       down_selection = cmuSelect_PRS;
823       break;
824 
825     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_HCLK:
826       down_selection = cmuSelect_HCLK;
827       break;
828 
829     default:
830       return SL_STATUS_NOT_AVAILABLE;
831   }
832 
833   switch (up_counter_selection) {
834     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_HFXO:
835       up_selection = cmuSelect_HFXO;
836       break;
837 
838     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_LFXO:
839       up_selection = cmuSelect_LFXO;
840       break;
841 
842     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_HFRCODPLL:
843       up_selection = cmuSelect_HFRCODPLL;
844       break;
845 
846 #if defined(HFRCOEM23_PRESENT)
847     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_HFRCOEM23:
848       up_selection = cmuSelect_HFRCOEM23;
849       break;
850 #endif
851 
852     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_FSRCO:
853       up_selection =  cmuSelect_FSRCO;
854       break;
855 
856     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_LFRCO:
857       up_selection = cmuSelect_LFRCO;
858       break;
859 
860     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_ULFRCO:
861       up_selection = cmuSelect_ULFRCO;
862       break;
863 
864     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_PRS:
865       up_selection = cmuSelect_PRS;
866       break;
867 
868     case SL_CLOCK_MANAGER_CLOCK_CALIBRATION_HCLK:
869       return SL_STATUS_NOT_SUPPORTED;
870 
871     default:
872       return SL_STATUS_NOT_AVAILABLE;
873   }
874 
875   CORE_DECLARE_IRQ_STATE;
876 
877   CORE_ENTER_ATOMIC();
878 
879   CMU_CalibrateConfig(cycles, down_selection, up_selection);
880   CMU_CalibrateCont(continuous_calibration);
881 
882   CORE_EXIT_ATOMIC();
883 
884   return SL_STATUS_OK;
885 }
886 
887 /***************************************************************************//**
888  * Starts the RCO calibration.
889  ******************************************************************************/
sli_clock_manager_hal_start_rco_calibration(void)890 void sli_clock_manager_hal_start_rco_calibration(void)
891 {
892   CMU_CalibrateStart();
893 }
894 
895 /***************************************************************************//**
896  * Stops the RCO calibration.
897  ******************************************************************************/
sli_clock_manager_hal_stop_rco_calibration(void)898 void sli_clock_manager_hal_stop_rco_calibration(void)
899 {
900   CMU_CalibrateStop();
901 }
902 
903 /***************************************************************************//**
904  * Waits for the RCO calibration to finish.
905  ******************************************************************************/
sli_clock_manager_hal_wait_rco_calibration(void)906 void sli_clock_manager_hal_wait_rco_calibration(void)
907 {
908   // Wait until calibration completes, UNLESS continuous calibration mode is on
909   if ((CMU->CALCTRL & CMU_CALCTRL_CONT) == 0UL) {
910     // Wait until calibration completes
911     while ((CMU->STATUS & CMU_STATUS_CALRDY) == 0UL) ;
912   }
913 }
914 
915 /***************************************************************************//**
916  * Gets calibration count value.
917  ******************************************************************************/
sli_clock_manager_hal_get_rco_calibration_count(uint32_t * count)918 sl_status_t sli_clock_manager_hal_get_rco_calibration_count(uint32_t *count)
919 {
920   *count = CMU->CALCNT;
921 
922   return SL_STATUS_OK;
923 }
924 
925 /***************************************************************************//**
926  * Updates SYSCLK clock source clock.
927  ******************************************************************************/
sli_clock_manager_hal_set_sysclk_source(sl_oscillator_t source)928 sl_status_t sli_clock_manager_hal_set_sysclk_source(sl_oscillator_t source)
929 {
930   CORE_DECLARE_IRQ_STATE;
931   sl_status_t return_status = SL_STATUS_OK;
932 
933   CORE_ENTER_ATOMIC();
934 
935   switch (source) {
936     case SL_OSCILLATOR_FSRCO:
937       sli_em_cmu_SYSCLKInitPreClockSelect();
938       CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_CLKSEL_MASK) | CMU_SYSCLKCTRL_CLKSEL_FSRCO;
939       sli_em_cmu_SYSCLKInitPostClockSelect(false);
940       break;
941     case SL_OSCILLATOR_HFXO:
942       sli_em_cmu_SYSCLKInitPreClockSelect();
943       CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_CLKSEL_MASK) | CMU_SYSCLKCTRL_CLKSEL_HFXO;
944       sli_em_cmu_SYSCLKInitPostClockSelect(false);
945       break;
946     case SL_OSCILLATOR_HFRCODPLL:
947       sli_em_cmu_SYSCLKInitPreClockSelect();
948       CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_CLKSEL_MASK) | CMU_SYSCLKCTRL_CLKSEL_HFRCODPLL;
949       sli_em_cmu_SYSCLKInitPostClockSelect(false);
950       break;
951 #if defined(CMU_SYSCLKCTRL_CLKSEL_RFFPLL0SYS)
952     case SL_OSCILLATOR_RFFPLL:
953       sli_em_cmu_SYSCLKInitPreClockSelect();
954       CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_CLKSEL_MASK) | CMU_SYSCLKCTRL_CLKSEL_RFFPLL0SYS;
955       sli_em_cmu_SYSCLKInitPostClockSelect(false);
956       break;
957 #endif
958     case SL_OSCILLATOR_CLKIN0:
959       sli_em_cmu_SYSCLKInitPreClockSelect();
960       CMU->SYSCLKCTRL = (CMU->SYSCLKCTRL & ~_CMU_SYSCLKCTRL_CLKSEL_MASK) | CMU_SYSCLKCTRL_CLKSEL_CLKIN0;
961       sli_em_cmu_SYSCLKInitPostClockSelect(false);
962       break;
963     default:
964       return_status = SL_STATUS_INVALID_PARAMETER;
965       break;
966   }
967 
968   CORE_EXIT_ATOMIC();
969 
970   return return_status;
971 }
972 
973 /***************************************************************************//**
974  * Gets SYSCLK clock source clock.
975  ******************************************************************************/
sli_clock_manager_hal_get_sysclk_source(sl_oscillator_t * source)976 sl_status_t sli_clock_manager_hal_get_sysclk_source(sl_oscillator_t *source)
977 {
978   switch (CMU->SYSCLKCTRL & _CMU_SYSCLKCTRL_CLKSEL_MASK) {
979     case  CMU_SYSCLKCTRL_CLKSEL_FSRCO:
980       *source = SL_OSCILLATOR_FSRCO;
981       break;
982     case  CMU_SYSCLKCTRL_CLKSEL_HFXO:
983       *source = SL_OSCILLATOR_HFXO;
984       break;
985     case  CMU_SYSCLKCTRL_CLKSEL_HFRCODPLL:
986       *source = SL_OSCILLATOR_HFRCODPLL;
987       break;
988     case  CMU_SYSCLKCTRL_CLKSEL_CLKIN0:
989       *source = SL_OSCILLATOR_CLKIN0;
990       break;
991 #if defined(CMU_SYSCLKCTRL_CLKSEL_RFFPLL0SYS)
992     case CMU_SYSCLKCTRL_CLKSEL_RFFPLL0SYS:
993       *source = SL_OSCILLATOR_RFFPLL;
994       break;
995 #endif
996     default:
997       EFM_ASSERT(false);
998       break;
999   }
1000 
1001   return SL_STATUS_OK;
1002 }
1003 
1004 /***************************************************************************//**
1005  * Waits for USBPLL clock to be ready.
1006  ******************************************************************************/
sli_clock_manager_hal_wait_usbpll(void)1007 sl_status_t sli_clock_manager_hal_wait_usbpll(void)
1008 {
1009 #if defined(USBPLL_PRESENT)
1010   while ((USBPLL0->STATUS & (USBPLL_STATUS_PLLRDY | USBPLL_STATUS_PLLLOCK))
1011          != (USBPLL_STATUS_PLLRDY | USBPLL_STATUS_PLLLOCK)) {
1012     // Wait for USB PLL lock and ready
1013   }
1014   return SL_STATUS_OK;
1015 #else
1016   return SL_STATUS_NOT_AVAILABLE;
1017 #endif
1018 }
1019 
1020 /***************************************************************************//**
1021  * Updates QSPI clock and reference clock.
1022  ******************************************************************************/
sli_clock_manager_hal_update_qspi_clk(sl_oscillator_t oscillator)1023 sl_status_t sli_clock_manager_hal_update_qspi_clk(sl_oscillator_t oscillator)
1024 {
1025   (void)oscillator;
1026   return SL_STATUS_NOT_AVAILABLE;
1027 }
1028 
1029 /***************************************************************************//**
1030  * Gets QSPI clock source.
1031  ******************************************************************************/
sli_clock_manager_get_current_qspi_clk(sl_oscillator_t * oscillator)1032 sl_status_t sli_clock_manager_get_current_qspi_clk(sl_oscillator_t *oscillator)
1033 {
1034   if (oscillator == NULL) {
1035     return SL_STATUS_NULL_POINTER;
1036   }
1037 
1038   (void)oscillator;
1039   return SL_STATUS_NOT_AVAILABLE;
1040 }
1041