1 /*
2 * Copyright 2024 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "fsl_clock.h"
9
10 /*******************************************************************************
11 * Definitions
12 ******************************************************************************/
13
14 /* Component ID definition, used by tools. */
15 #ifndef FSL_COMPONENT_ID
16 #define FSL_COMPONENT_ID "platform.drivers.clock"
17 #endif
18
19 #if (defined(OSC) && !(defined(OSC0)))
20 #define OSC0 OSC
21 #endif
22
23 #define MCG_HIRC_FREQ (48000000U)
24 #define MCG_LIRC_FREQ1 (2000000U)
25 #define MCG_LIRC_FREQ2 (8000000U)
26
27 #define MCG_S_CLKST_VAL ((MCG->S & MCG_S_CLKST_MASK) >> MCG_S_CLKST_SHIFT)
28 #define MCG_SC_FCRDIV_VAL ((MCG->SC & MCG_SC_FCRDIV_MASK) >> MCG_SC_FCRDIV_SHIFT)
29 #define MCG_MC_LIRC_DIV2_VAL ((MCG->MC & MCG_MC_LIRC_DIV2_MASK) >> MCG_MC_LIRC_DIV2_SHIFT)
30 #define MCG_C2_IRCS_VAL ((MCG->C2 & MCG_C2_IRCS_MASK) >> MCG_C2_IRCS_SHIFT)
31
32 #define SIM_CLKDIV1_OUTDIV1_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT)
33 #define SIM_CLKDIV1_OUTDIV4_VAL ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT)
34 #define SIM_SOPT1_OSC32KSEL_VAL ((SIM->SOPT1 & SIM_SOPT1_OSC32KSEL_MASK) >> SIM_SOPT1_OSC32KSEL_SHIFT)
35
36 /*******************************************************************************
37 * Variables
38 ******************************************************************************/
39
40 /* External XTAL0 (OSC0) clock frequency. */
41 volatile uint32_t g_xtal0Freq;
42 /* External XTAL32K clock frequency. */
43 volatile uint32_t g_xtal32Freq;
44
45 /*******************************************************************************
46 * Prototypes
47 ******************************************************************************/
48
49 /*!
50 * @brief Get the current MCG_Lite LIRC_CLK frequency in Hz.
51 *
52 * This function will return the LIRC_CLK value in frequency(Hz) based
53 * on current MCG_Lite configurations and settings. It is an internal function.
54 *
55 * @return MCG_Lite LIRC_CLK frequency.
56 */
57 static uint32_t CLOCK_GetLircClkFreq(void);
58
59 /*!
60 * @brief Get RANGE value based on OSC frequency.
61 *
62 * To setup external crystal oscillator, must set the register bits RANGE base
63 * on the crystal frequency. This function returns the RANGE base on the input
64 * frequency. This is an internal function.
65 *
66 * @return RANGE value.
67 */
68 static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq);
69
70 /*******************************************************************************
71 * Code
72 ******************************************************************************/
73
CLOCK_GetLircClkFreq(void)74 static uint32_t CLOCK_GetLircClkFreq(void)
75 {
76 static const uint32_t lircFreqs[] = {MCG_LIRC_FREQ1, MCG_LIRC_FREQ2};
77 uint32_t freq;
78
79 /* Check whether the LIRC is enabled. */
80 if (((MCG->C1 & MCG_C1_IRCLKEN_MASK) != 0U) || ((uint8_t)kMCGLITE_ClkSrcLirc == MCG_S_CLKST_VAL))
81 {
82 freq = lircFreqs[MCG_C2_IRCS_VAL];
83 }
84 else
85 {
86 freq = 0U;
87 }
88
89 return freq;
90 }
91
CLOCK_GetOscRangeFromFreq(uint32_t freq)92 static uint8_t CLOCK_GetOscRangeFromFreq(uint32_t freq)
93 {
94 uint8_t range;
95
96 if (freq <= 39063U)
97 {
98 range = 0U;
99 }
100 else if (freq <= 8000000U)
101 {
102 range = 1U;
103 }
104 else
105 {
106 range = 2U;
107 }
108
109 return range;
110 }
111
112 /*!
113 * brief Get the OSC0 external reference clock frequency (OSC0ERCLK).
114 *
115 * return Clock frequency in Hz.
116 */
CLOCK_GetOsc0ErClkFreq(void)117 uint32_t CLOCK_GetOsc0ErClkFreq(void)
118 {
119 uint32_t freq;
120
121 if ((OSC0->CR & OSC_CR_ERCLKEN_MASK) != 0U)
122 {
123 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
124 assert(g_xtal0Freq);
125 freq = g_xtal0Freq;
126 }
127 else
128 {
129 freq = 0U;
130 }
131
132 return freq;
133 }
134
135 /*!
136 * brief Get the external reference 32K clock frequency (ERCLK32K).
137 *
138 * return Clock frequency in Hz.
139 */
CLOCK_GetEr32kClkFreq(void)140 uint32_t CLOCK_GetEr32kClkFreq(void)
141 {
142 uint32_t freq;
143
144 switch (SIM_SOPT1_OSC32KSEL_VAL)
145 {
146 case 0U: /* OSC 32k clock */
147 freq = (CLOCK_GetOsc0ErClkFreq() == 32768U) ? 32768U : 0U;
148 break;
149 case 2U: /* RTC 32k clock */
150 /* Please call CLOCK_SetXtal32Freq base on board setting before using XTAL32K/RTC_CLKIN clock. */
151 assert(g_xtal32Freq);
152 freq = g_xtal32Freq;
153 break;
154 case 3U: /* LPO clock */
155 freq = LPO_CLK_FREQ;
156 break;
157 default:
158 freq = 0U;
159 break;
160 }
161 return freq;
162 }
163
164 /*!
165 * brief Get the platform clock frequency.
166 *
167 * return Clock frequency in Hz.
168 */
CLOCK_GetPlatClkFreq(void)169 uint32_t CLOCK_GetPlatClkFreq(void)
170 {
171 return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1U);
172 }
173
174 /*!
175 * brief Get the flash clock frequency.
176 *
177 * return Clock frequency in Hz.
178 */
CLOCK_GetFlashClkFreq(void)179 uint32_t CLOCK_GetFlashClkFreq(void)
180 {
181 uint32_t freq;
182
183 freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1U);
184 freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1U);
185
186 return freq;
187 }
188
189 /*!
190 * brief Get the bus clock frequency.
191 *
192 * return Clock frequency in Hz.
193 */
CLOCK_GetBusClkFreq(void)194 uint32_t CLOCK_GetBusClkFreq(void)
195 {
196 uint32_t freq;
197
198 freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1U);
199 freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1U);
200
201 return freq;
202 }
203
204 /*!
205 * brief Get the core clock or system clock frequency.
206 *
207 * return Clock frequency in Hz.
208 */
CLOCK_GetCoreSysClkFreq(void)209 uint32_t CLOCK_GetCoreSysClkFreq(void)
210 {
211 return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1U);
212 }
213
214 /*!
215 * brief Gets the clock frequency for a specific clock name.
216 *
217 * This function checks the current clock configurations and then calculates
218 * the clock frequency for a specific clock name defined in clock_name_t.
219 * The MCG must be properly configured before using this function.
220 *
221 * param clockName Clock names defined in clock_name_t
222 * return Clock frequency value in Hertz
223 */
CLOCK_GetFreq(clock_name_t clockName)224 uint32_t CLOCK_GetFreq(clock_name_t clockName)
225 {
226 uint32_t freq;
227
228 switch (clockName)
229 {
230 case kCLOCK_CoreSysClk:
231 case kCLOCK_PlatClk:
232 freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1U);
233 break;
234 case kCLOCK_BusClk:
235 case kCLOCK_FlashClk:
236 freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1U);
237 freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1U);
238 break;
239 case kCLOCK_Er32kClk:
240 freq = CLOCK_GetEr32kClkFreq();
241 break;
242 case kCLOCK_Osc0ErClk:
243 freq = CLOCK_GetOsc0ErClkFreq();
244 break;
245 case kCLOCK_McgInternalRefClk:
246 freq = CLOCK_GetInternalRefClkFreq();
247 break;
248 case kCLOCK_McgPeriphClk:
249 case kCLOCK_McgIrc48MClk:
250 freq = CLOCK_GetPeriphClkFreq();
251 break;
252 case kCLOCK_LpoClk:
253 freq = LPO_CLK_FREQ;
254 break;
255 default:
256 freq = 0U;
257 break;
258 }
259
260 return freq;
261 }
262
263 /*!
264 * brief Set the clock configure in SIM module.
265 *
266 * This function sets system layer clock settings in SIM module.
267 *
268 * param config Pointer to the configure structure.
269 */
CLOCK_SetSimConfig(sim_clock_config_t const * config)270 void CLOCK_SetSimConfig(sim_clock_config_t const *config)
271 {
272 SIM->CLKDIV1 = config->clkdiv1;
273 CLOCK_SetEr32kClock(config->er32kSrc);
274 }
275
276 /*! brief Enable USB FS clock.
277 *
278 * param src USB FS clock source.
279 * param freq The frequency specified by src.
280 * retval true The clock is set successfully.
281 * retval false The clock source is invalid to get proper USB FS clock.
282 */
CLOCK_EnableUsbfs0Clock(clock_usb_src_t src,uint32_t freq)283 bool CLOCK_EnableUsbfs0Clock(clock_usb_src_t src, uint32_t freq)
284 {
285 bool ret = true;
286
287 CLOCK_DisableClock(kCLOCK_Usbfs0);
288
289 if (kCLOCK_UsbSrcExt == src)
290 {
291 SIM->SOPT2 &= ~SIM_SOPT2_USBSRC_MASK;
292 }
293 else
294 {
295 SIM->SOPT2 |= SIM_SOPT2_USBSRC_MASK;
296 }
297
298 CLOCK_EnableClock(kCLOCK_Usbfs0);
299
300 if (kCLOCK_UsbSrcIrc48M == src)
301 {
302 USB0->CLK_RECOVER_IRC_EN = 0x03U;
303 USB0->CLK_RECOVER_CTRL |= USB_CLK_RECOVER_CTRL_CLOCK_RECOVER_EN_MASK;
304 }
305
306 return ret;
307 }
308
309 /*!
310 * brief Gets the MCG internal reference clock (MCGIRCLK) frequency.
311 *
312 * This function gets the MCG_Lite internal reference clock frequency in Hz based
313 * on the current MCG register value.
314 *
315 * return The frequency of MCGIRCLK.
316 */
CLOCK_GetInternalRefClkFreq(void)317 uint32_t CLOCK_GetInternalRefClkFreq(void)
318 {
319 uint8_t divider1 = MCG_SC_FCRDIV_VAL;
320 uint8_t divider2 = MCG_MC_LIRC_DIV2_VAL;
321 /* LIRC internal reference clock is selected*/
322 return CLOCK_GetLircClkFreq() >> (divider1 + divider2);
323 }
324
325 /*
326 * brief Gets the current MCGPCLK frequency.
327 *
328 * This function gets the MCGPCLK frequency in Hz based on the current MCG_Lite
329 * register settings.
330 *
331 * return The frequency of MCGPCLK.
332 */
CLOCK_GetPeriphClkFreq(void)333 uint32_t CLOCK_GetPeriphClkFreq(void)
334 {
335 uint32_t freq;
336
337 /* Check whether the HIRC is enabled. */
338 if (((MCG->MC & MCG_MC_HIRCEN_MASK) != 0U) || ((uint8_t)kMCGLITE_ClkSrcHirc == MCG_S_CLKST_VAL))
339 {
340 freq = MCG_HIRC_FREQ;
341 }
342 else
343 {
344 freq = 0U;
345 }
346
347 return freq;
348 }
349
350 /*!
351 * brief Gets the MCG_Lite output clock (MCGOUTCLK) frequency.
352 *
353 * This function gets the MCG_Lite output clock frequency in Hz based on the current
354 * MCG_Lite register value.
355 *
356 * return The frequency of MCGOUTCLK.
357 */
CLOCK_GetOutClkFreq(void)358 uint32_t CLOCK_GetOutClkFreq(void)
359 {
360 uint32_t freq;
361
362 switch (MCG_S_CLKST_VAL)
363 {
364 case (uint8_t)kMCGLITE_ClkSrcHirc:
365 freq = MCG_HIRC_FREQ;
366 break;
367 case (uint8_t)kMCGLITE_ClkSrcLirc:
368 freq = CLOCK_GetLircClkFreq() >> MCG_SC_FCRDIV_VAL;
369 break;
370 case (uint8_t)kMCGLITE_ClkSrcExt:
371 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
372 assert(g_xtal0Freq);
373 freq = g_xtal0Freq;
374 break;
375 default:
376 freq = 0U;
377 break;
378 }
379
380 return freq;
381 }
382
383 /*!
384 * brief Gets the current MCG_Lite mode.
385 *
386 * This function checks the MCG_Lite registers and determines the current MCG_Lite mode.
387 *
388 * return The current MCG_Lite mode or error code.
389 */
CLOCK_GetMode(void)390 mcglite_mode_t CLOCK_GetMode(void)
391 {
392 mcglite_mode_t mode;
393
394 switch (MCG_S_CLKST_VAL)
395 {
396 case (uint8_t)kMCGLITE_ClkSrcHirc: /* HIRC */
397 mode = kMCGLITE_ModeHirc48M;
398 break;
399 case (uint8_t)kMCGLITE_ClkSrcLirc: /* LIRC */
400 if ((uint8_t)kMCGLITE_Lirc2M == MCG_C2_IRCS_VAL)
401 {
402 mode = kMCGLITE_ModeLirc2M;
403 }
404 else
405 {
406 mode = kMCGLITE_ModeLirc8M;
407 }
408 break;
409 case (uint8_t)kMCGLITE_ClkSrcExt: /* EXT */
410 mode = kMCGLITE_ModeExt;
411 break;
412 default:
413 mode = kMCGLITE_ModeError;
414 break;
415 }
416
417 return mode;
418 }
419
420 /*!
421 * brief Sets the MCG_Lite configuration.
422 *
423 * This function configures the MCG_Lite, includes the output clock source, MCGIRCLK
424 * settings, HIRC settings, and so on. See ref mcglite_config_t for details.
425 *
426 * param targetConfig Pointer to the target MCG_Lite mode configuration structure.
427 * return Error code.
428 */
CLOCK_SetMcgliteConfig(mcglite_config_t const * targetConfig)429 status_t CLOCK_SetMcgliteConfig(mcglite_config_t const *targetConfig)
430 {
431 assert(targetConfig);
432
433 /*
434 * If switch between LIRC8M and LIRC2M, need to switch to HIRC mode first,
435 * because could not switch directly.
436 */
437 if (((uint8_t)kMCGLITE_ClkSrcLirc == MCG_S_CLKST_VAL) && (kMCGLITE_ClkSrcLirc == targetConfig->outSrc) &&
438 (MCG_C2_IRCS_VAL != (uint8_t)(targetConfig->ircs)))
439 {
440 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCGLITE_ClkSrcHirc));
441 while ((uint8_t)kMCGLITE_ClkSrcHirc != MCG_S_CLKST_VAL)
442 {
443 }
444 }
445
446 /* Set configuration now. */
447 MCG->SC = MCG_SC_FCRDIV(targetConfig->fcrdiv);
448 MCG->MC = MCG_MC_HIRCEN(targetConfig->hircEnableInNotHircMode) | MCG_MC_LIRC_DIV2(targetConfig->lircDiv2);
449 MCG->C2 = (uint8_t)((MCG->C2 & ~MCG_C2_IRCS_MASK) | MCG_C2_IRCS(targetConfig->ircs));
450 MCG->C1 = MCG_C1_CLKS(targetConfig->outSrc) | targetConfig->irclkEnableMode;
451
452 /*
453 * If external oscillator used and MCG_Lite is set to EXT mode, need to
454 * wait for the OSC stable.
455 */
456 if (((MCG->C2 & MCG_C2_EREFS0_MASK) != 0U) && (kMCGLITE_ClkSrcExt == targetConfig->outSrc))
457 {
458 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
459 {
460 }
461 }
462
463 /* Wait for clock source change completed. */
464 while ((uint8_t)targetConfig->outSrc != MCG_S_CLKST_VAL)
465 {
466 }
467
468 return kStatus_Success;
469 }
470
471 /*!
472 * brief Initializes the OSC0.
473 *
474 * This function initializes the OSC0 according to the board configuration.
475 *
476 * param config Pointer to the OSC0 configuration structure.
477 */
CLOCK_InitOsc0(osc_config_t const * config)478 void CLOCK_InitOsc0(osc_config_t const *config)
479 {
480 uint8_t range = CLOCK_GetOscRangeFromFreq(config->freq);
481
482 OSC_SetCapLoad(OSC0, config->capLoad);
483 OSC_SetExtRefClkConfig(OSC0, &config->oscerConfig);
484
485 MCG->C2 = ((MCG->C2 & MCG_C2_IRCS_MASK) | MCG_C2_RANGE0(range) | (uint8_t)config->workMode);
486
487 if ((kOSC_ModeExt != config->workMode) && ((OSC0->CR & OSC_CR_ERCLKEN_MASK) != 0U))
488 {
489 /* Wait for stable. */
490 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
491 {
492 }
493 }
494 }
495
496 /*!
497 * brief Deinitializes the OSC0.
498 *
499 * This function deinitializes the OSC0.
500 */
CLOCK_DeinitOsc0(void)501 void CLOCK_DeinitOsc0(void)
502 {
503 OSC0->CR = 0U;
504 MCG->C2 &= MCG_C2_IRCS_MASK;
505 }
506