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 #if defined(FSL_FEATURE_SOC_USB_COUNT) && FSL_FEATURE_SOC_USB_COUNT
277 /*! brief Enable USB FS clock.
278 *
279 * param src USB FS clock source.
280 * param freq The frequency specified by src.
281 * retval true The clock is set successfully.
282 * retval false The clock source is invalid to get proper USB FS clock.
283 */
CLOCK_EnableUsbfs0Clock(clock_usb_src_t src,uint32_t freq)284 bool CLOCK_EnableUsbfs0Clock(clock_usb_src_t src, uint32_t freq)
285 {
286 bool ret = true;
287
288 CLOCK_DisableClock(kCLOCK_Usbfs0);
289
290 if (kCLOCK_UsbSrcExt == src)
291 {
292 SIM->SOPT2 &= ~SIM_SOPT2_USBSRC_MASK;
293 }
294 else
295 {
296 SIM->SOPT2 |= SIM_SOPT2_USBSRC_MASK;
297 }
298
299 CLOCK_EnableClock(kCLOCK_Usbfs0);
300
301 if (kCLOCK_UsbSrcIrc48M == src)
302 {
303 USB0->CLK_RECOVER_IRC_EN = 0x03U;
304 USB0->CLK_RECOVER_CTRL |= USB_CLK_RECOVER_CTRL_CLOCK_RECOVER_EN_MASK;
305 }
306
307 return ret;
308 }
309 #endif
310
311 /*!
312 * brief Gets the MCG internal reference clock (MCGIRCLK) frequency.
313 *
314 * This function gets the MCG_Lite internal reference clock frequency in Hz based
315 * on the current MCG register value.
316 *
317 * return The frequency of MCGIRCLK.
318 */
CLOCK_GetInternalRefClkFreq(void)319 uint32_t CLOCK_GetInternalRefClkFreq(void)
320 {
321 uint8_t divider1 = MCG_SC_FCRDIV_VAL;
322 uint8_t divider2 = MCG_MC_LIRC_DIV2_VAL;
323 /* LIRC internal reference clock is selected*/
324 return CLOCK_GetLircClkFreq() >> (divider1 + divider2);
325 }
326
327 /*
328 * brief Gets the current MCGPCLK frequency.
329 *
330 * This function gets the MCGPCLK frequency in Hz based on the current MCG_Lite
331 * register settings.
332 *
333 * return The frequency of MCGPCLK.
334 */
CLOCK_GetPeriphClkFreq(void)335 uint32_t CLOCK_GetPeriphClkFreq(void)
336 {
337 uint32_t freq;
338
339 /* Check whether the HIRC is enabled. */
340 if (((MCG->MC & MCG_MC_HIRCEN_MASK) != 0U) || ((uint8_t)kMCGLITE_ClkSrcHirc == MCG_S_CLKST_VAL))
341 {
342 freq = MCG_HIRC_FREQ;
343 }
344 else
345 {
346 freq = 0U;
347 }
348
349 return freq;
350 }
351
352 /*!
353 * brief Gets the MCG_Lite output clock (MCGOUTCLK) frequency.
354 *
355 * This function gets the MCG_Lite output clock frequency in Hz based on the current
356 * MCG_Lite register value.
357 *
358 * return The frequency of MCGOUTCLK.
359 */
CLOCK_GetOutClkFreq(void)360 uint32_t CLOCK_GetOutClkFreq(void)
361 {
362 uint32_t freq;
363
364 switch (MCG_S_CLKST_VAL)
365 {
366 case (uint8_t)kMCGLITE_ClkSrcHirc:
367 freq = MCG_HIRC_FREQ;
368 break;
369 case (uint8_t)kMCGLITE_ClkSrcLirc:
370 freq = CLOCK_GetLircClkFreq() >> MCG_SC_FCRDIV_VAL;
371 break;
372 case (uint8_t)kMCGLITE_ClkSrcExt:
373 /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
374 assert(g_xtal0Freq);
375 freq = g_xtal0Freq;
376 break;
377 default:
378 freq = 0U;
379 break;
380 }
381
382 return freq;
383 }
384
385 /*!
386 * brief Gets the current MCG_Lite mode.
387 *
388 * This function checks the MCG_Lite registers and determines the current MCG_Lite mode.
389 *
390 * return The current MCG_Lite mode or error code.
391 */
CLOCK_GetMode(void)392 mcglite_mode_t CLOCK_GetMode(void)
393 {
394 mcglite_mode_t mode;
395
396 switch (MCG_S_CLKST_VAL)
397 {
398 case (uint8_t)kMCGLITE_ClkSrcHirc: /* HIRC */
399 mode = kMCGLITE_ModeHirc48M;
400 break;
401 case (uint8_t)kMCGLITE_ClkSrcLirc: /* LIRC */
402 if ((uint8_t)kMCGLITE_Lirc2M == MCG_C2_IRCS_VAL)
403 {
404 mode = kMCGLITE_ModeLirc2M;
405 }
406 else
407 {
408 mode = kMCGLITE_ModeLirc8M;
409 }
410 break;
411 case (uint8_t)kMCGLITE_ClkSrcExt: /* EXT */
412 mode = kMCGLITE_ModeExt;
413 break;
414 default:
415 mode = kMCGLITE_ModeError;
416 break;
417 }
418
419 return mode;
420 }
421
422 /*!
423 * brief Sets the MCG_Lite configuration.
424 *
425 * This function configures the MCG_Lite, includes the output clock source, MCGIRCLK
426 * settings, HIRC settings, and so on. See ref mcglite_config_t for details.
427 *
428 * param targetConfig Pointer to the target MCG_Lite mode configuration structure.
429 * return Error code.
430 */
CLOCK_SetMcgliteConfig(mcglite_config_t const * targetConfig)431 status_t CLOCK_SetMcgliteConfig(mcglite_config_t const *targetConfig)
432 {
433 assert(targetConfig);
434
435 /*
436 * If switch between LIRC8M and LIRC2M, need to switch to HIRC mode first,
437 * because could not switch directly.
438 */
439 if (((uint8_t)kMCGLITE_ClkSrcLirc == MCG_S_CLKST_VAL) && (kMCGLITE_ClkSrcLirc == targetConfig->outSrc) &&
440 (MCG_C2_IRCS_VAL != (uint8_t)(targetConfig->ircs)))
441 {
442 MCG->C1 = (uint8_t)((MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCGLITE_ClkSrcHirc));
443 while ((uint8_t)kMCGLITE_ClkSrcHirc != MCG_S_CLKST_VAL)
444 {
445 }
446 }
447
448 /* Set configuration now. */
449 MCG->SC = MCG_SC_FCRDIV(targetConfig->fcrdiv);
450 MCG->MC = MCG_MC_HIRCEN(targetConfig->hircEnableInNotHircMode) | MCG_MC_LIRC_DIV2(targetConfig->lircDiv2);
451 MCG->C2 = (uint8_t)((MCG->C2 & ~MCG_C2_IRCS_MASK) | MCG_C2_IRCS(targetConfig->ircs));
452 MCG->C1 = MCG_C1_CLKS(targetConfig->outSrc) | targetConfig->irclkEnableMode;
453
454 /*
455 * If external oscillator used and MCG_Lite is set to EXT mode, need to
456 * wait for the OSC stable.
457 */
458 if (((MCG->C2 & MCG_C2_EREFS0_MASK) != 0U) && (kMCGLITE_ClkSrcExt == targetConfig->outSrc))
459 {
460 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
461 {
462 }
463 }
464
465 /* Wait for clock source change completed. */
466 while ((uint8_t)targetConfig->outSrc != MCG_S_CLKST_VAL)
467 {
468 }
469
470 return kStatus_Success;
471 }
472
473 /*!
474 * brief Initializes the OSC0.
475 *
476 * This function initializes the OSC0 according to the board configuration.
477 *
478 * param config Pointer to the OSC0 configuration structure.
479 */
CLOCK_InitOsc0(osc_config_t const * config)480 void CLOCK_InitOsc0(osc_config_t const *config)
481 {
482 uint8_t range = CLOCK_GetOscRangeFromFreq(config->freq);
483
484 OSC_SetCapLoad(OSC0, config->capLoad);
485 OSC_SetExtRefClkConfig(OSC0, &config->oscerConfig);
486
487 MCG->C2 = ((MCG->C2 & MCG_C2_IRCS_MASK) | MCG_C2_RANGE0(range) | (uint8_t)config->workMode);
488
489 if ((kOSC_ModeExt != config->workMode) && ((OSC0->CR & OSC_CR_ERCLKEN_MASK) != 0U))
490 {
491 /* Wait for stable. */
492 while (0U == (MCG->S & MCG_S_OSCINIT0_MASK))
493 {
494 }
495 }
496 }
497
498 /*!
499 * brief Deinitializes the OSC0.
500 *
501 * This function deinitializes the OSC0.
502 */
CLOCK_DeinitOsc0(void)503 void CLOCK_DeinitOsc0(void)
504 {
505 OSC0->CR = 0U;
506 MCG->C2 &= MCG_C2_IRCS_MASK;
507 }
508