1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016 - 2019, 2023 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 ((uint32_t)(SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT)
72 #define SIM_CLKDIV1_OUTDIV2_VAL ((uint32_t)(SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV2_MASK) >> SIM_CLKDIV1_OUTDIV2_SHIFT)
73 #define SIM_CLKDIV1_OUTDIV4_VAL ((uint32_t)(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. */
78 enum _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. */
87 enum _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. */
98 static uint32_t s_slowIrcFreq = 32768U;
99 /* Fast internal reference clock frequency. */
100 static uint32_t s_fastIrcFreq = 4000000U;
101
102 /* External XTAL0 (OSC0) clock frequency. */
103 volatile uint32_t g_xtal0Freq;
104 /* External XTAL32K clock frequency. */
105 volatile 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 */
119 static 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 */
129 static 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 */
139 static 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 */
150 static uint32_t CLOCK_GetInternalRefClkSelectFreq(void);
151
152 /*!
153 * @brief Get the MCG PLL/PLL0 reference clock frequency.
154 *
155 * Get the current MCG PLL/PLL0 reference clock frequency in Hz.
156 * This is an internal function.
157 *
158 * @return MCG PLL/PLL0 reference clock frequency in Hz.
159 */
160 static uint32_t CLOCK_GetPll0RefFreq(void);
161
162 /*!
163 * @brief Calculate the RANGE value base on crystal frequency.
164 *
165 * To setup external crystal oscillator, must set the register bits RANGE
166 * base on the crystal frequency. This function returns the RANGE base on the
167 * input frequency. This is an internal function.
168 *
169 * @param freq Crystal frequency in Hz.
170 * @return The RANGE value.
171 */
172 static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq);
173
174 #ifndef MCG_USER_CONFIG_FLL_STABLE_DELAY_EN
175 /*!
176 * @brief Delay function to wait FLL stable.
177 *
178 * Delay function to wait FLL stable in FEI mode or FEE mode, should wait at least
179 * 1ms. Every time changes FLL setting, should wait this time for FLL stable.
180 */
181 static void CLOCK_FllStableDelay(void);
182 #endif
183
184 /*******************************************************************************
185 * Code
186 ******************************************************************************/
187
188 #ifndef MCG_USER_CONFIG_FLL_STABLE_DELAY_EN
CLOCK_FllStableDelay(void)189 static void CLOCK_FllStableDelay(void)
190 {
191 /*
192 Should wait at least 1ms. Because in these modes, the core clock is 100MHz
193 at most, so this function could obtain the 1ms delay.
194 */
195 volatile uint32_t i = 30000U;
196 while (0U != (i--))
197 {
198 __NOP();
199 }
200 }
201 #else /* With MCG_USER_CONFIG_FLL_STABLE_DELAY_EN defined. */
202 /* Once user defines the MCG_USER_CONFIG_FLL_STABLE_DELAY_EN to use their own delay function, they have to
203 * create their own CLOCK_FllStableDelay() function in application code. Since the clock functions in this
204 * file would call the CLOCK_FllStableDelay() regardless how it is defined.
205 */
206 extern void CLOCK_FllStableDelay(void);
207 #endif /* MCG_USER_CONFIG_FLL_STABLE_DELAY_EN */
208
CLOCK_GetMcgExtClkFreq(void)209 static uint32_t CLOCK_GetMcgExtClkFreq(void)
210 {
211 uint32_t freq;
212
213 switch (MCG_C7_OSCSEL_VAL)
214 {
215 case 0U:
216 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
217 assert(0U != g_xtal0Freq);
218 freq = g_xtal0Freq;
219 break;
220 case 1U:
221 /* Please call CLOCK_SetXtal32Freq base on board setting before using XTAL32K/RTC_CLKIN clock. */
222 assert(0U != g_xtal32Freq);
223 freq = g_xtal32Freq;
224 break;
225 case 2U:
226 freq = MCG_INTERNAL_IRC_48M;
227 break;
228 default:
229 freq = 0U;
230 break;
231 }
232
233 return freq;
234 }
235
CLOCK_GetFllExtRefClkFreq(void)236 static uint32_t CLOCK_GetFllExtRefClkFreq(void)
237 {
238 /* FllExtRef = McgExtRef / FllExtRefDiv */
239 uint8_t frdiv;
240 uint8_t range;
241 uint8_t oscsel;
242
243 uint32_t freq = CLOCK_GetMcgExtClkFreq();
244
245 frdiv = MCG_C1_FRDIV_VAL;
246 freq >>= frdiv;
247
248 range = MCG_C2_RANGE_VAL;
249 oscsel = MCG_C7_OSCSEL_VAL;
250
251 /*
252 When should use divider 32, 64, 128, 256, 512, 1024, 1280, 1536.
253 1. MCG_C7[OSCSEL] selects IRC48M.
254 2. MCG_C7[OSCSEL] selects OSC0 and MCG_C2[RANGE] is not 0.
255 */
256 if (((0U != range) && ((uint8_t)kMCG_OscselOsc == oscsel)) || ((uint8_t)kMCG_OscselIrc == oscsel))
257 {
258 switch (frdiv)
259 {
260 case 0:
261 case 1:
262 case 2:
263 case 3:
264 case 4:
265 case 5:
266 freq >>= 5u;
267 break;
268 case 6:
269 /* 64*20=1280 */
270 freq /= 20u;
271 break;
272 case 7:
273 /* 128*12=1536 */
274 freq /= 12u;
275 break;
276 default:
277 freq = 0u;
278 break;
279 }
280 }
281
282 return freq;
283 }
284
CLOCK_GetInternalRefClkSelectFreq(void)285 static uint32_t CLOCK_GetInternalRefClkSelectFreq(void)
286 {
287 uint32_t freq;
288
289 if ((uint8_t)kMCG_IrcSlow == MCG_S_IRCST_VAL)
290 {
291 /* Slow internal reference clock selected*/
292 freq = s_slowIrcFreq;
293 }
294 else
295 {
296 /* Fast internal reference clock selected*/
297 freq = s_fastIrcFreq >> MCG_SC_FCRDIV_VAL;
298 }
299
300 return freq;
301 }
302
CLOCK_GetFllRefClkFreq(void)303 static uint32_t CLOCK_GetFllRefClkFreq(void)
304 {
305 uint32_t freq;
306
307 /* If use external reference clock. */
308 if ((uint8_t)kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
309 {
310 freq = CLOCK_GetFllExtRefClkFreq();
311 }
312 /* If use internal reference clock. */
313 else
314 {
315 freq = s_slowIrcFreq;
316 }
317
318 return freq;
319 }
320
CLOCK_GetPll0RefFreq(void)321 static uint32_t CLOCK_GetPll0RefFreq(void)
322 {
323 /* MCG external reference clock. */
324 return CLOCK_GetMcgExtClkFreq();
325 }
326
CLOCK_GetOscRangeFromFreq(uint32_t freq)327 static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq)
328 {
329 uint8_t range;
330
331 if (freq <= 39063U)
332 {
333 range = 0U;
334 }
335 else if (freq <= 8000000U)
336 {
337 range = 1U;
338 }
339 else
340 {
341 range = 2U;
342 }
343
344 return range;
345 }
346
347 /*!
348 * brief Get the OSC0 external reference undivided clock frequency (OSC0ERCLK_UNDIV).
349 *
350 * return Clock frequency in Hz.
351 */
CLOCK_GetOsc0ErClkUndivFreq(void)352 uint32_t CLOCK_GetOsc0ErClkUndivFreq(void)
353 {
354 uint32_t freq;
355
356 if ((OSC0->CR & OSC_CR_ERCLKEN_MASK) != 0U)
357 {
358 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
359 assert(g_xtal0Freq);
360 freq = g_xtal0Freq;
361 }
362 else
363 {
364 freq = 0U;
365 }
366 return freq;
367 }
368
369 /*!
370 * brief Get the OSC0 external reference divided clock frequency.
371 *
372 * return Clock frequency in Hz.
373 */
CLOCK_GetOsc0ErClkDivFreq(void)374 uint32_t CLOCK_GetOsc0ErClkDivFreq(void)
375 {
376 uint32_t freq;
377
378 if ((OSC0->CR & OSC_CR_ERCLKEN_MASK) != 0U)
379 {
380 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
381 assert(g_xtal0Freq);
382 freq = g_xtal0Freq >> ((OSC0->DIV & OSC_DIV_ERPS_MASK) >> OSC_DIV_ERPS_SHIFT);
383 }
384 else
385 {
386 freq = 0U;
387 }
388 return freq;
389 }
390
391 /*!
392 * brief Get the external reference 32K clock frequency (ERCLK32K).
393 *
394 * return Clock frequency in Hz.
395 */
CLOCK_GetEr32kClkFreq(void)396 uint32_t CLOCK_GetEr32kClkFreq(void)
397 {
398 uint32_t freq;
399
400 switch (SIM_SOPT1_OSC32KSEL_VAL)
401 {
402 case 0U: /* OSC 32k clock */
403 freq = (CLOCK_GetOsc0ErClkUndivFreq() == 32768U) ? 32768U : 0U;
404 break;
405 case 2U: /* RTC 32k clock */
406 /* Please call CLOCK_SetXtal32Freq base on board setting before using XTAL32K/RTC_CLKIN clock. */
407 assert(g_xtal32Freq);
408 freq = g_xtal32Freq;
409 break;
410 case 3U: /* LPO clock */
411 freq = LPO_CLK_FREQ;
412 break;
413 default:
414 freq = 0U;
415 break;
416 }
417 return freq;
418 }
419
420 /*!
421 * brief Get the output clock frequency selected by SIM[PLLFLLSEL].
422 *
423 * return Clock frequency in Hz.
424 */
CLOCK_GetPllFllSelClkFreq(void)425 uint32_t CLOCK_GetPllFllSelClkFreq(void)
426 {
427 uint32_t freq;
428
429 switch (SIM_SOPT2_PLLFLLSEL_VAL)
430 {
431 case 0U: /* FLL. */
432 freq = CLOCK_GetFllFreq();
433 break;
434 case 1U: /* PLL. */
435 freq = CLOCK_GetPll0Freq();
436 break;
437 case 3U: /* MCG IRC48M. */
438 freq = MCG_INTERNAL_IRC_48M;
439 break;
440 default:
441 freq = 0U;
442 break;
443 }
444
445 return freq;
446 }
447
448 /*!
449 * brief Get the OSC0 external reference clock frequency (OSC0ERCLK).
450 *
451 * return Clock frequency in Hz.
452 */
CLOCK_GetOsc0ErClkFreq(void)453 uint32_t CLOCK_GetOsc0ErClkFreq(void)
454 {
455 return CLOCK_GetOsc0ErClkDivFreq();
456 }
457
458 /*!
459 * brief Get the platform clock frequency.
460 *
461 * return Clock frequency in Hz.
462 */
CLOCK_GetPlatClkFreq(void)463 uint32_t CLOCK_GetPlatClkFreq(void)
464 {
465 return CLOCK_GetOutClkFreq() / (uint32_t)(SIM_CLKDIV1_OUTDIV1_VAL + 1UL);
466 }
467
468 /*!
469 * brief Get the flash clock frequency.
470 *
471 * return Clock frequency in Hz.
472 */
CLOCK_GetFlashClkFreq(void)473 uint32_t CLOCK_GetFlashClkFreq(void)
474 {
475 return CLOCK_GetOutClkFreq() / ((uint32_t)(SIM_CLKDIV1_OUTDIV4_VAL + 1UL));
476 }
477
478 /*!
479 * brief Get the bus clock frequency.
480 *
481 * return Clock frequency in Hz.
482 */
CLOCK_GetBusClkFreq(void)483 uint32_t CLOCK_GetBusClkFreq(void)
484 {
485 return CLOCK_GetOutClkFreq() / (uint32_t)(SIM_CLKDIV1_OUTDIV2_VAL + 1UL);
486 }
487
488 /*!
489 * brief Get the core clock or system clock frequency.
490 *
491 * return Clock frequency in Hz.
492 */
CLOCK_GetCoreSysClkFreq(void)493 uint32_t CLOCK_GetCoreSysClkFreq(void)
494 {
495 return CLOCK_GetOutClkFreq() / ((uint32_t)(SIM_CLKDIV1_OUTDIV1_VAL + 1UL));
496 }
497
498 /*!
499 * brief Gets the clock frequency for a specific clock name.
500 *
501 * This function checks the current clock configurations and then calculates
502 * the clock frequency for a specific clock name defined in clock_name_t.
503 * The MCG must be properly configured before using this function.
504 *
505 * param clockName Clock names defined in clock_name_t
506 * return Clock frequency value in Hertz
507 */
CLOCK_GetFreq(clock_name_t clockName)508 uint32_t CLOCK_GetFreq(clock_name_t clockName)
509 {
510 uint32_t freq;
511
512 switch (clockName)
513 {
514 case kCLOCK_CoreSysClk:
515 case kCLOCK_PlatClk:
516 freq = CLOCK_GetOutClkFreq() / ((uint32_t)(SIM_CLKDIV1_OUTDIV1_VAL + 1UL));
517 break;
518 case kCLOCK_BusClk:
519 freq = CLOCK_GetOutClkFreq() / ((uint32_t)(SIM_CLKDIV1_OUTDIV2_VAL + 1UL));
520 break;
521 case kCLOCK_FlashClk:
522 freq = CLOCK_GetOutClkFreq() / ((uint32_t)(SIM_CLKDIV1_OUTDIV4_VAL + 1UL));
523 break;
524 case kCLOCK_PllFllSelClk:
525 freq = CLOCK_GetPllFllSelClkFreq();
526 break;
527 case kCLOCK_Er32kClk:
528 freq = CLOCK_GetEr32kClkFreq();
529 break;
530 case kCLOCK_McgFixedFreqClk:
531 freq = CLOCK_GetFixedFreqClkFreq();
532 break;
533 case kCLOCK_McgInternalRefClk:
534 freq = CLOCK_GetInternalRefClkFreq();
535 break;
536 case kCLOCK_McgFllClk:
537 freq = CLOCK_GetFllFreq();
538 break;
539 case kCLOCK_McgPll0Clk:
540 freq = CLOCK_GetPll0Freq();
541 break;
542 case kCLOCK_McgIrc48MClk:
543 freq = MCG_INTERNAL_IRC_48M;
544 break;
545 case kCLOCK_LpoClk:
546 freq = LPO_CLK_FREQ;
547 break;
548 case kCLOCK_Osc0ErClkUndiv:
549 freq = CLOCK_GetOsc0ErClkUndivFreq();
550 break;
551 case kCLOCK_Osc0ErClk:
552 freq = CLOCK_GetOsc0ErClkDivFreq();
553 break;
554 default:
555 freq = 0U;
556 break;
557 }
558
559 return freq;
560 }
561
562 /*!
563 * brief Set the clock configure in SIM module.
564 *
565 * This function sets system layer clock settings in SIM module.
566 *
567 * param config Pointer to the configure structure.
568 */
CLOCK_SetSimConfig(sim_clock_config_t const * config)569 void CLOCK_SetSimConfig(sim_clock_config_t const *config)
570 {
571 SIM->CLKDIV1 = config->clkdiv1;
572 CLOCK_SetPllFllSelClock(config->pllFllSel);
573 CLOCK_SetEr32kClock(config->er32kSrc);
574 }
575
576 /*!
577 * brief Gets the MCG output clock (MCGOUTCLK) frequency.
578 *
579 * This function gets the MCG output clock frequency in Hz based on the current MCG
580 * register value.
581 *
582 * return The frequency of MCGOUTCLK.
583 */
CLOCK_GetOutClkFreq(void)584 uint32_t CLOCK_GetOutClkFreq(void)
585 {
586 uint32_t mcgoutclk;
587 uint32_t clkst = (uint32_t)MCG_S_CLKST_VAL;
588
589 switch (clkst)
590 {
591 case (uint32_t)kMCG_ClkOutStatPll:
592 mcgoutclk = CLOCK_GetPll0Freq();
593 break;
594 case (uint32_t)kMCG_ClkOutStatFll:
595 mcgoutclk = CLOCK_GetFllFreq();
596 break;
597 case (uint32_t)kMCG_ClkOutStatInt:
598 mcgoutclk = CLOCK_GetInternalRefClkSelectFreq();
599 break;
600 case (uint32_t)kMCG_ClkOutStatExt:
601 mcgoutclk = CLOCK_GetMcgExtClkFreq();
602 break;
603 default:
604 mcgoutclk = 0U;
605 break;
606 }
607
608 return mcgoutclk;
609 }
610
611 /*!
612 * brief Gets the MCG FLL clock (MCGFLLCLK) frequency.
613 *
614 * This function gets the MCG FLL clock frequency in Hz based on the current MCG
615 * register value. The FLL is enabled in FEI/FBI/FEE/FBE mode and
616 * disabled in low power state in other modes.
617 *
618 * return The frequency of MCGFLLCLK.
619 */
CLOCK_GetFllFreq(void)620 uint32_t CLOCK_GetFllFreq(void)
621 {
622 static const uint16_t fllFactorTable[4][2] = {{640, 732}, {1280, 1464}, {1920, 2197}, {2560, 2929}};
623
624 uint8_t drs, dmx32;
625 uint32_t freq;
626 uint32_t ret;
627
628 /* If FLL is not enabled currently, then return 0U. */
629 if ((((MCG->C2 & MCG_C2_LP_MASK) != 0U) || ((MCG->S & MCG_S_PLLST_MASK) != 0U)))
630 {
631 ret = 0U;
632 }
633 else
634 {
635 /* Get FLL reference clock frequency. */
636 freq = CLOCK_GetFllRefClkFreq();
637 if (0U == freq)
638 {
639 ret = freq;
640 }
641 else
642 {
643 drs = MCG_C4_DRST_DRS_VAL;
644 dmx32 = MCG_C4_DMX32_VAL;
645 ret = freq * fllFactorTable[drs][dmx32];
646 }
647 }
648
649 return ret;
650 }
651
652 /*!
653 * brief Gets the MCG internal reference clock (MCGIRCLK) frequency.
654 *
655 * This function gets the MCG internal reference clock frequency in Hz based
656 * on the current MCG register value.
657 *
658 * return The frequency of MCGIRCLK.
659 */
CLOCK_GetInternalRefClkFreq(void)660 uint32_t CLOCK_GetInternalRefClkFreq(void)
661 {
662 uint32_t freq;
663
664 /* If MCGIRCLK is gated. */
665 if (0U == (MCG->C1 & MCG_C1_IRCLKEN_MASK))
666 {
667 freq = 0U;
668 }
669 else
670 {
671 freq = CLOCK_GetInternalRefClkSelectFreq();
672 }
673
674 return freq;
675 }
676
677 /*!
678 * brief Gets the MCG fixed frequency clock (MCGFFCLK) frequency.
679 *
680 * This function gets the MCG fixed frequency clock frequency in Hz based
681 * on the current MCG register value.
682 *
683 * return The frequency of MCGFFCLK.
684 */
CLOCK_GetFixedFreqClkFreq(void)685 uint32_t CLOCK_GetFixedFreqClkFreq(void)
686 {
687 uint32_t freq = CLOCK_GetFllRefClkFreq();
688 uint32_t ret;
689
690 /* MCGFFCLK must be no more than MCGOUTCLK/8. */
691 if ((freq <= (CLOCK_GetOutClkFreq() / 8U)) && (0U != freq))
692 {
693 ret = freq;
694 }
695 else
696 {
697 ret = 0U;
698 }
699
700 return ret;
701 }
702
703 /*!
704 * brief Gets the MCG PLL0 clock (MCGPLL0CLK) frequency.
705 *
706 * This function gets the MCG PLL0 clock frequency in Hz based on the current MCG
707 * register value.
708 *
709 * return The frequency of MCGPLL0CLK.
710 */
CLOCK_GetPll0Freq(void)711 uint32_t CLOCK_GetPll0Freq(void)
712 {
713 uint32_t mcgpll0clk;
714 uint32_t freq;
715
716 uint8_t mcgpll0prdiv;
717 uint8_t mcgpll0vdiv;
718 /* If PLL0 is not enabled, return 0. */
719 if (((MCG->S & MCG_S_LOCK0_MASK)) == 0U)
720 {
721 freq = 0U;
722 }
723 else
724 {
725 mcgpll0clk = CLOCK_GetPll0RefFreq();
726
727 /*
728 * Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock.
729 * Please call CLOCK_SetXtal1Freq base on board setting before using OSC1 clock.
730 */
731 assert(mcgpll0clk);
732
733 mcgpll0prdiv = ((uint8_t)FSL_FEATURE_MCG_PLL_PRDIV_BASE + MCG_C5_PRDIV0_VAL);
734 mcgpll0clk /= (uint32_t)mcgpll0prdiv;
735 mcgpll0vdiv = ((uint8_t)FSL_FEATURE_MCG_PLL_VDIV_BASE + MCG_C6_VDIV0_VAL);
736 mcgpll0clk *= (uint32_t)mcgpll0vdiv;
737
738 freq = mcgpll0clk;
739 }
740
741 return freq;
742 }
743
744 /*!
745 * brief Selects the MCG external reference clock.
746 *
747 * Selects the MCG external reference clock source, changes the MCG_C7[OSCSEL],
748 * and waits for the clock source to be stable. Because the external reference
749 * clock should not be changed in FEE/FBE/BLPE/PBE/PEE modes, do not call this function in these modes.
750 *
751 * param oscsel MCG external reference clock source, MCG_C7[OSCSEL].
752 * retval kStatus_MCG_SourceUsed Because the external reference clock is used as a clock source,
753 * the configuration should not be changed. Otherwise, a glitch occurs.
754 * retval kStatus_Success External reference clock set successfully.
755 */
CLOCK_SetExternalRefClkConfig(mcg_oscsel_t oscsel)756 status_t CLOCK_SetExternalRefClkConfig(mcg_oscsel_t oscsel)
757 {
758 bool needDelay;
759 uint32_t i;
760
761 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
762 /* If change MCG_C7[OSCSEL] and external reference clock is system clock source, return error. */
763 if ((MCG_C7_OSCSEL_VAL != oscsel) && (!(MCG->S & MCG_S_IREFST_MASK)))
764 {
765 return kStatus_MCG_SourceUsed;
766 }
767 #endif /* MCG_CONFIG_CHECK_PARAM */
768
769 if (MCG_C7_OSCSEL_VAL != (uint8_t)oscsel)
770 {
771 /* If change OSCSEL, need to delay, ERR009878. */
772 needDelay = true;
773 }
774 else
775 {
776 needDelay = false;
777 }
778
779 MCG->C7 = (uint8_t)(MCG->C7 & ~MCG_C7_OSCSEL_MASK) | MCG_C7_OSCSEL(oscsel);
780 if (needDelay)
781 {
782 /* ERR009878 Delay at least 50 micro-seconds for external clock change valid. */
783 i = 1500U;
784 while (0U != (i--))
785 {
786 __NOP();
787 }
788 }
789
790 return kStatus_Success;
791 }
792
793 /*!
794 * brief Configures the Internal Reference clock (MCGIRCLK).
795 *
796 * This function sets the \c MCGIRCLK base on parameters. It also selects the IRC
797 * source. If the fast IRC is used, this function sets the fast IRC divider.
798 * This function also sets whether the \c MCGIRCLK is enabled in stop mode.
799 * Calling this function in FBI/PBI/BLPI modes may change the system clock. As a result,
800 * using the function in these modes it is not allowed.
801 *
802 * param enableMode MCGIRCLK enable mode, OR'ed value of ref _mcg_irclk_enable_mode.
803 * param ircs MCGIRCLK clock source, choose fast or slow.
804 * param fcrdiv Fast IRC divider setting (\c FCRDIV).
805 * retval kStatus_MCG_SourceUsed Because the internal reference clock is used as a clock source,
806 * the configuration should not be changed. Otherwise, a glitch occurs.
807 * retval kStatus_Success MCGIRCLK configuration finished successfully.
808 */
CLOCK_SetInternalRefClkConfig(uint8_t enableMode,mcg_irc_mode_t ircs,uint8_t fcrdiv)809 status_t CLOCK_SetInternalRefClkConfig(uint8_t enableMode, mcg_irc_mode_t ircs, uint8_t fcrdiv)
810 {
811 uint32_t mcgOutClkState = (uint32_t)MCG_S_CLKST_VAL;
812 mcg_irc_mode_t curIrcs = (mcg_irc_mode_t)((uint32_t)MCG_S_IRCST_VAL);
813 uint8_t curFcrdiv = MCG_SC_FCRDIV_VAL;
814
815 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
816 /* If MCGIRCLK is used as system clock source. */
817 if ((uint32_t)kMCG_ClkOutStatInt == mcgOutClkState)
818 {
819 /* If need to change MCGIRCLK source or driver, return error. */
820 if (((kMCG_IrcFast == curIrcs) && (fcrdiv != curFcrdiv)) || (ircs != curIrcs))
821 {
822 return kStatus_MCG_SourceUsed;
823 }
824 }
825 #endif
826
827 /* If need to update the FCRDIV. */
828 if (fcrdiv != curFcrdiv)
829 {
830 /* If fast IRC is in use currently, change to slow IRC. */
831 if (((0U != (MCG->C1 & MCG_C1_IRCLKEN_MASK)) || (mcgOutClkState == (uint32_t)kMCG_ClkOutStatInt)) &&
832 (kMCG_IrcFast == curIrcs))
833 {
834 MCG->C2 = (uint8_t)((MCG->C2 & ~MCG_C2_IRCS_MASK) | (MCG_C2_IRCS(kMCG_IrcSlow)));
835 while (MCG_S_IRCST_VAL != (uint8_t)kMCG_IrcSlow)
836 {
837 }
838 }
839 /* Update FCRDIV. */
840 MCG->SC =
841 (uint8_t)(MCG->SC & ~(MCG_SC_FCRDIV_MASK | MCG_SC_ATMF_MASK | MCG_SC_LOCS0_MASK)) | MCG_SC_FCRDIV(fcrdiv);
842 }
843
844 /* Set internal reference clock selection. */
845 MCG->C2 = (uint8_t)((MCG->C2 & ~MCG_C2_IRCS_MASK) | (MCG_C2_IRCS(ircs)));
846 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_IRCLKEN_MASK | MCG_C1_IREFSTEN_MASK)) | (uint8_t)enableMode);
847
848 /* If MCGIRCLK is used, need to wait for MCG_S_IRCST. */
849 if ((mcgOutClkState == (uint32_t)kMCG_ClkOutStatInt) || (0U != (enableMode & (uint32_t)kMCG_IrclkEnable)))
850 {
851 while (MCG_S_IRCST_VAL != (uint8_t)ircs)
852 {
853 }
854 }
855
856 return kStatus_Success;
857 }
858
859 /*!
860 * brief Calculates the PLL divider setting for a desired output frequency.
861 *
862 * This function calculates the correct reference clock divider (\c PRDIV) and
863 * VCO divider (\c VDIV) to generate a desired PLL output frequency. It returns the
864 * closest frequency match with the corresponding \c PRDIV/VDIV
865 * returned from parameters. If a desired frequency is not valid, this function
866 * returns 0.
867 *
868 * param refFreq PLL reference clock frequency.
869 * param desireFreq Desired PLL output frequency.
870 * param prdiv PRDIV value to generate desired PLL frequency.
871 * param vdiv VDIV value to generate desired PLL frequency.
872 * return Closest frequency match that the PLL was able generate.
873 */
CLOCK_CalcPllDiv(uint32_t refFreq,uint32_t desireFreq,uint8_t * prdiv,uint8_t * vdiv)874 uint32_t CLOCK_CalcPllDiv(uint32_t refFreq, uint32_t desireFreq, uint8_t *prdiv, uint8_t *vdiv)
875 {
876 uint8_t ret_prdiv; /* PRDIV to return. */
877 uint8_t ret_vdiv; /* VDIV to return. */
878 uint8_t prdiv_min; /* Min PRDIV value to make reference clock in allowed range. */
879 uint8_t prdiv_max; /* Max PRDIV value to make reference clock in allowed range. */
880 uint8_t prdiv_cur; /* PRDIV value for iteration. */
881 uint8_t vdiv_cur; /* VDIV value for iteration. */
882 uint32_t ret_freq = 0U; /* PLL output frequency to return. */
883 uint32_t diff = 0xFFFFFFFFU; /* Difference between desireFreq and return frequency. */
884 uint32_t ref_div; /* Reference frequency after PRDIV. */
885
886 /*
887 Steps:
888 1. Get allowed prdiv with such rules:
889 1). refFreq / prdiv >= FSL_FEATURE_MCG_PLL_REF_MIN.
890 2). refFreq / prdiv <= FSL_FEATURE_MCG_PLL_REF_MAX.
891 2. For each allowed prdiv, there are two candidate vdiv values:
892 1). (desireFreq / (refFreq / prdiv)).
893 2). (desireFreq / (refFreq / prdiv)) + 1.
894 If could get the precise desired frequency, return current prdiv and
895 vdiv directly. Otherwise choose the one which is closer to desired
896 frequency.
897 */
898
899 /* Reference frequency is out of range. */
900 if ((refFreq < (uint32_t)FSL_FEATURE_MCG_PLL_REF_MIN) ||
901 (refFreq > ((uint32_t)FSL_FEATURE_MCG_PLL_REF_MAX *
902 ((uint32_t)FSL_FEATURE_MCG_PLL_PRDIV_MAX + (uint32_t)FSL_FEATURE_MCG_PLL_PRDIV_BASE))))
903 {
904 return 0U;
905 }
906
907 /* refFreq/PRDIV must in a range. First get the allowed PRDIV range. */
908 prdiv_max = (uint8_t)(refFreq / (uint32_t)FSL_FEATURE_MCG_PLL_REF_MIN);
909 prdiv_min =
910 (uint8_t)((refFreq + (uint32_t)FSL_FEATURE_MCG_PLL_REF_MAX - 1U) / (uint32_t)FSL_FEATURE_MCG_PLL_REF_MAX);
911
912 /* PRDIV traversal. */
913 for (prdiv_cur = prdiv_max; prdiv_cur >= prdiv_min; prdiv_cur--)
914 {
915 /* Reference frequency after PRDIV. */
916 ref_div = refFreq / prdiv_cur;
917
918 vdiv_cur = (uint8_t)(desireFreq / ref_div);
919
920 if ((vdiv_cur < ((uint8_t)FSL_FEATURE_MCG_PLL_VDIV_BASE - 1U)) ||
921 (vdiv_cur > (uint8_t)FSL_FEATURE_MCG_PLL_VDIV_BASE + 31U))
922 {
923 /* No VDIV is available with this PRDIV. */
924 continue;
925 }
926
927 ret_freq = vdiv_cur * ref_div;
928
929 if (vdiv_cur >= (uint8_t)FSL_FEATURE_MCG_PLL_VDIV_BASE)
930 {
931 if (ret_freq == desireFreq) /* If desire frequency is got. */
932 {
933 *prdiv = prdiv_cur - (uint8_t)FSL_FEATURE_MCG_PLL_PRDIV_BASE;
934 *vdiv = vdiv_cur - (uint8_t)FSL_FEATURE_MCG_PLL_VDIV_BASE;
935 return ret_freq;
936 }
937 /* New PRDIV/VDIV is closer. */
938 if (diff > desireFreq - ret_freq)
939 {
940 diff = desireFreq - ret_freq;
941 ret_prdiv = prdiv_cur;
942 ret_vdiv = vdiv_cur;
943 }
944 }
945 vdiv_cur++;
946 if (vdiv_cur <= ((uint8_t)FSL_FEATURE_MCG_PLL_VDIV_BASE + 31U))
947 {
948 ret_freq += ref_div;
949 /* New PRDIV/VDIV is closer. */
950 if (diff > ret_freq - desireFreq)
951 {
952 diff = ret_freq - desireFreq;
953 ret_prdiv = prdiv_cur;
954 ret_vdiv = vdiv_cur;
955 }
956 }
957 }
958
959 if (0xFFFFFFFFU != diff)
960 {
961 /* PRDIV/VDIV found. */
962 *prdiv = ret_prdiv - (uint8_t)FSL_FEATURE_MCG_PLL_PRDIV_BASE;
963 *vdiv = ret_vdiv - (uint8_t)FSL_FEATURE_MCG_PLL_VDIV_BASE;
964 ret_freq = (refFreq / ret_prdiv) * ret_vdiv;
965 return ret_freq;
966 }
967 else
968 {
969 /* No proper PRDIV/VDIV found. */
970 return 0U;
971 }
972 }
973
974 /*!
975 * brief Enables the PLL0 in FLL mode.
976 *
977 * This function sets us the PLL0 in FLL mode and reconfigures
978 * the PLL0. Ensure that the PLL reference
979 * clock is enabled before calling this function and that the PLL0 is not used as a clock source.
980 * The function CLOCK_CalcPllDiv gets the correct PLL
981 * divider values.
982 *
983 * param config Pointer to the configuration structure.
984 */
CLOCK_EnablePll0(mcg_pll_config_t const * config)985 void CLOCK_EnablePll0(mcg_pll_config_t const *config)
986 {
987 assert(config);
988
989 uint8_t mcg_c5 = 0U;
990
991 mcg_c5 |= MCG_C5_PRDIV0(config->prdiv);
992 MCG->C5 = mcg_c5; /* Disable the PLL first. */
993
994 MCG->C6 = (uint8_t)((MCG->C6 & ~MCG_C6_VDIV0_MASK) | MCG_C6_VDIV0(config->vdiv));
995
996 /* Set enable mode. */
997 MCG->C5 |= ((uint8_t)kMCG_PllEnableIndependent | (uint8_t)config->enableMode);
998
999 /* Wait for PLL lock. */
1000 while (((MCG->S & MCG_S_LOCK0_MASK)) == 0U)
1001 {
1002 }
1003 }
1004
1005 /*!
1006 * brief Sets the OSC0 clock monitor mode.
1007 *
1008 * This function sets the OSC0 clock monitor mode. See ref mcg_monitor_mode_t for details.
1009 *
1010 * param mode Monitor mode to set.
1011 */
CLOCK_SetOsc0MonitorMode(mcg_monitor_mode_t mode)1012 void CLOCK_SetOsc0MonitorMode(mcg_monitor_mode_t mode)
1013 {
1014 /* Clear the previous flag, MCG_SC[LOCS0]. */
1015 MCG->SC &= ~(uint8_t)MCG_SC_ATMF_MASK;
1016
1017 if (kMCG_MonitorNone == mode)
1018 {
1019 MCG->C6 &= ~(uint8_t)MCG_C6_CME0_MASK;
1020 }
1021 else
1022 {
1023 if (kMCG_MonitorInt == mode)
1024 {
1025 MCG->C2 &= ~(uint8_t)MCG_C2_LOCRE0_MASK;
1026 }
1027 else
1028 {
1029 MCG->C2 |= MCG_C2_LOCRE0_MASK;
1030 }
1031 MCG->C6 |= MCG_C6_CME0_MASK;
1032 }
1033 }
1034
1035 /*!
1036 * brief Sets the PLL0 clock monitor mode.
1037 *
1038 * This function sets the PLL0 clock monitor mode. See ref mcg_monitor_mode_t for details.
1039 *
1040 * param mode Monitor mode to set.
1041 */
CLOCK_SetPll0MonitorMode(mcg_monitor_mode_t mode)1042 void CLOCK_SetPll0MonitorMode(mcg_monitor_mode_t mode)
1043 {
1044 uint8_t mcg_c8;
1045
1046 /* Clear previous flag. */
1047 MCG->S = MCG_S_LOLS0_MASK;
1048
1049 if (kMCG_MonitorNone == mode)
1050 {
1051 MCG->C6 &= (uint8_t)(~MCG_C6_LOLIE0_MASK);
1052 }
1053 else
1054 {
1055 mcg_c8 = MCG->C8;
1056
1057 if (kMCG_MonitorInt == mode)
1058 {
1059 mcg_c8 &= (uint8_t)(~MCG_C8_LOLRE_MASK);
1060 }
1061 else
1062 {
1063 mcg_c8 |= MCG_C8_LOLRE_MASK;
1064 }
1065 MCG->C8 = mcg_c8;
1066 MCG->C6 |= MCG_C6_LOLIE0_MASK;
1067 }
1068 }
1069
1070 /*!
1071 * brief Gets the MCG status flags.
1072 *
1073 * This function gets the MCG clock status flags. All status flags are
1074 * returned as a logical OR of the enumeration ref _mcg_status_flags_t. To
1075 * check a specific flag, compare the return value with the flag.
1076 *
1077 * Example:
1078 * code
1079 * To check the clock lost lock status of OSC0 and PLL0.
1080 * uint32_t mcgFlags;
1081 *
1082 * mcgFlags = CLOCK_GetStatusFlags();
1083 *
1084 * if (mcgFlags & kMCG_Osc0LostFlag)
1085 * {
1086 * OSC0 clock lock lost. Do something.
1087 * }
1088 * if (mcgFlags & kMCG_Pll0LostFlag)
1089 * {
1090 * PLL0 clock lock lost. Do something.
1091 * }
1092 * endcode
1093 *
1094 * return Logical OR value of the ref _mcg_status_flags_t.
1095 */
CLOCK_GetStatusFlags(void)1096 uint32_t CLOCK_GetStatusFlags(void)
1097 {
1098 uint32_t ret = 0U;
1099 uint8_t mcg_s = MCG->S;
1100
1101 if ((MCG->SC & MCG_SC_LOCS0_MASK) != 0U)
1102 {
1103 ret |= (uint32_t)kMCG_Osc0LostFlag;
1104 }
1105 if ((mcg_s & MCG_S_OSCINIT0_MASK) != 0U)
1106 {
1107 ret |= (uint32_t)kMCG_Osc0InitFlag;
1108 }
1109 if ((mcg_s & MCG_S_LOLS0_MASK) != 0U)
1110 {
1111 ret |= (uint32_t)kMCG_Pll0LostFlag;
1112 }
1113 if ((mcg_s & MCG_S_LOCK0_MASK) != 0U)
1114 {
1115 ret |= (uint32_t)kMCG_Pll0LockFlag;
1116 }
1117 return ret;
1118 }
1119
1120 /*!
1121 * brief Clears the MCG status flags.
1122 *
1123 * This function clears the MCG clock lock lost status. The parameter is a logical
1124 * OR value of the flags to clear. See ref _mcg_status_flags_t.
1125 *
1126 * Example:
1127 * code
1128 * To clear the clock lost lock status flags of OSC0 and PLL0.
1129 *
1130 * CLOCK_ClearStatusFlags(kMCG_Osc0LostFlag | kMCG_Pll0LostFlag);
1131 * endcode
1132 *
1133 * param mask The status flags to clear. This is a logical OR of members of the
1134 * enumeration ref _mcg_status_flags_t.
1135 */
CLOCK_ClearStatusFlags(uint32_t mask)1136 void CLOCK_ClearStatusFlags(uint32_t mask)
1137 {
1138 if ((mask & (uint32_t)kMCG_Osc0LostFlag) != 0UL)
1139 {
1140 MCG->SC &= (uint8_t)(~MCG_SC_ATMF_MASK);
1141 }
1142 if ((mask & (uint32_t)kMCG_Pll0LostFlag) != 0UL)
1143 {
1144 MCG->S = MCG_S_LOLS0_MASK;
1145 }
1146 }
1147
1148 /*!
1149 * brief Initializes the OSC0.
1150 *
1151 * This function initializes the OSC0 according to the board configuration.
1152 *
1153 * param config Pointer to the OSC0 configuration structure.
1154 */
CLOCK_InitOsc0(osc_config_t const * config)1155 void CLOCK_InitOsc0(osc_config_t const *config)
1156 {
1157 uint8_t range = CLOCK_GetOscRangeFromFreq(config->freq);
1158
1159 OSC_SetCapLoad(OSC0, config->capLoad);
1160
1161 MCG->C2 = (uint8_t)((MCG->C2 & ~OSC_MODE_MASK) | MCG_C2_RANGE(range) | (uint8_t)config->workMode);
1162 OSC_SetExtRefClkConfig(OSC0, &config->oscerConfig);
1163
1164 if ((kOSC_ModeExt != config->workMode) && ((OSC0->CR & OSC_CR_ERCLKEN_MASK) != 0U))
1165 {
1166 /* Wait for stable. */
1167 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
1168 {
1169 }
1170 }
1171 }
1172
1173 /*!
1174 * brief Deinitializes the OSC0.
1175 *
1176 * This function deinitializes the OSC0.
1177 */
CLOCK_DeinitOsc0(void)1178 void CLOCK_DeinitOsc0(void)
1179 {
1180 OSC0->CR = 0U;
1181 MCG->C2 &= ~(uint8_t)OSC_MODE_MASK;
1182 }
1183
1184 /*!
1185 * brief Set the Slow IRC frequency based on the trimmed value
1186 *
1187 * param freq The Slow IRC frequency input clock frequency in Hz.
1188 */
CLOCK_SetSlowIrcFreq(uint32_t freq)1189 void CLOCK_SetSlowIrcFreq(uint32_t freq)
1190 {
1191 s_slowIrcFreq = freq;
1192 }
1193
1194 /*!
1195 * brief Set the Fast IRC frequency based on the trimmed value
1196 *
1197 * param freq The Fast IRC frequency input clock frequency in Hz.
1198 */
CLOCK_SetFastIrcFreq(uint32_t freq)1199 void CLOCK_SetFastIrcFreq(uint32_t freq)
1200 {
1201 s_fastIrcFreq = freq;
1202 }
1203
1204 /*!
1205 * brief Auto trims the internal reference clock.
1206 *
1207 * This function trims the internal reference clock by using the external clock. If
1208 * successful, it returns the kStatus_Success and the frequency after
1209 * trimming is received in the parameter p actualFreq. If an error occurs,
1210 * the error code is returned.
1211 *
1212 * param extFreq External clock frequency, which should be a bus clock.
1213 * param desireFreq Frequency to trim to.
1214 * param actualFreq Actual frequency after trimming.
1215 * param atms Trim fast or slow internal reference clock.
1216 * retval kStatus_Success ATM success.
1217 * retval kStatus_MCG_AtmBusClockInvalid The bus clock is not in allowed range for the ATM.
1218 * retval kStatus_MCG_AtmDesiredFreqInvalid MCGIRCLK could not be trimmed to the desired frequency.
1219 * retval kStatus_MCG_AtmIrcUsed Could not trim because MCGIRCLK is used as a bus clock source.
1220 * retval kStatus_MCG_AtmHardwareFail Hardware fails while trimming.
1221 */
CLOCK_TrimInternalRefClk(uint32_t extFreq,uint32_t desireFreq,uint32_t * actualFreq,mcg_atm_select_t atms)1222 status_t CLOCK_TrimInternalRefClk(uint32_t extFreq, uint32_t desireFreq, uint32_t *actualFreq, mcg_atm_select_t atms)
1223 {
1224 uint32_t multi; /* extFreq / desireFreq */
1225 uint32_t actv; /* Auto trim value. */
1226 uint8_t mcg_sc;
1227 status_t status = kStatus_Success;
1228
1229 static const uint32_t trimRange[2][2] = {
1230 /* Min Max */
1231 {TRIM_SIRC_MIN, TRIM_SIRC_MAX}, /* Slow IRC. */
1232 {TRIM_FIRC_MIN, TRIM_FIRC_MAX} /* Fast IRC. */
1233 };
1234
1235 if ((extFreq > TRIM_REF_CLK_MAX) || (extFreq < TRIM_REF_CLK_MIN))
1236 {
1237 status = kStatus_MCG_AtmBusClockInvalid;
1238 }
1239 /* Check desired frequency range. */
1240 else if ((desireFreq < trimRange[atms][0]) || (desireFreq > trimRange[atms][1]))
1241 {
1242 status = kStatus_MCG_AtmDesiredFreqInvalid;
1243 }
1244 /*
1245 Make sure internal reference clock is not used to generate bus clock.
1246 Here only need to check (MCG_S_IREFST == 1).
1247 */
1248 else if (MCG_S_IREFST(kMCG_FllSrcInternal) == (MCG->S & MCG_S_IREFST_MASK))
1249 {
1250 status = kStatus_MCG_AtmIrcUsed;
1251 }
1252 else
1253 {
1254 multi = extFreq / desireFreq;
1255 actv = multi * 21U;
1256
1257 if (kMCG_AtmSel4m == atms)
1258 {
1259 actv *= 128U;
1260 }
1261
1262 /* Now begin to start trim. */
1263 MCG->ATCVL = (uint8_t)actv;
1264 MCG->ATCVH = (uint8_t)(actv >> 8U);
1265
1266 mcg_sc = MCG->SC;
1267 mcg_sc &= ~(uint8_t)(MCG_SC_ATMS_MASK | MCG_SC_LOCS0_MASK);
1268 mcg_sc |= (MCG_SC_ATMF_MASK | MCG_SC_ATMS(atms));
1269 MCG->SC = (mcg_sc | MCG_SC_ATME_MASK);
1270
1271 /* Wait for MCG finished. */
1272 while (0U != (MCG->SC & MCG_SC_ATME_MASK))
1273 {
1274 }
1275
1276 /* Error occurs? */
1277 if (0U != (MCG->SC & MCG_SC_ATMF_MASK))
1278 {
1279 /* Clear the failed flag. */
1280 MCG->SC = mcg_sc;
1281 status = kStatus_MCG_AtmHardwareFail;
1282 }
1283 else
1284 {
1285 *actualFreq = extFreq / multi;
1286
1287 if (kMCG_AtmSel4m == atms)
1288 {
1289 s_fastIrcFreq = *actualFreq;
1290 }
1291 else
1292 {
1293 s_slowIrcFreq = *actualFreq;
1294 }
1295 }
1296 }
1297
1298 return status;
1299 }
1300
1301 /*!
1302 * brief Gets the current MCG mode.
1303 *
1304 * This function checks the MCG registers and determines the current MCG mode.
1305 *
1306 * return Current MCG mode or error code; See ref mcg_mode_t.
1307 */
CLOCK_GetMode(void)1308 mcg_mode_t CLOCK_GetMode(void)
1309 {
1310 mcg_mode_t mode = kMCG_ModeError;
1311 uint32_t clkst = (uint32_t)MCG_S_CLKST_VAL;
1312 uint32_t irefst = (uint32_t)MCG_S_IREFST_VAL;
1313 uint32_t lp = (uint32_t)MCG_C2_LP_VAL;
1314 uint32_t pllst = MCG_S_PLLST_VAL;
1315
1316 /*------------------------------------------------------------------
1317 Mode and Registers
1318 ____________________________________________________________________
1319
1320 Mode | CLKST | IREFST | PLLST | LP
1321 ____________________________________________________________________
1322
1323 FEI | 00(FLL) | 1(INT) | 0(FLL) | X
1324 ____________________________________________________________________
1325
1326 FEE | 00(FLL) | 0(EXT) | 0(FLL) | X
1327 ____________________________________________________________________
1328
1329 FBE | 10(EXT) | 0(EXT) | 0(FLL) | 0(NORMAL)
1330 ____________________________________________________________________
1331
1332 FBI | 01(INT) | 1(INT) | 0(FLL) | 0(NORMAL)
1333 ____________________________________________________________________
1334
1335 BLPI | 01(INT) | 1(INT) | 0(FLL) | 1(LOW POWER)
1336 ____________________________________________________________________
1337
1338 BLPE | 10(EXT) | 0(EXT) | X | 1(LOW POWER)
1339 ____________________________________________________________________
1340
1341 PEE | 11(PLL) | 0(EXT) | 1(PLL) | X
1342 ____________________________________________________________________
1343
1344 PBE | 10(EXT) | 0(EXT) | 1(PLL) | O(NORMAL)
1345 ____________________________________________________________________
1346
1347 PBI | 01(INT) | 1(INT) | 1(PLL) | 0(NORMAL)
1348 ____________________________________________________________________
1349
1350 PEI | 11(PLL) | 1(INT) | 1(PLL) | X
1351 ____________________________________________________________________
1352
1353 ----------------------------------------------------------------------*/
1354
1355 if (clkst == (uint32_t)kMCG_ClkOutStatFll)
1356 {
1357 if ((uint32_t)kMCG_FllSrcExternal == irefst)
1358 {
1359 mode = kMCG_ModeFEE;
1360 }
1361 else
1362 {
1363 mode = kMCG_ModeFEI;
1364 }
1365 }
1366 else if (clkst == (uint32_t)kMCG_ClkOutStatInt)
1367 {
1368 if (0U != lp)
1369 {
1370 mode = kMCG_ModeBLPI;
1371 }
1372 else
1373 {
1374 {
1375 mode = kMCG_ModeFBI;
1376 }
1377 }
1378 }
1379 else if (clkst == (uint32_t)kMCG_ClkOutStatExt)
1380 {
1381 if (0U != lp)
1382 {
1383 mode = kMCG_ModeBLPE;
1384 }
1385 else
1386 {
1387 if ((uint32_t)kMCG_PllstPll == pllst)
1388 {
1389 mode = kMCG_ModePBE;
1390 }
1391 else
1392 {
1393 mode = kMCG_ModeFBE;
1394 }
1395 }
1396 }
1397 else if (clkst == (uint32_t)kMCG_ClkOutStatPll)
1398 {
1399 {
1400 mode = kMCG_ModePEE;
1401 }
1402 }
1403 else
1404 {
1405 /*do nothing*/
1406 }
1407
1408 return mode;
1409 }
1410
1411 /*!
1412 * brief Sets the MCG to FEI mode.
1413 *
1414 * This function sets the MCG to FEI mode. If setting to FEI mode fails
1415 * from the current mode, this function returns an error.
1416 *
1417 * param dmx32 DMX32 in FEI mode.
1418 * param drs The DCO range selection.
1419 * param fllStableDelay Delay function to ensure that the FLL is stable. Passing
1420 * NULL does not cause a delay.
1421 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1422 * retval kStatus_Success Switched to the target mode successfully.
1423 * note If p dmx32 is set to kMCG_Dmx32Fine, the slow IRC must not be trimmed
1424 * to a frequency above 32768 Hz.
1425 */
CLOCK_SetFeiMode(mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1426 status_t CLOCK_SetFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1427 {
1428 uint8_t mcg_c4;
1429 bool change_drs = false;
1430
1431 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1432 mcg_mode_t mode = CLOCK_GetMode();
1433 if (!((kMCG_ModeFEI == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEE == mode)))
1434 {
1435 return kStatus_MCG_ModeUnreachable;
1436 }
1437 #endif
1438 mcg_c4 = MCG->C4;
1439
1440 /*
1441 Errata: ERR007993
1442 Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1443 reference clock source changes, then reset to previous value after
1444 reference clock changes.
1445 */
1446 if ((uint8_t)kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
1447 {
1448 change_drs = true;
1449 /* Change the LSB of DRST_DRS. */
1450 MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1451 }
1452
1453 /* Set CLKS and IREFS. */
1454 MCG->C1 = (uint8_t)(((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK))) |
1455 (MCG_C1_CLKS(kMCG_ClkOutSrcOut) /* CLKS = 0 */
1456 | MCG_C1_IREFS(kMCG_FllSrcInternal))); /* IREFS = 1 */
1457
1458 /* Wait and check status. */
1459 while ((uint8_t)kMCG_FllSrcInternal != MCG_S_IREFST_VAL)
1460 {
1461 }
1462
1463 /* Errata: ERR007993 */
1464 if (change_drs)
1465 {
1466 MCG->C4 = mcg_c4;
1467 }
1468
1469 /* In FEI mode, the MCG_C4[DMX32] is set to 0U. */
1470 MCG->C4 = (uint8_t)((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) |
1471 (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1472
1473 /* Check MCG_S[CLKST] */
1474 while ((uint8_t)kMCG_ClkOutStatFll != MCG_S_CLKST_VAL)
1475 {
1476 }
1477
1478 /* Wait for FLL stable time. */
1479 if (NULL != fllStableDelay)
1480 {
1481 fllStableDelay();
1482 }
1483
1484 return kStatus_Success;
1485 }
1486
1487 /*!
1488 * brief Sets the MCG to FEE mode.
1489 *
1490 * This function sets the MCG to FEE mode. If setting to FEE mode fails
1491 * from the current mode, this function returns an error.
1492 *
1493 * param frdiv FLL reference clock divider setting, FRDIV.
1494 * param dmx32 DMX32 in FEE mode.
1495 * param drs The DCO range selection.
1496 * param fllStableDelay Delay function to make sure FLL is stable. Passing
1497 * NULL does not cause a delay.
1498 *
1499 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1500 * retval kStatus_Success Switched to the target mode successfully.
1501 */
CLOCK_SetFeeMode(uint8_t frdiv,mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1502 status_t CLOCK_SetFeeMode(uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1503 {
1504 uint8_t mcg_c4;
1505 bool change_drs = false;
1506
1507 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1508 mcg_mode_t mode = CLOCK_GetMode();
1509 if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode)))
1510 {
1511 return kStatus_MCG_ModeUnreachable;
1512 }
1513 #endif
1514 mcg_c4 = MCG->C4;
1515
1516 /*
1517 Errata: ERR007993
1518 Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1519 reference clock source changes, then reset to previous value after
1520 reference clock changes.
1521 */
1522 if ((uint8_t)kMCG_FllSrcInternal == MCG_S_IREFST_VAL)
1523 {
1524 change_drs = true;
1525 /* Change the LSB of DRST_DRS. */
1526 MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1527 }
1528
1529 /* Set CLKS and IREFS. */
1530 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK)) |
1531 (MCG_C1_CLKS(kMCG_ClkOutSrcOut) /* CLKS = 0 */
1532 | MCG_C1_FRDIV(frdiv) /* FRDIV */
1533 | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
1534
1535 /* If use external crystal as clock source, wait for it stable. */
1536 if (MCG_C7_OSCSEL(kMCG_OscselOsc) == (MCG->C7 & MCG_C7_OSCSEL_MASK))
1537 {
1538 if (0U != (MCG->C2 & MCG_C2_EREFS_MASK))
1539 {
1540 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
1541 {
1542 }
1543 }
1544 }
1545
1546 /* Wait and check status. */
1547 while ((uint8_t)kMCG_FllSrcExternal != MCG_S_IREFST_VAL)
1548 {
1549 }
1550
1551 /* Errata: ERR007993 */
1552 if (change_drs)
1553 {
1554 MCG->C4 = mcg_c4;
1555 }
1556
1557 /* Set DRS and DMX32. */
1558 mcg_c4 = (uint8_t)((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) |
1559 (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1560 MCG->C4 = mcg_c4;
1561
1562 /* Wait for DRST_DRS update. */
1563 while (MCG->C4 != mcg_c4)
1564 {
1565 }
1566
1567 /* Check MCG_S[CLKST] */
1568 while ((uint8_t)kMCG_ClkOutStatFll != MCG_S_CLKST_VAL)
1569 {
1570 }
1571
1572 /* Wait for FLL stable time. */
1573 if (NULL != fllStableDelay)
1574 {
1575 fllStableDelay();
1576 }
1577
1578 return kStatus_Success;
1579 }
1580
1581 /*!
1582 * brief Sets the MCG to FBI mode.
1583 *
1584 * This function sets the MCG to FBI mode. If setting to FBI mode fails
1585 * from the current mode, this function returns an error.
1586 *
1587 * param dmx32 DMX32 in FBI mode.
1588 * param drs The DCO range selection.
1589 * param fllStableDelay Delay function to make sure FLL is stable. If the FLL
1590 * is not used in FBI mode, this parameter can be NULL. Passing
1591 * NULL does not cause a delay.
1592 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1593 * retval kStatus_Success Switched to the target mode successfully.
1594 * note If p dmx32 is set to kMCG_Dmx32Fine, the slow IRC must not be trimmed
1595 * to frequency above 32768 Hz.
1596 */
CLOCK_SetFbiMode(mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1597 status_t CLOCK_SetFbiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1598 {
1599 uint8_t mcg_c4;
1600 bool change_drs = false;
1601
1602 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1603 mcg_mode_t mode = CLOCK_GetMode();
1604
1605 if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode) ||
1606 (kMCG_ModeBLPI == mode)))
1607
1608 {
1609 return kStatus_MCG_ModeUnreachable;
1610 }
1611 #endif
1612
1613 mcg_c4 = MCG->C4;
1614
1615 MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK; /* Disable lowpower. */
1616
1617 /*
1618 Errata: ERR007993
1619 Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1620 reference clock source changes, then reset to previous value after
1621 reference clock changes.
1622 */
1623 if ((uint8_t)kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
1624 {
1625 change_drs = true;
1626 /* Change the LSB of DRST_DRS. */
1627 MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1628 }
1629
1630 /* Set CLKS and IREFS. */
1631 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) |
1632 (MCG_C1_CLKS(kMCG_ClkOutSrcInternal) /* CLKS = 1 */
1633 | MCG_C1_IREFS(kMCG_FllSrcInternal))); /* IREFS = 1 */
1634
1635 /* Wait and check status. */
1636 while ((uint8_t)kMCG_FllSrcInternal != MCG_S_IREFST_VAL)
1637 {
1638 }
1639
1640 /* Errata: ERR007993 */
1641 if (change_drs)
1642 {
1643 MCG->C4 = mcg_c4;
1644 }
1645
1646 while ((uint8_t)kMCG_ClkOutStatInt != MCG_S_CLKST_VAL)
1647 {
1648 }
1649
1650 MCG->C4 = (uint8_t)((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) |
1651 (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1652
1653 /* Wait for FLL stable time. */
1654 if (NULL != fllStableDelay)
1655 {
1656 fllStableDelay();
1657 }
1658
1659 return kStatus_Success;
1660 }
1661
1662 /*!
1663 * brief Sets the MCG to FBE mode.
1664 *
1665 * This function sets the MCG to FBE mode. If setting to FBE mode fails
1666 * from the current mode, this function returns an error.
1667 *
1668 * param frdiv FLL reference clock divider setting, FRDIV.
1669 * param dmx32 DMX32 in FBE mode.
1670 * param drs The DCO range selection.
1671 * param fllStableDelay Delay function to make sure FLL is stable. If the FLL
1672 * is not used in FBE mode, this parameter can be NULL. Passing NULL
1673 * does not cause a delay.
1674 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1675 * retval kStatus_Success Switched to the target mode successfully.
1676 */
CLOCK_SetFbeMode(uint8_t frdiv,mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1677 status_t CLOCK_SetFbeMode(uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1678 {
1679 uint8_t mcg_c4;
1680 bool change_drs = false;
1681
1682 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1683 mcg_mode_t mode = CLOCK_GetMode();
1684 if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode) ||
1685 (kMCG_ModePBE == mode) || (kMCG_ModeBLPE == mode)))
1686 {
1687 return kStatus_MCG_ModeUnreachable;
1688 }
1689 #endif
1690
1691 /* Change to FLL mode. */
1692 MCG->C6 &= ~(uint8_t)MCG_C6_PLLS_MASK;
1693 while ((MCG->S & MCG_S_PLLST_MASK) != 0U)
1694 {
1695 }
1696
1697 /* Set LP bit to enable the FLL */
1698 MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK;
1699
1700 mcg_c4 = MCG->C4;
1701
1702 /*
1703 Errata: ERR007993
1704 Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1705 reference clock source changes, then reset to previous value after
1706 reference clock changes.
1707 */
1708 if ((uint8_t)kMCG_FllSrcInternal == MCG_S_IREFST_VAL)
1709 {
1710 change_drs = true;
1711 /* Change the LSB of DRST_DRS. */
1712 MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1713 }
1714
1715 /* Set CLKS and IREFS. */
1716 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK)) |
1717 (MCG_C1_CLKS(kMCG_ClkOutSrcExternal) /* CLKS = 2 */
1718 | MCG_C1_FRDIV(frdiv) /* FRDIV = frdiv */
1719 | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
1720
1721 /* If use external crystal as clock source, wait for it stable. */
1722 if (MCG_C7_OSCSEL(kMCG_OscselOsc) == (MCG->C7 & MCG_C7_OSCSEL_MASK))
1723 {
1724 if (0U != (MCG->C2 & MCG_C2_EREFS_MASK))
1725 {
1726 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
1727 {
1728 }
1729 }
1730 }
1731
1732 /* Wait for Reference clock Status bit to clear */
1733 while ((uint8_t)kMCG_FllSrcExternal != MCG_S_IREFST_VAL)
1734 {
1735 }
1736
1737 /* Errata: ERR007993 */
1738 if (change_drs)
1739 {
1740 MCG->C4 = mcg_c4;
1741 }
1742
1743 /* Set DRST_DRS and DMX32. */
1744 mcg_c4 = (uint8_t)((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) |
1745 (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1746 MCG->C4 = mcg_c4;
1747
1748 /* Wait for clock status bits to show clock source is ext ref clk */
1749 while ((uint8_t)kMCG_ClkOutStatExt != MCG_S_CLKST_VAL)
1750 {
1751 }
1752
1753 /* Wait for fll stable time. */
1754 if (NULL != fllStableDelay)
1755 {
1756 fllStableDelay();
1757 }
1758
1759 return kStatus_Success;
1760 }
1761
1762 /*!
1763 * brief Sets the MCG to BLPI mode.
1764 *
1765 * This function sets the MCG to BLPI mode. If setting to BLPI mode fails
1766 * from the current mode, this function returns an error.
1767 *
1768 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1769 * retval kStatus_Success Switched to the target mode successfully.
1770 */
CLOCK_SetBlpiMode(void)1771 status_t CLOCK_SetBlpiMode(void)
1772 {
1773 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1774 if (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatInt)
1775 {
1776 return kStatus_MCG_ModeUnreachable;
1777 }
1778 #endif /* MCG_CONFIG_CHECK_PARAM */
1779
1780 /* Set LP. */
1781 MCG->C2 |= MCG_C2_LP_MASK;
1782
1783 return kStatus_Success;
1784 }
1785
1786 /*!
1787 * brief Sets the MCG to BLPE mode.
1788 *
1789 * This function sets the MCG to BLPE mode. If setting to BLPE mode fails
1790 * from the current mode, this function returns an error.
1791 *
1792 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1793 * retval kStatus_Success Switched to the target mode successfully.
1794 */
CLOCK_SetBlpeMode(void)1795 status_t CLOCK_SetBlpeMode(void)
1796 {
1797 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1798 if (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatExt)
1799 {
1800 return kStatus_MCG_ModeUnreachable;
1801 }
1802 #endif
1803
1804 /* Set LP bit to enter BLPE mode. */
1805 MCG->C2 |= MCG_C2_LP_MASK;
1806
1807 return kStatus_Success;
1808 }
1809
1810 /*!
1811 * brief Sets the MCG to PBE mode.
1812 *
1813 * This function sets the MCG to PBE mode. If setting to PBE mode fails
1814 * from the current mode, this function returns an error.
1815 *
1816 * param pllcs The PLL selection, PLLCS.
1817 * param config Pointer to the PLL configuration.
1818 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1819 * retval kStatus_Success Switched to the target mode successfully.
1820 *
1821 * note
1822 * 1. The parameter \c pllcs selects the PLL. For platforms with
1823 * only one PLL, the parameter pllcs is kept for interface compatibility.
1824 * 2. The parameter \c config is the PLL configuration structure. On some
1825 * platforms, it is possible to choose the external PLL directly, which renders the
1826 * configuration structure not necessary. In this case, pass in NULL.
1827 * For example: CLOCK_SetPbeMode(kMCG_OscselOsc, kMCG_PllClkSelExtPll, NULL);
1828 */
CLOCK_SetPbeMode(mcg_pll_clk_select_t pllcs,mcg_pll_config_t const * config)1829 status_t CLOCK_SetPbeMode(mcg_pll_clk_select_t pllcs, mcg_pll_config_t const *config)
1830 {
1831 assert(config);
1832
1833 /*
1834 This function is designed to change MCG to PBE mode from PEE/BLPE/FBE,
1835 but with this workflow, the source mode could be all modes except PEI/PBI.
1836 */
1837 MCG->C2 &= (uint8_t)(~MCG_C2_LP_MASK); /* Disable lowpower. */
1838
1839 /* Change to use external clock first. */
1840 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal));
1841
1842 /* Wait for CLKST clock status bits to show clock source is ext ref clk */
1843 while ((MCG->S & (MCG_S_IREFST_MASK | MCG_S_CLKST_MASK)) !=
1844 (MCG_S_IREFST(kMCG_FllSrcExternal) | MCG_S_CLKST(kMCG_ClkOutStatExt)))
1845 {
1846 }
1847
1848 /* Disable PLL first, then configure PLL. */
1849 MCG->C6 &= (uint8_t)(~MCG_C6_PLLS_MASK);
1850 while ((MCG->S & MCG_S_PLLST_MASK) != 0U)
1851 {
1852 }
1853
1854 /* Configure the PLL. */
1855 {
1856 CLOCK_EnablePll0(config);
1857 }
1858
1859 /* Change to PLL mode. */
1860 MCG->C6 |= MCG_C6_PLLS_MASK;
1861
1862 /* Wait for PLL mode changed. */
1863 while (((MCG->S & MCG_S_PLLST_MASK)) == 0U)
1864 {
1865 }
1866
1867 return kStatus_Success;
1868 }
1869
1870 /*!
1871 * brief Sets the MCG to PEE mode.
1872 *
1873 * This function sets the MCG to PEE mode.
1874 *
1875 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1876 * retval kStatus_Success Switched to the target mode successfully.
1877 *
1878 * note This function only changes the CLKS to use the PLL/FLL output. If the
1879 * PRDIV/VDIV are different than in the PBE mode, set them up
1880 * in PBE mode and wait. When the clock is stable, switch to PEE mode.
1881 */
CLOCK_SetPeeMode(void)1882 status_t CLOCK_SetPeeMode(void)
1883 {
1884 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1885 mcg_mode_t mode = CLOCK_GetMode();
1886 if (kMCG_ModePBE != mode)
1887 {
1888 return kStatus_MCG_ModeUnreachable;
1889 }
1890 #endif
1891
1892 /* Change to use PLL/FLL output clock first. */
1893 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcOut));
1894
1895 /* Wait for clock status bits to update */
1896 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatPll)
1897 {
1898 }
1899
1900 return kStatus_Success;
1901 }
1902
1903 /*!
1904 * brief Switches the MCG to FBE mode from the external mode.
1905 *
1906 * This function switches the MCG from external modes (PEE/PBE/BLPE/FEE) to the FBE mode quickly.
1907 * The external clock is used as the system clock source and PLL is disabled. However,
1908 * the FLL settings are not configured. This is a lite function with a small code size, which is useful
1909 * during the mode switch. For example, to switch from PEE mode to FEI mode:
1910 *
1911 * code
1912 * CLOCK_ExternalModeToFbeModeQuick();
1913 * CLOCK_SetFeiMode(...);
1914 * endcode
1915 *
1916 * retval kStatus_Success Switched successfully.
1917 * retval kStatus_MCG_ModeInvalid If the current mode is not an external mode, do not call this function.
1918 */
CLOCK_ExternalModeToFbeModeQuick(void)1919 status_t CLOCK_ExternalModeToFbeModeQuick(void)
1920 {
1921 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1922 if ((MCG->S & MCG_S_IREFST_MASK) != 0U)
1923 {
1924 return kStatus_MCG_ModeInvalid;
1925 }
1926 #endif /* MCG_CONFIG_CHECK_PARAM */
1927
1928 /* Disable low power */
1929 MCG->C2 &= (uint8_t)(~MCG_C2_LP_MASK);
1930
1931 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal));
1932 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatExt)
1933 {
1934 }
1935
1936 /* Disable PLL. */
1937 MCG->C6 &= ~(uint8_t)MCG_C6_PLLS_MASK;
1938 while ((MCG->S & MCG_S_PLLST_MASK) != 0U)
1939 {
1940 }
1941
1942 return kStatus_Success;
1943 }
1944
1945 /*!
1946 * brief Switches the MCG to FBI mode from internal modes.
1947 *
1948 * This function switches the MCG from internal modes (PEI/PBI/BLPI/FEI) to the FBI mode quickly.
1949 * The MCGIRCLK is used as the system clock source and PLL is disabled. However,
1950 * FLL settings are not configured. This is a lite function with a small code size, which is useful
1951 * during the mode switch. For example, to switch from PEI mode to FEE mode:
1952 *
1953 * code
1954 * CLOCK_InternalModeToFbiModeQuick();
1955 * CLOCK_SetFeeMode(...);
1956 * endcode
1957 *
1958 * retval kStatus_Success Switched successfully.
1959 * retval kStatus_MCG_ModeInvalid If the current mode is not an internal mode, do not call this function.
1960 */
CLOCK_InternalModeToFbiModeQuick(void)1961 status_t CLOCK_InternalModeToFbiModeQuick(void)
1962 {
1963 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1964 if ((MCG->S & MCG_S_IREFST_MASK) == 0U)
1965 {
1966 return kStatus_MCG_ModeInvalid;
1967 }
1968 #endif
1969
1970 /* Disable low power */
1971 MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK;
1972
1973 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal));
1974 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatInt)
1975 {
1976 }
1977
1978 return kStatus_Success;
1979 }
1980
1981 /*!
1982 * brief Sets the MCG to FEI mode during system boot up.
1983 *
1984 * This function sets the MCG to FEI mode from the reset mode. It can also be used to
1985 * set up MCG during system boot up.
1986 *
1987 * param dmx32 DMX32 in FEI mode.
1988 * param drs The DCO range selection.
1989 * param fllStableDelay Delay function to ensure that the FLL is stable.
1990 *
1991 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1992 * retval kStatus_Success Switched to the target mode successfully.
1993 * note If p dmx32 is set to kMCG_Dmx32Fine, the slow IRC must not be trimmed
1994 * to frequency above 32768 Hz.
1995 */
CLOCK_BootToFeiMode(mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1996 status_t CLOCK_BootToFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1997 {
1998 return CLOCK_SetFeiMode(dmx32, drs, fllStableDelay);
1999 }
2000
2001 /*!
2002 * brief Sets the MCG to FEE mode during system bootup.
2003 *
2004 * This function sets MCG to FEE mode from the reset mode. It can also be used to
2005 * set up the MCG during system boot up.
2006 *
2007 * param oscsel OSC clock select, OSCSEL.
2008 * param frdiv FLL reference clock divider setting, FRDIV.
2009 * param dmx32 DMX32 in FEE mode.
2010 * param drs The DCO range selection.
2011 * param fllStableDelay Delay function to ensure that the FLL is stable.
2012 *
2013 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
2014 * retval kStatus_Success Switched to the target mode successfully.
2015 */
CLOCK_BootToFeeMode(mcg_oscsel_t oscsel,uint8_t frdiv,mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))2016 status_t CLOCK_BootToFeeMode(
2017 mcg_oscsel_t oscsel, uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
2018 {
2019 (void)CLOCK_SetExternalRefClkConfig(oscsel);
2020
2021 return CLOCK_SetFeeMode(frdiv, dmx32, drs, fllStableDelay);
2022 }
2023
2024 /*!
2025 * brief Sets the MCG to BLPI mode during system boot up.
2026 *
2027 * This function sets the MCG to BLPI mode from the reset mode. It can also be used to
2028 * set up the MCG during system boot up.
2029 *
2030 * param fcrdiv Fast IRC divider, FCRDIV.
2031 * param ircs The internal reference clock to select, IRCS.
2032 * param ircEnableMode The MCGIRCLK enable mode, OR'ed value of ref _mcg_irclk_enable_mode.
2033 *
2034 * retval kStatus_MCG_SourceUsed Could not change MCGIRCLK setting.
2035 * retval kStatus_Success Switched to the target mode successfully.
2036 */
CLOCK_BootToBlpiMode(uint8_t fcrdiv,mcg_irc_mode_t ircs,uint8_t ircEnableMode)2037 status_t CLOCK_BootToBlpiMode(uint8_t fcrdiv, mcg_irc_mode_t ircs, uint8_t ircEnableMode)
2038 {
2039 /* If reset mode is FEI mode, set MCGIRCLK and always success. */
2040 (void)CLOCK_SetInternalRefClkConfig(ircEnableMode, ircs, fcrdiv);
2041
2042 /* If reset mode is not BLPI, first enter FBI mode. */
2043 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal));
2044 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatInt)
2045 {
2046 }
2047
2048 /* Enter BLPI mode. */
2049 MCG->C2 |= MCG_C2_LP_MASK;
2050
2051 return kStatus_Success;
2052 }
2053
2054 /*!
2055 * brief Sets the MCG to BLPE mode during system boot up.
2056 *
2057 * This function sets the MCG to BLPE mode from the reset mode. It can also be used to
2058 * set up the MCG during system boot up.
2059 *
2060 * param oscsel OSC clock select, MCG_C7[OSCSEL].
2061 *
2062 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
2063 * retval kStatus_Success Switched to the target mode successfully.
2064 */
CLOCK_BootToBlpeMode(mcg_oscsel_t oscsel)2065 status_t CLOCK_BootToBlpeMode(mcg_oscsel_t oscsel)
2066 {
2067 (void)CLOCK_SetExternalRefClkConfig(oscsel);
2068
2069 /* Set to FBE mode. */
2070 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) |
2071 (MCG_C1_CLKS(kMCG_ClkOutSrcExternal) /* CLKS = 2 */
2072 | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
2073
2074 /* If use external crystal as clock source, wait for it stable. */
2075 if (MCG_C7_OSCSEL(kMCG_OscselOsc) == (MCG->C7 & MCG_C7_OSCSEL_MASK))
2076 {
2077 if (0U != (MCG->C2 & MCG_C2_EREFS_MASK))
2078 {
2079 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
2080 {
2081 }
2082 }
2083 }
2084
2085 /* Wait for MCG_S[CLKST] and MCG_S[IREFST]. */
2086 while ((MCG->S & (MCG_S_IREFST_MASK | MCG_S_CLKST_MASK)) !=
2087 (MCG_S_IREFST(kMCG_FllSrcExternal) | MCG_S_CLKST(kMCG_ClkOutStatExt)))
2088 {
2089 }
2090
2091 /* In FBE now, start to enter BLPE. */
2092 MCG->C2 |= MCG_C2_LP_MASK;
2093
2094 return kStatus_Success;
2095 }
2096
2097 /*!
2098 * brief Sets the MCG to PEE mode during system boot up.
2099 *
2100 * This function sets the MCG to PEE mode from reset mode. It can also be used to
2101 * set up the MCG during system boot up.
2102 *
2103 * param oscsel OSC clock select, MCG_C7[OSCSEL].
2104 * param pllcs The PLL selection, PLLCS.
2105 * param config Pointer to the PLL configuration.
2106 *
2107 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
2108 * retval kStatus_Success Switched to the target mode successfully.
2109 */
CLOCK_BootToPeeMode(mcg_oscsel_t oscsel,mcg_pll_clk_select_t pllcs,mcg_pll_config_t const * config)2110 status_t CLOCK_BootToPeeMode(mcg_oscsel_t oscsel, mcg_pll_clk_select_t pllcs, mcg_pll_config_t const *config)
2111 {
2112 assert(config);
2113
2114 (void)CLOCK_SetExternalRefClkConfig(oscsel);
2115
2116 (void)CLOCK_SetPbeMode(pllcs, config);
2117
2118 /* Change to use PLL output clock. */
2119 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcOut));
2120 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatPll)
2121 {
2122 }
2123
2124 return kStatus_Success;
2125 }
2126
2127 /*
2128 The transaction matrix. It defines the path for mode switch, the row is for
2129 current mode and the column is target mode.
2130 For example, switch from FEI to PEE:
2131 1. Current mode FEI, next mode is mcgModeMatrix[FEI][PEE] = FBE, so swith to FBE.
2132 2. Current mode FBE, next mode is mcgModeMatrix[FBE][PEE] = PBE, so swith to PBE.
2133 3. Current mode PBE, next mode is mcgModeMatrix[PBE][PEE] = PEE, so swith to PEE.
2134 Thus the MCG mode has changed from FEI to PEE.
2135 */
2136 static const mcg_mode_t mcgModeMatrix[8][8] = {
2137 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE,
2138 kMCG_ModeFBE}, /* FEI */
2139 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeBLPI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE,
2140 kMCG_ModeFBE}, /* FBI */
2141 {kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeBLPI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFBI,
2142 kMCG_ModeFBI}, /* BLPI */
2143 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE,
2144 kMCG_ModeFBE}, /* FEE */
2145 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeBLPE, kMCG_ModePBE,
2146 kMCG_ModePBE}, /* FBE */
2147 {kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeBLPE, kMCG_ModePBE,
2148 kMCG_ModePBE}, /* BLPE */
2149 {kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeBLPE, kMCG_ModePBE,
2150 kMCG_ModePEE}, /* PBE */
2151 {kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE, kMCG_ModePBE,
2152 kMCG_ModePBE} /* PEE */
2153 /* FEI FBI BLPI FEE FBE BLPE PBE PEE */
2154 };
2155
2156 /*!
2157 * brief Sets the MCG to a target mode.
2158 *
2159 * This function sets MCG to a target mode defined by the configuration
2160 * structure. If switching to the target mode fails, this function
2161 * chooses the correct path.
2162 *
2163 * param config Pointer to the target MCG mode configuration structure.
2164 * return Return kStatus_Success if switched successfully; Otherwise, it returns an error code #_mcg_status.
2165 *
2166 * note If the external clock is used in the target mode, ensure that it is
2167 * enabled. For example, if the OSC0 is used, set up OSC0 correctly before calling this
2168 * function.
2169 */
CLOCK_SetMcgConfig(const mcg_config_t * config)2170 status_t CLOCK_SetMcgConfig(const mcg_config_t *config)
2171 {
2172 mcg_mode_t next_mode;
2173 status_t status = kStatus_Success;
2174
2175 mcg_pll_clk_select_t pllcs = kMCG_PllClkSelPll0;
2176
2177 /* If need to change external clock, MCG_C7[OSCSEL]. */
2178 if (MCG_C7_OSCSEL_VAL != (uint8_t)(config->oscsel))
2179 {
2180 /* If external clock is in use, change to FEI first. */
2181 if ((uint8_t)kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
2182 {
2183 (void)CLOCK_ExternalModeToFbeModeQuick();
2184 (void)CLOCK_SetFeiMode(config->dmx32, config->drs, NULL);
2185 }
2186
2187 (void)CLOCK_SetExternalRefClkConfig(config->oscsel);
2188 }
2189
2190 /* Re-configure MCGIRCLK, if MCGIRCLK is used as system clock source, then change to FEI/PEI first. */
2191 if (MCG_S_CLKST_VAL == (uint8_t)kMCG_ClkOutStatInt)
2192 {
2193 MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK; /* Disable lowpower. */
2194
2195 {
2196 (void)CLOCK_SetFeiMode(config->dmx32, config->drs, CLOCK_FllStableDelay);
2197 }
2198 }
2199
2200 /* Configure MCGIRCLK. */
2201 (void)CLOCK_SetInternalRefClkConfig(config->irclkEnableMode, config->ircs, config->fcrdiv);
2202
2203 next_mode = CLOCK_GetMode();
2204
2205 do
2206 {
2207 next_mode = mcgModeMatrix[next_mode][config->mcgMode];
2208
2209 switch (next_mode)
2210 {
2211 case kMCG_ModeFEI:
2212 status = CLOCK_SetFeiMode(config->dmx32, config->drs, CLOCK_FllStableDelay);
2213 break;
2214 case kMCG_ModeFEE:
2215 status = CLOCK_SetFeeMode(config->frdiv, config->dmx32, config->drs, CLOCK_FllStableDelay);
2216 break;
2217 case kMCG_ModeFBI:
2218 status = CLOCK_SetFbiMode(config->dmx32, config->drs, NULL);
2219 break;
2220 case kMCG_ModeFBE:
2221 status = CLOCK_SetFbeMode(config->frdiv, config->dmx32, config->drs, NULL);
2222 break;
2223 case kMCG_ModeBLPI:
2224 status = CLOCK_SetBlpiMode();
2225 break;
2226 case kMCG_ModeBLPE:
2227 status = CLOCK_SetBlpeMode();
2228 break;
2229 case kMCG_ModePBE:
2230 /* If target mode is not PBE or PEE, then only need to set CLKS = EXT here. */
2231 if ((kMCG_ModePEE == config->mcgMode) || (kMCG_ModePBE == config->mcgMode))
2232 {
2233 {
2234 status = CLOCK_SetPbeMode(pllcs, &config->pll0Config);
2235 }
2236 }
2237 else
2238 {
2239 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal));
2240 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatExt)
2241 {
2242 }
2243 }
2244 break;
2245 case kMCG_ModePEE:
2246 status = CLOCK_SetPeeMode();
2247 break;
2248 default:
2249 assert(false);
2250 break;
2251 }
2252 if (kStatus_Success != status)
2253 {
2254 break;
2255 }
2256 } while (next_mode != config->mcgMode);
2257
2258 if (status == kStatus_Success)
2259 {
2260 if ((config->pll0Config.enableMode & (uint8_t)kMCG_PllEnableIndependent) != 0U)
2261 {
2262 CLOCK_EnablePll0(&config->pll0Config);
2263 }
2264 else
2265 {
2266 MCG->C5 &= ~(uint8_t)kMCG_PllEnableIndependent;
2267 }
2268 }
2269
2270 return status;
2271 }
2272