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