aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios-contrib/ext/mcux-sdk/devices/MK22F12810/drivers/fsl_clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chibios-contrib/ext/mcux-sdk/devices/MK22F12810/drivers/fsl_clock.c')
-rw-r--r--lib/chibios-contrib/ext/mcux-sdk/devices/MK22F12810/drivers/fsl_clock.c1905
1 files changed, 1905 insertions, 0 deletions
diff --git a/lib/chibios-contrib/ext/mcux-sdk/devices/MK22F12810/drivers/fsl_clock.c b/lib/chibios-contrib/ext/mcux-sdk/devices/MK22F12810/drivers/fsl_clock.c
new file mode 100644
index 000000000..47c93e141
--- /dev/null
+++ b/lib/chibios-contrib/ext/mcux-sdk/devices/MK22F12810/drivers/fsl_clock.c
@@ -0,0 +1,1905 @@
1/*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016 - 2020, NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9#include "fsl_clock.h"
10
11/*******************************************************************************
12 * Definitions
13 ******************************************************************************/
14
15/* Component ID definition, used by tools. */
16#ifndef FSL_COMPONENT_ID
17#define FSL_COMPONENT_ID "platform.drivers.clock"
18#endif
19
20/* Macro definition remap workaround. */
21#if (defined(MCG_C2_EREFS_MASK) && !(defined(MCG_C2_EREFS0_MASK)))
22#define MCG_C2_EREFS0_MASK MCG_C2_EREFS_MASK
23#endif
24#if (defined(MCG_C2_HGO_MASK) && !(defined(MCG_C2_HGO0_MASK)))
25#define MCG_C2_HGO0_MASK MCG_C2_HGO_MASK
26#endif
27#if (defined(MCG_C2_RANGE_MASK) && !(defined(MCG_C2_RANGE0_MASK)))
28#define MCG_C2_RANGE0_MASK MCG_C2_RANGE_MASK
29#endif
30#if (defined(MCG_C6_CME_MASK) && !(defined(MCG_C6_CME0_MASK)))
31#define MCG_C6_CME0_MASK MCG_C6_CME_MASK
32#endif
33
34/* PLL fixed multiplier when there is not PRDIV and VDIV. */
35#define PLL_FIXED_MULT (375U)
36/* Max frequency of the reference clock used for internal clock trim. */
37#define TRIM_REF_CLK_MIN (8000000U)
38/* Min frequency of the reference clock used for internal clock trim. */
39#define TRIM_REF_CLK_MAX (16000000U)
40/* Max trim value of fast internal reference clock. */
41#define TRIM_FIRC_MAX (5000000U)
42/* Min trim value of fast internal reference clock. */
43#define TRIM_FIRC_MIN (3000000U)
44/* Max trim value of fast internal reference clock. */
45#define TRIM_SIRC_MAX (39063U)
46/* Min trim value of fast internal reference clock. */
47#define TRIM_SIRC_MIN (31250U)
48
49#define MCG_S_IRCST_VAL (((uint32_t)MCG->S & (uint32_t)MCG_S_IRCST_MASK) >> (uint32_t)MCG_S_IRCST_SHIFT)
50#define MCG_S_CLKST_VAL (((uint32_t)MCG->S & (uint32_t)MCG_S_CLKST_MASK) >> (uint32_t)MCG_S_CLKST_SHIFT)
51#define MCG_S_IREFST_VAL (((uint32_t)MCG->S & (uint32_t)MCG_S_IREFST_MASK) >> (uint32_t)MCG_S_IREFST_SHIFT)
52#define MCG_S_PLLST_VAL (((uint32_t)MCG->S & (uint32_t)MCG_S_PLLST_MASK) >> (uint32_t)MCG_S_PLLST_SHIFT)
53#define MCG_C1_FRDIV_VAL ((MCG->C1 & MCG_C1_FRDIV_MASK) >> MCG_C1_FRDIV_SHIFT)
54#define MCG_C2_LP_VAL (((uint32_t)MCG->C2 & (uint32_t)MCG_C2_LP_MASK) >> (uint32_t)MCG_C2_LP_SHIFT)
55#define MCG_C2_RANGE_VAL ((MCG->C2 & MCG_C2_RANGE_MASK) >> MCG_C2_RANGE_SHIFT)
56#define MCG_SC_FCRDIV_VAL ((MCG->SC & MCG_SC_FCRDIV_MASK) >> MCG_SC_FCRDIV_SHIFT)
57#define MCG_S2_PLLCST_VAL (((uint32_t)MCG->S2 & (uint32_t)MCG_S2_PLLCST_MASK) >> (uint32_t)MCG_S2_PLLCST_SHIFT)
58#define MCG_C7_OSCSEL_VAL ((MCG->C7 & MCG_C7_OSCSEL_MASK) >> MCG_C7_OSCSEL_SHIFT)
59#define MCG_C4_DMX32_VAL ((MCG->C4 & MCG_C4_DMX32_MASK) >> MCG_C4_DMX32_SHIFT)
60#define MCG_C4_DRST_DRS_VAL ((MCG->C4 & MCG_C4_DRST_DRS_MASK) >> MCG_C4_DRST_DRS_SHIFT)
61#define MCG_C7_PLL32KREFSEL_VAL ((MCG->C7 & MCG_C7_PLL32KREFSEL_MASK) >> MCG_C7_PLL32KREFSEL_SHIFT)
62#define MCG_C5_PLLREFSEL0_VAL ((MCG->C5 & MCG_C5_PLLREFSEL0_MASK) >> MCG_C5_PLLREFSEL0_SHIFT)
63#define MCG_C11_PLLREFSEL1_VAL ((MCG->C11 & MCG_C11_PLLREFSEL1_MASK) >> MCG_C11_PLLREFSEL1_SHIFT)
64#define MCG_C11_PRDIV1_VAL ((MCG->C11 & MCG_C11_PRDIV1_MASK) >> MCG_C11_PRDIV1_SHIFT)
65#define MCG_C12_VDIV1_VAL ((MCG->C12 & MCG_C12_VDIV1_MASK) >> MCG_C12_VDIV1_SHIFT)
66#define MCG_C5_PRDIV0_VAL ((uint8_t)(MCG->C5 & MCG_C5_PRDIV0_MASK) >> MCG_C5_PRDIV0_SHIFT)
67#define MCG_C6_VDIV0_VAL ((uint8_t)(MCG->C6 & MCG_C6_VDIV0_MASK) >> MCG_C6_VDIV0_SHIFT)
68
69#define OSC_MODE_MASK (MCG_C2_EREFS0_MASK | MCG_C2_HGO0_MASK | MCG_C2_RANGE0_MASK)
70
71#define SIM_CLKDIV1_OUTDIV1_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT)
72#define SIM_CLKDIV1_OUTDIV2_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV2_MASK) >> SIM_CLKDIV1_OUTDIV2_SHIFT)
73#define SIM_CLKDIV1_OUTDIV4_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT)
74#define SIM_SOPT1_OSC32KSEL_VAL ((SIM->SOPT1 & SIM_SOPT1_OSC32KSEL_MASK) >> SIM_SOPT1_OSC32KSEL_SHIFT)
75#define SIM_SOPT2_PLLFLLSEL_VAL ((SIM->SOPT2 & SIM_SOPT2_PLLFLLSEL_MASK) >> SIM_SOPT2_PLLFLLSEL_SHIFT)
76
77/* MCG_S_CLKST definition. */
78enum _mcg_clkout_stat
79{
80 kMCG_ClkOutStatFll, /* FLL. */
81 kMCG_ClkOutStatInt, /* Internal clock. */
82 kMCG_ClkOutStatExt, /* External clock. */
83 kMCG_ClkOutStatPll /* PLL. */
84};
85
86/* MCG_S_PLLST definition. */
87enum _mcg_pllst
88{
89 kMCG_PllstFll, /* FLL is used. */
90 kMCG_PllstPll /* PLL is used. */
91};
92
93/*******************************************************************************
94 * Variables
95 ******************************************************************************/
96
97/* Slow internal reference clock frequency. */
98static uint32_t s_slowIrcFreq = 32768U;
99/* Fast internal reference clock frequency. */
100static uint32_t s_fastIrcFreq = 4000000U;
101
102/* External XTAL0 (OSC0) clock frequency. */
103volatile uint32_t g_xtal0Freq;
104/* External XTAL32K clock frequency. */
105volatile uint32_t g_xtal32Freq;
106
107/*******************************************************************************
108 * Prototypes
109 ******************************************************************************/
110
111/*!
112 * @brief Get the MCG external reference clock frequency.
113 *
114 * Get the current MCG external reference clock frequency in Hz. It is
115 * the frequency select by MCG_C7[OSCSEL]. This is an internal function.
116 *
117 * @return MCG external reference clock frequency in Hz.
118 */
119static uint32_t CLOCK_GetMcgExtClkFreq(void);
120
121/*!
122 * @brief Get the MCG FLL external reference clock frequency.
123 *
124 * Get the current MCG FLL external reference clock frequency in Hz. It is
125 * the frequency after by MCG_C1[FRDIV]. This is an internal function.
126 *
127 * @return MCG FLL external reference clock frequency in Hz.
128 */
129static uint32_t CLOCK_GetFllExtRefClkFreq(void);
130
131/*!
132 * @brief Get the MCG FLL reference clock frequency.
133 *
134 * Get the current MCG FLL reference clock frequency in Hz. It is
135 * the frequency select by MCG_C1[IREFS]. This is an internal function.
136 *
137 * @return MCG FLL reference clock frequency in Hz.
138 */
139static uint32_t CLOCK_GetFllRefClkFreq(void);
140
141/*!
142 * @brief Get the frequency of clock selected by MCG_C2[IRCS].
143 *
144 * This clock's two output:
145 * 1. MCGOUTCLK when MCG_S[CLKST]=0.
146 * 2. MCGIRCLK when MCG_C1[IRCLKEN]=1.
147 *
148 * @return The frequency in Hz.
149 */
150static uint32_t CLOCK_GetInternalRefClkSelectFreq(void);
151
152/*!
153 * @brief Calculate the RANGE value base on crystal frequency.
154 *
155 * To setup external crystal oscillator, must set the register bits RANGE
156 * base on the crystal frequency. This function returns the RANGE base on the
157 * input frequency. This is an internal function.
158 *
159 * @param freq Crystal frequency in Hz.
160 * @return The RANGE value.
161 */
162static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq);
163
164#ifndef MCG_USER_CONFIG_FLL_STABLE_DELAY_EN
165/*!
166 * @brief Delay function to wait FLL stable.
167 *
168 * Delay function to wait FLL stable in FEI mode or FEE mode, should wait at least
169 * 1ms. Every time changes FLL setting, should wait this time for FLL stable.
170 */
171static void CLOCK_FllStableDelay(void);
172#endif
173
174/*******************************************************************************
175 * Code
176 ******************************************************************************/
177
178#ifndef MCG_USER_CONFIG_FLL_STABLE_DELAY_EN
179static void CLOCK_FllStableDelay(void)
180{
181 /*
182 Should wait at least 1ms. Because in these modes, the core clock is 100MHz
183 at most, so this function could obtain the 1ms delay.
184 */
185 volatile uint32_t i = 30000U;
186 while (0U != (i--))
187 {
188 __NOP();
189 }
190}
191#else /* With MCG_USER_CONFIG_FLL_STABLE_DELAY_EN defined. */
192/* Once user defines the MCG_USER_CONFIG_FLL_STABLE_DELAY_EN to use their own delay function, he has to
193 * create his own CLOCK_FllStableDelay() function in application code. Since the clock functions in this
194 * file would call the CLOCK_FllStableDelay() regardless how it is defined.
195 */
196extern void CLOCK_FllStableDelay(void);
197#endif /* MCG_USER_CONFIG_FLL_STABLE_DELAY_EN */
198
199static uint32_t CLOCK_GetMcgExtClkFreq(void)
200{
201 uint32_t freq;
202
203 switch (MCG_C7_OSCSEL_VAL)
204 {
205 case 0U:
206 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
207 assert(0U != g_xtal0Freq);
208 freq = g_xtal0Freq;
209 break;
210 case 1U:
211 /* Please call CLOCK_SetXtal32Freq base on board setting before using XTAL32K/RTC_CLKIN clock. */
212 assert(0U != g_xtal32Freq);
213 freq = g_xtal32Freq;
214 break;
215 case 2U:
216 freq = MCG_INTERNAL_IRC_48M;
217 break;
218 default:
219 freq = 0U;
220 break;
221 }
222
223 return freq;
224}
225
226static uint32_t CLOCK_GetFllExtRefClkFreq(void)
227{
228 /* FllExtRef = McgExtRef / FllExtRefDiv */
229 uint8_t frdiv;
230 uint8_t range;
231 uint8_t oscsel;
232
233 uint32_t freq = CLOCK_GetMcgExtClkFreq();
234
235 frdiv = MCG_C1_FRDIV_VAL;
236 freq >>= frdiv;
237
238 range = MCG_C2_RANGE_VAL;
239 oscsel = MCG_C7_OSCSEL_VAL;
240
241 /*
242 When should use divider 32, 64, 128, 256, 512, 1024, 1280, 1536.
243 1. MCG_C7[OSCSEL] selects IRC48M.
244 2. MCG_C7[OSCSEL] selects OSC0 and MCG_C2[RANGE] is not 0.
245 */
246 if (((0U != range) && ((uint8_t)kMCG_OscselOsc == oscsel)) || ((uint8_t)kMCG_OscselIrc == oscsel))
247 {
248 switch (frdiv)
249 {
250 case 0:
251 case 1:
252 case 2:
253 case 3:
254 case 4:
255 case 5:
256 freq >>= 5u;
257 break;
258 case 6:
259 /* 64*20=1280 */
260 freq /= 20u;
261 break;
262 case 7:
263 /* 128*12=1536 */
264 freq /= 12u;
265 break;
266 default:
267 freq = 0u;
268 break;
269 }
270 }
271
272 return freq;
273}
274
275static uint32_t CLOCK_GetInternalRefClkSelectFreq(void)
276{
277 uint32_t freq;
278
279 if ((uint8_t)kMCG_IrcSlow == MCG_S_IRCST_VAL)
280 {
281 /* Slow internal reference clock selected*/
282 freq = s_slowIrcFreq;
283 }
284 else
285 {
286 /* Fast internal reference clock selected*/
287 freq = s_fastIrcFreq >> MCG_SC_FCRDIV_VAL;
288 }
289
290 return freq;
291}
292
293static uint32_t CLOCK_GetFllRefClkFreq(void)
294{
295 uint32_t freq;
296
297 /* If use external reference clock. */
298 if ((uint8_t)kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
299 {
300 freq = CLOCK_GetFllExtRefClkFreq();
301 }
302 /* If use internal reference clock. */
303 else
304 {
305 freq = s_slowIrcFreq;
306 }
307
308 return freq;
309}
310
311static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq)
312{
313 uint8_t range;
314
315 if (freq <= 39063U)
316 {
317 range = 0U;
318 }
319 else if (freq <= 8000000U)
320 {
321 range = 1U;
322 }
323 else
324 {
325 range = 2U;
326 }
327
328 return range;
329}
330
331/*!
332 * brief Get the OSC0 external reference undivided clock frequency (OSC0ERCLK_UNDIV).
333 *
334 * return Clock frequency in Hz.
335 */
336uint32_t CLOCK_GetOsc0ErClkUndivFreq(void)
337{
338 if ((OSC0->CR & OSC_CR_ERCLKEN_MASK) != 0U)
339 {
340 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
341 assert(g_xtal0Freq);
342 return g_xtal0Freq;
343 }
344 else
345 {
346 return 0U;
347 }
348}
349
350/*!
351 * brief Get the OSC0 external reference divided clock frequency.
352 *
353 * return Clock frequency in Hz.
354 */
355uint32_t CLOCK_GetOsc0ErClkDivFreq(void)
356{
357 uint32_t freq;
358 uint8_t temp;
359 if ((OSC0->CR & OSC_CR_ERCLKEN_MASK) != 0U)
360 {
361 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
362 assert(g_xtal0Freq);
363 temp = OSC0->DIV & OSC_DIV_ERPS_MASK;
364 freq = g_xtal0Freq >> ((temp) >> OSC_DIV_ERPS_SHIFT);
365 }
366 else
367 {
368 freq = 0U;
369 }
370 return freq;
371}
372
373/*!
374 * brief Get the external reference 32K clock frequency (ERCLK32K).
375 *
376 * return Clock frequency in Hz.
377 */
378uint32_t CLOCK_GetEr32kClkFreq(void)
379{
380 uint32_t freq;
381
382 switch (SIM_SOPT1_OSC32KSEL_VAL)
383 {
384 case 0U: /* OSC 32k clock */
385 freq = (CLOCK_GetOsc0ErClkUndivFreq() == 32768U) ? 32768U : 0U;
386 break;
387 case 2U: /* RTC 32k clock */
388 /* Please call CLOCK_SetXtal32Freq base on board setting before using XTAL32K/RTC_CLKIN clock. */
389 assert(g_xtal32Freq);
390 freq = g_xtal32Freq;
391 break;
392 case 3U: /* LPO clock */
393 freq = LPO_CLK_FREQ;
394 break;
395 default:
396 freq = 0U;
397 break;
398 }
399 return freq;
400}
401
402/*!
403 * brief Get the output clock frequency selected by SIM[PLLFLLSEL].
404 *
405 * return Clock frequency in Hz.
406 */
407uint32_t CLOCK_GetPllFllSelClkFreq(void)
408{
409 uint32_t freq;
410
411 switch (SIM_SOPT2_PLLFLLSEL_VAL)
412 {
413 case 0U: /* FLL. */
414 freq = CLOCK_GetFllFreq();
415 break;
416 case 3U: /* MCG IRC48M. */
417 freq = MCG_INTERNAL_IRC_48M;
418 break;
419 default:
420 freq = 0U;
421 break;
422 }
423
424 return freq;
425}
426
427/*!
428 * brief Get the OSC0 external reference clock frequency (OSC0ERCLK).
429 *
430 * return Clock frequency in Hz.
431 */
432uint32_t CLOCK_GetOsc0ErClkFreq(void)
433{
434 return CLOCK_GetOsc0ErClkDivFreq();
435}
436
437/*!
438 * brief Get the platform clock frequency.
439 *
440 * return Clock frequency in Hz.
441 */
442uint32_t CLOCK_GetPlatClkFreq(void)
443{
444 return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1UL);
445}
446
447/*!
448 * brief Get the flash clock frequency.
449 *
450 * return Clock frequency in Hz.
451 */
452uint32_t CLOCK_GetFlashClkFreq(void)
453{
454 return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV4_VAL + 1UL);
455}
456
457/*!
458 * brief Get the bus clock frequency.
459 *
460 * return Clock frequency in Hz.
461 */
462uint32_t CLOCK_GetBusClkFreq(void)
463{
464 return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV2_VAL + 1UL);
465}
466
467/*!
468 * brief Get the core clock or system clock frequency.
469 *
470 * return Clock frequency in Hz.
471 */
472uint32_t CLOCK_GetCoreSysClkFreq(void)
473{
474 return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1UL);
475}
476
477/*!
478 * brief Gets the clock frequency for a specific clock name.
479 *
480 * This function checks the current clock configurations and then calculates
481 * the clock frequency for a specific clock name defined in clock_name_t.
482 * The MCG must be properly configured before using this function.
483 *
484 * param clockName Clock names defined in clock_name_t
485 * return Clock frequency value in Hertz
486 */
487uint32_t CLOCK_GetFreq(clock_name_t clockName)
488{
489 uint32_t freq;
490
491 switch (clockName)
492 {
493 case kCLOCK_CoreSysClk:
494 case kCLOCK_PlatClk:
495 freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1UL);
496 break;
497 case kCLOCK_BusClk:
498 freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV2_VAL + 1UL);
499 break;
500 case kCLOCK_FlashClk:
501 freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV4_VAL + 1UL);
502 break;
503 case kCLOCK_PllFllSelClk:
504 freq = CLOCK_GetPllFllSelClkFreq();
505 break;
506 case kCLOCK_Er32kClk:
507 freq = CLOCK_GetEr32kClkFreq();
508 break;
509 case kCLOCK_McgFixedFreqClk:
510 freq = CLOCK_GetFixedFreqClkFreq();
511 break;
512 case kCLOCK_McgInternalRefClk:
513 freq = CLOCK_GetInternalRefClkFreq();
514 break;
515 case kCLOCK_McgFllClk:
516 freq = CLOCK_GetFllFreq();
517 break;
518 case kCLOCK_McgIrc48MClk:
519 freq = MCG_INTERNAL_IRC_48M;
520 break;
521 case kCLOCK_LpoClk:
522 freq = LPO_CLK_FREQ;
523 break;
524 case kCLOCK_Osc0ErClkUndiv:
525 freq = CLOCK_GetOsc0ErClkUndivFreq();
526 break;
527 case kCLOCK_Osc0ErClk:
528 freq = CLOCK_GetOsc0ErClkDivFreq();
529 break;
530 default:
531 freq = 0U;
532 break;
533 }
534
535 return freq;
536}
537
538/*!
539 * brief Set the clock configure in SIM module.
540 *
541 * This function sets system layer clock settings in SIM module.
542 *
543 * param config Pointer to the configure structure.
544 */
545void CLOCK_SetSimConfig(sim_clock_config_t const *config)
546{
547 SIM->CLKDIV1 = config->clkdiv1;
548 CLOCK_SetPllFllSelClock(config->pllFllSel);
549 CLOCK_SetEr32kClock(config->er32kSrc);
550}
551
552/*! brief Enable USB FS clock.
553 *
554 * param src USB FS clock source.
555 * param freq The frequency specified by src.
556 * retval true The clock is set successfully.
557 * retval false The clock source is invalid to get proper USB FS clock.
558 */
559bool CLOCK_EnableUsbfs0Clock(clock_usb_src_t src, uint32_t freq)
560{
561 bool ret = true;
562
563 CLOCK_DisableClock(kCLOCK_Usbfs0);
564
565 if (kCLOCK_UsbSrcExt == src)
566 {
567 SIM->SOPT2 &= ~SIM_SOPT2_USBSRC_MASK;
568 }
569 else
570 {
571 switch (freq)
572 {
573 case 120000000U:
574 SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(4) | SIM_CLKDIV2_USBFRAC(1);
575 break;
576 case 96000000U:
577 SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(1) | SIM_CLKDIV2_USBFRAC(0);
578 break;
579 case 72000000U:
580 SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(2) | SIM_CLKDIV2_USBFRAC(1);
581 break;
582 case 48000000U:
583 SIM->CLKDIV2 = SIM_CLKDIV2_USBDIV(0) | SIM_CLKDIV2_USBFRAC(0);
584 break;
585 default:
586 ret = false;
587 break;
588 }
589
590 SIM->SOPT2 = ((SIM->SOPT2 & ~(SIM_SOPT2_PLLFLLSEL_MASK | SIM_SOPT2_USBSRC_MASK)) | (uint32_t)src);
591 }
592
593 CLOCK_EnableClock(kCLOCK_Usbfs0);
594
595 if (kCLOCK_UsbSrcIrc48M == src)
596 {
597 USB0->CLK_RECOVER_IRC_EN = 0x03U;
598 USB0->CLK_RECOVER_CTRL |= USB_CLK_RECOVER_CTRL_CLOCK_RECOVER_EN_MASK;
599 }
600 return ret;
601}
602
603/*!
604 * brief Gets the MCG output clock (MCGOUTCLK) frequency.
605 *
606 * This function gets the MCG output clock frequency in Hz based on the current MCG
607 * register value.
608 *
609 * return The frequency of MCGOUTCLK.
610 */
611uint32_t CLOCK_GetOutClkFreq(void)
612{
613 uint32_t mcgoutclk;
614 uint32_t clkst = (uint32_t)MCG_S_CLKST_VAL;
615
616 switch (clkst)
617 {
618 case (uint32_t)kMCG_ClkOutStatFll:
619 mcgoutclk = CLOCK_GetFllFreq();
620 break;
621 case (uint32_t)kMCG_ClkOutStatInt:
622 mcgoutclk = CLOCK_GetInternalRefClkSelectFreq();
623 break;
624 case (uint32_t)kMCG_ClkOutStatExt:
625 mcgoutclk = CLOCK_GetMcgExtClkFreq();
626 break;
627 default:
628 mcgoutclk = 0U;
629 break;
630 }
631
632 return mcgoutclk;
633}
634
635/*!
636 * brief Gets the MCG FLL clock (MCGFLLCLK) frequency.
637 *
638 * This function gets the MCG FLL clock frequency in Hz based on the current MCG
639 * register value. The FLL is enabled in FEI/FBI/FEE/FBE mode and
640 * disabled in low power state in other modes.
641 *
642 * return The frequency of MCGFLLCLK.
643 */
644uint32_t CLOCK_GetFllFreq(void)
645{
646 static const uint16_t fllFactorTable[4][2] = {{640, 732}, {1280, 1464}, {1920, 2197}, {2560, 2929}};
647
648 uint8_t drs, dmx32;
649 uint32_t freq;
650 uint32_t ret;
651
652 /* If FLL is not enabled currently, then return 0U. */
653 if (0U != (MCG->C2 & MCG_C2_LP_MASK))
654 {
655 ret = 0U;
656 }
657 else
658 {
659 /* Get FLL reference clock frequency. */
660 freq = CLOCK_GetFllRefClkFreq();
661 if (0U == freq)
662 {
663 ret = freq;
664 }
665 else
666 {
667 drs = MCG_C4_DRST_DRS_VAL;
668 dmx32 = MCG_C4_DMX32_VAL;
669 ret = freq * fllFactorTable[drs][dmx32];
670 }
671 }
672
673 return ret;
674}
675
676/*!
677 * brief Gets the MCG internal reference clock (MCGIRCLK) frequency.
678 *
679 * This function gets the MCG internal reference clock frequency in Hz based
680 * on the current MCG register value.
681 *
682 * return The frequency of MCGIRCLK.
683 */
684uint32_t CLOCK_GetInternalRefClkFreq(void)
685{
686 uint32_t freq;
687
688 /* If MCGIRCLK is gated. */
689 if (0U == (MCG->C1 & MCG_C1_IRCLKEN_MASK))
690 {
691 freq = 0U;
692 }
693 else
694 {
695 freq = CLOCK_GetInternalRefClkSelectFreq();
696 }
697
698 return freq;
699}
700
701/*!
702 * brief Gets the MCG fixed frequency clock (MCGFFCLK) frequency.
703 *
704 * This function gets the MCG fixed frequency clock frequency in Hz based
705 * on the current MCG register value.
706 *
707 * return The frequency of MCGFFCLK.
708 */
709uint32_t CLOCK_GetFixedFreqClkFreq(void)
710{
711 uint32_t freq = CLOCK_GetFllRefClkFreq();
712 uint32_t ret;
713
714 /* MCGFFCLK must be no more than MCGOUTCLK/8. */
715 if ((freq <= (CLOCK_GetOutClkFreq() / 8U)) && (0U != freq))
716 {
717 ret = freq;
718 }
719 else
720 {
721 ret = 0U;
722 }
723
724 return ret;
725}
726
727/*!
728 * brief Selects the MCG external reference clock.
729 *
730 * Selects the MCG external reference clock source, changes the MCG_C7[OSCSEL],
731 * and waits for the clock source to be stable. Because the external reference
732 * clock should not be changed in FEE/FBE/BLPE/PBE/PEE modes, do not call this function in these modes.
733 *
734 * param oscsel MCG external reference clock source, MCG_C7[OSCSEL].
735 * retval kStatus_MCG_SourceUsed Because the external reference clock is used as a clock source,
736 * the configuration should not be changed. Otherwise, a glitch occurs.
737 * retval kStatus_Success External reference clock set successfully.
738 */
739status_t CLOCK_SetExternalRefClkConfig(mcg_oscsel_t oscsel)
740{
741 bool needDelay;
742 uint32_t i;
743
744#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
745 /* If change MCG_C7[OSCSEL] and external reference clock is system clock source, return error. */
746 if ((MCG_C7_OSCSEL_VAL != oscsel) && (!(MCG->S & MCG_S_IREFST_MASK)))
747 {
748 return kStatus_MCG_SourceUsed;
749 }
750#endif /* MCG_CONFIG_CHECK_PARAM */
751
752 if (MCG_C7_OSCSEL_VAL != (uint8_t)oscsel)
753 {
754 /* If change OSCSEL, need to delay, ERR009878. */
755 needDelay = true;
756 }
757 else
758 {
759 needDelay = false;
760 }
761
762 MCG->C7 = (uint8_t)(MCG->C7 & ~MCG_C7_OSCSEL_MASK) | MCG_C7_OSCSEL(oscsel);
763 if (needDelay)
764 {
765 /* ERR009878 Delay at least 50 micro-seconds for external clock change valid. */
766 i = 1500U;
767 while (0U != (i--))
768 {
769 __NOP();
770 }
771 }
772
773 return kStatus_Success;
774}
775
776/*!
777 * brief Configures the Internal Reference clock (MCGIRCLK).
778 *
779 * This function sets the \c MCGIRCLK base on parameters. It also selects the IRC
780 * source. If the fast IRC is used, this function sets the fast IRC divider.
781 * This function also sets whether the \c MCGIRCLK is enabled in stop mode.
782 * Calling this function in FBI/PBI/BLPI modes may change the system clock. As a result,
783 * using the function in these modes it is not allowed.
784 *
785 * param enableMode MCGIRCLK enable mode, OR'ed value of ref _mcg_irclk_enable_mode.
786 * param ircs MCGIRCLK clock source, choose fast or slow.
787 * param fcrdiv Fast IRC divider setting (\c FCRDIV).
788 * retval kStatus_MCG_SourceUsed Because the internal reference clock is used as a clock source,
789 * the configuration should not be changed. Otherwise, a glitch occurs.
790 * retval kStatus_Success MCGIRCLK configuration finished successfully.
791 */
792status_t CLOCK_SetInternalRefClkConfig(uint8_t enableMode, mcg_irc_mode_t ircs, uint8_t fcrdiv)
793{
794 uint32_t mcgOutClkState = (uint32_t)MCG_S_CLKST_VAL;
795 mcg_irc_mode_t curIrcs = (mcg_irc_mode_t)((uint32_t)MCG_S_IRCST_VAL);
796 uint8_t curFcrdiv = MCG_SC_FCRDIV_VAL;
797
798#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
799 /* If MCGIRCLK is used as system clock source. */
800 if ((uint32_t)kMCG_ClkOutStatInt == mcgOutClkState)
801 {
802 /* If need to change MCGIRCLK source or driver, return error. */
803 if (((kMCG_IrcFast == curIrcs) && (fcrdiv != curFcrdiv)) || (ircs != curIrcs))
804 {
805 return kStatus_MCG_SourceUsed;
806 }
807 }
808#endif
809
810 /* If need to update the FCRDIV. */
811 if (fcrdiv != curFcrdiv)
812 {
813 /* If fast IRC is in use currently, change to slow IRC. */
814 if (((0U != (MCG->C1 & MCG_C1_IRCLKEN_MASK)) || (mcgOutClkState == (uint32_t)kMCG_ClkOutStatInt)) &&
815 (kMCG_IrcFast == curIrcs))
816 {
817 MCG->C2 = (uint8_t)((MCG->C2 & ~MCG_C2_IRCS_MASK) | (MCG_C2_IRCS(kMCG_IrcSlow)));
818 while (MCG_S_IRCST_VAL != (uint8_t)kMCG_IrcSlow)
819 {
820 }
821 }
822 /* Update FCRDIV. */
823 MCG->SC =
824 (uint8_t)(MCG->SC & ~(MCG_SC_FCRDIV_MASK | MCG_SC_ATMF_MASK | MCG_SC_LOCS0_MASK)) | MCG_SC_FCRDIV(fcrdiv);
825 }
826
827 /* Set internal reference clock selection. */
828 MCG->C2 = (uint8_t)((MCG->C2 & ~MCG_C2_IRCS_MASK) | (MCG_C2_IRCS(ircs)));
829 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_IRCLKEN_MASK | MCG_C1_IREFSTEN_MASK)) | (uint8_t)enableMode);
830
831 /* If MCGIRCLK is used, need to wait for MCG_S_IRCST. */
832 if ((mcgOutClkState == (uint32_t)kMCG_ClkOutStatInt) || (0U != (enableMode & (uint32_t)kMCG_IrclkEnable)))
833 {
834 while (MCG_S_IRCST_VAL != (uint8_t)ircs)
835 {
836 }
837 }
838
839 return kStatus_Success;
840}
841
842/*!
843 * brief Sets the OSC0 clock monitor mode.
844 *
845 * This function sets the OSC0 clock monitor mode. See ref mcg_monitor_mode_t for details.
846 *
847 * param mode Monitor mode to set.
848 */
849void CLOCK_SetOsc0MonitorMode(mcg_monitor_mode_t mode)
850{
851 /* Clear the previous flag, MCG_SC[LOCS0]. */
852 MCG->SC &= ~(uint8_t)MCG_SC_ATMF_MASK;
853
854 if (kMCG_MonitorNone == mode)
855 {
856 MCG->C6 &= ~(uint8_t)MCG_C6_CME0_MASK;
857 }
858 else
859 {
860 if (kMCG_MonitorInt == mode)
861 {
862 MCG->C2 &= ~(uint8_t)MCG_C2_LOCRE0_MASK;
863 }
864 else
865 {
866 MCG->C2 |= MCG_C2_LOCRE0_MASK;
867 }
868 MCG->C6 |= MCG_C6_CME0_MASK;
869 }
870}
871
872/*!
873 * brief Sets the RTC OSC clock monitor mode.
874 *
875 * This function sets the RTC OSC clock monitor mode. See ref mcg_monitor_mode_t for details.
876 *
877 * param mode Monitor mode to set.
878 */
879void CLOCK_SetRtcOscMonitorMode(mcg_monitor_mode_t mode)
880{
881 uint8_t mcg_c8 = MCG->C8;
882
883 mcg_c8 &= ~(uint8_t)(MCG_C8_CME1_MASK | MCG_C8_LOCRE1_MASK);
884
885 if (kMCG_MonitorNone != mode)
886 {
887 if (kMCG_MonitorReset == mode)
888 {
889 mcg_c8 |= MCG_C8_LOCRE1_MASK;
890 }
891 mcg_c8 |= MCG_C8_CME1_MASK;
892 }
893 MCG->C8 = mcg_c8;
894}
895
896/*!
897 * brief Gets the MCG status flags.
898 *
899 * This function gets the MCG clock status flags. All status flags are
900 * returned as a logical OR of the enumeration ref _mcg_status_flags_t. To
901 * check a specific flag, compare the return value with the flag.
902 *
903 * Example:
904 * code
905 * To check the clock lost lock status of OSC0 and PLL0.
906 * uint32_t mcgFlags;
907 *
908 * mcgFlags = CLOCK_GetStatusFlags();
909 *
910 * if (mcgFlags & kMCG_Osc0LostFlag)
911 * {
912 * OSC0 clock lock lost. Do something.
913 * }
914 * if (mcgFlags & kMCG_Pll0LostFlag)
915 * {
916 * PLL0 clock lock lost. Do something.
917 * }
918 * endcode
919 *
920 * return Logical OR value of the ref _mcg_status_flags_t.
921 */
922uint32_t CLOCK_GetStatusFlags(void)
923{
924 uint32_t ret = 0U;
925 uint8_t mcg_s = MCG->S;
926
927 if ((MCG->SC & MCG_SC_LOCS0_MASK) != 0U)
928 {
929 ret |= (uint32_t)kMCG_Osc0LostFlag;
930 }
931 if ((mcg_s & MCG_S_OSCINIT0_MASK) != 0U)
932 {
933 ret |= (uint32_t)kMCG_Osc0InitFlag;
934 }
935 if (0U != (MCG->C8 & MCG_C8_LOCS1_MASK))
936 {
937 ret |= (uint32_t)kMCG_RtcOscLostFlag;
938 }
939 return ret;
940}
941
942/*!
943 * brief Clears the MCG status flags.
944 *
945 * This function clears the MCG clock lock lost status. The parameter is a logical
946 * OR value of the flags to clear. See ref _mcg_status_flags_t.
947 *
948 * Example:
949 * code
950 * To clear the clock lost lock status flags of OSC0 and PLL0.
951 *
952 * CLOCK_ClearStatusFlags(kMCG_Osc0LostFlag | kMCG_Pll0LostFlag);
953 * endcode
954 *
955 * param mask The status flags to clear. This is a logical OR of members of the
956 * enumeration ref _mcg_status_flags_t.
957 */
958void CLOCK_ClearStatusFlags(uint32_t mask)
959{
960 uint8_t reg;
961
962 if ((mask & (uint32_t)kMCG_Osc0LostFlag) != 0UL)
963 {
964 MCG->SC &= (uint8_t)(~MCG_SC_ATMF_MASK);
965 }
966 if (0U != (mask & (uint32_t)kMCG_RtcOscLostFlag))
967 {
968 reg = MCG->C8;
969 MCG->C8 = reg;
970 }
971}
972
973/*!
974 * brief Initializes the OSC0.
975 *
976 * This function initializes the OSC0 according to the board configuration.
977 *
978 * param config Pointer to the OSC0 configuration structure.
979 */
980void CLOCK_InitOsc0(osc_config_t const *config)
981{
982 uint8_t range = CLOCK_GetOscRangeFromFreq(config->freq);
983
984 OSC_SetCapLoad(OSC0, config->capLoad);
985
986 MCG->C2 = (uint8_t)((MCG->C2 & ~OSC_MODE_MASK) | MCG_C2_RANGE(range) | (uint8_t)config->workMode);
987 OSC_SetExtRefClkConfig(OSC0, &config->oscerConfig);
988
989 if ((kOSC_ModeExt != config->workMode) && ((OSC0->CR & OSC_CR_ERCLKEN_MASK) != 0U))
990 {
991 /* Wait for stable. */
992 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
993 {
994 }
995 }
996}
997
998/*!
999 * brief Deinitializes the OSC0.
1000 *
1001 * This function deinitializes the OSC0.
1002 */
1003void CLOCK_DeinitOsc0(void)
1004{
1005 OSC0->CR = 0U;
1006 MCG->C2 &= ~(uint8_t)OSC_MODE_MASK;
1007}
1008
1009/*!
1010 * brief Set the Slow IRC frequency based on the trimmed value
1011 *
1012 * param freq The Slow IRC frequency input clock frequency in Hz.
1013 */
1014void CLOCK_SetSlowIrcFreq(uint32_t freq)
1015{
1016 s_slowIrcFreq = freq;
1017}
1018
1019/*!
1020 * brief Set the Fast IRC frequency based on the trimmed value
1021 *
1022 * param freq The Fast IRC frequency input clock frequency in Hz.
1023 */
1024void CLOCK_SetFastIrcFreq(uint32_t freq)
1025{
1026 s_fastIrcFreq = freq;
1027}
1028
1029/*!
1030 * brief Auto trims the internal reference clock.
1031 *
1032 * This function trims the internal reference clock by using the external clock. If
1033 * successful, it returns the kStatus_Success and the frequency after
1034 * trimming is received in the parameter p actualFreq. If an error occurs,
1035 * the error code is returned.
1036 *
1037 * param extFreq External clock frequency, which should be a bus clock.
1038 * param desireFreq Frequency to trim to.
1039 * param actualFreq Actual frequency after trimming.
1040 * param atms Trim fast or slow internal reference clock.
1041 * retval kStatus_Success ATM success.
1042 * retval kStatus_MCG_AtmBusClockInvalid The bus clock is not in allowed range for the ATM.
1043 * retval kStatus_MCG_AtmDesiredFreqInvalid MCGIRCLK could not be trimmed to the desired frequency.
1044 * retval kStatus_MCG_AtmIrcUsed Could not trim because MCGIRCLK is used as a bus clock source.
1045 * retval kStatus_MCG_AtmHardwareFail Hardware fails while trimming.
1046 */
1047status_t CLOCK_TrimInternalRefClk(uint32_t extFreq, uint32_t desireFreq, uint32_t *actualFreq, mcg_atm_select_t atms)
1048{
1049 uint32_t multi; /* extFreq / desireFreq */
1050 uint32_t actv; /* Auto trim value. */
1051 uint8_t mcg_sc;
1052 status_t status = kStatus_Success;
1053
1054 static const uint32_t trimRange[2][2] = {
1055 /* Min Max */
1056 {TRIM_SIRC_MIN, TRIM_SIRC_MAX}, /* Slow IRC. */
1057 {TRIM_FIRC_MIN, TRIM_FIRC_MAX} /* Fast IRC. */
1058 };
1059
1060 if ((extFreq > TRIM_REF_CLK_MAX) || (extFreq < TRIM_REF_CLK_MIN))
1061 {
1062 status = kStatus_MCG_AtmBusClockInvalid;
1063 }
1064 /* Check desired frequency range. */
1065 else if ((desireFreq < trimRange[atms][0]) || (desireFreq > trimRange[atms][1]))
1066 {
1067 status = kStatus_MCG_AtmDesiredFreqInvalid;
1068 }
1069 /*
1070 Make sure internal reference clock is not used to generate bus clock.
1071 Here only need to check (MCG_S_IREFST == 1).
1072 */
1073 else if (MCG_S_IREFST(kMCG_FllSrcInternal) == (MCG->S & MCG_S_IREFST_MASK))
1074 {
1075 status = kStatus_MCG_AtmIrcUsed;
1076 }
1077 else
1078 {
1079 multi = extFreq / desireFreq;
1080 actv = multi * 21U;
1081
1082 if (kMCG_AtmSel4m == atms)
1083 {
1084 actv *= 128U;
1085 }
1086
1087 /* Now begin to start trim. */
1088 MCG->ATCVL = (uint8_t)actv;
1089 MCG->ATCVH = (uint8_t)(actv >> 8U);
1090
1091 mcg_sc = MCG->SC;
1092 mcg_sc &= ~(uint8_t)(MCG_SC_ATMS_MASK | MCG_SC_LOCS0_MASK);
1093 mcg_sc |= (MCG_SC_ATMF_MASK | MCG_SC_ATMS(atms));
1094 MCG->SC = (mcg_sc | MCG_SC_ATME_MASK);
1095
1096 /* Wait for MCG finished. */
1097 while (0U != (MCG->SC & MCG_SC_ATME_MASK))
1098 {
1099 }
1100
1101 /* Error occurs? */
1102 if (0U != (MCG->SC & MCG_SC_ATMF_MASK))
1103 {
1104 /* Clear the failed flag. */
1105 MCG->SC = mcg_sc;
1106 status = kStatus_MCG_AtmHardwareFail;
1107 }
1108 else
1109 {
1110 *actualFreq = extFreq / multi;
1111
1112 if (kMCG_AtmSel4m == atms)
1113 {
1114 s_fastIrcFreq = *actualFreq;
1115 }
1116 else
1117 {
1118 s_slowIrcFreq = *actualFreq;
1119 }
1120 }
1121 }
1122
1123 return status;
1124}
1125
1126/*!
1127 * brief Gets the current MCG mode.
1128 *
1129 * This function checks the MCG registers and determines the current MCG mode.
1130 *
1131 * return Current MCG mode or error code; See ref mcg_mode_t.
1132 */
1133mcg_mode_t CLOCK_GetMode(void)
1134{
1135 mcg_mode_t mode = kMCG_ModeError;
1136 uint32_t clkst = (uint32_t)MCG_S_CLKST_VAL;
1137 uint32_t irefst = (uint32_t)MCG_S_IREFST_VAL;
1138 uint32_t lp = (uint32_t)MCG_C2_LP_VAL;
1139
1140 /*------------------------------------------------------------------
1141 Mode and Registers
1142 ____________________________________________________________________
1143
1144 Mode | CLKST | IREFST | PLLST | LP
1145 ____________________________________________________________________
1146
1147 FEI | 00(FLL) | 1(INT) | 0(FLL) | X
1148 ____________________________________________________________________
1149
1150 FEE | 00(FLL) | 0(EXT) | 0(FLL) | X
1151 ____________________________________________________________________
1152
1153 FBE | 10(EXT) | 0(EXT) | 0(FLL) | 0(NORMAL)
1154 ____________________________________________________________________
1155
1156 FBI | 01(INT) | 1(INT) | 0(FLL) | 0(NORMAL)
1157 ____________________________________________________________________
1158
1159 BLPI | 01(INT) | 1(INT) | 0(FLL) | 1(LOW POWER)
1160 ____________________________________________________________________
1161
1162 BLPE | 10(EXT) | 0(EXT) | X | 1(LOW POWER)
1163 ____________________________________________________________________
1164
1165 PEE | 11(PLL) | 0(EXT) | 1(PLL) | X
1166 ____________________________________________________________________
1167
1168 PBE | 10(EXT) | 0(EXT) | 1(PLL) | O(NORMAL)
1169 ____________________________________________________________________
1170
1171 PBI | 01(INT) | 1(INT) | 1(PLL) | 0(NORMAL)
1172 ____________________________________________________________________
1173
1174 PEI | 11(PLL) | 1(INT) | 1(PLL) | X
1175 ____________________________________________________________________
1176
1177 ----------------------------------------------------------------------*/
1178
1179 if (clkst == (uint32_t)kMCG_ClkOutStatFll)
1180 {
1181 if ((uint32_t)kMCG_FllSrcExternal == irefst)
1182 {
1183 mode = kMCG_ModeFEE;
1184 }
1185 else
1186 {
1187 mode = kMCG_ModeFEI;
1188 }
1189 }
1190 else if (clkst == (uint32_t)kMCG_ClkOutStatInt)
1191 {
1192 if (0U != lp)
1193 {
1194 mode = kMCG_ModeBLPI;
1195 }
1196 else
1197 {
1198 {
1199 mode = kMCG_ModeFBI;
1200 }
1201 }
1202 }
1203 else if (clkst == (uint32_t)kMCG_ClkOutStatExt)
1204 {
1205 if (0U != lp)
1206 {
1207 mode = kMCG_ModeBLPE;
1208 }
1209 else
1210 {
1211 {
1212 mode = kMCG_ModeFBE;
1213 }
1214 }
1215 }
1216 else
1217 {
1218 /*do nothing*/
1219 }
1220
1221 return mode;
1222}
1223
1224/*!
1225 * brief Sets the MCG to FEI mode.
1226 *
1227 * This function sets the MCG to FEI mode. If setting to FEI mode fails
1228 * from the current mode, this function returns an error.
1229 *
1230 * param dmx32 DMX32 in FEI mode.
1231 * param drs The DCO range selection.
1232 * param fllStableDelay Delay function to ensure that the FLL is stable. Passing
1233 * NULL does not cause a delay.
1234 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1235 * retval kStatus_Success Switched to the target mode successfully.
1236 * note If p dmx32 is set to kMCG_Dmx32Fine, the slow IRC must not be trimmed
1237 * to a frequency above 32768 Hz.
1238 */
1239status_t CLOCK_SetFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1240{
1241 uint8_t mcg_c4;
1242 bool change_drs = false;
1243
1244#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1245 mcg_mode_t mode = CLOCK_GetMode();
1246 if (!((kMCG_ModeFEI == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEE == mode)))
1247 {
1248 return kStatus_MCG_ModeUnreachable;
1249 }
1250#endif
1251 mcg_c4 = MCG->C4;
1252
1253 /*
1254 Errata: ERR007993
1255 Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1256 reference clock source changes, then reset to previous value after
1257 reference clock changes.
1258 */
1259 if ((uint8_t)kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
1260 {
1261 change_drs = true;
1262 /* Change the LSB of DRST_DRS. */
1263 MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1264 }
1265
1266 /* Set CLKS and IREFS. */
1267 MCG->C1 = (uint8_t)(((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK))) |
1268 (MCG_C1_CLKS(kMCG_ClkOutSrcOut) /* CLKS = 0 */
1269 | MCG_C1_IREFS(kMCG_FllSrcInternal))); /* IREFS = 1 */
1270
1271 /* Wait and check status. */
1272 while ((uint8_t)kMCG_FllSrcInternal != MCG_S_IREFST_VAL)
1273 {
1274 }
1275
1276 /* Errata: ERR007993 */
1277 if (change_drs)
1278 {
1279 MCG->C4 = mcg_c4;
1280 }
1281
1282 /* In FEI mode, the MCG_C4[DMX32] is set to 0U. */
1283 MCG->C4 = (uint8_t)((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) |
1284 (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1285
1286 /* Check MCG_S[CLKST] */
1287 while ((uint8_t)kMCG_ClkOutStatFll != MCG_S_CLKST_VAL)
1288 {
1289 }
1290
1291 /* Wait for FLL stable time. */
1292 if (NULL != fllStableDelay)
1293 {
1294 fllStableDelay();
1295 }
1296
1297 return kStatus_Success;
1298}
1299
1300/*!
1301 * brief Sets the MCG to FEE mode.
1302 *
1303 * This function sets the MCG to FEE mode. If setting to FEE mode fails
1304 * from the current mode, this function returns an error.
1305 *
1306 * param frdiv FLL reference clock divider setting, FRDIV.
1307 * param dmx32 DMX32 in FEE mode.
1308 * param drs The DCO range selection.
1309 * param fllStableDelay Delay function to make sure FLL is stable. Passing
1310 * NULL does not cause a delay.
1311 *
1312 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1313 * retval kStatus_Success Switched to the target mode successfully.
1314 */
1315status_t CLOCK_SetFeeMode(uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1316{
1317 uint8_t mcg_c4;
1318 bool change_drs = false;
1319
1320#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1321 mcg_mode_t mode = CLOCK_GetMode();
1322 if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode)))
1323 {
1324 return kStatus_MCG_ModeUnreachable;
1325 }
1326#endif
1327 mcg_c4 = MCG->C4;
1328
1329 /*
1330 Errata: ERR007993
1331 Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1332 reference clock source changes, then reset to previous value after
1333 reference clock changes.
1334 */
1335 if ((uint8_t)kMCG_FllSrcInternal == MCG_S_IREFST_VAL)
1336 {
1337 change_drs = true;
1338 /* Change the LSB of DRST_DRS. */
1339 MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1340 }
1341
1342 /* Set CLKS and IREFS. */
1343 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK)) |
1344 (MCG_C1_CLKS(kMCG_ClkOutSrcOut) /* CLKS = 0 */
1345 | MCG_C1_FRDIV(frdiv) /* FRDIV */
1346 | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
1347
1348 /* If use external crystal as clock source, wait for it stable. */
1349 if (MCG_C7_OSCSEL(kMCG_OscselOsc) == (MCG->C7 & MCG_C7_OSCSEL_MASK))
1350 {
1351 if (0U != (MCG->C2 & MCG_C2_EREFS_MASK))
1352 {
1353 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
1354 {
1355 }
1356 }
1357 }
1358
1359 /* Wait and check status. */
1360 while ((uint8_t)kMCG_FllSrcExternal != MCG_S_IREFST_VAL)
1361 {
1362 }
1363
1364 /* Errata: ERR007993 */
1365 if (change_drs)
1366 {
1367 MCG->C4 = mcg_c4;
1368 }
1369
1370 /* Set DRS and DMX32. */
1371 mcg_c4 = (uint8_t)((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) |
1372 (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1373 MCG->C4 = mcg_c4;
1374
1375 /* Wait for DRST_DRS update. */
1376 while (MCG->C4 != mcg_c4)
1377 {
1378 }
1379
1380 /* Check MCG_S[CLKST] */
1381 while ((uint8_t)kMCG_ClkOutStatFll != MCG_S_CLKST_VAL)
1382 {
1383 }
1384
1385 /* Wait for FLL stable time. */
1386 if (NULL != fllStableDelay)
1387 {
1388 fllStableDelay();
1389 }
1390
1391 return kStatus_Success;
1392}
1393
1394/*!
1395 * brief Sets the MCG to FBI mode.
1396 *
1397 * This function sets the MCG to FBI mode. If setting to FBI mode fails
1398 * from the current mode, this function returns an error.
1399 *
1400 * param dmx32 DMX32 in FBI mode.
1401 * param drs The DCO range selection.
1402 * param fllStableDelay Delay function to make sure FLL is stable. If the FLL
1403 * is not used in FBI mode, this parameter can be NULL. Passing
1404 * NULL does not cause a delay.
1405 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1406 * retval kStatus_Success Switched to the target mode successfully.
1407 * note If p dmx32 is set to kMCG_Dmx32Fine, the slow IRC must not be trimmed
1408 * to frequency above 32768 Hz.
1409 */
1410status_t CLOCK_SetFbiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1411{
1412 uint8_t mcg_c4;
1413 bool change_drs = false;
1414
1415#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1416 mcg_mode_t mode = CLOCK_GetMode();
1417
1418 if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode) ||
1419 (kMCG_ModeBLPI == mode)))
1420
1421 {
1422 return kStatus_MCG_ModeUnreachable;
1423 }
1424#endif
1425
1426 mcg_c4 = MCG->C4;
1427
1428 MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK; /* Disable lowpower. */
1429
1430 /*
1431 Errata: ERR007993
1432 Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1433 reference clock source changes, then reset to previous value after
1434 reference clock changes.
1435 */
1436 if ((uint8_t)kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
1437 {
1438 change_drs = true;
1439 /* Change the LSB of DRST_DRS. */
1440 MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1441 }
1442
1443 /* Set CLKS and IREFS. */
1444 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) |
1445 (MCG_C1_CLKS(kMCG_ClkOutSrcInternal) /* CLKS = 1 */
1446 | MCG_C1_IREFS(kMCG_FllSrcInternal))); /* IREFS = 1 */
1447
1448 /* Wait and check status. */
1449 while ((uint8_t)kMCG_FllSrcInternal != MCG_S_IREFST_VAL)
1450 {
1451 }
1452
1453 /* Errata: ERR007993 */
1454 if (change_drs)
1455 {
1456 MCG->C4 = mcg_c4;
1457 }
1458
1459 while ((uint8_t)kMCG_ClkOutStatInt != MCG_S_CLKST_VAL)
1460 {
1461 }
1462
1463 MCG->C4 = (uint8_t)((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) |
1464 (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1465
1466 /* Wait for FLL stable time. */
1467 if (NULL != fllStableDelay)
1468 {
1469 fllStableDelay();
1470 }
1471
1472 return kStatus_Success;
1473}
1474
1475/*!
1476 * brief Sets the MCG to FBE mode.
1477 *
1478 * This function sets the MCG to FBE mode. If setting to FBE mode fails
1479 * from the current mode, this function returns an error.
1480 *
1481 * param frdiv FLL reference clock divider setting, FRDIV.
1482 * param dmx32 DMX32 in FBE mode.
1483 * param drs The DCO range selection.
1484 * param fllStableDelay Delay function to make sure FLL is stable. If the FLL
1485 * is not used in FBE mode, this parameter can be NULL. Passing NULL
1486 * does not cause a delay.
1487 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1488 * retval kStatus_Success Switched to the target mode successfully.
1489 */
1490status_t CLOCK_SetFbeMode(uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1491{
1492 uint8_t mcg_c4;
1493 bool change_drs = false;
1494
1495#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1496 mcg_mode_t mode = CLOCK_GetMode();
1497 if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode) ||
1498 (kMCG_ModeBLPE == mode)))
1499 {
1500 return kStatus_MCG_ModeUnreachable;
1501 }
1502#endif
1503
1504 /* Set LP bit to enable the FLL */
1505 MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK;
1506
1507 mcg_c4 = MCG->C4;
1508
1509 /*
1510 Errata: ERR007993
1511 Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1512 reference clock source changes, then reset to previous value after
1513 reference clock changes.
1514 */
1515 if ((uint8_t)kMCG_FllSrcInternal == MCG_S_IREFST_VAL)
1516 {
1517 change_drs = true;
1518 /* Change the LSB of DRST_DRS. */
1519 MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1520 }
1521
1522 /* Set CLKS and IREFS. */
1523 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK)) |
1524 (MCG_C1_CLKS(kMCG_ClkOutSrcExternal) /* CLKS = 2 */
1525 | MCG_C1_FRDIV(frdiv) /* FRDIV = frdiv */
1526 | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
1527
1528 /* If use external crystal as clock source, wait for it stable. */
1529 if (MCG_C7_OSCSEL(kMCG_OscselOsc) == (MCG->C7 & MCG_C7_OSCSEL_MASK))
1530 {
1531 if (0U != (MCG->C2 & MCG_C2_EREFS_MASK))
1532 {
1533 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
1534 {
1535 }
1536 }
1537 }
1538
1539 /* Wait for Reference clock Status bit to clear */
1540 while ((uint8_t)kMCG_FllSrcExternal != MCG_S_IREFST_VAL)
1541 {
1542 }
1543
1544 /* Errata: ERR007993 */
1545 if (change_drs)
1546 {
1547 MCG->C4 = mcg_c4;
1548 }
1549
1550 /* Set DRST_DRS and DMX32. */
1551 mcg_c4 = (uint8_t)((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) |
1552 (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1553
1554 /* Wait for clock status bits to show clock source is ext ref clk */
1555 while ((uint8_t)kMCG_ClkOutStatExt != MCG_S_CLKST_VAL)
1556 {
1557 }
1558
1559 /* Wait for fll stable time. */
1560 if (NULL != fllStableDelay)
1561 {
1562 fllStableDelay();
1563 }
1564
1565 return kStatus_Success;
1566}
1567
1568/*!
1569 * brief Sets the MCG to BLPI mode.
1570 *
1571 * This function sets the MCG to BLPI mode. If setting to BLPI mode fails
1572 * from the current mode, this function returns an error.
1573 *
1574 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1575 * retval kStatus_Success Switched to the target mode successfully.
1576 */
1577status_t CLOCK_SetBlpiMode(void)
1578{
1579#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1580 if (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatInt)
1581 {
1582 return kStatus_MCG_ModeUnreachable;
1583 }
1584#endif /* MCG_CONFIG_CHECK_PARAM */
1585
1586 /* Set LP. */
1587 MCG->C2 |= MCG_C2_LP_MASK;
1588
1589 return kStatus_Success;
1590}
1591
1592/*!
1593 * brief Sets the MCG to BLPE mode.
1594 *
1595 * This function sets the MCG to BLPE mode. If setting to BLPE mode fails
1596 * from the current mode, this function returns an error.
1597 *
1598 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1599 * retval kStatus_Success Switched to the target mode successfully.
1600 */
1601status_t CLOCK_SetBlpeMode(void)
1602{
1603#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1604 if (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatExt)
1605 {
1606 return kStatus_MCG_ModeUnreachable;
1607 }
1608#endif
1609
1610 /* Set LP bit to enter BLPE mode. */
1611 MCG->C2 |= MCG_C2_LP_MASK;
1612
1613 return kStatus_Success;
1614}
1615
1616/*!
1617 * brief Switches the MCG to FBE mode from the external mode.
1618 *
1619 * This function switches the MCG from external modes (PEE/PBE/BLPE/FEE) to the FBE mode quickly.
1620 * The external clock is used as the system clock source and PLL is disabled. However,
1621 * the FLL settings are not configured. This is a lite function with a small code size, which is useful
1622 * during the mode switch. For example, to switch from PEE mode to FEI mode:
1623 *
1624 * code
1625 * CLOCK_ExternalModeToFbeModeQuick();
1626 * CLOCK_SetFeiMode(...);
1627 * endcode
1628 *
1629 * retval kStatus_Success Switched successfully.
1630 * retval kStatus_MCG_ModeInvalid If the current mode is not an external mode, do not call this function.
1631 */
1632status_t CLOCK_ExternalModeToFbeModeQuick(void)
1633{
1634#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1635 if ((MCG->S & MCG_S_IREFST_MASK) != 0U)
1636 {
1637 return kStatus_MCG_ModeInvalid;
1638 }
1639#endif /* MCG_CONFIG_CHECK_PARAM */
1640
1641 /* Disable low power */
1642 MCG->C2 &= (uint8_t)(~MCG_C2_LP_MASK);
1643
1644 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal));
1645 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatExt)
1646 {
1647 }
1648
1649 return kStatus_Success;
1650}
1651
1652/*!
1653 * brief Switches the MCG to FBI mode from internal modes.
1654 *
1655 * This function switches the MCG from internal modes (PEI/PBI/BLPI/FEI) to the FBI mode quickly.
1656 * The MCGIRCLK is used as the system clock source and PLL is disabled. However,
1657 * FLL settings are not configured. This is a lite function with a small code size, which is useful
1658 * during the mode switch. For example, to switch from PEI mode to FEE mode:
1659 *
1660 * code
1661 * CLOCK_InternalModeToFbiModeQuick();
1662 * CLOCK_SetFeeMode(...);
1663 * endcode
1664 *
1665 * retval kStatus_Success Switched successfully.
1666 * retval kStatus_MCG_ModeInvalid If the current mode is not an internal mode, do not call this function.
1667 */
1668status_t CLOCK_InternalModeToFbiModeQuick(void)
1669{
1670#if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1671 if ((MCG->S & MCG_S_IREFST_MASK) == 0U)
1672 {
1673 return kStatus_MCG_ModeInvalid;
1674 }
1675#endif
1676
1677 /* Disable low power */
1678 MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK;
1679
1680 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal));
1681 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatInt)
1682 {
1683 }
1684
1685 return kStatus_Success;
1686}
1687
1688/*!
1689 * brief Sets the MCG to FEI mode during system boot up.
1690 *
1691 * This function sets the MCG to FEI mode from the reset mode. It can also be used to
1692 * set up MCG during system boot up.
1693 *
1694 * param dmx32 DMX32 in FEI mode.
1695 * param drs The DCO range selection.
1696 * param fllStableDelay Delay function to ensure that the FLL is stable.
1697 *
1698 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1699 * retval kStatus_Success Switched to the target mode successfully.
1700 * note If p dmx32 is set to kMCG_Dmx32Fine, the slow IRC must not be trimmed
1701 * to frequency above 32768 Hz.
1702 */
1703status_t CLOCK_BootToFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1704{
1705 return CLOCK_SetFeiMode(dmx32, drs, fllStableDelay);
1706}
1707
1708/*!
1709 * brief Sets the MCG to FEE mode during system bootup.
1710 *
1711 * This function sets MCG to FEE mode from the reset mode. It can also be used to
1712 * set up the MCG during system boot up.
1713 *
1714 * param oscsel OSC clock select, OSCSEL.
1715 * param frdiv FLL reference clock divider setting, FRDIV.
1716 * param dmx32 DMX32 in FEE mode.
1717 * param drs The DCO range selection.
1718 * param fllStableDelay Delay function to ensure that the FLL is stable.
1719 *
1720 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1721 * retval kStatus_Success Switched to the target mode successfully.
1722 */
1723status_t CLOCK_BootToFeeMode(
1724 mcg_oscsel_t oscsel, uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1725{
1726 (void)CLOCK_SetExternalRefClkConfig(oscsel);
1727
1728 return CLOCK_SetFeeMode(frdiv, dmx32, drs, fllStableDelay);
1729}
1730
1731/*!
1732 * brief Sets the MCG to BLPI mode during system boot up.
1733 *
1734 * This function sets the MCG to BLPI mode from the reset mode. It can also be used to
1735 * set up the MCG during system boot up.
1736 *
1737 * param fcrdiv Fast IRC divider, FCRDIV.
1738 * param ircs The internal reference clock to select, IRCS.
1739 * param ircEnableMode The MCGIRCLK enable mode, OR'ed value of ref _mcg_irclk_enable_mode.
1740 *
1741 * retval kStatus_MCG_SourceUsed Could not change MCGIRCLK setting.
1742 * retval kStatus_Success Switched to the target mode successfully.
1743 */
1744status_t CLOCK_BootToBlpiMode(uint8_t fcrdiv, mcg_irc_mode_t ircs, uint8_t ircEnableMode)
1745{
1746 /* If reset mode is FEI mode, set MCGIRCLK and always success. */
1747 (void)CLOCK_SetInternalRefClkConfig(ircEnableMode, ircs, fcrdiv);
1748
1749 /* If reset mode is not BLPI, first enter FBI mode. */
1750 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal));
1751 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatInt)
1752 {
1753 }
1754
1755 /* Enter BLPI mode. */
1756 MCG->C2 |= MCG_C2_LP_MASK;
1757
1758 return kStatus_Success;
1759}
1760
1761/*!
1762 * brief Sets the MCG to BLPE mode during system boot up.
1763 *
1764 * This function sets the MCG to BLPE mode from the reset mode. It can also be used to
1765 * set up the MCG during system boot up.
1766 *
1767 * param oscsel OSC clock select, MCG_C7[OSCSEL].
1768 *
1769 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1770 * retval kStatus_Success Switched to the target mode successfully.
1771 */
1772status_t CLOCK_BootToBlpeMode(mcg_oscsel_t oscsel)
1773{
1774 (void)CLOCK_SetExternalRefClkConfig(oscsel);
1775
1776 /* Set to FBE mode. */
1777 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) |
1778 (MCG_C1_CLKS(kMCG_ClkOutSrcExternal) /* CLKS = 2 */
1779 | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
1780
1781 /* If use external crystal as clock source, wait for it stable. */
1782 if (MCG_C7_OSCSEL(kMCG_OscselOsc) == (MCG->C7 & MCG_C7_OSCSEL_MASK))
1783 {
1784 if (0U != (MCG->C2 & MCG_C2_EREFS_MASK))
1785 {
1786 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
1787 {
1788 }
1789 }
1790 }
1791
1792 /* Wait for MCG_S[CLKST] and MCG_S[IREFST]. */
1793 while ((MCG->S & (MCG_S_IREFST_MASK | MCG_S_CLKST_MASK)) !=
1794 (MCG_S_IREFST(kMCG_FllSrcExternal) | MCG_S_CLKST(kMCG_ClkOutStatExt)))
1795 {
1796 }
1797
1798 /* In FBE now, start to enter BLPE. */
1799 MCG->C2 |= MCG_C2_LP_MASK;
1800
1801 return kStatus_Success;
1802}
1803
1804/*
1805 The transaction matrix. It defines the path for mode switch, the row is for
1806 current mode and the column is target mode.
1807 For example, switch from FEI to PEE:
1808 1. Current mode FEI, next mode is mcgModeMatrix[FEI][PEE] = FBE, so swith to FBE.
1809 2. Current mode FBE, next mode is mcgModeMatrix[FBE][PEE] = PBE, so swith to PBE.
1810 3. Current mode PBE, next mode is mcgModeMatrix[PBE][PEE] = PEE, so swith to PEE.
1811 Thus the MCG mode has changed from FEI to PEE.
1812 */
1813static const mcg_mode_t mcgModeMatrix[6][6] = {
1814 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE}, /* FEI */
1815 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeBLPI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE}, /* FBI */
1816 {kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeBLPI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFBI}, /* BLPI */
1817 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE}, /* FEE */
1818 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeBLPE}, /* FBE */
1819 {kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeBLPE}, /* BLPE */
1820 /* FEI FBI BLPI FEE FBE BLPE */
1821};
1822
1823/*!
1824 * brief Sets the MCG to a target mode.
1825 *
1826 * This function sets MCG to a target mode defined by the configuration
1827 * structure. If switching to the target mode fails, this function
1828 * chooses the correct path.
1829 *
1830 * param config Pointer to the target MCG mode configuration structure.
1831 * return Return kStatus_Success if switched successfully; Otherwise, it returns an error code #_mcg_status.
1832 *
1833 * note If the external clock is used in the target mode, ensure that it is
1834 * enabled. For example, if the OSC0 is used, set up OSC0 correctly before calling this
1835 * function.
1836 */
1837status_t CLOCK_SetMcgConfig(const mcg_config_t *config)
1838{
1839 mcg_mode_t next_mode;
1840 status_t status = kStatus_Success;
1841
1842 /* If need to change external clock, MCG_C7[OSCSEL]. */
1843 if (MCG_C7_OSCSEL_VAL != (uint8_t)(config->oscsel))
1844 {
1845 /* If external clock is in use, change to FEI first. */
1846 if ((uint8_t)kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
1847 {
1848 (void)CLOCK_ExternalModeToFbeModeQuick();
1849 (void)CLOCK_SetFeiMode(config->dmx32, config->drs, NULL);
1850 }
1851
1852 (void)CLOCK_SetExternalRefClkConfig(config->oscsel);
1853 }
1854
1855 /* Re-configure MCGIRCLK, if MCGIRCLK is used as system clock source, then change to FEI/PEI first. */
1856 if (MCG_S_CLKST_VAL == (uint8_t)kMCG_ClkOutStatInt)
1857 {
1858 MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK; /* Disable lowpower. */
1859
1860 {
1861 (void)CLOCK_SetFeiMode(config->dmx32, config->drs, CLOCK_FllStableDelay);
1862 }
1863 }
1864
1865 /* Configure MCGIRCLK. */
1866 (void)CLOCK_SetInternalRefClkConfig(config->irclkEnableMode, config->ircs, config->fcrdiv);
1867
1868 next_mode = CLOCK_GetMode();
1869
1870 do
1871 {
1872 next_mode = mcgModeMatrix[next_mode][config->mcgMode];
1873
1874 switch (next_mode)
1875 {
1876 case kMCG_ModeFEI:
1877 status = CLOCK_SetFeiMode(config->dmx32, config->drs, CLOCK_FllStableDelay);
1878 break;
1879 case kMCG_ModeFEE:
1880 status = CLOCK_SetFeeMode(config->frdiv, config->dmx32, config->drs, CLOCK_FllStableDelay);
1881 break;
1882 case kMCG_ModeFBI:
1883 status = CLOCK_SetFbiMode(config->dmx32, config->drs, NULL);
1884 break;
1885 case kMCG_ModeFBE:
1886 status = CLOCK_SetFbeMode(config->frdiv, config->dmx32, config->drs, NULL);
1887 break;
1888 case kMCG_ModeBLPI:
1889 status = CLOCK_SetBlpiMode();
1890 break;
1891 case kMCG_ModeBLPE:
1892 status = CLOCK_SetBlpeMode();
1893 break;
1894 default:
1895 assert(false);
1896 break;
1897 }
1898 if (kStatus_Success != status)
1899 {
1900 break;
1901 }
1902 } while (next_mode != config->mcgMode);
1903
1904 return status;
1905}