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