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