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