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  * Code
62  ******************************************************************************/
63 
CLOCK_GetLircClkFreq(void)64 static uint32_t CLOCK_GetLircClkFreq(void)
65 {
66     static const uint32_t lircFreqs[] = {MCG_LIRC_FREQ1, MCG_LIRC_FREQ2};
67 
68     /* Check whether the LIRC is enabled. */
69     if ((MCG->C1 & MCG_C1_IRCLKEN_MASK) || (kMCGLITE_ClkSrcLirc == MCG_S_CLKST_VAL))
70     {
71         return lircFreqs[MCG_C2_IRCS_VAL];
72     }
73     else
74     {
75         return 0U;
76     }
77 }
78 
79 /*!
80  * brief Get the OSC0 external reference clock frequency (OSC0ERCLK).
81  *
82  * return Clock frequency in Hz.
83  */
CLOCK_GetOsc0ErClkFreq(void)84 uint32_t CLOCK_GetOsc0ErClkFreq(void)
85 {
86     if (OSC->CR & OSC_CR_ERCLKEN_MASK)
87     {
88         /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
89         assert(g_xtal0Freq);
90         return g_xtal0Freq;
91     }
92     else
93     {
94         return 0U;
95     }
96 }
97 
98 /*!
99  * brief Get the external reference 32K clock frequency (ERCLK32K).
100  *
101  * return Clock frequency in Hz.
102  */
CLOCK_GetEr32kClkFreq(void)103 uint32_t CLOCK_GetEr32kClkFreq(void)
104 {
105     uint32_t freq;
106 
107     switch (SIM_SOPT1_OSC32KSEL_VAL)
108     {
109         case 0U: /* OSC 32k clock  */
110             freq = (CLOCK_GetOsc0ErClkFreq() == 32768U) ? 32768U : 0U;
111             break;
112         case 2U: /* RTC 32k clock  */
113             /* Please call CLOCK_SetXtal32Freq base on board setting before using XTAL32K/RTC_CLKIN clock. */
114             assert(g_xtal32Freq);
115             freq = g_xtal32Freq;
116             break;
117         case 3U: /* LPO clock      */
118             freq = LPO_CLK_FREQ;
119             break;
120         default:
121             freq = 0U;
122             break;
123     }
124     return freq;
125 }
126 
127 /*!
128  * brief Get the platform clock frequency.
129  *
130  * return Clock frequency in Hz.
131  */
CLOCK_GetPlatClkFreq(void)132 uint32_t CLOCK_GetPlatClkFreq(void)
133 {
134     return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
135 }
136 
137 /*!
138  * brief Get the flash clock frequency.
139  *
140  * return Clock frequency in Hz.
141  */
CLOCK_GetFlashClkFreq(void)142 uint32_t CLOCK_GetFlashClkFreq(void)
143 {
144     uint32_t freq;
145 
146     freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
147     freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1);
148 
149     return freq;
150 }
151 
152 /*!
153  * brief Get the bus clock frequency.
154  *
155  * return Clock frequency in Hz.
156  */
CLOCK_GetBusClkFreq(void)157 uint32_t CLOCK_GetBusClkFreq(void)
158 {
159     uint32_t freq;
160 
161     freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
162     freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1);
163 
164     return freq;
165 }
166 
167 /*!
168  * brief Get the core clock or system clock frequency.
169  *
170  * return Clock frequency in Hz.
171  */
CLOCK_GetCoreSysClkFreq(void)172 uint32_t CLOCK_GetCoreSysClkFreq(void)
173 {
174     return CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
175 }
176 
177 /*!
178  * brief Gets the clock frequency for a specific clock name.
179  *
180  * This function checks the current clock configurations and then calculates
181  * the clock frequency for a specific clock name defined in clock_name_t.
182  * The MCG must be properly configured before using this function.
183  *
184  * param clockName Clock names defined in clock_name_t
185  * return Clock frequency value in Hertz
186  */
CLOCK_GetFreq(clock_name_t clockName)187 uint32_t CLOCK_GetFreq(clock_name_t clockName)
188 {
189     uint32_t freq;
190 
191     switch (clockName)
192     {
193         case kCLOCK_CoreSysClk:
194         case kCLOCK_PlatClk:
195             freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
196             break;
197         case kCLOCK_BusClk:
198         case kCLOCK_FlashClk:
199             freq = CLOCK_GetOutClkFreq() / (SIM_CLKDIV1_OUTDIV1_VAL + 1);
200             freq /= (SIM_CLKDIV1_OUTDIV4_VAL + 1);
201             break;
202         case kCLOCK_Er32kClk:
203             freq = CLOCK_GetEr32kClkFreq();
204             break;
205         case kCLOCK_Osc0ErClk:
206             freq = CLOCK_GetOsc0ErClkFreq();
207             break;
208         case kCLOCK_McgInternalRefClk:
209             freq = CLOCK_GetInternalRefClkFreq();
210             break;
211         case kCLOCK_McgPeriphClk:
212         case kCLOCK_McgIrc48MClk:
213             freq = CLOCK_GetPeriphClkFreq();
214             break;
215         case kCLOCK_LpoClk:
216             freq = LPO_CLK_FREQ;
217             break;
218         default:
219             freq = 0U;
220             break;
221     }
222 
223     return freq;
224 }
225 
226 /*!
227  * brief Set the clock configure in SIM module.
228  *
229  * This function sets system layer clock settings in SIM module.
230  *
231  * param config Pointer to the configure structure.
232  */
CLOCK_SetSimConfig(sim_clock_config_t const * config)233 void CLOCK_SetSimConfig(sim_clock_config_t const *config)
234 {
235     SIM->CLKDIV1 = config->clkdiv1;
236     CLOCK_SetEr32kClock(config->er32kSrc);
237 }
238 
239 /*!
240  * brief Gets the MCG internal reference clock (MCGIRCLK) frequency.
241  *
242  * This function gets the MCG_Lite internal reference clock frequency in Hz based
243  * on the current MCG register value.
244  *
245  * return The frequency of MCGIRCLK.
246  */
CLOCK_GetInternalRefClkFreq(void)247 uint32_t CLOCK_GetInternalRefClkFreq(void)
248 {
249     uint8_t divider1 = MCG_SC_FCRDIV_VAL;
250     uint8_t divider2 = MCG_MC_LIRC_DIV2_VAL;
251     /* LIRC internal reference clock is selected*/
252     return CLOCK_GetLircClkFreq() >> (divider1 + divider2);
253 }
254 
255 /*
256  * brief Gets the current MCGPCLK frequency.
257  *
258  * This function gets the MCGPCLK frequency in Hz based on the current MCG_Lite
259  * register settings.
260  *
261  * return The frequency of MCGPCLK.
262  */
CLOCK_GetPeriphClkFreq(void)263 uint32_t CLOCK_GetPeriphClkFreq(void)
264 {
265     /* Check whether the HIRC is enabled. */
266     if ((MCG->MC & MCG_MC_HIRCEN_MASK) || (kMCGLITE_ClkSrcHirc == MCG_S_CLKST_VAL))
267     {
268         return MCG_HIRC_FREQ;
269     }
270     else
271     {
272         return 0U;
273     }
274 }
275 
276 /*!
277  * brief Gets the MCG_Lite output clock (MCGOUTCLK) frequency.
278  *
279  * This function gets the MCG_Lite output clock frequency in Hz based on the current
280  * MCG_Lite register value.
281  *
282  * return The frequency of MCGOUTCLK.
283  */
CLOCK_GetOutClkFreq(void)284 uint32_t CLOCK_GetOutClkFreq(void)
285 {
286     uint32_t freq;
287 
288     switch (MCG_S_CLKST_VAL)
289     {
290         case kMCGLITE_ClkSrcHirc:
291             freq = MCG_HIRC_FREQ;
292             break;
293         case kMCGLITE_ClkSrcLirc:
294             freq = CLOCK_GetLircClkFreq() >> MCG_SC_FCRDIV_VAL;
295             break;
296         case kMCGLITE_ClkSrcExt:
297             /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */
298             assert(g_xtal0Freq);
299             freq = g_xtal0Freq;
300             break;
301         default:
302             freq = 0U;
303             break;
304     }
305 
306     return freq;
307 }
308 
309 /*!
310  * brief Gets the current MCG_Lite mode.
311  *
312  * This function checks the MCG_Lite registers and determines the current MCG_Lite mode.
313  *
314  * return The current MCG_Lite mode or error code.
315  */
CLOCK_GetMode(void)316 mcglite_mode_t CLOCK_GetMode(void)
317 {
318     mcglite_mode_t mode;
319 
320     switch (MCG_S_CLKST_VAL)
321     {
322         case kMCGLITE_ClkSrcHirc: /* HIRC */
323             mode = kMCGLITE_ModeHirc48M;
324             break;
325         case kMCGLITE_ClkSrcLirc: /* LIRC */
326             if (kMCGLITE_Lirc2M == MCG_C2_IRCS_VAL)
327             {
328                 mode = kMCGLITE_ModeLirc2M;
329             }
330             else
331             {
332                 mode = kMCGLITE_ModeLirc8M;
333             }
334             break;
335         case kMCGLITE_ClkSrcExt: /* EXT  */
336             mode = kMCGLITE_ModeExt;
337             break;
338         default:
339             mode = kMCGLITE_ModeError;
340             break;
341     }
342 
343     return mode;
344 }
345 
346 /*!
347  * brief Sets the MCG_Lite configuration.
348  *
349  * This function configures the MCG_Lite, includes the output clock source, MCGIRCLK
350  * settings, HIRC settings, and so on. See ref mcglite_config_t for details.
351  *
352  * param  targetConfig Pointer to the target MCG_Lite mode configuration structure.
353  * return Error code.
354  */
CLOCK_SetMcgliteConfig(mcglite_config_t const * targetConfig)355 status_t CLOCK_SetMcgliteConfig(mcglite_config_t const *targetConfig)
356 {
357     assert(targetConfig);
358 
359     /*
360      * If switch between LIRC8M and LIRC2M, need to switch to HIRC mode first,
361      * because could not switch directly.
362      */
363     if ((kMCGLITE_ClkSrcLirc == MCG_S_CLKST_VAL) && (kMCGLITE_ClkSrcLirc == targetConfig->outSrc) &&
364         (MCG_C2_IRCS_VAL != targetConfig->ircs))
365     {
366         MCG->C1 = (MCG->C1 & ~MCG_C1_CLKS_MASK) | MCG_C1_CLKS(kMCGLITE_ClkSrcHirc);
367         while (kMCGLITE_ClkSrcHirc != MCG_S_CLKST_VAL)
368         {
369         }
370     }
371 
372     /* Set configuration now. */
373     MCG->SC = MCG_SC_FCRDIV(targetConfig->fcrdiv);
374     MCG->MC = MCG_MC_HIRCEN(targetConfig->hircEnableInNotHircMode) | MCG_MC_LIRC_DIV2(targetConfig->lircDiv2);
375     MCG->C2 = (MCG->C2 & ~MCG_C2_IRCS_MASK) | MCG_C2_IRCS(targetConfig->ircs);
376     MCG->C1 = MCG_C1_CLKS(targetConfig->outSrc) | targetConfig->irclkEnableMode;
377 
378     /*
379      * If external oscillator used and MCG_Lite is set to EXT mode, need to
380      * wait for the OSC stable.
381      */
382     if ((MCG->C2 & MCG_C2_EREFS0_MASK) && (kMCGLITE_ClkSrcExt == targetConfig->outSrc))
383     {
384         while (!(MCG->S & MCG_S_OSCINIT0_MASK))
385         {
386         }
387     }
388 
389     /* Wait for clock source change completed. */
390     while (targetConfig->outSrc != MCG_S_CLKST_VAL)
391     {
392     }
393 
394     return kStatus_Success;
395 }
396 
397 /*!
398  * brief Initializes the OSC0.
399  *
400  * This function initializes the OSC0 according to the board configuration.
401  *
402  * param  config Pointer to the OSC0 configuration structure.
403  */
CLOCK_InitOsc0(osc_config_t const * config)404 void CLOCK_InitOsc0(osc_config_t const *config)
405 {
406     OSC_SetCapLoad(OSC0, config->capLoad);
407     OSC_SetExtRefClkConfig(OSC0, &config->oscerConfig);
408 
409     MCG->C2 = ((MCG->C2 & MCG_C2_IRCS_MASK) | (uint8_t)config->workMode);
410 
411     if ((kOSC_ModeExt != config->workMode) && (OSC0->CR & OSC_CR_ERCLKEN_MASK))
412     {
413         /* Wait for stable. */
414         while (!(MCG->S & MCG_S_OSCINIT0_MASK))
415         {
416         }
417     }
418 }
419 
420 /*!
421  * brief Deinitializes the OSC0.
422  *
423  * This function deinitializes the OSC0.
424  */
CLOCK_DeinitOsc0(void)425 void CLOCK_DeinitOsc0(void)
426 {
427     OSC0->CR = 0U;
428     MCG->C2 &= MCG_C2_IRCS_MASK;
429 }
430