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