1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016 - 2019, NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_clock.h"
10
11 /*******************************************************************************
12 * Definitions
13 ******************************************************************************/
14
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.clock"
18 #endif
19
20 /* Macro definition remap workaround. */
21 #if (defined(MCG_C2_EREFS_MASK) && !(defined(MCG_C2_EREFS0_MASK)))
22 #define MCG_C2_EREFS0_MASK MCG_C2_EREFS_MASK
23 #endif
24 #if (defined(MCG_C2_HGO_MASK) && !(defined(MCG_C2_HGO0_MASK)))
25 #define MCG_C2_HGO0_MASK MCG_C2_HGO_MASK
26 #endif
27 #if (defined(MCG_C2_RANGE_MASK) && !(defined(MCG_C2_RANGE0_MASK)))
28 #define MCG_C2_RANGE0_MASK MCG_C2_RANGE_MASK
29 #endif
30 #if (defined(MCG_C6_CME_MASK) && !(defined(MCG_C6_CME0_MASK)))
31 #define MCG_C6_CME0_MASK MCG_C6_CME_MASK
32 #endif
33
34 /* PLL fixed multiplier when there is not PRDIV and VDIV. */
35 #define PLL_FIXED_MULT (375U)
36 /* Max frequency of the reference clock used for internal clock trim. */
37 #define TRIM_REF_CLK_MIN (8000000U)
38 /* Min frequency of the reference clock used for internal clock trim. */
39 #define TRIM_REF_CLK_MAX (16000000U)
40 /* Max trim value of fast internal reference clock. */
41 #define TRIM_FIRC_MAX (5000000U)
42 /* Min trim value of fast internal reference clock. */
43 #define TRIM_FIRC_MIN (3000000U)
44 /* Max trim value of fast internal reference clock. */
45 #define TRIM_SIRC_MAX (39063U)
46 /* Min trim value of fast internal reference clock. */
47 #define TRIM_SIRC_MIN (31250U)
48
49 #define MCG_S_IRCST_VAL ((MCG->S & MCG_S_IRCST_MASK) >> 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 ((MCG->S & MCG_S_PLLST_MASK) >> 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 ((MCG->S2 & MCG_S2_PLLCST_MASK) >> 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 ((MCG->C5 & MCG_C5_PRDIV0_MASK) >> MCG_C5_PRDIV0_SHIFT)
67 #define MCG_C6_VDIV0_VAL ((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_OUTDIV4_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT)
73 #define SIM_CLKDIV1_OUTDIV5_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV5_MASK) >> SIM_CLKDIV1_OUTDIV5_SHIFT)
74 #define SIM_SOPT1_OSC32KSEL_VAL ((SIM->SOPT1 & SIM_SOPT1_OSC32KSEL_MASK) >> SIM_SOPT1_OSC32KSEL_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 Calculate the RANGE value base on crystal frequency.
153 *
154 * To setup external crystal oscillator, must set the register bits RANGE
155 * base on the crystal frequency. This function returns the RANGE base on the
156 * input frequency. This is an internal function.
157 *
158 * @param freq Crystal frequency in Hz.
159 * @return The RANGE value.
160 */
161 static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq);
162
163 #ifndef MCG_USER_CONFIG_FLL_STABLE_DELAY_EN
164 /*!
165 * @brief Delay function to wait FLL stable.
166 *
167 * Delay function to wait FLL stable in FEI mode or FEE mode, should wait at least
168 * 1ms. Every time changes FLL setting, should wait this time for FLL stable.
169 */
170 static void CLOCK_FllStableDelay(void);
171 #endif
172
173 /*******************************************************************************
174 * Code
175 ******************************************************************************/
176
177 #ifndef MCG_USER_CONFIG_FLL_STABLE_DELAY_EN
CLOCK_FllStableDelay(void)178 static void CLOCK_FllStableDelay(void)
179 {
180 /*
181 Should wait at least 1ms. Because in these modes, the core clock is 100MHz
182 at most, so this function could obtain the 1ms delay.
183 */
184 volatile uint32_t i = 30000U;
185 while (0U != (i--))
186 {
187 __NOP();
188 }
189 }
190 #else /* With MCG_USER_CONFIG_FLL_STABLE_DELAY_EN defined. */
191 /* Once user defines the MCG_USER_CONFIG_FLL_STABLE_DELAY_EN to use their own delay function, they have to
192 * create their own CLOCK_FllStableDelay() function in application code. Since the clock functions in this
193 * file would call the CLOCK_FllStableDelay() regardless how it is defined.
194 */
195 extern void CLOCK_FllStableDelay(void);
196 #endif /* MCG_USER_CONFIG_FLL_STABLE_DELAY_EN */
197
CLOCK_GetMcgExtClkFreq(void)198 static uint32_t CLOCK_GetMcgExtClkFreq(void)
199 {
200 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
201 assert(0U != g_xtal0Freq);
202 return g_xtal0Freq;
203 }
204
CLOCK_GetFllExtRefClkFreq(void)205 static uint32_t CLOCK_GetFllExtRefClkFreq(void)
206 {
207 /* FllExtRef = McgExtRef / FllExtRefDiv */
208 uint8_t frdiv;
209 uint8_t range;
210
211 uint32_t freq = CLOCK_GetMcgExtClkFreq();
212
213 if (0U == freq)
214 {
215 return freq;
216 }
217
218 frdiv = MCG_C1_FRDIV_VAL;
219 freq >>= frdiv;
220
221 range = MCG_C2_RANGE_VAL;
222
223 /*
224 When should use divider 32, 64, 128, 256, 512, 1024, 1280, 1536.
225 1. MCG_C7[OSCSEL] selects IRC48M.
226 2. MCG_C7[OSCSEL] selects OSC0 and MCG_C2[RANGE] is not 0.
227 */
228 if (((0U != range)))
229 {
230 switch (frdiv)
231 {
232 case 0:
233 case 1:
234 case 2:
235 case 3:
236 case 4:
237 case 5:
238 freq >>= 5u;
239 break;
240 case 6:
241 /* 64*20=1280 */
242 freq /= 20u;
243 break;
244 case 7:
245 /* 128*12=1536 */
246 freq /= 12u;
247 break;
248 default:
249 freq = 0u;
250 break;
251 }
252 }
253
254 return freq;
255 }
256
CLOCK_GetInternalRefClkSelectFreq(void)257 static uint32_t CLOCK_GetInternalRefClkSelectFreq(void)
258 {
259 if ((uint8_t)kMCG_IrcSlow == MCG_S_IRCST_VAL)
260 {
261 /* Slow internal reference clock selected*/
262 return s_slowIrcFreq;
263 }
264 else
265 {
266 /* Fast internal reference clock selected*/
267 return s_fastIrcFreq >> MCG_SC_FCRDIV_VAL;
268 }
269 }
270
CLOCK_GetFllRefClkFreq(void)271 static uint32_t CLOCK_GetFllRefClkFreq(void)
272 {
273 /* If use external reference clock. */
274 if ((uint8_t)kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
275 {
276 return CLOCK_GetFllExtRefClkFreq();
277 }
278 /* If use internal reference clock. */
279 else
280 {
281 return s_slowIrcFreq;
282 }
283 }
284
CLOCK_GetOscRangeFromFreq(uint32_t freq)285 static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq)
286 {
287 uint8_t range;
288
289 if (freq <= 39063U)
290 {
291 range = 0U;
292 }
293 else if (freq <= 8000000U)
294 {
295 range = 1U;
296 }
297 else
298 {
299 range = 2U;
300 }
301
302 return range;
303 }
304
305 /*!
306 * brief Get the OSC0 external reference clock frequency (OSC0ERCLK).
307 *
308 * return Clock frequency in Hz.
309 */
CLOCK_GetOsc0ErClkFreq(void)310 uint32_t CLOCK_GetOsc0ErClkFreq(void)
311 {
312 if (OSC0->CR & OSC_CR_ERCLKEN_MASK)
313 {
314 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
315 assert(g_xtal0Freq);
316 return g_xtal0Freq;
317 }
318 else
319 {
320 return 0U;
321 }
322 }
323
324 /*!
325 * brief Get the external reference 32K clock frequency (ERCLK32K).
326 *
327 * return Clock frequency in Hz.
328 */
CLOCK_GetEr32kClkFreq(void)329 uint32_t CLOCK_GetEr32kClkFreq(void)
330 {
331 uint32_t freq;
332
333 switch (SIM_SOPT1_OSC32KSEL_VAL)
334 {
335 case 0U: /* OSC 32k clock */
336 freq = (CLOCK_GetOsc0ErClkFreq() == 32768U) ? 32768U : 0U;
337 break;
338 case 3U: /* LPO clock */
339 freq = LPO_CLK_FREQ;
340 break;
341 default:
342 freq = 0U;
343 break;
344 }
345
346 return freq;
347 }
348
349 /*!
350 * brief Get the platform clock frequency.
351 *
352 * return Clock frequency in Hz.
353 */
CLOCK_GetPlatClkFreq(void)354 uint32_t CLOCK_GetPlatClkFreq(void)
355 {
356 return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
357 }
358
359 /*!
360 * brief Get the flash clock frequency.
361 *
362 * return Clock frequency in Hz.
363 */
CLOCK_GetFlashClkFreq(void)364 uint32_t CLOCK_GetFlashClkFreq(void)
365 {
366 uint32_t freq;
367
368 freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
369 freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1);
370
371 return freq;
372 }
373
374 /*!
375 * brief Get the bus clock frequency.
376 *
377 * return Clock frequency in Hz.
378 */
CLOCK_GetBusClkFreq(void)379 uint32_t CLOCK_GetBusClkFreq(void)
380 {
381 uint32_t freq;
382
383 freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
384 freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1);
385
386 return freq;
387 }
388
389 /*!
390 * brief Get the core clock or system clock frequency.
391 *
392 * return Clock frequency in Hz.
393 */
CLOCK_GetCoreSysClkFreq(void)394 uint32_t CLOCK_GetCoreSysClkFreq(void)
395 {
396 return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
397 }
398
399 /*!
400 * brief Gets the clock frequency for a specific clock name.
401 *
402 * This function checks the current clock configurations and then calculates
403 * the clock frequency for a specific clock name defined in clock_name_t.
404 * The MCG must be properly configured before using this function.
405 *
406 * param clockName Clock names defined in clock_name_t
407 * return Clock frequency value in Hertz
408 */
CLOCK_GetFreq(clock_name_t clockName)409 uint32_t CLOCK_GetFreq(clock_name_t clockName)
410 {
411 uint32_t freq;
412
413 switch (clockName)
414 {
415 case kCLOCK_CoreSysClk:
416 case kCLOCK_PlatClk:
417 freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
418 break;
419 case kCLOCK_BusClk:
420 case kCLOCK_FlashClk:
421 freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
422 freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1);
423 break;
424 case kCLOCK_AltAdc:
425 freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
426 freq /= (SIM_CLKDIV1_OUTDIV5_VAL + 1);
427 break;
428 case kCLOCK_Er32kClk:
429 freq = CLOCK_GetEr32kClkFreq();
430 break;
431 case kCLOCK_McgFixedFreqClk:
432 freq = CLOCK_GetFixedFreqClkFreq();
433 break;
434 case kCLOCK_McgInternalRefClk:
435 freq = CLOCK_GetInternalRefClkFreq();
436 break;
437 case kCLOCK_McgFllClk:
438 freq = CLOCK_GetFllFreq();
439 break;
440 case kCLOCK_LpoClk:
441 freq = LPO_CLK_FREQ;
442 break;
443 case kCLOCK_Osc0ErClk:
444 freq = CLOCK_GetOsc0ErClkFreq();
445 break;
446 default:
447 freq = 0U;
448 break;
449 }
450
451 return freq;
452 }
453
454 /*!
455 * brief Set the clock configure in SIM module.
456 *
457 * This function sets system layer clock settings in SIM module.
458 *
459 * param config Pointer to the configure structure.
460 */
CLOCK_SetSimConfig(sim_clock_config_t const * config)461 void CLOCK_SetSimConfig(sim_clock_config_t const *config)
462 {
463 SIM->CLKDIV1 = config->clkdiv1;
464 CLOCK_SetEr32kClock(config->er32kSrc);
465 }
466
467 /*!
468 * brief Gets the MCG output clock (MCGOUTCLK) frequency.
469 *
470 * This function gets the MCG output clock frequency in Hz based on the current MCG
471 * register value.
472 *
473 * return The frequency of MCGOUTCLK.
474 */
CLOCK_GetOutClkFreq(void)475 uint32_t CLOCK_GetOutClkFreq(void)
476 {
477 uint32_t mcgoutclk;
478 uint32_t clkst = (uint32_t)MCG_S_CLKST_VAL;
479
480 switch (clkst)
481 {
482 case (uint32_t)kMCG_ClkOutStatFll:
483 mcgoutclk = CLOCK_GetFllFreq();
484 break;
485 case (uint32_t)kMCG_ClkOutStatInt:
486 mcgoutclk = CLOCK_GetInternalRefClkSelectFreq();
487 break;
488 case (uint32_t)kMCG_ClkOutStatExt:
489 mcgoutclk = CLOCK_GetMcgExtClkFreq();
490 break;
491 default:
492 mcgoutclk = 0U;
493 break;
494 }
495 return mcgoutclk;
496 }
497
498 /*!
499 * brief Gets the MCG FLL clock (MCGFLLCLK) frequency.
500 *
501 * This function gets the MCG FLL clock frequency in Hz based on the current MCG
502 * register value. The FLL is enabled in FEI/FBI/FEE/FBE mode and
503 * disabled in low power state in other modes.
504 *
505 * return The frequency of MCGFLLCLK.
506 */
CLOCK_GetFllFreq(void)507 uint32_t CLOCK_GetFllFreq(void)
508 {
509 static const uint16_t fllFactorTable[4][2] = {{640, 732}, {1280, 1464}, {1920, 2197}, {2560, 2929}};
510
511 uint8_t drs, dmx32;
512 uint32_t freq;
513
514 /* If FLL is not enabled currently, then return 0U. */
515 if (0U != (MCG->C2 & MCG_C2_LP_MASK))
516 {
517 return 0U;
518 }
519
520 /* Get FLL reference clock frequency. */
521 freq = CLOCK_GetFllRefClkFreq();
522 if (0U == freq)
523 {
524 return freq;
525 }
526
527 drs = MCG_C4_DRST_DRS_VAL;
528 dmx32 = MCG_C4_DMX32_VAL;
529
530 return freq * fllFactorTable[drs][dmx32];
531 }
532
533 /*!
534 * brief Gets the MCG internal reference clock (MCGIRCLK) frequency.
535 *
536 * This function gets the MCG internal reference clock frequency in Hz based
537 * on the current MCG register value.
538 *
539 * return The frequency of MCGIRCLK.
540 */
CLOCK_GetInternalRefClkFreq(void)541 uint32_t CLOCK_GetInternalRefClkFreq(void)
542 {
543 /* If MCGIRCLK is gated. */
544 if (0U == (MCG->C1 & MCG_C1_IRCLKEN_MASK))
545 {
546 return 0U;
547 }
548
549 return CLOCK_GetInternalRefClkSelectFreq();
550 }
551
552 /*!
553 * brief Gets the MCG fixed frequency clock (MCGFFCLK) frequency.
554 *
555 * This function gets the MCG fixed frequency clock frequency in Hz based
556 * on the current MCG register value.
557 *
558 * return The frequency of MCGFFCLK.
559 */
CLOCK_GetFixedFreqClkFreq(void)560 uint32_t CLOCK_GetFixedFreqClkFreq(void)
561 {
562 uint32_t freq = CLOCK_GetFllRefClkFreq();
563
564 /* MCGFFCLK must be no more than MCGOUTCLK/8. */
565 if ((freq <= (CLOCK_GetOutClkFreq() / 8U)) && (0U != freq))
566 {
567 return freq;
568 }
569 else
570 {
571 return 0U;
572 }
573 }
574
575 /*!
576 * brief Selects the MCG external reference clock.
577 *
578 * Selects the MCG external reference clock source, changes the MCG_C7[OSCSEL],
579 * and waits for the clock source to be stable. Because the external reference
580 * clock should not be changed in FEE/FBE/BLPE/PBE/PEE modes, do not call this function in these modes.
581 *
582 * param oscsel MCG external reference clock source, MCG_C7[OSCSEL].
583 * retval kStatus_MCG_SourceUsed Because the external reference clock is used as a clock source,
584 * the configuration should not be changed. Otherwise, a glitch occurs.
585 * retval kStatus_Success External reference clock set successfully.
586 */
CLOCK_SetExternalRefClkConfig(mcg_oscsel_t oscsel)587 status_t CLOCK_SetExternalRefClkConfig(mcg_oscsel_t oscsel)
588 {
589 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
590 #endif /* MCG_CONFIG_CHECK_PARAM */
591
592 return kStatus_Success;
593 }
594
595 /*!
596 * brief Configures the Internal Reference clock (MCGIRCLK).
597 *
598 * This function sets the \c MCGIRCLK base on parameters. It also selects the IRC
599 * source. If the fast IRC is used, this function sets the fast IRC divider.
600 * This function also sets whether the \c MCGIRCLK is enabled in stop mode.
601 * Calling this function in FBI/PBI/BLPI modes may change the system clock. As a result,
602 * using the function in these modes it is not allowed.
603 *
604 * param enableMode MCGIRCLK enable mode, OR'ed value of ref _mcg_irclk_enable_mode.
605 * param ircs MCGIRCLK clock source, choose fast or slow.
606 * param fcrdiv Fast IRC divider setting (\c FCRDIV).
607 * retval kStatus_MCG_SourceUsed Because the internal reference clock is used as a clock source,
608 * the configuration should not be changed. Otherwise, a glitch occurs.
609 * retval kStatus_Success MCGIRCLK configuration finished successfully.
610 */
CLOCK_SetInternalRefClkConfig(uint8_t enableMode,mcg_irc_mode_t ircs,uint8_t fcrdiv)611 status_t CLOCK_SetInternalRefClkConfig(uint8_t enableMode, mcg_irc_mode_t ircs, uint8_t fcrdiv)
612 {
613 uint32_t mcgOutClkState = (uint32_t)MCG_S_CLKST_VAL;
614 mcg_irc_mode_t curIrcs = (mcg_irc_mode_t)MCG_S_IRCST_VAL;
615 uint8_t curFcrdiv = MCG_SC_FCRDIV_VAL;
616
617 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
618 /* If MCGIRCLK is used as system clock source. */
619 if ((uint32_t)kMCG_ClkOutStatInt == mcgOutClkState)
620 {
621 /* If need to change MCGIRCLK source or driver, return error. */
622 if (((kMCG_IrcFast == curIrcs) && (fcrdiv != curFcrdiv)) || (ircs != curIrcs))
623 {
624 return kStatus_MCG_SourceUsed;
625 }
626 }
627 #endif
628
629 /* If need to update the FCRDIV. */
630 if (fcrdiv != curFcrdiv)
631 {
632 /* If fast IRC is in use currently, change to slow IRC. */
633 if (((0U != (MCG->C1 & MCG_C1_IRCLKEN_MASK)) || (mcgOutClkState == (uint32_t)kMCG_ClkOutStatInt)) &&
634 (kMCG_IrcFast == curIrcs))
635 {
636 MCG->C2 = (uint8_t)((MCG->C2 & ~MCG_C2_IRCS_MASK) | (MCG_C2_IRCS(kMCG_IrcSlow)));
637 while (MCG_S_IRCST_VAL != (uint8_t)kMCG_IrcSlow)
638 {
639 }
640 }
641 /* Update FCRDIV. */
642 MCG->SC =
643 (uint8_t)(MCG->SC & ~(MCG_SC_FCRDIV_MASK | MCG_SC_ATMF_MASK | MCG_SC_LOCS0_MASK)) | MCG_SC_FCRDIV(fcrdiv);
644 }
645
646 /* Set internal reference clock selection. */
647 MCG->C2 = (uint8_t)((MCG->C2 & ~MCG_C2_IRCS_MASK) | (MCG_C2_IRCS(ircs)));
648 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_IRCLKEN_MASK | MCG_C1_IREFSTEN_MASK)) | (uint8_t)enableMode);
649
650 /* If MCGIRCLK is used, need to wait for MCG_S_IRCST. */
651 if ((mcgOutClkState == (uint32_t)kMCG_ClkOutStatInt) || (0U != (enableMode & (uint32_t)kMCG_IrclkEnable)))
652 {
653 while (MCG_S_IRCST_VAL != (uint8_t)ircs)
654 {
655 }
656 }
657
658 return kStatus_Success;
659 }
660
661 /*!
662 * brief Sets the OSC0 clock monitor mode.
663 *
664 * This function sets the OSC0 clock monitor mode. See ref mcg_monitor_mode_t for details.
665 *
666 * param mode Monitor mode to set.
667 */
CLOCK_SetOsc0MonitorMode(mcg_monitor_mode_t mode)668 void CLOCK_SetOsc0MonitorMode(mcg_monitor_mode_t mode)
669 {
670 /* Clear the previous flag, MCG_SC[LOCS0]. */
671 MCG->SC &= ~(uint8_t)MCG_SC_ATMF_MASK;
672
673 if (kMCG_MonitorNone == mode)
674 {
675 MCG->C6 &= ~(uint8_t)MCG_C6_CME0_MASK;
676 }
677 else
678 {
679 if (kMCG_MonitorInt == mode)
680 {
681 MCG->C2 &= ~(uint8_t)MCG_C2_LOCRE0_MASK;
682 }
683 else
684 {
685 MCG->C2 |= MCG_C2_LOCRE0_MASK;
686 }
687 MCG->C6 |= MCG_C6_CME0_MASK;
688 }
689 }
690
691 /*!
692 * brief Gets the MCG status flags.
693 *
694 * This function gets the MCG clock status flags. All status flags are
695 * returned as a logical OR of the enumeration ref _mcg_status_flags_t. To
696 * check a specific flag, compare the return value with the flag.
697 *
698 * Example:
699 * code
700 * To check the clock lost lock status of OSC0 and PLL0.
701 * uint32_t mcgFlags;
702 *
703 * mcgFlags = CLOCK_GetStatusFlags();
704 *
705 * if (mcgFlags & kMCG_Osc0LostFlag)
706 * {
707 * OSC0 clock lock lost. Do something.
708 * }
709 * if (mcgFlags & kMCG_Pll0LostFlag)
710 * {
711 * PLL0 clock lock lost. Do something.
712 * }
713 * endcode
714 *
715 * return Logical OR value of the ref _mcg_status_flags_t.
716 */
CLOCK_GetStatusFlags(void)717 uint32_t CLOCK_GetStatusFlags(void)
718 {
719 uint32_t ret = 0U;
720 uint8_t mcg_s = MCG->S;
721
722 if (MCG->SC & MCG_SC_LOCS0_MASK)
723 {
724 ret |= (uint32_t)kMCG_Osc0LostFlag;
725 }
726 if (mcg_s & MCG_S_OSCINIT0_MASK)
727 {
728 ret |= (uint32_t)kMCG_Osc0InitFlag;
729 }
730 return ret;
731 }
732
733 /*!
734 * brief Clears the MCG status flags.
735 *
736 * This function clears the MCG clock lock lost status. The parameter is a logical
737 * OR value of the flags to clear. See ref _mcg_status_flags_t.
738 *
739 * Example:
740 * code
741 * To clear the clock lost lock status flags of OSC0 and PLL0.
742 *
743 * CLOCK_ClearStatusFlags(kMCG_Osc0LostFlag | kMCG_Pll0LostFlag);
744 * endcode
745 *
746 * param mask The status flags to clear. This is a logical OR of members of the
747 * enumeration ref _mcg_status_flags_t.
748 */
CLOCK_ClearStatusFlags(uint32_t mask)749 void CLOCK_ClearStatusFlags(uint32_t mask)
750 {
751 if (mask & kMCG_Osc0LostFlag)
752 {
753 MCG->SC &= ~MCG_SC_ATMF_MASK;
754 }
755 }
756
757 /*!
758 * brief Initializes the OSC0.
759 *
760 * This function initializes the OSC0 according to the board configuration.
761 *
762 * param config Pointer to the OSC0 configuration structure.
763 */
CLOCK_InitOsc0(osc_config_t const * config)764 void CLOCK_InitOsc0(osc_config_t const *config)
765 {
766 uint8_t range = CLOCK_GetOscRangeFromFreq(config->freq);
767
768 OSC_SetCapLoad(OSC0, config->capLoad);
769
770 MCG->C2 = (uint8_t)((MCG->C2 & ~OSC_MODE_MASK) | MCG_C2_RANGE(range) | (uint8_t)config->workMode);
771 OSC_SetExtRefClkConfig(OSC0, &config->oscerConfig);
772
773 if ((kOSC_ModeExt != config->workMode) && (OSC0->CR & OSC_CR_ERCLKEN_MASK))
774 {
775 /* Wait for stable. */
776 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
777 {
778 }
779 }
780 }
781
782 /*!
783 * brief Deinitializes the OSC0.
784 *
785 * This function deinitializes the OSC0.
786 */
CLOCK_DeinitOsc0(void)787 void CLOCK_DeinitOsc0(void)
788 {
789 OSC0->CR = 0U;
790 MCG->C2 &= ~(uint8_t)OSC_MODE_MASK;
791 }
792
793 /*!
794 * brief Set the Slow IRC frequency based on the trimmed value
795 *
796 * param freq The Slow IRC frequency input clock frequency in Hz.
797 */
CLOCK_SetSlowIrcFreq(uint32_t freq)798 void CLOCK_SetSlowIrcFreq(uint32_t freq)
799 {
800 s_slowIrcFreq = freq;
801 }
802
803 /*!
804 * brief Set the Fast IRC frequency based on the trimmed value
805 *
806 * param freq The Fast IRC frequency input clock frequency in Hz.
807 */
CLOCK_SetFastIrcFreq(uint32_t freq)808 void CLOCK_SetFastIrcFreq(uint32_t freq)
809 {
810 s_fastIrcFreq = freq;
811 }
812
813 /*!
814 * brief Auto trims the internal reference clock.
815 *
816 * This function trims the internal reference clock by using the external clock. If
817 * successful, it returns the kStatus_Success and the frequency after
818 * trimming is received in the parameter p actualFreq. If an error occurs,
819 * the error code is returned.
820 *
821 * param extFreq External clock frequency, which should be a bus clock.
822 * param desireFreq Frequency to trim to.
823 * param actualFreq Actual frequency after trimming.
824 * param atms Trim fast or slow internal reference clock.
825 * retval kStatus_Success ATM success.
826 * retval kStatus_MCG_AtmBusClockInvalid The bus clock is not in allowed range for the ATM.
827 * retval kStatus_MCG_AtmDesiredFreqInvalid MCGIRCLK could not be trimmed to the desired frequency.
828 * retval kStatus_MCG_AtmIrcUsed Could not trim because MCGIRCLK is used as a bus clock source.
829 * retval kStatus_MCG_AtmHardwareFail Hardware fails while trimming.
830 */
CLOCK_TrimInternalRefClk(uint32_t extFreq,uint32_t desireFreq,uint32_t * actualFreq,mcg_atm_select_t atms)831 status_t CLOCK_TrimInternalRefClk(uint32_t extFreq, uint32_t desireFreq, uint32_t *actualFreq, mcg_atm_select_t atms)
832 {
833 uint32_t multi; /* extFreq / desireFreq */
834 uint32_t actv; /* Auto trim value. */
835 uint8_t mcg_sc;
836
837 static const uint32_t trimRange[2][2] = {
838 /* Min Max */
839 {TRIM_SIRC_MIN, TRIM_SIRC_MAX}, /* Slow IRC. */
840 {TRIM_FIRC_MIN, TRIM_FIRC_MAX} /* Fast IRC. */
841 };
842
843 if ((extFreq > TRIM_REF_CLK_MAX) || (extFreq < TRIM_REF_CLK_MIN))
844 {
845 return kStatus_MCG_AtmBusClockInvalid;
846 }
847
848 /* Check desired frequency range. */
849 if ((desireFreq < trimRange[atms][0]) || (desireFreq > trimRange[atms][1]))
850 {
851 return kStatus_MCG_AtmDesiredFreqInvalid;
852 }
853
854 /*
855 Make sure internal reference clock is not used to generate bus clock.
856 Here only need to check (MCG_S_IREFST == 1).
857 */
858 if (MCG_S_IREFST(kMCG_FllSrcInternal) == (MCG->S & MCG_S_IREFST_MASK))
859 {
860 return kStatus_MCG_AtmIrcUsed;
861 }
862
863 multi = extFreq / desireFreq;
864 actv = multi * 21U;
865
866 if (kMCG_AtmSel4m == atms)
867 {
868 actv *= 128U;
869 }
870
871 /* Now begin to start trim. */
872 MCG->ATCVL = (uint8_t)actv;
873 MCG->ATCVH = (uint8_t)(actv >> 8U);
874
875 mcg_sc = MCG->SC;
876 mcg_sc &= ~(uint8_t)(MCG_SC_ATMS_MASK | MCG_SC_LOCS0_MASK);
877 mcg_sc |= (MCG_SC_ATMF_MASK | MCG_SC_ATMS(atms));
878 MCG->SC = (mcg_sc | MCG_SC_ATME_MASK);
879
880 /* Wait for finished. */
881 while (0U != (MCG->SC & MCG_SC_ATME_MASK))
882 {
883 }
884
885 /* Error occurs? */
886 if (0U != (MCG->SC & MCG_SC_ATMF_MASK))
887 {
888 /* Clear the failed flag. */
889 MCG->SC = mcg_sc;
890 return kStatus_MCG_AtmHardwareFail;
891 }
892
893 *actualFreq = extFreq / multi;
894
895 if (kMCG_AtmSel4m == atms)
896 {
897 s_fastIrcFreq = *actualFreq;
898 }
899 else
900 {
901 s_slowIrcFreq = *actualFreq;
902 }
903
904 return kStatus_Success;
905 }
906
907 /*!
908 * brief Gets the current MCG mode.
909 *
910 * This function checks the MCG registers and determines the current MCG mode.
911 *
912 * return Current MCG mode or error code; See ref mcg_mode_t.
913 */
CLOCK_GetMode(void)914 mcg_mode_t CLOCK_GetMode(void)
915 {
916 mcg_mode_t mode = kMCG_ModeError;
917 uint32_t clkst = (uint32_t)MCG_S_CLKST_VAL;
918 uint32_t irefst = (uint32_t)MCG_S_IREFST_VAL;
919 uint32_t lp = (uint32_t)MCG_C2_LP_VAL;
920
921 /*------------------------------------------------------------------
922 Mode and Registers
923 ____________________________________________________________________
924
925 Mode | CLKST | IREFST | PLLST | LP
926 ____________________________________________________________________
927
928 FEI | 00(FLL) | 1(INT) | 0(FLL) | X
929 ____________________________________________________________________
930
931 FEE | 00(FLL) | 0(EXT) | 0(FLL) | X
932 ____________________________________________________________________
933
934 FBE | 10(EXT) | 0(EXT) | 0(FLL) | 0(NORMAL)
935 ____________________________________________________________________
936
937 FBI | 01(INT) | 1(INT) | 0(FLL) | 0(NORMAL)
938 ____________________________________________________________________
939
940 BLPI | 01(INT) | 1(INT) | 0(FLL) | 1(LOW POWER)
941 ____________________________________________________________________
942
943 BLPE | 10(EXT) | 0(EXT) | X | 1(LOW POWER)
944 ____________________________________________________________________
945
946 PEE | 11(PLL) | 0(EXT) | 1(PLL) | X
947 ____________________________________________________________________
948
949 PBE | 10(EXT) | 0(EXT) | 1(PLL) | O(NORMAL)
950 ____________________________________________________________________
951
952 PBI | 01(INT) | 1(INT) | 1(PLL) | 0(NORMAL)
953 ____________________________________________________________________
954
955 PEI | 11(PLL) | 1(INT) | 1(PLL) | X
956 ____________________________________________________________________
957
958 ----------------------------------------------------------------------*/
959
960 if (clkst == (uint32_t)kMCG_ClkOutStatFll)
961 {
962 if ((uint32_t)kMCG_FllSrcExternal == irefst)
963 {
964 mode = kMCG_ModeFEE;
965 }
966 else
967 {
968 mode = kMCG_ModeFEI;
969 }
970 }
971 else if (clkst == (uint32_t)kMCG_ClkOutStatInt)
972 {
973 if (0U != lp)
974 {
975 mode = kMCG_ModeBLPI;
976 }
977 else
978 {
979 {
980 mode = kMCG_ModeFBI;
981 }
982 }
983 }
984 else if (clkst == (uint32_t)kMCG_ClkOutStatExt)
985 {
986 if (0U != lp)
987 {
988 mode = kMCG_ModeBLPE;
989 }
990 else
991 {
992 {
993 mode = kMCG_ModeFBE;
994 }
995 }
996 }
997 else
998 {
999 /*do nothing*/
1000 }
1001
1002 return mode;
1003 }
1004
1005 /*!
1006 * brief Sets the MCG to FEI mode.
1007 *
1008 * This function sets the MCG to FEI mode. If setting to FEI mode fails
1009 * from the current mode, this function returns an error.
1010 *
1011 * param dmx32 DMX32 in FEI mode.
1012 * param drs The DCO range selection.
1013 * param fllStableDelay Delay function to ensure that the FLL is stable. Passing
1014 * NULL does not cause a delay.
1015 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1016 * retval kStatus_Success Switched to the target mode successfully.
1017 * note If p dmx32 is set to kMCG_Dmx32Fine, the slow IRC must not be trimmed
1018 * to a frequency above 32768 Hz.
1019 */
CLOCK_SetFeiMode(mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1020 status_t CLOCK_SetFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1021 {
1022 uint8_t mcg_c4;
1023 bool change_drs = false;
1024
1025 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1026 mcg_mode_t mode = CLOCK_GetMode();
1027 if (!((kMCG_ModeFEI == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEE == mode)))
1028 {
1029 return kStatus_MCG_ModeUnreachable;
1030 }
1031 #endif
1032 mcg_c4 = MCG->C4;
1033
1034 /*
1035 Errata: ERR007993
1036 Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1037 reference clock source changes, then reset to previous value after
1038 reference clock changes.
1039 */
1040 if ((uint8_t)kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
1041 {
1042 change_drs = true;
1043 /* Change the LSB of DRST_DRS. */
1044 MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1045 }
1046
1047 /* Set CLKS and IREFS. */
1048 MCG->C1 = (uint8_t)(((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK))) |
1049 (MCG_C1_CLKS(kMCG_ClkOutSrcOut) /* CLKS = 0 */
1050 | MCG_C1_IREFS(kMCG_FllSrcInternal))); /* IREFS = 1 */
1051
1052 /* Wait and check status. */
1053 while ((uint8_t)kMCG_FllSrcInternal != MCG_S_IREFST_VAL)
1054 {
1055 }
1056
1057 /* Errata: ERR007993 */
1058 if (change_drs)
1059 {
1060 MCG->C4 = mcg_c4;
1061 }
1062
1063 /* In FEI mode, the MCG_C4[DMX32] is set to 0U. */
1064 MCG->C4 = (uint8_t)((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) |
1065 (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1066
1067 /* Check MCG_S[CLKST] */
1068 while ((uint8_t)kMCG_ClkOutStatFll != MCG_S_CLKST_VAL)
1069 {
1070 }
1071
1072 /* Wait for FLL stable time. */
1073 if (NULL != fllStableDelay)
1074 {
1075 fllStableDelay();
1076 }
1077
1078 return kStatus_Success;
1079 }
1080
1081 /*!
1082 * brief Sets the MCG to FEE mode.
1083 *
1084 * This function sets the MCG to FEE mode. If setting to FEE mode fails
1085 * from the current mode, this function returns an error.
1086 *
1087 * param frdiv FLL reference clock divider setting, FRDIV.
1088 * param dmx32 DMX32 in FEE mode.
1089 * param drs The DCO range selection.
1090 * param fllStableDelay Delay function to make sure FLL is stable. Passing
1091 * NULL does not cause a delay.
1092 *
1093 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1094 * retval kStatus_Success Switched to the target mode successfully.
1095 */
CLOCK_SetFeeMode(uint8_t frdiv,mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1096 status_t CLOCK_SetFeeMode(uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1097 {
1098 uint8_t mcg_c4;
1099 bool change_drs = false;
1100
1101 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1102 mcg_mode_t mode = CLOCK_GetMode();
1103 if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode)))
1104 {
1105 return kStatus_MCG_ModeUnreachable;
1106 }
1107 #endif
1108 mcg_c4 = MCG->C4;
1109
1110 /*
1111 Errata: ERR007993
1112 Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1113 reference clock source changes, then reset to previous value after
1114 reference clock changes.
1115 */
1116 if ((uint8_t)kMCG_FllSrcInternal == MCG_S_IREFST_VAL)
1117 {
1118 change_drs = true;
1119 /* Change the LSB of DRST_DRS. */
1120 MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1121 }
1122
1123 /* Set CLKS and IREFS. */
1124 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK)) |
1125 (MCG_C1_CLKS(kMCG_ClkOutSrcOut) /* CLKS = 0 */
1126 | MCG_C1_FRDIV(frdiv) /* FRDIV */
1127 | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
1128
1129 /* If use external crystal as clock source, wait for it stable. */
1130 {
1131 if (0U != (MCG->C2 & MCG_C2_EREFS_MASK))
1132 {
1133 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
1134 {
1135 }
1136 }
1137 }
1138
1139 /* Wait and check status. */
1140 while ((uint8_t)kMCG_FllSrcExternal != MCG_S_IREFST_VAL)
1141 {
1142 }
1143
1144 /* Errata: ERR007993 */
1145 if (change_drs)
1146 {
1147 MCG->C4 = mcg_c4;
1148 }
1149
1150 /* Set DRS and DMX32. */
1151 mcg_c4 = (uint8_t)((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) |
1152 (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1153 MCG->C4 = mcg_c4;
1154
1155 /* Wait for DRST_DRS update. */
1156 while (MCG->C4 != mcg_c4)
1157 {
1158 }
1159
1160 /* Check MCG_S[CLKST] */
1161 while ((uint8_t)kMCG_ClkOutStatFll != MCG_S_CLKST_VAL)
1162 {
1163 }
1164
1165 /* Wait for FLL stable time. */
1166 if (NULL != fllStableDelay)
1167 {
1168 fllStableDelay();
1169 }
1170
1171 return kStatus_Success;
1172 }
1173
1174 /*!
1175 * brief Sets the MCG to FBI mode.
1176 *
1177 * This function sets the MCG to FBI mode. If setting to FBI mode fails
1178 * from the current mode, this function returns an error.
1179 *
1180 * param dmx32 DMX32 in FBI mode.
1181 * param drs The DCO range selection.
1182 * param fllStableDelay Delay function to make sure FLL is stable. If the FLL
1183 * is not used in FBI mode, this parameter can be NULL. Passing
1184 * NULL does not cause a delay.
1185 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1186 * retval kStatus_Success Switched to the target mode successfully.
1187 * note If p dmx32 is set to kMCG_Dmx32Fine, the slow IRC must not be trimmed
1188 * to frequency above 32768 Hz.
1189 */
CLOCK_SetFbiMode(mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1190 status_t CLOCK_SetFbiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1191 {
1192 uint8_t mcg_c4;
1193 bool change_drs = false;
1194
1195 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1196 mcg_mode_t mode = CLOCK_GetMode();
1197
1198 if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode) ||
1199 (kMCG_ModeBLPI == mode)))
1200
1201 {
1202 return kStatus_MCG_ModeUnreachable;
1203 }
1204 #endif
1205
1206 mcg_c4 = MCG->C4;
1207
1208 MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK; /* Disable lowpower. */
1209
1210 /*
1211 Errata: ERR007993
1212 Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1213 reference clock source changes, then reset to previous value after
1214 reference clock changes.
1215 */
1216 if ((uint8_t)kMCG_FllSrcExternal == MCG_S_IREFST_VAL)
1217 {
1218 change_drs = true;
1219 /* Change the LSB of DRST_DRS. */
1220 MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1221 }
1222
1223 /* Set CLKS and IREFS. */
1224 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) |
1225 (MCG_C1_CLKS(kMCG_ClkOutSrcInternal) /* CLKS = 1 */
1226 | MCG_C1_IREFS(kMCG_FllSrcInternal))); /* IREFS = 1 */
1227
1228 /* Wait and check status. */
1229 while ((uint8_t)kMCG_FllSrcInternal != MCG_S_IREFST_VAL)
1230 {
1231 }
1232
1233 /* Errata: ERR007993 */
1234 if (change_drs)
1235 {
1236 MCG->C4 = mcg_c4;
1237 }
1238
1239 while ((uint8_t)kMCG_ClkOutStatInt != MCG_S_CLKST_VAL)
1240 {
1241 }
1242
1243 MCG->C4 = (uint8_t)((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) |
1244 (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1245
1246 /* Wait for FLL stable time. */
1247 if (NULL != fllStableDelay)
1248 {
1249 fllStableDelay();
1250 }
1251
1252 return kStatus_Success;
1253 }
1254
1255 /*!
1256 * brief Sets the MCG to FBE mode.
1257 *
1258 * This function sets the MCG to FBE mode. If setting to FBE mode fails
1259 * from the current mode, this function returns an error.
1260 *
1261 * param frdiv FLL reference clock divider setting, FRDIV.
1262 * param dmx32 DMX32 in FBE mode.
1263 * param drs The DCO range selection.
1264 * param fllStableDelay Delay function to make sure FLL is stable. If the FLL
1265 * is not used in FBE mode, this parameter can be NULL. Passing NULL
1266 * does not cause a delay.
1267 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1268 * retval kStatus_Success Switched to the target mode successfully.
1269 */
CLOCK_SetFbeMode(uint8_t frdiv,mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1270 status_t CLOCK_SetFbeMode(uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1271 {
1272 uint8_t mcg_c4;
1273 bool change_drs = false;
1274
1275 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1276 mcg_mode_t mode = CLOCK_GetMode();
1277 if (!((kMCG_ModeFEE == mode) || (kMCG_ModeFBI == mode) || (kMCG_ModeFBE == mode) || (kMCG_ModeFEI == mode) ||
1278 (kMCG_ModeBLPE == mode)))
1279 {
1280 return kStatus_MCG_ModeUnreachable;
1281 }
1282 #endif
1283
1284 /* Set LP bit to enable the FLL */
1285 MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK;
1286
1287 mcg_c4 = MCG->C4;
1288
1289 /*
1290 Errata: ERR007993
1291 Workaround: Invert MCG_C4[DMX32] or change MCG_C4[DRST_DRS] before
1292 reference clock source changes, then reset to previous value after
1293 reference clock changes.
1294 */
1295 if ((uint8_t)kMCG_FllSrcInternal == MCG_S_IREFST_VAL)
1296 {
1297 change_drs = true;
1298 /* Change the LSB of DRST_DRS. */
1299 MCG->C4 ^= (1U << MCG_C4_DRST_DRS_SHIFT);
1300 }
1301
1302 /* Set CLKS and IREFS. */
1303 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_FRDIV_MASK | MCG_C1_IREFS_MASK)) |
1304 (MCG_C1_CLKS(kMCG_ClkOutSrcExternal) /* CLKS = 2 */
1305 | MCG_C1_FRDIV(frdiv) /* FRDIV = frdiv */
1306 | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
1307
1308 /* If use external crystal as clock source, wait for it stable. */
1309 {
1310 if (0U != (MCG->C2 & MCG_C2_EREFS_MASK))
1311 {
1312 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
1313 {
1314 }
1315 }
1316 }
1317
1318 /* Wait for Reference clock Status bit to clear */
1319 while ((uint8_t)kMCG_FllSrcExternal != MCG_S_IREFST_VAL)
1320 {
1321 }
1322
1323 /* Errata: ERR007993 */
1324 if (change_drs)
1325 {
1326 MCG->C4 = mcg_c4;
1327 }
1328
1329 /* Set DRST_DRS and DMX32. */
1330 mcg_c4 = (uint8_t)((mcg_c4 & ~(MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) |
1331 (MCG_C4_DMX32(dmx32) | MCG_C4_DRST_DRS(drs)));
1332
1333 /* Wait for clock status bits to show clock source is ext ref clk */
1334 while ((uint8_t)kMCG_ClkOutStatExt != MCG_S_CLKST_VAL)
1335 {
1336 }
1337
1338 /* Wait for fll stable time. */
1339 if (NULL != fllStableDelay)
1340 {
1341 fllStableDelay();
1342 }
1343
1344 return kStatus_Success;
1345 }
1346
1347 /*!
1348 * brief Sets the MCG to BLPI mode.
1349 *
1350 * This function sets the MCG to BLPI mode. If setting to BLPI mode fails
1351 * from the current mode, this function returns an error.
1352 *
1353 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1354 * retval kStatus_Success Switched to the target mode successfully.
1355 */
CLOCK_SetBlpiMode(void)1356 status_t CLOCK_SetBlpiMode(void)
1357 {
1358 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1359 if (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatInt)
1360 {
1361 return kStatus_MCG_ModeUnreachable;
1362 }
1363 #endif /* MCG_CONFIG_CHECK_PARAM */
1364
1365 /* Set LP. */
1366 MCG->C2 |= MCG_C2_LP_MASK;
1367
1368 return kStatus_Success;
1369 }
1370
1371 /*!
1372 * brief Sets the MCG to BLPE mode.
1373 *
1374 * This function sets the MCG to BLPE mode. If setting to BLPE mode fails
1375 * from the current mode, this function returns an error.
1376 *
1377 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1378 * retval kStatus_Success Switched to the target mode successfully.
1379 */
CLOCK_SetBlpeMode(void)1380 status_t CLOCK_SetBlpeMode(void)
1381 {
1382 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1383 if (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatExt)
1384 {
1385 return kStatus_MCG_ModeUnreachable;
1386 }
1387 #endif
1388
1389 /* Set LP bit to enter BLPE mode. */
1390 MCG->C2 |= MCG_C2_LP_MASK;
1391
1392 return kStatus_Success;
1393 }
1394
1395 /*!
1396 * brief Switches the MCG to FBE mode from the external mode.
1397 *
1398 * This function switches the MCG from external modes (PEE/PBE/BLPE/FEE) to the FBE mode quickly.
1399 * The external clock is used as the system clock source and PLL is disabled. However,
1400 * the FLL settings are not configured. This is a lite function with a small code size, which is useful
1401 * during the mode switch. For example, to switch from PEE mode to FEI mode:
1402 *
1403 * code
1404 * CLOCK_ExternalModeToFbeModeQuick();
1405 * CLOCK_SetFeiMode(...);
1406 * endcode
1407 *
1408 * retval kStatus_Success Switched successfully.
1409 * retval kStatus_MCG_ModeInvalid If the current mode is not an external mode, do not call this function.
1410 */
CLOCK_ExternalModeToFbeModeQuick(void)1411 status_t CLOCK_ExternalModeToFbeModeQuick(void)
1412 {
1413 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1414 if (MCG->S & MCG_S_IREFST_MASK)
1415 {
1416 return kStatus_MCG_ModeInvalid;
1417 }
1418 #endif /* MCG_CONFIG_CHECK_PARAM */
1419
1420 /* Disable low power */
1421 MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK;
1422
1423 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcExternal));
1424 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatExt)
1425 {
1426 }
1427
1428 return kStatus_Success;
1429 }
1430
1431 /*!
1432 * brief Switches the MCG to FBI mode from internal modes.
1433 *
1434 * This function switches the MCG from internal modes (PEI/PBI/BLPI/FEI) to the FBI mode quickly.
1435 * The MCGIRCLK is used as the system clock source and PLL is disabled. However,
1436 * FLL settings are not configured. This is a lite function with a small code size, which is useful
1437 * during the mode switch. For example, to switch from PEI mode to FEE mode:
1438 *
1439 * code
1440 * CLOCK_InternalModeToFbiModeQuick();
1441 * CLOCK_SetFeeMode(...);
1442 * endcode
1443 *
1444 * retval kStatus_Success Switched successfully.
1445 * retval kStatus_MCG_ModeInvalid If the current mode is not an internal mode, do not call this function.
1446 */
CLOCK_InternalModeToFbiModeQuick(void)1447 status_t CLOCK_InternalModeToFbiModeQuick(void)
1448 {
1449 #if (defined(MCG_CONFIG_CHECK_PARAM) && MCG_CONFIG_CHECK_PARAM)
1450 if (!(MCG->S & MCG_S_IREFST_MASK))
1451 {
1452 return kStatus_MCG_ModeInvalid;
1453 }
1454 #endif
1455
1456 /* Disable low power */
1457 MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK;
1458
1459 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal));
1460 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatInt)
1461 {
1462 }
1463
1464 return kStatus_Success;
1465 }
1466
1467 /*!
1468 * brief Sets the MCG to FEI mode during system boot up.
1469 *
1470 * This function sets the MCG to FEI mode from the reset mode. It can also be used to
1471 * set up MCG during system boot up.
1472 *
1473 * param dmx32 DMX32 in FEI mode.
1474 * param drs The DCO range selection.
1475 * param fllStableDelay Delay function to ensure that the FLL is stable.
1476 *
1477 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1478 * retval kStatus_Success Switched to the target mode successfully.
1479 * note If p dmx32 is set to kMCG_Dmx32Fine, the slow IRC must not be trimmed
1480 * to frequency above 32768 Hz.
1481 */
CLOCK_BootToFeiMode(mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1482 status_t CLOCK_BootToFeiMode(mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1483 {
1484 return CLOCK_SetFeiMode(dmx32, drs, fllStableDelay);
1485 }
1486
1487 /*!
1488 * brief Sets the MCG to FEE mode during system bootup.
1489 *
1490 * This function sets MCG to FEE mode from the reset mode. It can also be used to
1491 * set up the MCG during system boot up.
1492 *
1493 * param oscsel OSC clock select, OSCSEL.
1494 * param frdiv FLL reference clock divider setting, FRDIV.
1495 * param dmx32 DMX32 in FEE mode.
1496 * param drs The DCO range selection.
1497 * param fllStableDelay Delay function to ensure that the FLL is stable.
1498 *
1499 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1500 * retval kStatus_Success Switched to the target mode successfully.
1501 */
CLOCK_BootToFeeMode(mcg_oscsel_t oscsel,uint8_t frdiv,mcg_dmx32_t dmx32,mcg_drs_t drs,void (* fllStableDelay)(void))1502 status_t CLOCK_BootToFeeMode(
1503 mcg_oscsel_t oscsel, uint8_t frdiv, mcg_dmx32_t dmx32, mcg_drs_t drs, void (*fllStableDelay)(void))
1504 {
1505 (void)CLOCK_SetExternalRefClkConfig(oscsel);
1506
1507 return CLOCK_SetFeeMode(frdiv, dmx32, drs, fllStableDelay);
1508 }
1509
1510 /*!
1511 * brief Sets the MCG to BLPI mode during system boot up.
1512 *
1513 * This function sets the MCG to BLPI mode from the reset mode. It can also be used to
1514 * set up the MCG during system boot up.
1515 *
1516 * param fcrdiv Fast IRC divider, FCRDIV.
1517 * param ircs The internal reference clock to select, IRCS.
1518 * param ircEnableMode The MCGIRCLK enable mode, OR'ed value of ref _mcg_irclk_enable_mode.
1519 *
1520 * retval kStatus_MCG_SourceUsed Could not change MCGIRCLK setting.
1521 * retval kStatus_Success Switched to the target mode successfully.
1522 */
CLOCK_BootToBlpiMode(uint8_t fcrdiv,mcg_irc_mode_t ircs,uint8_t ircEnableMode)1523 status_t CLOCK_BootToBlpiMode(uint8_t fcrdiv, mcg_irc_mode_t ircs, uint8_t ircEnableMode)
1524 {
1525 /* If reset mode is FEI mode, set MCGIRCLK and always success. */
1526 (void)CLOCK_SetInternalRefClkConfig(ircEnableMode, ircs, fcrdiv);
1527
1528 /* If reset mode is not BLPI, first enter FBI mode. */
1529 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCG_ClkOutSrcInternal));
1530 while (MCG_S_CLKST_VAL != (uint8_t)kMCG_ClkOutStatInt)
1531 {
1532 }
1533
1534 /* Enter BLPI mode. */
1535 MCG->C2 |= MCG_C2_LP_MASK;
1536
1537 return kStatus_Success;
1538 }
1539
1540 /*!
1541 * brief Sets the MCG to BLPE mode during system boot up.
1542 *
1543 * This function sets the MCG to BLPE mode from the reset mode. It can also be used to
1544 * set up the MCG during system boot up.
1545 *
1546 * param oscsel OSC clock select, MCG_C7[OSCSEL].
1547 *
1548 * retval kStatus_MCG_ModeUnreachable Could not switch to the target mode.
1549 * retval kStatus_Success Switched to the target mode successfully.
1550 */
CLOCK_BootToBlpeMode(mcg_oscsel_t oscsel)1551 status_t CLOCK_BootToBlpeMode(mcg_oscsel_t oscsel)
1552 {
1553 (void)CLOCK_SetExternalRefClkConfig(oscsel);
1554
1555 /* Set to FBE mode. */
1556 MCG->C1 = (uint8_t)((MCG->C1 & ~(MCG_C1_CLKS_MASK | MCG_C1_IREFS_MASK)) |
1557 (MCG_C1_CLKS(kMCG_ClkOutSrcExternal) /* CLKS = 2 */
1558 | MCG_C1_IREFS(kMCG_FllSrcExternal))); /* IREFS = 0 */
1559
1560 /* If use external crystal as clock source, wait for it stable. */
1561 {
1562 if (0U != (MCG->C2 & MCG_C2_EREFS_MASK))
1563 {
1564 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
1565 {
1566 }
1567 }
1568 }
1569
1570 /* Wait for MCG_S[CLKST] and MCG_S[IREFST]. */
1571 while ((MCG->S & (MCG_S_IREFST_MASK | MCG_S_CLKST_MASK)) !=
1572 (MCG_S_IREFST(kMCG_FllSrcExternal) | MCG_S_CLKST(kMCG_ClkOutStatExt)))
1573 {
1574 }
1575
1576 /* In FBE now, start to enter BLPE. */
1577 MCG->C2 |= MCG_C2_LP_MASK;
1578
1579 return kStatus_Success;
1580 }
1581
1582 /*
1583 The transaction matrix. It defines the path for mode switch, the row is for
1584 current mode and the column is target mode.
1585 For example, switch from FEI to PEE:
1586 1. Current mode FEI, next mode is mcgModeMatrix[FEI][PEE] = FBE, so swith to FBE.
1587 2. Current mode FBE, next mode is mcgModeMatrix[FBE][PEE] = PBE, so swith to PBE.
1588 3. Current mode PBE, next mode is mcgModeMatrix[PBE][PEE] = PEE, so swith to PEE.
1589 Thus the MCG mode has changed from FEI to PEE.
1590 */
1591 static const mcg_mode_t mcgModeMatrix[6][6] = {
1592 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE}, /* FEI */
1593 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeBLPI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE}, /* FBI */
1594 {kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeBLPI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFBI}, /* BLPI */
1595 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeFBE}, /* FEE */
1596 {kMCG_ModeFEI, kMCG_ModeFBI, kMCG_ModeFBI, kMCG_ModeFEE, kMCG_ModeFBE, kMCG_ModeBLPE}, /* FBE */
1597 {kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeFBE, kMCG_ModeBLPE}, /* BLPE */
1598 /* FEI FBI BLPI FEE FBE BLPE */
1599 };
1600
1601 /*!
1602 * brief Sets the MCG to a target mode.
1603 *
1604 * This function sets MCG to a target mode defined by the configuration
1605 * structure. If switching to the target mode fails, this function
1606 * chooses the correct path.
1607 *
1608 * param config Pointer to the target MCG mode configuration structure.
1609 * return Return kStatus_Success if switched successfully; Otherwise, it returns an error code #_mcg_status.
1610 *
1611 * note If the external clock is used in the target mode, ensure that it is
1612 * enabled. For example, if the OSC0 is used, set up OSC0 correctly before calling this
1613 * function.
1614 */
CLOCK_SetMcgConfig(const mcg_config_t * config)1615 status_t CLOCK_SetMcgConfig(const mcg_config_t *config)
1616 {
1617 mcg_mode_t next_mode;
1618 status_t status = kStatus_Success;
1619
1620 /* Re-configure MCGIRCLK, if MCGIRCLK is used as system clock source, then change to FEI/PEI first. */
1621 if (MCG_S_CLKST_VAL == (uint8_t)kMCG_ClkOutStatInt)
1622 {
1623 MCG->C2 &= ~(uint8_t)MCG_C2_LP_MASK; /* Disable lowpower. */
1624
1625 {
1626 (void)CLOCK_SetFeiMode(config->dmx32, config->drs, CLOCK_FllStableDelay);
1627 }
1628 }
1629
1630 /* Configure MCGIRCLK. */
1631 (void)CLOCK_SetInternalRefClkConfig(config->irclkEnableMode, config->ircs, config->fcrdiv);
1632
1633 next_mode = CLOCK_GetMode();
1634
1635 do
1636 {
1637 next_mode = mcgModeMatrix[next_mode][config->mcgMode];
1638
1639 switch (next_mode)
1640 {
1641 case kMCG_ModeFEI:
1642 status = CLOCK_SetFeiMode(config->dmx32, config->drs, CLOCK_FllStableDelay);
1643 break;
1644 case kMCG_ModeFEE:
1645 status = CLOCK_SetFeeMode(config->frdiv, config->dmx32, config->drs, CLOCK_FllStableDelay);
1646 break;
1647 case kMCG_ModeFBI:
1648 status = CLOCK_SetFbiMode(config->dmx32, config->drs, NULL);
1649 break;
1650 case kMCG_ModeFBE:
1651 status = CLOCK_SetFbeMode(config->frdiv, config->dmx32, config->drs, NULL);
1652 break;
1653 case kMCG_ModeBLPI:
1654 status = CLOCK_SetBlpiMode();
1655 break;
1656 case kMCG_ModeBLPE:
1657 status = CLOCK_SetBlpeMode();
1658 break;
1659 default:
1660 break;
1661 }
1662 if (kStatus_Success != status)
1663 {
1664 return status;
1665 }
1666 } while (next_mode != config->mcgMode);
1667
1668 return kStatus_Success;
1669 }
1670