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