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