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