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