1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright (c) 2016 - 2017 , NXP
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without modification,
7  * are permitted provided that the following conditions are met:
8  *
9  * o Redistributions of source code must retain the above copyright notice, this list
10  *   of conditions and the following disclaimer.
11  *
12  * o Redistributions in binary form must reproduce the above copyright notice, this
13  *   list of conditions and the following disclaimer in the documentation and/or
14  *   other materials provided with the distribution.
15  *
16  * o Neither the name of copyright holder nor the names of its
17  *   contributors may be used to endorse or promote products derived from this
18  *   software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
24  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * Copyright (c) 2016, NXP Semiconductors, Inc.
32  * All rights reserved.
33  *
34  * Redistribution and use in source and binary forms, with or without modification,
35  * are permitted provided that the following conditions are met:
36  *
37  * o Redistributions of source code must retain the above copyright notice, this list
38  *   of conditions and the following disclaimer.
39  *
40  * o Redistributions in binary form must reproduce the above copyright notice, this
41  *   list of conditions and the following disclaimer in the documentation and/or
42  *   other materials provided with the distribution.
43  *
44  * o Neither the name of NXP Semiconductors, Inc. nor the names of its
45  *   contributors may be used to endorse or promote products derived from this
46  *   software without specific prior written permission.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
49  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
50  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
51  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
52  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
53  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
54  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
55  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
57  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58  */
59 
60 #include "fsl_clock.h"
61 
62 /*******************************************************************************
63  * Definitions
64  ******************************************************************************/
65 
66 /* Macro definition remap workaround. */
67 #if (defined(MCG_C2_EREFS_MASK) && !(defined(MCG_C2_EREFS0_MASK)))
68 #define MCG_C2_EREFS0_MASK MCG_C2_EREFS_MASK
69 #endif
70 #if (defined(MCG_C2_HGO_MASK) && !(defined(MCG_C2_HGO0_MASK)))
71 #define MCG_C2_HGO0_MASK MCG_C2_HGO_MASK
72 #endif
73 #if (defined(MCG_C2_RANGE_MASK) && !(defined(MCG_C2_RANGE0_MASK)))
74 #define MCG_C2_RANGE0_MASK MCG_C2_RANGE_MASK
75 #endif
76 #if (defined(MCG_C6_CME_MASK) && !(defined(MCG_C6_CME0_MASK)))
77 #define MCG_C6_CME0_MASK MCG_C6_CME_MASK
78 #endif
79 
80 /* PLL fixed multiplier when there is not PRDIV and VDIV. */
81 #define PLL_FIXED_MULT (375U)
82 /* Max frequency of the reference clock used for internal clock trim. */
83 #define TRIM_REF_CLK_MIN (8000000U)
84 /* Min frequency of the reference clock used for internal clock trim. */
85 #define TRIM_REF_CLK_MAX (16000000U)
86 /* Max trim value of fast internal reference clock. */
87 #define TRIM_FIRC_MAX (5000000U)
88 /* Min trim value of fast internal reference clock. */
89 #define TRIM_FIRC_MIN (3000000U)
90 /* Max trim value of fast internal reference clock. */
91 #define TRIM_SIRC_MAX (39063U)
92 /* Min trim value of fast internal reference clock. */
93 #define TRIM_SIRC_MIN (31250U)
94 
95 #define MCG_S_IRCST_VAL ((MCG->S & MCG_S_IRCST_MASK) >> MCG_S_IRCST_SHIFT)
96 #define MCG_S_CLKST_VAL ((MCG->S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT)
97 #define MCG_S_IREFST_VAL ((MCG->S & MCG_S_IREFST_MASK) >> MCG_S_IREFST_SHIFT)
98 #define MCG_S_PLLST_VAL ((MCG->S & MCG_S_PLLST_MASK) >> MCG_S_PLLST_SHIFT)
99 #define MCG_C1_FRDIV_VAL ((MCG->C1 & MCG_C1_FRDIV_MASK) >> MCG_C1_FRDIV_SHIFT)
100 #define MCG_C2_LP_VAL ((MCG->C2 & MCG_C2_LP_MASK) >> MCG_C2_LP_SHIFT)
101 #define MCG_C2_RANGE_VAL ((MCG->C2 & MCG_C2_RANGE_MASK) >> MCG_C2_RANGE_SHIFT)
102 #define MCG_SC_FCRDIV_VAL ((MCG->SC & MCG_SC_FCRDIV_MASK) >> MCG_SC_FCRDIV_SHIFT)
103 #define MCG_S2_PLLCST_VAL ((MCG->S2 & MCG_S2_PLLCST_MASK) >> MCG_S2_PLLCST_SHIFT)
104 #define MCG_C7_OSCSEL_VAL ((MCG->C7 & MCG_C7_OSCSEL_MASK) >> MCG_C7_OSCSEL_SHIFT)
105 #define MCG_C4_DMX32_VAL ((MCG->C4 & MCG_C4_DMX32_MASK) >> MCG_C4_DMX32_SHIFT)
106 #define MCG_C4_DRST_DRS_VAL ((MCG->C4 & MCG_C4_DRST_DRS_MASK) >> MCG_C4_DRST_DRS_SHIFT)
107 #define MCG_C7_PLL32KREFSEL_VAL ((MCG->C7 & MCG_C7_PLL32KREFSEL_MASK) >> MCG_C7_PLL32KREFSEL_SHIFT)
108 #define MCG_C5_PLLREFSEL0_VAL ((MCG->C5 & MCG_C5_PLLREFSEL0_MASK) >> MCG_C5_PLLREFSEL0_SHIFT)
109 #define MCG_C11_PLLREFSEL1_VAL ((MCG->C11 & MCG_C11_PLLREFSEL1_MASK) >> MCG_C11_PLLREFSEL1_SHIFT)
110 #define MCG_C11_PRDIV1_VAL ((MCG->C11 & MCG_C11_PRDIV1_MASK) >> MCG_C11_PRDIV1_SHIFT)
111 #define MCG_C12_VDIV1_VAL ((MCG->C12 & MCG_C12_VDIV1_MASK) >> MCG_C12_VDIV1_SHIFT)
112 #define MCG_C5_PRDIV0_VAL ((MCG->C5 & MCG_C5_PRDIV0_MASK) >> MCG_C5_PRDIV0_SHIFT)
113 #define MCG_C6_VDIV0_VAL ((MCG->C6 & MCG_C6_VDIV0_MASK) >> MCG_C6_VDIV0_SHIFT)
114 
115 #define OSC_MODE_MASK (MCG_C2_EREFS0_MASK | MCG_C2_HGO0_MASK | MCG_C2_RANGE0_MASK)
116 
117 #define SIM_CLKDIV1_OUTDIV1_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT)
118 #define SIM_CLKDIV1_OUTDIV4_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT)
119 #define SIM_SOPT1_OSC32KSEL_VAL ((SIM->SOPT1 & SIM_SOPT1_OSC32KSEL_MASK) >> SIM_SOPT1_OSC32KSEL_SHIFT)
120 
121 /* MCG_S_CLKST definition. */
122 enum _mcg_clkout_stat
123 {
124     kMCG_ClkOutStatFll, /* FLL.            */
125     kMCG_ClkOutStatInt, /* Internal clock. */
126     kMCG_ClkOutStatExt, /* External clock. */
127     kMCG_ClkOutStatPll  /* PLL.            */
128 };
129 
130 /* MCG_S_PLLST definition. */
131 enum _mcg_pllst
132 {
133     kMCG_PllstFll, /* FLL is used. */
134     kMCG_PllstPll  /* PLL is used. */
135 };
136 
137 /*******************************************************************************
138  * Variables
139  ******************************************************************************/
140 
141 /* Slow internal reference clock frequency. */
142 static uint32_t s_slowIrcFreq = 32768U;
143 /* Fast internal reference clock frequency. */
144 static uint32_t s_fastIrcFreq = 4000000U;
145 
146 /* External XTAL0 (OSC0) clock frequency. */
147 uint32_t g_xtal0Freq;
148 /* External XTAL32K clock frequency. */
149 uint32_t g_xtal32Freq;
150 
151 
152 
153 /*******************************************************************************
154  * Prototypes
155  ******************************************************************************/
156 
157 /*!
158  * @brief Get the MCG external reference clock frequency.
159  *
160  * Get the current MCG external reference clock frequency in Hz. It is
161  * the frequency select by MCG_C7[OSCSEL]. This is an internal function.
162  *
163  * @return MCG external reference clock frequency in Hz.
164  */
165 static uint32_t CLOCK_GetMcgExtClkFreq(void);
166 
167 /*!
168  * @brief Get the MCG FLL external reference clock frequency.
169  *
170  * Get the current MCG FLL external reference clock frequency in Hz. It is
171  * the frequency after by MCG_C1[FRDIV]. This is an internal function.
172  *
173  * @return MCG FLL external reference clock frequency in Hz.
174  */
175 static uint32_t CLOCK_GetFllExtRefClkFreq(void);
176 
177 /*!
178  * @brief Get the MCG FLL reference clock frequency.
179  *
180  * Get the current MCG FLL reference clock frequency in Hz. It is
181  * the frequency select by MCG_C1[IREFS]. This is an internal function.
182  *
183  * @return MCG FLL reference clock frequency in Hz.
184  */
185 static uint32_t CLOCK_GetFllRefClkFreq(void);
186 
187 /*!
188  * @brief Get the frequency of clock selected by MCG_C2[IRCS].
189  *
190  * This clock's two output:
191  *  1. MCGOUTCLK when MCG_S[CLKST]=0.
192  *  2. MCGIRCLK when MCG_C1[IRCLKEN]=1.
193  *
194  * @return The frequency in Hz.
195  */
196 static uint32_t CLOCK_GetInternalRefClkSelectFreq(void);
197 
198 
199 /*!
200  * @brief Calculate the RANGE value base on crystal frequency.
201  *
202  * To setup external crystal oscillator, must set the register bits RANGE
203  * base on the crystal frequency. This function returns the RANGE base on the
204  * input frequency. This is an internal function.
205  *
206  * @param freq Crystal frequency in Hz.
207  * @return The RANGE value.
208  */
209 static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq);
210 
211 
212 
213 
214 /*******************************************************************************
215  * Code
216  ******************************************************************************/
217 
218 #ifndef MCG_USER_CONFIG_FLL_STABLE_DELAY_EN
219 /*!
220  * @brief Delay function to wait FLL stable.
221  *
222  * Delay function to wait FLL stable in FEI mode or FEE mode, should wait at least
223  * 1ms. Every time changes FLL setting, should wait this time for FLL stable.
224  */
CLOCK_FllStableDelay(void)225 void CLOCK_FllStableDelay(void)
226 {
227     /*
228        Should wait at least 1ms. Because in these modes, the core clock is 100MHz
229        at most, so this function could obtain the 1ms delay.
230      */
231     volatile uint32_t i = 30000U;
232     while (i--)
233     {
234         __NOP();
235     }
236 }
237 #else /* With MCG_USER_CONFIG_FLL_STABLE_DELAY_EN defined. */
238 /* Once user defines the MCG_USER_CONFIG_FLL_STABLE_DELAY_EN to use their own delay function, they have to
239  * create their own CLOCK_FllStableDelay() function in application code. Since the clock functions in this
240  * file would call the CLOCK_FllStableDelay() regardness how it is defined.
241  */
242 extern void CLOCK_FllStableDelay(void);
243 #endif /* MCG_USER_CONFIG_FLL_STABLE_DELAY_EN */
244 
CLOCK_GetMcgExtClkFreq(void)245 static uint32_t CLOCK_GetMcgExtClkFreq(void)
246 {
247     uint32_t freq;
248 
249     switch (MCG_C7_OSCSEL_VAL)
250     {
251         case 0U:
252             /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
253             assert(g_xtal0Freq);
254             freq = g_xtal0Freq;
255             break;
256         case 1U:
257             /* Please call CLOCK_SetXtal32Freq base on board setting before using XTAL32K/RTC_CLKIN clock. */
258             assert(g_xtal32Freq);
259             freq = g_xtal32Freq;
260             break;
261         default:
262             freq = 0U;
263             break;
264     }
265 
266     return freq;
267 }
268 
CLOCK_GetFllExtRefClkFreq(void)269 static uint32_t CLOCK_GetFllExtRefClkFreq(void)
270 {
271     /* FllExtRef = McgExtRef / FllExtRefDiv */
272     uint8_t frdiv;
273     uint8_t range;
274     uint8_t oscsel;
275 
276     uint32_t freq = CLOCK_GetMcgExtClkFreq();
277 
278     if (!freq)
279     {
280         return freq;
281     }
282 
283     frdiv = MCG_C1_FRDIV_VAL;
284     freq >>= frdiv;
285 
286     range = MCG_C2_RANGE_VAL;
287     oscsel = MCG_C7_OSCSEL_VAL;
288 
289     /*
290        When should use divider 32, 64, 128, 256, 512, 1024, 1280, 1536.
291        1. MCG_C7[OSCSEL] selects IRC48M.
292        2. MCG_C7[OSCSEL] selects OSC0 and MCG_C2[RANGE] is not 0.
293     */
294     if (((0U != range)
295          && (kMCG_OscselOsc == oscsel)
296              )
297             )
298     {
299         switch (frdiv)
300         {
301             case 0:
302             case 1:
303             case 2:
304             case 3:
305             case 4:
306             case 5:
307                 freq >>= 5u;
308                 break;
309             case 6:
310                 /* 64*20=1280 */
311                 freq /= 20u;
312                 break;
313             case 7:
314                 /* 128*12=1536 */
315                 freq /= 12u;
316                 break;
317             default:
318                 freq = 0u;
319                 break;
320         }
321     }
322 
323     return freq;
324 }
325 
CLOCK_GetInternalRefClkSelectFreq(void)326 static uint32_t CLOCK_GetInternalRefClkSelectFreq(void)
327 {
328     if (kMCG_IrcSlow == MCG_S_IRCST_VAL)
329     {
330         /* Slow internal reference clock selected*/
331         return s_slowIrcFreq;
332     }
333     else
334     {
335         /* Fast internal reference clock selected*/
336         return s_fastIrcFreq >> MCG_SC_FCRDIV_VAL;
337     }
338 }
339 
CLOCK_GetFllRefClkFreq(void)340 static uint32_t CLOCK_GetFllRefClkFreq(void)
341 {
342     /* If use external reference clock. */
343     if (kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
344     {
345         return CLOCK_GetFllExtRefClkFreq();
346     }
347     /* If use internal reference clock. */
348     else
349     {
350         return s_slowIrcFreq;
351     }
352 }
353 
354 
CLOCK_GetOscRangeFromFreq(uint32_t freq)355 static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq)
356 {
357     uint8_t range;
358 
359     if (freq <= 39063U)
360     {
361         range = 0U;
362     }
363     else if (freq <= 8000000U)
364     {
365         range = 1U;
366     }
367     else
368     {
369         range = 2U;
370     }
371 
372     return range;
373 }
374 
375 
CLOCK_GetEr32kClkFreq(void)376 uint32_t CLOCK_GetEr32kClkFreq(void)
377 {
378     uint32_t freq;
379 
380     switch (SIM_SOPT1_OSC32KSEL_VAL)
381     {
382         case 0U: /* OSC 32k clock  */
383         case 2U: /* RTC 32k clock  */
384             /* Please call CLOCK_SetXtal32Freq base on board setting before using XTAL32K/RTC_CLKIN clock. */
385             assert(g_xtal32Freq);
386             freq = g_xtal32Freq;
387             break;
388         case 3U: /* LPO clock      */
389             freq = LPO_CLK_FREQ;
390             break;
391         default:
392             freq = 0U;
393             break;
394     }
395     return freq;
396 }
397 
CLOCK_GetOsc0ErClkFreq(void)398 uint32_t CLOCK_GetOsc0ErClkFreq(void)
399 {
400     /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
401     assert(g_xtal0Freq);
402     return g_xtal0Freq;
403 }
404 
CLOCK_GetPlatClkFreq(void)405 uint32_t CLOCK_GetPlatClkFreq(void)
406 {
407     return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
408 }
409 
CLOCK_GetFlashClkFreq(void)410 uint32_t CLOCK_GetFlashClkFreq(void)
411 {
412     uint32_t freq;
413 
414     freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
415     freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1);
416 
417     return freq;
418 }
419 
CLOCK_GetBusClkFreq(void)420 uint32_t CLOCK_GetBusClkFreq(void)
421 {
422     uint32_t freq;
423 
424     freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
425     freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1);
426 
427     return freq;
428 }
429 
CLOCK_GetCoreSysClkFreq(void)430 uint32_t CLOCK_GetCoreSysClkFreq(void)
431 {
432     return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
433 }
434 
CLOCK_GetFreq(clock_name_t clockName)435 uint32_t CLOCK_GetFreq(clock_name_t clockName)
436 {
437     uint32_t freq;
438 
439     switch (clockName)
440     {
441         case kCLOCK_CoreSysClk:
442         case kCLOCK_PlatClk:
443             freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
444             break;
445         case kCLOCK_BusClk:
446         case kCLOCK_FlashClk:
447             freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
448             freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1);
449             break;
450         case kCLOCK_Er32kClk:
451             freq = CLOCK_GetEr32kClkFreq();
452             break;
453         case kCLOCK_McgInternalRefClk:
454             freq = CLOCK_GetInternalRefClkFreq();
455             break;
456         case kCLOCK_McgFllClk:
457             freq = CLOCK_GetFllFreq();
458             break;
459         case kCLOCK_LpoClk:
460             freq = LPO_CLK_FREQ;
461             break;
462         case kCLOCK_Osc0ErClk:
463             /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
464             assert(g_xtal0Freq);
465             freq = g_xtal0Freq;
466             break;
467         default:
468             freq = 0U;
469             break;
470     }
471 
472     return freq;
473 }
474 
CLOCK_SetSimConfig(sim_clock_config_t const * config)475 void CLOCK_SetSimConfig(sim_clock_config_t const *config)
476 {
477     SIM->CLKDIV1 = config->clkdiv1;
478     CLOCK_SetEr32kClock(config->er32kSrc);
479 }
480 
CLOCK_GetOutClkFreq(void)481 uint32_t CLOCK_GetOutClkFreq(void)
482 {
483     uint32_t mcgoutclk;
484     uint32_t clkst = MCG_S_CLKST_VAL;
485 
486     switch (clkst)
487     {
488         case kMCG_ClkOutStatFll:
489             mcgoutclk = CLOCK_GetFllFreq();
490             break;
491         case kMCG_ClkOutStatInt:
492             mcgoutclk = CLOCK_GetInternalRefClkSelectFreq();
493             break;
494         case kMCG_ClkOutStatExt:
495             mcgoutclk = CLOCK_GetMcgExtClkFreq();
496             break;
497         default:
498             mcgoutclk = 0U;
499             break;
500     }
501     return mcgoutclk;
502 }
503 
CLOCK_GetFllFreq(void)504 uint32_t CLOCK_GetFllFreq(void)
505 {
506     static const uint16_t fllFactorTable[4][2] = {{640, 732}, {1280, 1464}, {1920, 2197}, {2560, 2929}};
507 
508     uint8_t drs, dmx32;
509     uint32_t freq;
510 
511     /* If FLL is not enabled currently, then return 0U. */
512     if ((MCG->C2 & MCG_C2_LP_MASK)
513             )
514     {
515         return 0U;
516     }
517 
518     /* Get FLL reference clock frequency. */
519     freq = CLOCK_GetFllRefClkFreq();
520     if (!freq)
521     {
522         return freq;
523     }
524 
525     drs = MCG_C4_DRST_DRS_VAL;
526     dmx32 = MCG_C4_DMX32_VAL;
527 
528     return freq * fllFactorTable[drs][dmx32];
529 }
530 
CLOCK_GetInternalRefClkFreq(void)531 uint32_t CLOCK_GetInternalRefClkFreq(void)
532 {
533     /* If MCGIRCLK is gated. */
534     if (!(MCG->C1 & MCG_C1_IRCLKEN_MASK))
535     {
536         return 0U;
537     }
538 
539     return CLOCK_GetInternalRefClkSelectFreq();
540 }
541 
CLOCK_GetFixedFreqClkFreq(void)542 uint32_t CLOCK_GetFixedFreqClkFreq(void)
543 {
544     uint32_t freq = CLOCK_GetFllRefClkFreq();
545 
546     /* MCGFFCLK must be no more than MCGOUTCLK/8. */
547     if ((freq) && (freq <= (CLOCK_GetOutClkFreq() / 8U)))
548     {
549         return freq;
550     }
551     else
552     {
553         return 0U;
554     }
555 }
556 
557 
CLOCK_SetExternalRefClkConfig(mcg_oscsel_t oscsel)558 status_t CLOCK_SetExternalRefClkConfig(mcg_oscsel_t oscsel)
559 {
560     bool needDelay;
561     uint32_t i;
562 
563 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
564     /* If change MCG_C7[OSCSEL] and external reference clock is system clock source, return error. */
565     if ((MCG_C7_OSCSEL_VAL != oscsel) && (!(MCG->S & MCG_S_IREFST_MASK)))
566     {
567         return kStatus_MCG_SourceUsed;
568     }
569 #endif /* MCG_CONFIG_CHECK_PARAM */
570 
571     if (MCG_C7_OSCSEL_VAL != oscsel)
572     {
573         /* If change OSCSEL, need to delay, ERR009878. */
574         needDelay = true;
575     }
576     else
577     {
578         needDelay = false;
579     }
580 
581     MCG->C7 = (MCG->C7 & ~MCG_C7_OSCSEL_MASK) | MCG_C7_OSCSEL(oscsel);
582     if (needDelay)
583     {
584         /* ERR009878 Delay at least 50 micro-seconds for external clock change valid. */
585         i = 1500U;
586         while (i--)
587         {
588             __NOP();
589         }
590     }
591 
592     return kStatus_Success;
593 }
594 
CLOCK_SetInternalRefClkConfig(uint8_t enableMode,mcg_irc_mode_t ircs,uint8_t fcrdiv)595 status_t CLOCK_SetInternalRefClkConfig(uint8_t enableMode, mcg_irc_mode_t ircs, uint8_t fcrdiv)
596 {
597     uint32_t mcgOutClkState = MCG_S_CLKST_VAL;
598     mcg_irc_mode_t curIrcs = (mcg_irc_mode_t)MCG_S_IRCST_VAL;
599     uint8_t curFcrdiv = MCG_SC_FCRDIV_VAL;
600 
601 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
602     /* If MCGIRCLK is used as system clock source. */
603     if (kMCG_ClkOutStatInt == mcgOutClkState)
604     {
605         /* If need to change MCGIRCLK source or driver, return error. */
606         if (((kMCG_IrcFast == curIrcs) && (fcrdiv != curFcrdiv)) || (ircs != curIrcs))
607         {
608             return kStatus_MCG_SourceUsed;
609         }
610     }
611 #endif
612 
613     /* If need to update the FCRDIV. */
614     if (fcrdiv != curFcrdiv)
615     {
616         /* If fast IRC is in use currently, change to slow IRC. */
617         if ((kMCG_IrcFast == curIrcs) && ((mcgOutClkState == kMCG_ClkOutStatInt) || (MCG->C1 & MCG_C1_IRCLKEN_MASK)))
618         {
619             MCG->C2 = ((MCG->C2 & ~MCG_C2_IRCS_MASK) | (MCG_C2_IRCS(kMCG_IrcSlow)));
620             while (MCG_S_IRCST_VAL != kMCG_IrcSlow)
621             {
622             }
623         }
624         /* Update FCRDIV. */
625         MCG->SC = (MCG->SC & ~(MCG_SC_FCRDIV_MASK | MCG_SC_ATMF_MASK | MCG_SC_LOCS0_MASK)) | MCG_SC_FCRDIV(fcrdiv);
626     }
627 
628     /* Set internal reference clock selection. */
629     MCG->C2 = (MCG->C2 & ~MCG_C2_IRCS_MASK) | (MCG_C2_IRCS(ircs));
630     MCG->C1 = (MCG->C1 & ~(MCG_C1_IRCLKEN_MASK | MCG_C1_IREFSTEN_MASK)) | (uint8_t)enableMode;
631 
632     /* If MCGIRCLK is used, need to wait for MCG_S_IRCST. */
633     if ((mcgOutClkState == kMCG_ClkOutStatInt) || (enableMode & kMCG_IrclkEnable))
634     {
635         while (MCG_S_IRCST_VAL != ircs)
636         {
637         }
638     }
639 
640     return kStatus_Success;
641 }
642 
643 
644 
CLOCK_SetOsc0MonitorMode(mcg_monitor_mode_t mode)645 void CLOCK_SetOsc0MonitorMode(mcg_monitor_mode_t mode)
646 {
647     /* Clear the previous flag, MCG_SC[LOCS0]. */
648     MCG->SC &= ~MCG_SC_ATMF_MASK;
649 
650     if (kMCG_MonitorNone == mode)
651     {
652         MCG->C6 &= ~MCG_C6_CME0_MASK;
653     }
654     else
655     {
656         if (kMCG_MonitorInt == mode)
657         {
658             MCG->C2 &= ~MCG_C2_LOCRE0_MASK;
659         }
660         else
661         {
662             MCG->C2 |= MCG_C2_LOCRE0_MASK;
663         }
664         MCG->C6 |= MCG_C6_CME0_MASK;
665     }
666 }
667 
668 
CLOCK_SetRtcOscMonitorMode(mcg_monitor_mode_t mode)669 void CLOCK_SetRtcOscMonitorMode(mcg_monitor_mode_t mode)
670 {
671     uint8_t mcg_c8 = MCG->C8;
672 
673     mcg_c8 &= ~(MCG_C8_CME1_MASK | MCG_C8_LOCRE1_MASK);
674 
675     if (kMCG_MonitorNone != mode)
676     {
677         if (kMCG_MonitorReset == mode)
678         {
679             mcg_c8 |= MCG_C8_LOCRE1_MASK;
680         }
681         mcg_c8 |= MCG_C8_CME1_MASK;
682     }
683     MCG->C8 = mcg_c8;
684 }
685 
686 
CLOCK_GetStatusFlags(void)687 uint32_t CLOCK_GetStatusFlags(void)
688 {
689     uint32_t ret = 0U;
690 
691     if (MCG->C8 & MCG_C8_LOCS1_MASK)
692     {
693         ret |= kMCG_RtcOscLostFlag;
694     }
695     return ret;
696 }
697 
CLOCK_ClearStatusFlags(uint32_t mask)698 void CLOCK_ClearStatusFlags(uint32_t mask)
699 {
700     uint8_t reg;
701 
702     if (mask & kMCG_RtcOscLostFlag)
703     {
704         reg = MCG->C8;
705         MCG->C8 = reg;
706     }
707 }
708 
CLOCK_InitOsc0(osc_config_t const * config)709 void CLOCK_InitOsc0(osc_config_t const *config)
710 {
711     uint8_t range = CLOCK_GetOscRangeFromFreq(config->freq);
712 
713 
714     MCG->C2 = ((MCG->C2 & ~OSC_MODE_MASK) | MCG_C2_RANGE(range) | (uint8_t)config->workMode);
715 
716     if ((kOSC_ModeExt != config->workMode)
717             )
718     {
719         /* Wait for stable. */
720         while (!(MCG->S & MCG_S_OSCINIT0_MASK))
721         {
722         }
723     }
724 }
725 
CLOCK_DeinitOsc0(void)726 void CLOCK_DeinitOsc0(void)
727 {
728     MCG->C2 &= ~OSC_MODE_MASK;
729 }
730 
731 
CLOCK_TrimInternalRefClk(uint32_t extFreq,uint32_t desireFreq,uint32_t * actualFreq,mcg_atm_select_t atms)732 status_t CLOCK_TrimInternalRefClk(uint32_t extFreq, uint32_t desireFreq, uint32_t *actualFreq, mcg_atm_select_t atms)
733 {
734     uint32_t multi; /* extFreq / desireFreq */
735     uint32_t actv;  /* Auto trim value. */
736     uint8_t mcg_sc;
737 
738     static const uint32_t trimRange[2][2] = {
739         /*     Min           Max      */
740         {TRIM_SIRC_MIN, TRIM_SIRC_MAX}, /* Slow IRC. */
741         {TRIM_FIRC_MIN, TRIM_FIRC_MAX}  /* Fast IRC. */
742     };
743 
744     if ((extFreq > TRIM_REF_CLK_MAX) || (extFreq < TRIM_REF_CLK_MIN))
745     {
746         return kStatus_MCG_AtmBusClockInvalid;
747     }
748 
749     /* Check desired frequency range. */
750     if ((desireFreq < trimRange[atms][0]) || (desireFreq > trimRange[atms][1]))
751     {
752         return kStatus_MCG_AtmDesiredFreqInvalid;
753     }
754 
755     /*
756        Make sure internal reference clock is not used to generate bus clock.
757        Here only need to check (MCG_S_IREFST == 1).
758      */
759     if (MCG_S_IREFST(kMCG_FllSrcInternal) == (MCG->S & MCG_S_IREFST_MASK))
760     {
761         return kStatus_MCG_AtmIrcUsed;
762     }
763 
764     multi = extFreq / desireFreq;
765     actv = multi * 21U;
766 
767     if (kMCG_AtmSel4m == atms)
768     {
769         actv *= 128U;
770     }
771 
772     /* Now begin to start trim. */
773     MCG->ATCVL = (uint8_t)actv;
774     MCG->ATCVH = (uint8_t)(actv >> 8U);
775 
776     mcg_sc = MCG->SC;
777     mcg_sc &= ~(MCG_SC_ATMS_MASK | MCG_SC_LOCS0_MASK);
778     mcg_sc |= (MCG_SC_ATMF_MASK | MCG_SC_ATMS(atms));
779     MCG->SC = (mcg_sc | MCG_SC_ATME_MASK);
780 
781     /* Wait for finished. */
782     while (MCG->SC & MCG_SC_ATME_MASK)
783     {
784     }
785 
786     /* Error occurs? */
787     if (MCG->SC & MCG_SC_ATMF_MASK)
788     {
789         /* Clear the failed flag. */
790         MCG->SC = mcg_sc;
791         return kStatus_MCG_AtmHardwareFail;
792     }
793 
794     *actualFreq = extFreq / multi;
795 
796     if (kMCG_AtmSel4m == atms)
797     {
798         s_fastIrcFreq = *actualFreq;
799     }
800     else
801     {
802         s_slowIrcFreq = *actualFreq;
803     }
804 
805     return kStatus_Success;
806 }
807 
CLOCK_GetMode(void)808 mcg_mode_t CLOCK_GetMode(void)
809 {
810     mcg_mode_t mode = kMCG_ModeError;
811     uint32_t clkst = MCG_S_CLKST_VAL;
812     uint32_t irefst = MCG_S_IREFST_VAL;
813     uint32_t lp = MCG_C2_LP_VAL;
814 
815     /*------------------------------------------------------------------
816                            Mode and Registers
817     ____________________________________________________________________
818 
819       Mode   |   CLKST    |   IREFST   |   PLLST   |      LP
820     ____________________________________________________________________
821 
822       FEI    |  00(FLL)   |   1(INT)   |   0(FLL)  |      X
823     ____________________________________________________________________
824 
825       FEE    |  00(FLL)   |   0(EXT)   |   0(FLL)  |      X
826     ____________________________________________________________________
827 
828       FBE    |  10(EXT)   |   0(EXT)   |   0(FLL)  |   0(NORMAL)
829     ____________________________________________________________________
830 
831       FBI    |  01(INT)   |   1(INT)   |   0(FLL)  |   0(NORMAL)
832     ____________________________________________________________________
833 
834       BLPI   |  01(INT)   |   1(INT)   |   0(FLL)  |   1(LOW POWER)
835     ____________________________________________________________________
836 
837       BLPE   |  10(EXT)   |   0(EXT)   |     X     |   1(LOW POWER)
838     ____________________________________________________________________
839 
840       PEE    |  11(PLL)   |   0(EXT)   |   1(PLL)  |      X
841     ____________________________________________________________________
842 
843       PBE    |  10(EXT)   |   0(EXT)   |   1(PLL)  |   O(NORMAL)
844     ____________________________________________________________________
845 
846       PBI    |  01(INT)   |   1(INT)   |   1(PLL)  |   0(NORMAL)
847     ____________________________________________________________________
848 
849       PEI    |  11(PLL)   |   1(INT)   |   1(PLL)  |      X
850     ____________________________________________________________________
851 
852     ----------------------------------------------------------------------*/
853 
854     switch (clkst)
855     {
856         case kMCG_ClkOutStatFll:
857             if (kMCG_FllSrcExternal == irefst)
858             {
859                 mode = kMCG_ModeFEE;
860             }
861             else
862             {
863                 mode = kMCG_ModeFEI;
864             }
865             break;
866         case kMCG_ClkOutStatInt:
867             if (lp)
868             {
869                 mode = kMCG_ModeBLPI;
870             }
871             else
872             {
873                 {
874                     mode = kMCG_ModeFBI;
875                 }
876             }
877             break;
878         case kMCG_ClkOutStatExt:
879             if (lp)
880             {
881                 mode = kMCG_ModeBLPE;
882             }
883             else
884             {
885                 {
886                     mode = kMCG_ModeFBE;
887                 }
888             }
889             break;
890         default:
891             break;
892     }
893 
894     return mode;
895 }
896 
CLOCK_SetFeiMode(mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))897 status_t CLOCK_SetFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
898 {
899     uint8_t mcg_c4;
900     bool change_drs = false;
901 
902 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
903     mcg_mode_t mode = CLOCK_GetMode();
904     if (!((kMCG_ModeFEI == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEE == mode)))
905     {
906         return kStatus_MCG_ModeUnreachable;
907     }
908 #endif
909     mcg_c4 = MCG->C4;
910 
911     /*
912        Errata: ERR007993
913        Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
914        reference clock source changes, then reset to previous value after
915        reference clock changes.
916      */
917     if (kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
918     {
919         change_drs = true;
920         /* Change the LSB of DRST_DRS. */
921         MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
922     }
923 
924     /* Set CLKS and IREFS. */
925     MCG->C1 =
926         ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK))) | (MCG_C1_CLKS(kMCG_ClkOutSrcOut)        /* CLKS = 0 */
927                                                                  | MCG_C1_IREFS(kMCG_FllSrcInternal)); /* IREFS = 1 */
928 
929     /* Wait and check status. */
930     while (kMCG_FllSrcInternal != MCG_S_IREFST_VAL)
931     {
932     }
933 
934     /* Errata: ERR007993 */
935     if (change_drs)
936     {
937         MCG->C4 = mcg_c4;
938     }
939 
940     /* In FEI mode, the MCG_C4[DMX32] is set to 0U. */
941     MCG->C4 = (mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs));
942 
943     /* Check MCG_S[CLKST] */
944     while (kMCG_ClkOutStatFll != MCG_S_CLKST_VAL)
945     {
946     }
947 
948     /* Wait for FLL stable time. */
949     if (fllStableDelay)
950     {
951         fllStableDelay();
952     }
953 
954     return kStatus_Success;
955 }
956 
CLOCK_SetFeeMode(uint8_t frdiv,mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))957 status_t CLOCK_SetFeeMode(uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
958 {
959     uint8_t mcg_c4;
960     bool change_drs = false;
961 
962 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
963     mcg_mode_t mode = CLOCK_GetMode();
964     if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode)))
965     {
966         return kStatus_MCG_ModeUnreachable;
967     }
968 #endif
969     mcg_c4 = MCG->C4;
970 
971     /*
972        Errata: ERR007993
973        Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
974        reference clock source changes, then reset to previous value after
975        reference clock changes.
976      */
977     if (kMCG_FllSrcInternal == MCG_S_IREFST_VAL)
978     {
979         change_drs = true;
980         /* Change the LSB of DRST_DRS. */
981         MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
982     }
983 
984     /* Set CLKS and IREFS. */
985     MCG->C1 = ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK)) |
986                (MCG_C1_CLKS(kMCG_ClkOutSrcOut)         /* CLKS = 0 */
987                 | MCG_C1_FRDIV(frdiv)                  /* FRDIV */
988                 | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
989 
990     /* If use external crystal as clock source, wait for it stable. */
991     if (MCG_C7_OSCSEL(kMCG_OscselOsc) == (MCG->C7 & MCG_C7_OSCSEL_MASK))
992     {
993         if (MCG->C2 & MCG_C2_EREFS_MASK)
994         {
995             while (!(MCG->S & MCG_S_OSCINIT0_MASK))
996             {
997             }
998         }
999     }
1000 
1001     /* Wait and check status. */
1002     while (kMCG_FllSrcExternal != MCG_S_IREFST_VAL)
1003     {
1004     }
1005 
1006     /* Errata: ERR007993 */
1007     if (change_drs)
1008     {
1009         MCG->C4 = mcg_c4;
1010     }
1011 
1012     /* Set DRS and DMX32. */
1013     mcg_c4 = ((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1014     MCG->C4 = mcg_c4;
1015 
1016     /* Wait for DRST_DRS update. */
1017     while (MCG->C4 != mcg_c4)
1018     {
1019     }
1020 
1021     /* Check MCG_S[CLKST] */
1022     while (kMCG_ClkOutStatFll != MCG_S_CLKST_VAL)
1023     {
1024     }
1025 
1026     /* Wait for FLL stable time. */
1027     if (fllStableDelay)
1028     {
1029         fllStableDelay();
1030     }
1031 
1032     return kStatus_Success;
1033 }
1034 
CLOCK_SetFbiMode(mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1035 status_t CLOCK_SetFbiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1036 {
1037     uint8_t mcg_c4;
1038     bool change_drs = false;
1039 
1040 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1041     mcg_mode_t mode = CLOCK_GetMode();
1042 
1043     if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode) ||
1044           (kMCG_ModeBLPI == mode)))
1045 
1046     {
1047         return kStatus_MCG_ModeUnreachable;
1048     }
1049 #endif
1050 
1051     mcg_c4 = MCG->C4;
1052 
1053     MCG->C2 &= ~MCG_C2_LP_MASK; /* Disable lowpower. */
1054 
1055     /*
1056        Errata: ERR007993
1057        Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1058        reference clock source changes, then reset to previous value after
1059        reference clock changes.
1060      */
1061     if (kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
1062     {
1063         change_drs = true;
1064         /* Change the LSB of DRST_DRS. */
1065         MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1066     }
1067 
1068     /* Set CLKS and IREFS. */
1069     MCG->C1 =
1070         ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | (MCG_C1_CLKS(kMCG_ClkOutSrcInternal)    /* CLKS = 1 */
1071                                                                 | MCG_C1_IREFS(kMCG_FllSrcInternal))); /* IREFS = 1 */
1072 
1073     /* Wait and check status. */
1074     while (kMCG_FllSrcInternal != MCG_S_IREFST_VAL)
1075     {
1076     }
1077 
1078     /* Errata: ERR007993 */
1079     if (change_drs)
1080     {
1081         MCG->C4 = mcg_c4;
1082     }
1083 
1084     while (kMCG_ClkOutStatInt != MCG_S_CLKST_VAL)
1085     {
1086     }
1087 
1088     MCG->C4 = (mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs));
1089 
1090     /* Wait for FLL stable time. */
1091     if (fllStableDelay)
1092     {
1093         fllStableDelay();
1094     }
1095 
1096     return kStatus_Success;
1097 }
1098 
CLOCK_SetFbeMode(uint8_t frdiv,mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1099 status_t CLOCK_SetFbeMode(uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1100 {
1101     uint8_t mcg_c4;
1102     bool change_drs = false;
1103 
1104 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1105     mcg_mode_t mode = CLOCK_GetMode();
1106     if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode) ||
1107           (kMCG_ModeBLPE == mode)))
1108     {
1109         return kStatus_MCG_ModeUnreachable;
1110     }
1111 #endif
1112 
1113 
1114     /* Set LP bit to enable the FLL */
1115     MCG->C2 &= ~MCG_C2_LP_MASK;
1116 
1117     mcg_c4 = MCG->C4;
1118 
1119     /*
1120        Errata: ERR007993
1121        Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1122        reference clock source changes, then reset to previous value after
1123        reference clock changes.
1124      */
1125     if (kMCG_FllSrcInternal == MCG_S_IREFST_VAL)
1126     {
1127         change_drs = true;
1128         /* Change the LSB of DRST_DRS. */
1129         MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1130     }
1131 
1132     /* Set CLKS and IREFS. */
1133     MCG->C1 = ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK)) |
1134                (MCG_C1_CLKS(kMCG_ClkOutSrcExternal)    /* CLKS = 2 */
1135                 | MCG_C1_FRDIV(frdiv)                  /* FRDIV = frdiv */
1136                 | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
1137 
1138     /* If use external crystal as clock source, wait for it stable. */
1139     if (MCG_C7_OSCSEL(kMCG_OscselOsc) == (MCG->C7 & MCG_C7_OSCSEL_MASK))
1140     {
1141         if (MCG->C2 & MCG_C2_EREFS_MASK)
1142         {
1143             while (!(MCG->S & MCG_S_OSCINIT0_MASK))
1144             {
1145             }
1146         }
1147     }
1148 
1149     /* Wait for Reference clock Status bit to clear */
1150     while (kMCG_FllSrcExternal != MCG_S_IREFST_VAL)
1151     {
1152     }
1153 
1154     /* Errata: ERR007993 */
1155     if (change_drs)
1156     {
1157         MCG->C4 = mcg_c4;
1158     }
1159 
1160     /* Set DRST_DRS and DMX32. */
1161     mcg_c4 = ((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) | (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1162 
1163     /* Wait for clock status bits to show clock source is ext ref clk */
1164     while (kMCG_ClkOutStatExt != MCG_S_CLKST_VAL)
1165     {
1166     }
1167 
1168     /* Wait for fll stable time. */
1169     if (fllStableDelay)
1170     {
1171         fllStableDelay();
1172     }
1173 
1174     return kStatus_Success;
1175 }
1176 
CLOCK_SetBlpiMode(void)1177 status_t CLOCK_SetBlpiMode(void)
1178 {
1179 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1180     if (MCG_S_CLKST_VAL != kMCG_ClkOutStatInt)
1181     {
1182         return kStatus_MCG_ModeUnreachable;
1183     }
1184 #endif /* MCG_CONFIG_CHECK_PARAM */
1185 
1186     /* Set LP. */
1187     MCG->C2 |= MCG_C2_LP_MASK;
1188 
1189     return kStatus_Success;
1190 }
1191 
CLOCK_SetBlpeMode(void)1192 status_t CLOCK_SetBlpeMode(void)
1193 {
1194 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1195     if (MCG_S_CLKST_VAL != kMCG_ClkOutStatExt)
1196     {
1197         return kStatus_MCG_ModeUnreachable;
1198     }
1199 #endif
1200 
1201     /* Set LP bit to enter BLPE mode. */
1202     MCG->C2 |= MCG_C2_LP_MASK;
1203 
1204     return kStatus_Success;
1205 }
1206 
1207 
CLOCK_ExternalModeToFbeModeQuick(void)1208 status_t CLOCK_ExternalModeToFbeModeQuick(void)
1209 {
1210 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1211     if (MCG->S & MCG_S_IREFST_MASK)
1212     {
1213         return kStatus_MCG_ModeInvalid;
1214     }
1215 #endif /* MCG_CONFIG_CHECK_PARAM */
1216 
1217     /* Disable low power */
1218     MCG->C2 &= ~MCG_C2_LP_MASK;
1219 
1220     MCG->C1 = ((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal));
1221     while (MCG_S_CLKST_VAL != kMCG_ClkOutStatExt)
1222     {
1223     }
1224 
1225 
1226     return kStatus_Success;
1227 }
1228 
CLOCK_InternalModeToFbiModeQuick(void)1229 status_t CLOCK_InternalModeToFbiModeQuick(void)
1230 {
1231 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1232     if (!(MCG->S & MCG_S_IREFST_MASK))
1233     {
1234         return kStatus_MCG_ModeInvalid;
1235     }
1236 #endif
1237 
1238     /* Disable low power */
1239     MCG->C2 &= ~MCG_C2_LP_MASK;
1240 
1241     MCG->C1 = ((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal));
1242     while (MCG_S_CLKST_VAL != kMCG_ClkOutStatInt)
1243     {
1244     }
1245 
1246 
1247     return kStatus_Success;
1248 }
1249 
CLOCK_BootToFeiMode(mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1250 status_t CLOCK_BootToFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1251 {
1252     return CLOCK_SetFeiMode(dmx32, drs, fllStableDelay);
1253 }
1254 
CLOCK_BootToFeeMode(mcg_oscsel_t oscsel,uint8_t frdiv,mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1255 status_t CLOCK_BootToFeeMode(
1256     mcg_oscsel_t oscsel, uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1257 {
1258 
1259     CLOCK_SetExternalRefClkConfig(oscsel);
1260 
1261     return CLOCK_SetFeeMode(frdiv, dmx32, drs, fllStableDelay);
1262 }
1263 
CLOCK_BootToBlpiMode(uint8_t fcrdiv,mcg_irc_mode_t ircs,uint8_t ircEnableMode)1264 status_t CLOCK_BootToBlpiMode(uint8_t fcrdiv, mcg_irc_mode_t ircs, uint8_t ircEnableMode)
1265 {
1266     /* If reset mode is FEI mode, set MCGIRCLK and always success. */
1267     CLOCK_SetInternalRefClkConfig(ircEnableMode, ircs, fcrdiv);
1268 
1269     /* If reset mode is not BLPI, first enter FBI mode. */
1270     MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal);
1271     while (MCG_S_CLKST_VAL != kMCG_ClkOutStatInt)
1272     {
1273     }
1274 
1275     /* Enter BLPI mode. */
1276     MCG->C2 |= MCG_C2_LP_MASK;
1277 
1278     return kStatus_Success;
1279 }
1280 
CLOCK_BootToBlpeMode(mcg_oscsel_t oscsel)1281 status_t CLOCK_BootToBlpeMode(mcg_oscsel_t oscsel)
1282 {
1283 
1284     CLOCK_SetExternalRefClkConfig(oscsel);
1285 
1286     /* Set to FBE mode. */
1287     MCG->C1 =
1288         ((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) | (MCG_C1_CLKS(kMCG_ClkOutSrcExternal)    /* CLKS = 2 */
1289                                                                 | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
1290 
1291     /* If use external crystal as clock source, wait for it stable. */
1292     if (MCG_C7_OSCSEL(kMCG_OscselOsc) == (MCG->C7 & MCG_C7_OSCSEL_MASK))
1293     {
1294         if (MCG->C2 & MCG_C2_EREFS_MASK)
1295         {
1296             while (!(MCG->S & MCG_S_OSCINIT0_MASK))
1297             {
1298             }
1299         }
1300     }
1301 
1302     /* Wait for MCG_S[CLKST] and MCG_S[IREFST]. */
1303     while ((MCG->S & (MCG_S_IREFST_MASK | MCG_S_CLKST_MASK)) !=
1304            (MCG_S_IREFST(kMCG_FllSrcExternal) | MCG_S_CLKST(kMCG_ClkOutStatExt)))
1305     {
1306     }
1307 
1308     /* In FBE now, start to enter BLPE. */
1309     MCG->C2 |= MCG_C2_LP_MASK;
1310 
1311     return kStatus_Success;
1312 }
1313 
1314 
1315 /*
1316    The transaction matrix. It defines the path for mode switch, the row is for
1317    current mode and the column is target mode.
1318    For example, switch from FEI to PEE:
1319    1. Current mode FEI, next mode is mcgModeMatrix[FEI][PEE] = FBE, so swith to FBE.
1320    2. Current mode FBE, next mode is mcgModeMatrix[FBE][PEE] = PBE, so swith to PBE.
1321    3. Current mode PBE, next mode is mcgModeMatrix[PBE][PEE] = PEE, so swith to PEE.
1322    Thus the MCG mode has changed from FEI to PEE.
1323  */
1324 static const mcg_mode_t mcgModeMatrix[6][6] = {
1325     {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE},  /* FEI */
1326     {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeBLPI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE}, /* FBI */
1327     {kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeBLPI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFBI}, /* BLPI */
1328     {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE},  /* FEE */
1329     {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeBLPE}, /* FBE */
1330     {kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeBLPE}, /* BLPE */
1331     /*      FEI           FBI           BLPI          FEE           FBE           BLPE      */
1332 };
1333 
CLOCK_SetMcgConfig(const mcg_config_t * config)1334 status_t CLOCK_SetMcgConfig(const mcg_config_t *config)
1335 {
1336     mcg_mode_t next_mode;
1337     status_t status = kStatus_Success;
1338 
1339 
1340     /* If need to change external clock, MCG_C7[OSCSEL]. */
1341     if (MCG_C7_OSCSEL_VAL != config->oscsel)
1342     {
1343         /* If external clock is in use, change to FEI first. */
1344         if (!(MCG->S & MCG_S_IRCST_MASK))
1345         {
1346             CLOCK_ExternalModeToFbeModeQuick();
1347             CLOCK_SetFeiMode(config->dmx32, config->drs, (void (*)(void))0);
1348         }
1349 
1350         CLOCK_SetExternalRefClkConfig(config->oscsel);
1351     }
1352 
1353     /* Re-configure MCGIRCLK, if MCGIRCLK is used as system clock source, then change to FEI/PEI first. */
1354     if (MCG_S_CLKST_VAL == kMCG_ClkOutStatInt)
1355     {
1356         MCG->C2 &= ~MCG_C2_LP_MASK; /* Disable lowpower. */
1357 
1358         {
1359             CLOCK_SetFeiMode(config->dmx32, config->drs, CLOCK_FllStableDelay);
1360         }
1361     }
1362 
1363     /* Configure MCGIRCLK. */
1364     CLOCK_SetInternalRefClkConfig(config->irclkEnableMode, config->ircs, config->fcrdiv);
1365 
1366     next_mode = CLOCK_GetMode();
1367 
1368     do
1369     {
1370         next_mode = mcgModeMatrix[next_mode][config->mcgMode];
1371 
1372         switch (next_mode)
1373         {
1374             case kMCG_ModeFEI:
1375                 status = CLOCK_SetFeiMode(config->dmx32, config->drs, CLOCK_FllStableDelay);
1376                 break;
1377             case kMCG_ModeFEE:
1378                 status = CLOCK_SetFeeMode(config->frdiv, config->dmx32, config->drs, CLOCK_FllStableDelay);
1379                 break;
1380             case kMCG_ModeFBI:
1381                 status = CLOCK_SetFbiMode(config->dmx32, config->drs, (void (*)(void))0);
1382                 break;
1383             case kMCG_ModeFBE:
1384                 status = CLOCK_SetFbeMode(config->frdiv, config->dmx32, config->drs, (void (*)(void))0);
1385                 break;
1386             case kMCG_ModeBLPI:
1387                 status = CLOCK_SetBlpiMode();
1388                 break;
1389             case kMCG_ModeBLPE:
1390                 status = CLOCK_SetBlpeMode();
1391                 break;
1392             default:
1393                 break;
1394         }
1395         if (kStatus_Success != status)
1396         {
1397             return status;
1398         }
1399     } while (next_mode != config->mcgMode);
1400 
1401     return kStatus_Success;
1402 }
1403