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