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