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