1 /*
2 * Copyright 2020 - 2021 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "fsl_clock.h"
9 /* Component ID definition, used by tools. */
10 #ifndef FSL_COMPONENT_ID
11 #define FSL_COMPONENT_ID "platform.drivers.clock"
12 #endif
13
14 /*******************************************************************************
15 * Definitions
16 ******************************************************************************/
17 /* To make full use of CM7 hardware FPU, use double instead of uint64_t in clock driver to
18 achieve better performance, it is depend on the IDE Floating point settings, if double precision is selected
19 in IDE, clock_64b_t will switch to double type automatically. only support IAR and MDK here */
20 #if __FPU_USED
21
22 #if (defined(__ICCARM__))
23
24 #if (__ARMVFP__ >= __ARMFPV5__) && \
25 (__ARM_FP == 0xE) /*0xe implies support for half, single and double precision operations*/
26 typedef double clock_64b_t;
27 #else
28 typedef uint64_t clock_64b_t;
29 #endif
30
31 #elif (defined(__GNUC__))
32
33 #if (__ARM_FP == 0xE) /*0xe implies support for half, single and double precision operations*/
34 typedef double clock_64b_t;
35 #else
36 typedef uint64_t clock_64b_t;
37 #endif
38
39 #elif defined(__CC_ARM) || defined(__ARMCC_VERSION)
40
41 #if defined __TARGET_FPU_FPV5_D16
42 typedef double clock_64b_t;
43 #else
44 typedef uint64_t clock_64b_t;
45 #endif
46
47 #else
48 typedef uint64_t clock_64b_t;
49 #endif
50
51 #else
52 typedef uint64_t clock_64b_t;
53 #endif
54
55 /*******************************************************************************
56 * Variables
57 ******************************************************************************/
58
59 /* External XTAL (OSC) clock frequency. */
60 volatile uint32_t g_xtalFreq;
61 /* External RTC XTAL clock frequency. */
62 volatile uint32_t g_rtcXtalFreq;
63
64 /*******************************************************************************
65 * Prototypes
66 ******************************************************************************/
67
68 /*!
69 * @brief Get the periph clock frequency.
70 *
71 * @return Periph clock frequency in Hz.
72 */
73 static uint32_t CLOCK_GetPeriphClkFreq(void);
74
75 /*!
76 * @brief Get the frequency of PLL USB1 software clock.
77 *
78 * @return The frequency of PLL USB1 software clock.
79 */
80 static uint32_t CLOCK_GetPllUsb1SWFreq(void);
81
82 /*******************************************************************************
83 * Code
84 ******************************************************************************/
85
CLOCK_GetPeriphClkFreq(void)86 static uint32_t CLOCK_GetPeriphClkFreq(void)
87 {
88 uint32_t freq;
89
90 /* Periph_clk2_clk ---> Periph_clk */
91 if ((CCM->CBCDR & CCM_CBCDR_PERIPH_CLK_SEL_MASK) != 0UL)
92 {
93 switch (CCM->CBCMR & CCM_CBCMR_PERIPH_CLK2_SEL_MASK)
94 {
95 /* Pll3_sw_clk ---> Periph_clk2_clk ---> Periph_clk */
96 case CCM_CBCMR_PERIPH_CLK2_SEL(0U):
97 freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
98 break;
99
100 /* Osc_clk ---> Periph_clk2_clk ---> Periph_clk */
101 case CCM_CBCMR_PERIPH_CLK2_SEL(1U):
102 freq = CLOCK_GetOscFreq();
103 break;
104
105 case CCM_CBCMR_PERIPH_CLK2_SEL(2U):
106 freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
107 break;
108
109 case CCM_CBCMR_PERIPH_CLK2_SEL(3U):
110 default:
111 freq = 0U;
112 break;
113 }
114
115 freq /= (((CCM->CBCDR & CCM_CBCDR_PERIPH_CLK2_PODF_MASK) >> CCM_CBCDR_PERIPH_CLK2_PODF_SHIFT) + 1U);
116 }
117 /* Pre_Periph_clk ---> Periph_clk */
118 else
119 {
120 switch (CCM->CBCMR & CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK)
121 {
122 /* PLL2 */
123 case CCM_CBCMR_PRE_PERIPH_CLK_SEL(0U):
124 freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
125 break;
126
127 /* PLL3 PFD3 */
128 case CCM_CBCMR_PRE_PERIPH_CLK_SEL(1U):
129 freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd3);
130 break;
131
132 /* PLL2 PFD3 */
133 case CCM_CBCMR_PRE_PERIPH_CLK_SEL(2U):
134 freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd3);
135 break;
136
137 /* PLL6 divided(/1) */
138 case CCM_CBCMR_PRE_PERIPH_CLK_SEL(3U):
139 freq = 500000000U;
140 break;
141
142 default:
143 freq = 0U;
144 break;
145 }
146 }
147
148 return freq;
149 }
150
CLOCK_GetPllUsb1SWFreq(void)151 static uint32_t CLOCK_GetPllUsb1SWFreq(void)
152 {
153 uint32_t freq;
154
155 switch ((CCM->CCSR & CCM_CCSR_PLL3_SW_CLK_SEL_MASK) >> CCM_CCSR_PLL3_SW_CLK_SEL_SHIFT)
156 {
157 case 0:
158 {
159 freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
160 break;
161 }
162 case 1:
163 {
164 freq = 24000000UL;
165 break;
166 }
167 default:
168 freq = 0UL;
169 break;
170 }
171
172 return freq;
173 }
174 /*!
175 * brief Initialize the external 24MHz clock.
176 *
177 * This function supports two modes:
178 * 1. Use external crystal oscillator.
179 * 2. Bypass the external crystal oscillator, using input source clock directly.
180 *
181 * After this function, please call ref CLOCK_SetXtal0Freq to inform clock driver
182 * the external clock frequency.
183 *
184 * param bypassXtalOsc Pass in true to bypass the external crystal oscillator.
185 * note This device does not support bypass external crystal oscillator, so
186 * the input parameter should always be false.
187 */
CLOCK_InitExternalClk(bool bypassXtalOsc)188 void CLOCK_InitExternalClk(bool bypassXtalOsc)
189 {
190 /* This device does not support bypass XTAL OSC. */
191 assert(!bypassXtalOsc);
192
193 CCM_ANALOG->MISC0_CLR = CCM_ANALOG_MISC0_XTAL_24M_PWD_MASK; /* Power up */
194 while ((XTALOSC24M->LOWPWR_CTRL & XTALOSC24M_LOWPWR_CTRL_XTALOSC_PWRUP_STAT_MASK) == 0UL)
195 {
196 }
197 CCM_ANALOG->MISC0_SET = (uint32_t)CCM_ANALOG_MISC0_OSC_XTALOK_EN_MASK; /* detect freq */
198 while ((CCM_ANALOG->MISC0 & CCM_ANALOG_MISC0_OSC_XTALOK_MASK) == 0UL)
199 {
200 }
201 CCM_ANALOG->MISC0_CLR = (uint32_t)CCM_ANALOG_MISC0_OSC_XTALOK_EN_MASK;
202 }
203
204 /*!
205 * brief Deinitialize the external 24MHz clock.
206 *
207 * This function disables the external 24MHz clock.
208 *
209 * After this function, please call ref CLOCK_SetXtal0Freq to set external clock
210 * frequency to 0.
211 */
CLOCK_DeinitExternalClk(void)212 void CLOCK_DeinitExternalClk(void)
213 {
214 CCM_ANALOG->MISC0_SET = CCM_ANALOG_MISC0_XTAL_24M_PWD_MASK; /* Power down */
215 }
216
217 /*!
218 * brief Switch the OSC.
219 *
220 * This function switches the OSC source for SoC.
221 *
222 * param osc OSC source to switch to.
223 */
CLOCK_SwitchOsc(clock_osc_t osc)224 void CLOCK_SwitchOsc(clock_osc_t osc)
225 {
226 if (osc == kCLOCK_RcOsc)
227 {
228 XTALOSC24M->LOWPWR_CTRL_SET = XTALOSC24M_LOWPWR_CTRL_SET_OSC_SEL_MASK;
229 }
230 else
231 {
232 XTALOSC24M->LOWPWR_CTRL_CLR = XTALOSC24M_LOWPWR_CTRL_CLR_OSC_SEL_MASK;
233 }
234 }
235
236 /*!
237 * brief Initialize the RC oscillator 24MHz clock.
238 */
CLOCK_InitRcOsc24M(void)239 void CLOCK_InitRcOsc24M(void)
240 {
241 XTALOSC24M->LOWPWR_CTRL |= XTALOSC24M_LOWPWR_CTRL_RC_OSC_EN_MASK;
242 }
243
244 /*!
245 * brief Power down the RCOSC 24M clock.
246 */
CLOCK_DeinitRcOsc24M(void)247 void CLOCK_DeinitRcOsc24M(void)
248 {
249 XTALOSC24M->LOWPWR_CTRL &= ~XTALOSC24M_LOWPWR_CTRL_RC_OSC_EN_MASK;
250 }
251
252 /*!
253 * brief Gets the AHB clock frequency.
254 *
255 * return The AHB clock frequency value in hertz.
256 */
CLOCK_GetAhbFreq(void)257 uint32_t CLOCK_GetAhbFreq(void)
258 {
259 return CLOCK_GetPeriphClkFreq() / (((CCM->CBCDR & CCM_CBCDR_AHB_PODF_MASK) >> CCM_CBCDR_AHB_PODF_SHIFT) + 1U);
260 }
261
262 /*!
263 * brief Gets the SEMC clock frequency.
264 *
265 * return The SEMC clock frequency value in hertz.
266 */
CLOCK_GetSemcFreq(void)267 uint32_t CLOCK_GetSemcFreq(void)
268 {
269 uint32_t freq;
270
271 /* SEMC alternative clock ---> SEMC Clock */
272 if ((CCM->CBCDR & CCM_CBCDR_SEMC_CLK_SEL_MASK) != 0UL)
273 {
274 /* PLL3 PFD1 ---> SEMC alternative clock ---> SEMC Clock */
275 if ((CCM->CBCDR & CCM_CBCDR_SEMC_ALT_CLK_SEL_MASK) != 0UL)
276 {
277 freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd1);
278 }
279 /* PLL2 PFD2 ---> SEMC alternative clock ---> SEMC Clock */
280 else
281 {
282 freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);
283 }
284 }
285 /* Periph_clk ---> SEMC Clock */
286 else
287 {
288 freq = CLOCK_GetPeriphClkFreq();
289 }
290
291 freq /= (((CCM->CBCDR & CCM_CBCDR_SEMC_PODF_MASK) >> CCM_CBCDR_SEMC_PODF_SHIFT) + 1U);
292
293 return freq;
294 }
295
296 /*!
297 * brief Gets the IPG clock frequency.
298 *
299 * return The IPG clock frequency value in hertz.
300 */
CLOCK_GetIpgFreq(void)301 uint32_t CLOCK_GetIpgFreq(void)
302 {
303 return CLOCK_GetAhbFreq() / (((CCM->CBCDR & CCM_CBCDR_IPG_PODF_MASK) >> CCM_CBCDR_IPG_PODF_SHIFT) + 1U);
304 }
305
306 /*!
307 * brief Gets the PER clock frequency.
308 *
309 * return The PER clock frequency value in hertz.
310 */
CLOCK_GetPerClkFreq(void)311 uint32_t CLOCK_GetPerClkFreq(void)
312 {
313 uint32_t freq;
314
315 /* Osc_clk ---> PER Clock*/
316 if ((CCM->CSCMR1 & CCM_CSCMR1_PERCLK_CLK_SEL_MASK) != 0UL)
317 {
318 freq = CLOCK_GetOscFreq();
319 }
320 /* Periph_clk ---> AHB Clock ---> IPG Clock ---> PER Clock */
321 else
322 {
323 freq = CLOCK_GetIpgFreq();
324 }
325
326 freq /= (((CCM->CSCMR1 & CCM_CSCMR1_PERCLK_PODF_MASK) >> CCM_CSCMR1_PERCLK_PODF_SHIFT) + 1U);
327
328 return freq;
329 }
330
331 /*!
332 * brief Gets the clock frequency for a specific clock name.
333 *
334 * This function checks the current clock configurations and then calculates
335 * the clock frequency for a specific clock name defined in clock_name_t.
336 *
337 * param clockName Clock names defined in clock_name_t
338 * return Clock frequency value in hertz
339 */
CLOCK_GetFreq(clock_name_t name)340 uint32_t CLOCK_GetFreq(clock_name_t name)
341 {
342 uint32_t freq;
343
344 switch (name)
345 {
346 case kCLOCK_CpuClk:
347 case kCLOCK_AhbClk:
348 freq = CLOCK_GetAhbFreq();
349 break;
350
351 case kCLOCK_SemcClk:
352 freq = CLOCK_GetSemcFreq();
353 break;
354
355 case kCLOCK_IpgClk:
356 freq = CLOCK_GetIpgFreq();
357 break;
358
359 case kCLOCK_PerClk:
360 freq = CLOCK_GetPerClkFreq();
361 break;
362
363 case kCLOCK_OscClk:
364 freq = CLOCK_GetOscFreq();
365 break;
366 case kCLOCK_RtcClk:
367 freq = CLOCK_GetRtcFreq();
368 break;
369 case kCLOCK_Usb1PllClk:
370 freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
371 break;
372 case kCLOCK_Usb1PllPfd0Clk:
373 freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd0);
374 break;
375 case kCLOCK_Usb1PllPfd1Clk:
376 freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd1);
377 break;
378 case kCLOCK_Usb1PllPfd2Clk:
379 freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd2);
380 break;
381 case kCLOCK_Usb1PllPfd3Clk:
382 freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd3);
383 break;
384 case kCLOCK_Usb1SwClk:
385 freq = CLOCK_GetPllUsb1SWFreq();
386 break;
387 case kCLOCK_Usb1Sw60MClk:
388 freq = CLOCK_GetPllUsb1SWFreq() / 8UL;
389 break;
390 case kCLOCK_Usb1Sw80MClk:
391 freq = CLOCK_GetPllUsb1SWFreq() / 6UL;
392 break;
393
394 case kCLOCK_SysPllClk:
395 freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
396 break;
397 case kCLOCK_SysPllPfd0Clk:
398 freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0);
399 break;
400 case kCLOCK_SysPllPfd1Clk:
401 freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd1);
402 break;
403 case kCLOCK_SysPllPfd2Clk:
404 freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);
405 break;
406 case kCLOCK_SysPllPfd3Clk:
407 freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd3);
408 break;
409 case kCLOCK_EnetPllClk:
410 freq = CLOCK_GetPllFreq(kCLOCK_PllEnet);
411 break;
412 case kCLOCK_EnetPll25MClk:
413 freq = CLOCK_GetPllFreq(kCLOCK_PllEnet25M);
414 break;
415 case kCLOCK_EnetPll500MClk:
416 freq = CLOCK_GetPllFreq(kCLOCK_PllEnet500M);
417 break;
418 case kCLOCK_AudioPllClk:
419 freq = CLOCK_GetPllFreq(kCLOCK_PllAudio);
420 break;
421 default:
422 freq = 0U;
423 break;
424 }
425
426 return freq;
427 }
428
429 /*!
430 * brief Gets the frequency of selected clock root.
431 *
432 * param clockRoot The clock root used to get the frequency, please refer to @ref clock_root_t.
433 * return The frequency of selected clock root.
434 */
CLOCK_GetClockRootFreq(clock_root_t clockRoot)435 uint32_t CLOCK_GetClockRootFreq(clock_root_t clockRoot)
436 {
437 static const clock_name_t clockRootSourceArray[][4] = CLOCK_ROOT_SOUCE;
438 static const clock_mux_t clockRootMuxTupleArray[] = CLOCK_ROOT_MUX_TUPLE;
439 static const clock_div_t clockRootDivTupleArray[][2] = CLOCK_ROOT_DIV_TUPLE;
440 uint32_t freq = 0UL;
441 clock_mux_t clockRootMuxTuple = clockRootMuxTupleArray[(uint8_t)clockRoot];
442 clock_div_t clockRootPreDivTuple = clockRootDivTupleArray[(uint8_t)clockRoot][0];
443 clock_div_t clockRootPostDivTuple = clockRootDivTupleArray[(uint8_t)clockRoot][1];
444 uint32_t clockRootMuxValue = (CCM_TUPLE_REG(CCM, clockRootMuxTuple) & CCM_TUPLE_MASK(clockRootMuxTuple)) >>
445 CCM_TUPLE_SHIFT(clockRootMuxTuple);
446 clock_name_t clockSourceName;
447
448 clockSourceName = clockRootSourceArray[(uint8_t)clockRoot][clockRootMuxValue];
449
450 assert(clockSourceName != kCLOCK_NoneName);
451
452 freq = CLOCK_GetFreq(clockSourceName);
453
454 if (clockRootPreDivTuple != kCLOCK_NonePreDiv)
455 {
456 freq /= ((CCM_TUPLE_REG(CCM, clockRootPreDivTuple) & CCM_TUPLE_MASK(clockRootPreDivTuple)) >>
457 CCM_TUPLE_SHIFT(clockRootPreDivTuple)) +
458 1UL;
459 }
460
461 freq /= ((CCM_TUPLE_REG(CCM, clockRootPostDivTuple) & CCM_TUPLE_MASK(clockRootPostDivTuple)) >>
462 CCM_TUPLE_SHIFT(clockRootPostDivTuple)) +
463 1UL;
464
465 return freq;
466 }
467
468 /*! brief Enable USB HS clock.
469 *
470 * This function only enables the access to USB HS prepheral, upper layer
471 * should first call the ref CLOCK_EnableUsbhs0PhyPllClock to enable the PHY
472 * clock to use USB HS.
473 *
474 * param src USB HS does not care about the clock source, here must be ref kCLOCK_UsbSrcUnused.
475 * param freq USB HS does not care about the clock source, so this parameter is ignored.
476 * retval true The clock is set successfully.
477 * retval false The clock source is invalid to get proper USB HS clock.
478 */
CLOCK_EnableUsbhs0Clock(clock_usb_src_t src,uint32_t freq)479 bool CLOCK_EnableUsbhs0Clock(clock_usb_src_t src, uint32_t freq)
480 {
481 uint32_t i;
482 CCM->CCGR6 |= CCM_CCGR6_CG0_MASK;
483 USB->USBCMD |= USBHS_USBCMD_RST_MASK;
484
485 /* Add a delay between RST and RS so make sure there is a DP pullup sequence*/
486 for (i = 0; i < 400000UL; i++)
487 {
488 __ASM("nop");
489 }
490 PMU->REG_3P0 = (PMU->REG_3P0 & (~PMU_REG_3P0_OUTPUT_TRG_MASK)) |
491 (PMU_REG_3P0_OUTPUT_TRG(0x17) | PMU_REG_3P0_ENABLE_LINREG_MASK);
492 return true;
493 }
494
495 /*! brief Enable USB HS PHY PLL clock.
496 *
497 * This function enables the internal 480MHz USB PHY PLL clock.
498 *
499 * param src USB HS PHY PLL clock source.
500 * param freq The frequency specified by src.
501 * retval true The clock is set successfully.
502 * retval false The clock source is invalid to get proper USB HS clock.
503 */
CLOCK_EnableUsbhs0PhyPllClock(clock_usb_phy_src_t src,uint32_t freq)504 bool CLOCK_EnableUsbhs0PhyPllClock(clock_usb_phy_src_t src, uint32_t freq)
505 {
506 static const clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U};
507 if ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_ENABLE_MASK) != 0UL)
508 {
509 CCM_ANALOG->PLL_USB1 |= CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK;
510 }
511 else
512 {
513 CLOCK_InitUsb1Pll(&g_ccmConfigUsbPll);
514 }
515 USBPHY->CTRL &= ~USBPHY_CTRL_SFTRST_MASK; /* release PHY from reset */
516 USBPHY->CTRL &= ~USBPHY_CTRL_CLKGATE_MASK;
517
518 USBPHY->PWD = 0;
519 USBPHY->CTRL |= USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK | USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK |
520 USBPHY_CTRL_ENUTMILEVEL2_MASK | USBPHY_CTRL_ENUTMILEVEL3_MASK;
521 return true;
522 }
523
524 /*! brief Disable USB HS PHY PLL clock.
525 *
526 * This function disables USB HS PHY PLL clock.
527 */
CLOCK_DisableUsbhs0PhyPllClock(void)528 void CLOCK_DisableUsbhs0PhyPllClock(void)
529 {
530 CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK;
531 USBPHY->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* Set to 1U to gate clocks */
532 }
533
534 /*!
535 * brief Initialize the System PLL.
536 *
537 * This function initializes the System PLL with specific settings
538 *
539 * param config Configuration to set to PLL.
540 */
CLOCK_InitSysPll(const clock_sys_pll_config_t * config)541 void CLOCK_InitSysPll(const clock_sys_pll_config_t *config)
542 {
543 /* Bypass PLL first */
544 CCM_ANALOG->PLL_SYS = (CCM_ANALOG->PLL_SYS & (~CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC_MASK)) |
545 CCM_ANALOG_PLL_SYS_BYPASS_MASK | CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC(config->src);
546
547 CCM_ANALOG->PLL_SYS =
548 (CCM_ANALOG->PLL_SYS & (~(CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK | CCM_ANALOG_PLL_SYS_POWERDOWN_MASK))) |
549 CCM_ANALOG_PLL_SYS_ENABLE_MASK | CCM_ANALOG_PLL_SYS_DIV_SELECT(config->loopDivider);
550
551 /* Initialize the fractional mode */
552 CCM_ANALOG->PLL_SYS_NUM = CCM_ANALOG_PLL_SYS_NUM_A(config->numerator);
553 CCM_ANALOG->PLL_SYS_DENOM = CCM_ANALOG_PLL_SYS_DENOM_B(config->denominator);
554
555 /* Initialize the spread spectrum mode */
556 CCM_ANALOG->PLL_SYS_SS = CCM_ANALOG_PLL_SYS_SS_STEP(config->ss_step) |
557 CCM_ANALOG_PLL_SYS_SS_ENABLE(config->ss_enable) |
558 CCM_ANALOG_PLL_SYS_SS_STOP(config->ss_stop);
559
560 while ((CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_LOCK_MASK) == 0UL)
561 {
562 }
563
564 /* Disable Bypass */
565 CCM_ANALOG->PLL_SYS &= ~CCM_ANALOG_PLL_SYS_BYPASS_MASK;
566 }
567
568 /*!
569 * brief De-initialize the System PLL.
570 */
CLOCK_DeinitSysPll(void)571 void CLOCK_DeinitSysPll(void)
572 {
573 CCM_ANALOG->PLL_SYS = CCM_ANALOG_PLL_SYS_POWERDOWN_MASK;
574 }
575
576 /*!
577 * brief Initialize the USB1 PLL.
578 *
579 * This function initializes the USB1 PLL with specific settings
580 *
581 * param config Configuration to set to PLL.
582 */
CLOCK_InitUsb1Pll(const clock_usb_pll_config_t * config)583 void CLOCK_InitUsb1Pll(const clock_usb_pll_config_t *config)
584 {
585 /* Bypass PLL first */
586 CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & (~CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_MASK)) |
587 CCM_ANALOG_PLL_USB1_BYPASS_MASK | CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC(config->src);
588
589 CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & (~CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK)) |
590 CCM_ANALOG_PLL_USB1_ENABLE_MASK | CCM_ANALOG_PLL_USB1_POWER_MASK |
591 CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK | CCM_ANALOG_PLL_USB1_DIV_SELECT(config->loopDivider);
592
593 while ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_LOCK_MASK) == 0UL)
594 {
595 }
596
597 /* Disable Bypass */
598 CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_BYPASS_MASK;
599 }
600
601 /*!
602 * brief Deinitialize the USB1 PLL.
603 */
CLOCK_DeinitUsb1Pll(void)604 void CLOCK_DeinitUsb1Pll(void)
605 {
606 CCM_ANALOG->PLL_USB1 = 0U;
607 }
608
609 /*!
610 * brief Initializes the Audio PLL.
611 *
612 * This function initializes the Audio PLL with specific settings
613 *
614 * param config Configuration to set to PLL.
615 */
CLOCK_InitAudioPll(const clock_audio_pll_config_t * config)616 void CLOCK_InitAudioPll(const clock_audio_pll_config_t *config)
617 {
618 uint32_t pllAudio;
619 uint32_t misc2 = 0;
620
621 /* Bypass PLL first */
622 CCM_ANALOG->PLL_AUDIO = (CCM_ANALOG->PLL_AUDIO & (~CCM_ANALOG_PLL_AUDIO_BYPASS_CLK_SRC_MASK)) |
623 CCM_ANALOG_PLL_AUDIO_BYPASS_MASK | CCM_ANALOG_PLL_AUDIO_BYPASS_CLK_SRC(config->src);
624
625 CCM_ANALOG->PLL_AUDIO_NUM = CCM_ANALOG_PLL_AUDIO_NUM_A(config->numerator);
626 CCM_ANALOG->PLL_AUDIO_DENOM = CCM_ANALOG_PLL_AUDIO_DENOM_B(config->denominator);
627
628 /*
629 * Set post divider:
630 *
631 * ------------------------------------------------------------------------
632 * | config->postDivider | PLL_AUDIO[POST_DIV_SELECT] | MISC2[AUDIO_DIV] |
633 * ------------------------------------------------------------------------
634 * | 1 | 2 | 0 |
635 * ------------------------------------------------------------------------
636 * | 2 | 1 | 0 |
637 * ------------------------------------------------------------------------
638 * | 4 | 2 | 3 |
639 * ------------------------------------------------------------------------
640 * | 8 | 1 | 3 |
641 * ------------------------------------------------------------------------
642 * | 16 | 0 | 3 |
643 * ------------------------------------------------------------------------
644 */
645 pllAudio =
646 (CCM_ANALOG->PLL_AUDIO & (~(CCM_ANALOG_PLL_AUDIO_DIV_SELECT_MASK | CCM_ANALOG_PLL_AUDIO_POWERDOWN_MASK))) |
647 CCM_ANALOG_PLL_AUDIO_ENABLE_MASK | CCM_ANALOG_PLL_AUDIO_DIV_SELECT(config->loopDivider);
648
649 switch (config->postDivider)
650 {
651 case 16:
652 pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(0);
653 misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
654 break;
655
656 case 8:
657 pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1);
658 misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
659 break;
660
661 case 4:
662 pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2);
663 misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
664 break;
665
666 case 2:
667 pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1);
668 break;
669
670 default:
671 pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2);
672 break;
673 }
674
675 CCM_ANALOG->MISC2 =
676 (CCM_ANALOG->MISC2 & ~(CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK)) | misc2;
677
678 CCM_ANALOG->PLL_AUDIO = pllAudio;
679
680 while ((CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_LOCK_MASK) == 0UL)
681 {
682 }
683
684 /* Disable Bypass */
685 CCM_ANALOG->PLL_AUDIO &= ~CCM_ANALOG_PLL_AUDIO_BYPASS_MASK;
686 }
687
688 /*!
689 * brief De-initialize the Audio PLL.
690 */
CLOCK_DeinitAudioPll(void)691 void CLOCK_DeinitAudioPll(void)
692 {
693 CCM_ANALOG->PLL_AUDIO = CCM_ANALOG_PLL_AUDIO_POWERDOWN_MASK;
694 }
695
696 /*!
697 * brief Initialize the ENET PLL.
698 *
699 * This function initializes the ENET PLL with specific settings.
700 *
701 * param config Configuration to set to PLL.
702 */
CLOCK_InitEnetPll(const clock_enet_pll_config_t * config)703 void CLOCK_InitEnetPll(const clock_enet_pll_config_t *config)
704 {
705 uint32_t enet_pll = CCM_ANALOG_PLL_ENET_DIV_SELECT(config->loopDivider);
706
707 CCM_ANALOG->PLL_ENET = (CCM_ANALOG->PLL_ENET & (~CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC_MASK)) |
708 CCM_ANALOG_PLL_ENET_BYPASS_MASK | CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC(config->src);
709
710 if (config->enableClkOutput)
711 {
712 enet_pll |= CCM_ANALOG_PLL_ENET_ENABLE_MASK;
713 }
714
715 if (config->enableClkOutput25M)
716 {
717 enet_pll |= CCM_ANALOG_PLL_ENET_ENET_25M_REF_EN_MASK;
718 }
719
720 if (config->enableClkOutput500M)
721 {
722 enet_pll |= CCM_ANALOG_PLL_ENET_ENET_500M_REF_EN_MASK;
723 }
724
725 CCM_ANALOG->PLL_ENET =
726 (CCM_ANALOG->PLL_ENET & (~(CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK | CCM_ANALOG_PLL_ENET_POWERDOWN_MASK))) |
727 enet_pll;
728
729 /* Wait for stable */
730 while ((CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_LOCK_MASK) == 0UL)
731 {
732 }
733
734 /* Disable Bypass */
735 CCM_ANALOG->PLL_ENET &= ~CCM_ANALOG_PLL_ENET_BYPASS_MASK;
736 }
737
738 /*!
739 * brief Deinitialize the ENET PLL.
740 *
741 * This function disables the ENET PLL.
742 */
CLOCK_DeinitEnetPll(void)743 void CLOCK_DeinitEnetPll(void)
744 {
745 CCM_ANALOG->PLL_ENET = CCM_ANALOG_PLL_ENET_POWERDOWN_MASK;
746 }
747
748 /*!
749 * brief Get current PLL output frequency.
750 *
751 * This function get current output frequency of specific PLL
752 *
753 * param pll pll name to get frequency.
754 * return The PLL output frequency in hertz.
755 */
CLOCK_GetPllFreq(clock_pll_t pll)756 uint32_t CLOCK_GetPllFreq(clock_pll_t pll)
757 {
758 uint32_t freq;
759 uint32_t divSelect;
760 clock_64b_t freqTmp;
761
762 static const uint32_t enetRefClkFreq[] = {
763 25000000U, /* 25M */
764 50000000U, /* 50M */
765 100000000U, /* 100M */
766 125000000U /* 125M */
767 };
768
769 /* check if PLL is enabled */
770 if (!CLOCK_IsPllEnabled(CCM_ANALOG, pll))
771 {
772 return 0U;
773 }
774
775 /* get pll reference clock */
776 freq = CLOCK_GetPllBypassRefClk(CCM_ANALOG, pll);
777
778 /* check if pll is bypassed */
779 if (CLOCK_IsPllBypassed(CCM_ANALOG, pll))
780 {
781 return freq;
782 }
783
784 switch (pll)
785 {
786 case kCLOCK_PllSys:
787 /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */
788 freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_SYS_NUM)));
789 freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_SYS_DENOM));
790
791 if ((CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK) != 0UL)
792 {
793 freq *= 22U;
794 }
795 else
796 {
797 freq *= 20U;
798 }
799
800 freq += (uint32_t)freqTmp;
801 break;
802
803 case kCLOCK_PllUsb1:
804 freq = (freq * (((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK) != 0UL) ? 22U : 20U));
805 break;
806
807 case kCLOCK_PllAudio:
808 /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */
809 divSelect =
810 (CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_AUDIO_DIV_SELECT_SHIFT;
811
812 freqTmp = ((clock_64b_t)freq * ((clock_64b_t)(CCM_ANALOG->PLL_AUDIO_NUM)));
813 freqTmp /= ((clock_64b_t)(CCM_ANALOG->PLL_AUDIO_DENOM));
814
815 freq = freq * divSelect + (uint32_t)freqTmp;
816
817 /* AUDIO PLL output = PLL output frequency / POSTDIV. */
818
819 /*
820 * Post divider:
821 *
822 * PLL_AUDIO[POST_DIV_SELECT]:
823 * 0x00: 4
824 * 0x01: 2
825 * 0x02: 1
826 *
827 * MISC2[AUDO_DIV]:
828 * 0x00: 1
829 * 0x01: 2
830 * 0x02: 1
831 * 0x03: 4
832 */
833 switch (CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT_MASK)
834 {
835 case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(0U):
836 freq = freq >> 2U;
837 break;
838
839 case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1U):
840 freq = freq >> 1U;
841 break;
842
843 case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2U):
844 freq = freq >> 0U;
845 break;
846
847 default:
848 assert(false);
849 break;
850 }
851
852 switch (CCM_ANALOG->MISC2 & (CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK))
853 {
854 case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(1) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(1):
855 freq >>= 2U;
856 break;
857
858 case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(0) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(1):
859 freq >>= 1U;
860 break;
861
862 case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(0) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(0):
863 case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(1) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(0):
864 freq >>= 0U;
865 break;
866
867 default:
868 assert(false);
869 break;
870 }
871 break;
872
873 case kCLOCK_PllEnet:
874 divSelect =
875 (CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_ENET_DIV_SELECT_SHIFT;
876 freq = enetRefClkFreq[divSelect];
877 break;
878
879 case kCLOCK_PllEnet25M:
880 /* ref_enetpll1 if fixed at 25MHz. */
881 freq = 25000000UL;
882 break;
883
884 case kCLOCK_PllEnet500M:
885 /* PLL6 is fixed at 25MHz. */
886 freq = 500000000UL;
887 break;
888
889 default:
890 freq = 0U;
891 break;
892 }
893
894 return freq;
895 }
896
897 /*!
898 * brief Initialize the System PLL PFD.
899 *
900 * This function initializes the System PLL PFD. During new value setting,
901 * the clock output is disabled to prevent glitch.
902 *
903 * param pfd Which PFD clock to enable.
904 * param pfdFrac The PFD FRAC value.
905 * note It is recommended that PFD settings are kept between 12-35.
906 */
CLOCK_InitSysPfd(clock_pfd_t pfd,uint8_t pfdFrac)907 void CLOCK_InitSysPfd(clock_pfd_t pfd, uint8_t pfdFrac)
908 {
909 uint32_t pfdIndex = (uint32_t)pfd;
910 uint32_t pfd528;
911
912 pfd528 = CCM_ANALOG->PFD_528 &
913 ~(((uint32_t)((uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK | (uint32_t)CCM_ANALOG_PFD_528_PFD0_FRAC_MASK)
914 << (8UL * pfdIndex)));
915
916 /* Disable the clock output first. */
917 CCM_ANALOG->PFD_528 = pfd528 | ((uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8UL * pfdIndex));
918
919 /* Set the new value and enable output. */
920 CCM_ANALOG->PFD_528 = pfd528 | (CCM_ANALOG_PFD_528_PFD0_FRAC(pfdFrac) << (8UL * pfdIndex));
921 }
922
923 /*!
924 * brief De-initialize the System PLL PFD.
925 *
926 * This function disables the System PLL PFD.
927 *
928 * param pfd Which PFD clock to disable.
929 */
CLOCK_DeinitSysPfd(clock_pfd_t pfd)930 void CLOCK_DeinitSysPfd(clock_pfd_t pfd)
931 {
932 CCM_ANALOG->PFD_528 |= (uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8UL * (uint32_t)pfd);
933 }
934
935 /*!
936 * brief Check if Sys PFD is enabled
937 *
938 * param pfd PFD control name
939 * return PFD bypass status.
940 * - true: power on.
941 * - false: power off.
942 */
CLOCK_IsSysPfdEnabled(clock_pfd_t pfd)943 bool CLOCK_IsSysPfdEnabled(clock_pfd_t pfd)
944 {
945 return ((CCM_ANALOG->PFD_528 & (uint32_t)CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8UL * (uint32_t)pfd)) == 0U);
946 }
947
948 /*!
949 * brief Initialize the USB1 PLL PFD.
950 *
951 * This function initializes the USB1 PLL PFD. During new value setting,
952 * the clock output is disabled to prevent glitch.
953 *
954 * param pfd Which PFD clock to enable.
955 * param pfdFrac The PFD FRAC value.
956 * note It is recommended that PFD settings are kept between 12-35.
957 */
CLOCK_InitUsb1Pfd(clock_pfd_t pfd,uint8_t pfdFrac)958 void CLOCK_InitUsb1Pfd(clock_pfd_t pfd, uint8_t pfdFrac)
959 {
960 uint32_t pfdIndex = (uint32_t)pfd;
961 uint32_t pfd480;
962
963 pfd480 = CCM_ANALOG->PFD_480 &
964 ~((uint32_t)((uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK | (uint32_t)CCM_ANALOG_PFD_480_PFD0_FRAC_MASK)
965 << (8UL * pfdIndex));
966
967 /* Disable the clock output first. */
968 CCM_ANALOG->PFD_480 = pfd480 | ((uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8UL * pfdIndex));
969
970 /* Set the new value and enable output. */
971 CCM_ANALOG->PFD_480 = pfd480 | (CCM_ANALOG_PFD_480_PFD0_FRAC(pfdFrac) << (8UL * pfdIndex));
972 }
973
974 /*!
975 * brief De-initialize the USB1 PLL PFD.
976 *
977 * This function disables the USB1 PLL PFD.
978 *
979 * param pfd Which PFD clock to disable.
980 */
CLOCK_DeinitUsb1Pfd(clock_pfd_t pfd)981 void CLOCK_DeinitUsb1Pfd(clock_pfd_t pfd)
982 {
983 CCM_ANALOG->PFD_480 |= (uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8UL * (uint32_t)pfd);
984 }
985
986 /*!
987 * brief Check if Usb1 PFD is enabled
988 *
989 * param pfd PFD control name.
990 * return PFD bypass status.
991 * - true: power on.
992 * - false: power off.
993 */
CLOCK_IsUsb1PfdEnabled(clock_pfd_t pfd)994 bool CLOCK_IsUsb1PfdEnabled(clock_pfd_t pfd)
995 {
996 return ((CCM_ANALOG->PFD_480 & (uint32_t)CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8UL * (uint32_t)pfd)) == 0U);
997 }
998
999 /*!
1000 * brief Get current System PLL PFD output frequency.
1001 *
1002 * This function get current output frequency of specific System PLL PFD
1003 *
1004 * param pfd pfd name to get frequency.
1005 * return The PFD output frequency in hertz.
1006 */
CLOCK_GetSysPfdFreq(clock_pfd_t pfd)1007 uint32_t CLOCK_GetSysPfdFreq(clock_pfd_t pfd)
1008 {
1009 uint32_t freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
1010
1011 switch (pfd)
1012 {
1013 case kCLOCK_Pfd0:
1014 freq /= ((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD0_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD0_FRAC_SHIFT);
1015 break;
1016
1017 case kCLOCK_Pfd1:
1018 freq /= ((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD1_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD1_FRAC_SHIFT);
1019 break;
1020
1021 case kCLOCK_Pfd2:
1022 freq /= ((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD2_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD2_FRAC_SHIFT);
1023 break;
1024
1025 case kCLOCK_Pfd3:
1026 freq /= ((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD3_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD3_FRAC_SHIFT);
1027 break;
1028
1029 default:
1030 freq = 0U;
1031 break;
1032 }
1033 freq *= 18U;
1034
1035 return freq;
1036 }
1037
1038 /*!
1039 * brief Get current USB1 PLL PFD output frequency.
1040 *
1041 * This function get current output frequency of specific USB1 PLL PFD
1042 *
1043 * param pfd pfd name to get frequency.
1044 * return The PFD output frequency in hertz.
1045 */
CLOCK_GetUsb1PfdFreq(clock_pfd_t pfd)1046 uint32_t CLOCK_GetUsb1PfdFreq(clock_pfd_t pfd)
1047 {
1048 uint32_t freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
1049
1050 switch (pfd)
1051 {
1052 case kCLOCK_Pfd0:
1053 freq /= ((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD0_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD0_FRAC_SHIFT);
1054 break;
1055
1056 case kCLOCK_Pfd1:
1057 freq /= ((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD1_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD1_FRAC_SHIFT);
1058 break;
1059
1060 case kCLOCK_Pfd2:
1061 freq /= ((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD2_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD2_FRAC_SHIFT);
1062 break;
1063
1064 case kCLOCK_Pfd3:
1065 freq /= ((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD3_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD3_FRAC_SHIFT);
1066 break;
1067
1068 default:
1069 freq = 0U;
1070 break;
1071 }
1072 freq *= 18U;
1073
1074 return freq;
1075 }
1076
1077 /*!
1078 * brief Set the clock source and the divider of the clock output1.
1079 *
1080 * param selection The clock source to be output, please refer to clock_output1_selection_t.
1081 * param divider The divider of the output clock signal, please refer to clock_output_divider_t.
1082 */
CLOCK_SetClockOutput1(clock_output1_selection_t selection,clock_output_divider_t divider)1083 void CLOCK_SetClockOutput1(clock_output1_selection_t selection, clock_output_divider_t divider)
1084 {
1085 uint32_t tmp32;
1086
1087 tmp32 = CCM->CCOSR;
1088 if (selection == kCLOCK_DisableClockOutput1)
1089 {
1090 tmp32 &= ~CCM_CCOSR_CLKO1_EN_MASK;
1091 }
1092 else
1093 {
1094 tmp32 |= CCM_CCOSR_CLKO1_EN_MASK;
1095 tmp32 &= ~(CCM_CCOSR_CLKO1_SEL_MASK | CCM_CCOSR_CLKO1_DIV_MASK);
1096 tmp32 |= CCM_CCOSR_CLKO1_SEL(selection) | CCM_CCOSR_CLKO1_DIV(divider);
1097 }
1098 CCM->CCOSR = tmp32;
1099 }
1100
1101 /*!
1102 * brief Set the clock source and the divider of the clock output2.
1103 *
1104 * param selection The clock source to be output, please refer to clock_output2_selection_t.
1105 * param divider The divider of the output clock signal, please refer to clock_output_divider_t.
1106 */
CLOCK_SetClockOutput2(clock_output2_selection_t selection,clock_output_divider_t divider)1107 void CLOCK_SetClockOutput2(clock_output2_selection_t selection, clock_output_divider_t divider)
1108 {
1109 uint32_t tmp32;
1110
1111 tmp32 = CCM->CCOSR;
1112 if (selection == kCLOCK_DisableClockOutput2)
1113 {
1114 tmp32 &= CCM_CCOSR_CLKO2_EN_MASK;
1115 }
1116 else
1117 {
1118 tmp32 |= CCM_CCOSR_CLKO2_EN_MASK;
1119 tmp32 &= ~(CCM_CCOSR_CLKO2_SEL_MASK | CCM_CCOSR_CLKO2_DIV_MASK);
1120 tmp32 |= CCM_CCOSR_CLKO2_SEL(selection) | CCM_CCOSR_CLKO2_DIV(divider);
1121 }
1122
1123 CCM->CCOSR = tmp32;
1124 }
1125
1126 /*!
1127 * brief Get the frequency of clock output1 clock signal.
1128 *
1129 * return The frequency of clock output1 clock signal.
1130 */
CLOCK_GetClockOutCLKO1Freq(void)1131 uint32_t CLOCK_GetClockOutCLKO1Freq(void)
1132 {
1133 uint32_t freq = 0U;
1134 uint32_t tmp32;
1135
1136 tmp32 = CCM->CCOSR;
1137
1138 if ((tmp32 & CCM_CCOSR_CLKO1_EN_MASK) != 0UL)
1139 {
1140 switch ((tmp32 & CCM_CCOSR_CLKO1_SEL_MASK) >> CCM_CCOSR_CLKO1_SEL_SHIFT)
1141 {
1142 case (uint32_t)kCLOCK_OutputPllUsb1Sw:
1143 freq = CLOCK_GetPllUsb1SWFreq() / 2UL;
1144 break;
1145 case (uint32_t)kCLOCK_OutputPllSys:
1146 freq = CLOCK_GetPllFreq(kCLOCK_PllSys) / 2UL;
1147 break;
1148 case (uint32_t)kCLOCK_OutputPllENET500M:
1149 freq = CLOCK_GetPllFreq(kCLOCK_PllEnet500M) / 2UL;
1150 break;
1151 case (uint32_t)kCLOCK_OutputSemcClk:
1152 freq = CLOCK_GetSemcFreq();
1153 break;
1154 case (uint32_t)kCLOCK_OutputAhbClk:
1155 freq = CLOCK_GetAhbFreq();
1156 break;
1157 case (uint32_t)kCLOCK_OutputIpgClk:
1158 freq = CLOCK_GetIpgFreq();
1159 break;
1160 case (uint32_t)kCLOCK_OutputPerClk:
1161 freq = CLOCK_GetPerClkFreq();
1162 break;
1163 case (uint32_t)kCLOCK_OutputPll4MainClk:
1164 freq = CLOCK_GetPllFreq(kCLOCK_PllAudio);
1165 break;
1166 default:
1167 /* This branch should never be hit. */
1168 break;
1169 }
1170
1171 freq /= (((tmp32 & CCM_CCOSR_CLKO1_DIV_MASK) >> CCM_CCOSR_CLKO1_DIV_SHIFT) + 1U);
1172 }
1173 else
1174 {
1175 freq = 0UL;
1176 }
1177
1178 return freq;
1179 }
1180
1181 /*!
1182 * brief Get the frequency of clock output2 clock signal.
1183 *
1184 * return The frequency of clock output2 clock signal.
1185 */
CLOCK_GetClockOutClkO2Freq(void)1186 uint32_t CLOCK_GetClockOutClkO2Freq(void)
1187 {
1188 uint32_t freq = 0U;
1189 uint32_t tmp32;
1190
1191 tmp32 = CCM->CCOSR;
1192
1193 if ((tmp32 & CCM_CCOSR_CLKO2_EN_MASK) != 0UL)
1194 {
1195 switch ((tmp32 & CCM_CCOSR_CLKO2_SEL_MASK) >> CCM_CCOSR_CLKO2_SEL_SHIFT)
1196 {
1197 case (uint32_t)kCLOCK_OutputUsdhc1Clk:
1198 freq = CLOCK_GetClockRootFreq(kCLOCK_Usdhc1ClkRoot);
1199 break;
1200 case (uint32_t)kCLOCK_OutputLpi2cClk:
1201 freq = CLOCK_GetClockRootFreq(kCLOCK_Lpi2cClkRoot);
1202 break;
1203 case (uint32_t)kCLOCK_OutputOscClk:
1204 freq = CLOCK_GetOscFreq();
1205 break;
1206 case (uint32_t)kCLOCK_OutputLpspiClk:
1207 freq = CLOCK_GetClockRootFreq(kCLOCK_LpspiClkRoot);
1208 break;
1209 case (uint32_t)kCLOCK_OutputUsdhc2Clk:
1210 freq = CLOCK_GetClockRootFreq(kCLOCK_Usdhc2ClkRoot);
1211 break;
1212 case (uint32_t)kCLOCK_OutputSai1Clk:
1213 freq = CLOCK_GetClockRootFreq(kCLOCK_Sai1ClkRoot);
1214 break;
1215 case (uint32_t)kCLOCK_OutputSai2Clk:
1216 freq = CLOCK_GetClockRootFreq(kCLOCK_Sai2ClkRoot);
1217 break;
1218 case (uint32_t)kCLOCK_OutputSai3Clk:
1219 freq = CLOCK_GetClockRootFreq(kCLOCK_Sai3ClkRoot);
1220 break;
1221 case (uint32_t)kCLOCK_OutputTraceClk:
1222 freq = CLOCK_GetClockRootFreq(kCLOCK_TraceClkRoot);
1223 break;
1224 case (uint32_t)kCLOCK_OutputCanClk:
1225 freq = CLOCK_GetClockRootFreq(kCLOCK_CanClkRoot);
1226 break;
1227 case (uint32_t)kCLOCK_OutputFlexspiClk:
1228 freq = CLOCK_GetClockRootFreq(kCLOCK_FlexspiClkRoot);
1229 break;
1230 case (uint32_t)kCLOCK_OutputUartClk:
1231 freq = CLOCK_GetClockRootFreq(kCLOCK_UartClkRoot);
1232 break;
1233 case (uint32_t)kCLOCK_OutputSpdif0Clk:
1234 freq = CLOCK_GetClockRootFreq(kCLOCK_SpdifClkRoot);
1235 break;
1236 default:
1237 /* This branch should never be hit. */
1238 break;
1239 }
1240
1241 freq /= (((tmp32 & CCM_CCOSR_CLKO2_DIV_MASK) >> CCM_CCOSR_CLKO2_DIV_SHIFT) + 1U);
1242 }
1243 else
1244 {
1245 freq = 0UL;
1246 }
1247
1248 return freq;
1249 }
1250