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