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