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