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