diff options
Diffstat (limited to 'lib/chibios-contrib/ext/mcux-sdk/devices/LPC55S14/drivers/fsl_clock.c')
-rw-r--r-- | lib/chibios-contrib/ext/mcux-sdk/devices/LPC55S14/drivers/fsl_clock.c | 2154 |
1 files changed, 2154 insertions, 0 deletions
diff --git a/lib/chibios-contrib/ext/mcux-sdk/devices/LPC55S14/drivers/fsl_clock.c b/lib/chibios-contrib/ext/mcux-sdk/devices/LPC55S14/drivers/fsl_clock.c new file mode 100644 index 000000000..e04a78d8b --- /dev/null +++ b/lib/chibios-contrib/ext/mcux-sdk/devices/LPC55S14/drivers/fsl_clock.c | |||
@@ -0,0 +1,2154 @@ | |||
1 | /* | ||
2 | * Copyright 2017 - 2020 , NXP | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * SPDX-License-Identifier: BSD-3-Clause | ||
6 | */ | ||
7 | |||
8 | #include "fsl_clock.h" | ||
9 | #include "fsl_power.h" | ||
10 | /******************************************************************************* | ||
11 | * Definitions | ||
12 | ******************************************************************************/ | ||
13 | /* Component ID definition, used by tools. */ | ||
14 | #ifndef FSL_COMPONENT_ID | ||
15 | #define FSL_COMPONENT_ID "platform.drivers.clock" | ||
16 | #endif | ||
17 | #define NVALMAX (0x100U) | ||
18 | #define PVALMAX (0x20U) | ||
19 | #define MVALMAX (0x10000U) | ||
20 | |||
21 | #define PLL_MAX_N_DIV 0x100U | ||
22 | |||
23 | /*-------------------------------------------------------------------------- | ||
24 | !!! If required these #defines can be moved to chip library file | ||
25 | ----------------------------------------------------------------------------*/ | ||
26 | |||
27 | #define PLL_SSCG1_MDEC_VAL_P (10U) /* MDEC is in bits 25 downto 10 */ | ||
28 | #define PLL_SSCG1_MDEC_VAL_M (0xFFFFULL << PLL_SSCG1_MDEC_VAL_P) | ||
29 | #define PLL_NDEC_VAL_P (0U) /* NDEC is in bits 9:0 */ | ||
30 | #define PLL_NDEC_VAL_M (0xFFUL << PLL_NDEC_VAL_P) | ||
31 | #define PLL_PDEC_VAL_P (0U) /*!< PDEC is in bits 6:0 */ | ||
32 | #define PLL_PDEC_VAL_M (0x1FUL << PLL_PDEC_VAL_P) | ||
33 | |||
34 | #define PLL_MIN_CCO_FREQ_MHZ (275000000U) | ||
35 | #define PLL_MAX_CCO_FREQ_MHZ (550000000U) | ||
36 | #define PLL_LOWER_IN_LIMIT (2000U) /*!< Minimum PLL input rate */ | ||
37 | #define PLL_HIGHER_IN_LIMIT (150000000U) /*!< Maximum PLL input rate */ | ||
38 | #define PLL_MIN_IN_SSMODE (3000000U) | ||
39 | #define PLL_MAX_IN_SSMODE \ | ||
40 | (100000000U) /*!< Not find the value in UM, Just use the maximum frequency which device support */ | ||
41 | |||
42 | /* PLL NDEC reg */ | ||
43 | #define PLL_NDEC_VAL_SET(value) (((unsigned long)(value) << PLL_NDEC_VAL_P) & PLL_NDEC_VAL_M) | ||
44 | /* PLL PDEC reg */ | ||
45 | #define PLL_PDEC_VAL_SET(value) (((unsigned long)(value) << PLL_PDEC_VAL_P) & PLL_PDEC_VAL_M) | ||
46 | /* SSCG control1 */ | ||
47 | #define PLL_SSCG1_MDEC_VAL_SET(value) (((uint64_t)(value) << PLL_SSCG1_MDEC_VAL_P) & PLL_SSCG1_MDEC_VAL_M) | ||
48 | |||
49 | /* PLL0 SSCG control1 */ | ||
50 | #define PLL0_SSCG_MD_FRACT_P 0U | ||
51 | #define PLL0_SSCG_MD_INT_P 25U | ||
52 | #define PLL0_SSCG_MD_FRACT_M (0x1FFFFFFUL << PLL0_SSCG_MD_FRACT_P) | ||
53 | #define PLL0_SSCG_MD_INT_M ((uint64_t)0xFFUL << PLL0_SSCG_MD_INT_P) | ||
54 | |||
55 | #define PLL0_SSCG_MD_FRACT_SET(value) (((uint64_t)(value) << PLL0_SSCG_MD_FRACT_P) & PLL0_SSCG_MD_FRACT_M) | ||
56 | #define PLL0_SSCG_MD_INT_SET(value) (((uint64_t)(value) << PLL0_SSCG_MD_INT_P) & PLL0_SSCG_MD_INT_M) | ||
57 | |||
58 | /* Saved value of PLL output rate, computed whenever needed to save run-time | ||
59 | computation on each call to retrive the PLL rate. */ | ||
60 | static uint32_t s_Pll0_Freq; | ||
61 | static uint32_t s_Pll1_Freq; | ||
62 | |||
63 | /** External clock rate on the CLKIN pin in Hz. If not used, | ||
64 | set this to 0. Otherwise, set it to the exact rate in Hz this pin is | ||
65 | being driven at. */ | ||
66 | static uint32_t s_Ext_Clk_Freq = 16000000U; | ||
67 | static uint32_t s_I2S_Mclk_Freq = 0U; | ||
68 | static uint32_t s_PLU_ClkIn_Freq = 0U; | ||
69 | |||
70 | /******************************************************************************* | ||
71 | * Variables | ||
72 | ******************************************************************************/ | ||
73 | |||
74 | /******************************************************************************* | ||
75 | * Prototypes | ||
76 | ******************************************************************************/ | ||
77 | /* Find SELP, SELI, and SELR values for raw M value, max M = MVALMAX */ | ||
78 | static void pllFindSel(uint32_t M, uint32_t *pSelP, uint32_t *pSelI, uint32_t *pSelR); | ||
79 | /* Get predivider (N) from PLL0 NDEC setting */ | ||
80 | static uint32_t findPll0PreDiv(void); | ||
81 | /* Get predivider (N) from PLL1 NDEC setting */ | ||
82 | static uint32_t findPll1PreDiv(void); | ||
83 | /* Get postdivider (P) from PLL0 PDEC setting */ | ||
84 | static uint32_t findPll0PostDiv(void); | ||
85 | /* Get postdivider (P) from PLL1 PDEC setting. */ | ||
86 | static uint32_t findPll1PostDiv(void); | ||
87 | /* Get multiplier (M) from PLL0 MDEC and SSCG settings */ | ||
88 | static float findPll0MMult(void); | ||
89 | /* Get multiplier (M) from PLL1 MDEC. */ | ||
90 | static uint32_t findPll1MMult(void); | ||
91 | /* Get the greatest common divisor */ | ||
92 | static uint32_t FindGreatestCommonDivisor(uint32_t m, uint32_t n); | ||
93 | /* Set PLL output based on desired output rate */ | ||
94 | static pll_error_t CLOCK_GetPll0Config(uint32_t finHz, uint32_t foutHz, pll_setup_t *pSetup, bool useSS); | ||
95 | /* Update local PLL rate variable */ | ||
96 | static void CLOCK_GetPLL0OutFromSetupUpdate(pll_setup_t *pSetup); | ||
97 | /* Update local PLL1 rate variable */ | ||
98 | static void CLOCK_GetPLL1OutFromSetupUpdate(pll_setup_t *pSetup); | ||
99 | |||
100 | /******************************************************************************* | ||
101 | * Code | ||
102 | ******************************************************************************/ | ||
103 | |||
104 | /* Clock Selection for IP */ | ||
105 | /** | ||
106 | * brief Configure the clock selection muxes. | ||
107 | * param connection : Clock to be configured. | ||
108 | * return Nothing | ||
109 | */ | ||
110 | void CLOCK_AttachClk(clock_attach_id_t connection) | ||
111 | { | ||
112 | uint8_t mux; | ||
113 | uint8_t sel; | ||
114 | uint16_t item; | ||
115 | uint32_t tmp32 = (uint32_t)connection; | ||
116 | uint32_t i; | ||
117 | volatile uint32_t *pClkSel; | ||
118 | |||
119 | pClkSel = &(SYSCON->SYSTICKCLKSELX[0]); | ||
120 | |||
121 | if (kNONE_to_NONE != connection) | ||
122 | { | ||
123 | for (i = 0U; i < 2U; i++) | ||
124 | { | ||
125 | if (tmp32 == 0U) | ||
126 | { | ||
127 | break; | ||
128 | } | ||
129 | item = (uint16_t)GET_ID_ITEM(tmp32); | ||
130 | if (item != 0U) | ||
131 | { | ||
132 | mux = (uint8_t)GET_ID_ITEM_MUX(item); | ||
133 | sel = (uint8_t)GET_ID_ITEM_SEL(item); | ||
134 | if (mux == CM_RTCOSC32KCLKSEL) | ||
135 | { | ||
136 | PMC->RTCOSC32K = (PMC->RTCOSC32K & ~PMC_RTCOSC32K_SEL_MASK) | PMC_RTCOSC32K_SEL(sel); | ||
137 | } | ||
138 | else if (mux == CM_OSTIMERCLKSEL) | ||
139 | { | ||
140 | PMC->OSTIMERr = (PMC->OSTIMERr & ~PMC_OSTIMER_OSTIMERCLKSEL_MASK) | PMC_OSTIMER_OSTIMERCLKSEL(sel); | ||
141 | } | ||
142 | else | ||
143 | { | ||
144 | pClkSel[mux] = sel; | ||
145 | } | ||
146 | } | ||
147 | tmp32 = GET_ID_NEXT_ITEM(tmp32); /* pick up next descriptor */ | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | |||
152 | /* Return the actual clock attach id */ | ||
153 | /** | ||
154 | * brief Get the actual clock attach id. | ||
155 | * This fuction uses the offset in input attach id, then it reads the actual source value in | ||
156 | * the register and combine the offset to obtain an actual attach id. | ||
157 | * param attachId : Clock attach id to get. | ||
158 | * return Clock source value. | ||
159 | */ | ||
160 | clock_attach_id_t CLOCK_GetClockAttachId(clock_attach_id_t attachId) | ||
161 | { | ||
162 | uint8_t mux; | ||
163 | uint32_t actualSel; | ||
164 | uint32_t tmp32 = (uint32_t)attachId; | ||
165 | uint32_t i; | ||
166 | uint32_t actualAttachId = 0U; | ||
167 | uint32_t selector = GET_ID_SELECTOR(tmp32); | ||
168 | volatile uint32_t *pClkSel; | ||
169 | |||
170 | pClkSel = &(SYSCON->SYSTICKCLKSELX[0]); | ||
171 | |||
172 | if (kNONE_to_NONE == attachId) | ||
173 | { | ||
174 | return kNONE_to_NONE; | ||
175 | } | ||
176 | |||
177 | for (i = 0U; i < 2U; i++) | ||
178 | { | ||
179 | mux = (uint8_t)GET_ID_ITEM_MUX(tmp32); | ||
180 | if (tmp32 != 0UL) | ||
181 | { | ||
182 | if (mux == CM_RTCOSC32KCLKSEL) | ||
183 | { | ||
184 | actualSel = ((PMC->RTCOSC32K) & PMC_RTCOSC32K_SEL_MASK) >> PMC_RTCOSC32K_SEL_SHIFT; | ||
185 | } | ||
186 | else if (mux == CM_OSTIMERCLKSEL) | ||
187 | { | ||
188 | actualSel = ((PMC->OSTIMERr) & PMC_OSTIMER_OSTIMERCLKSEL_MASK) >> PMC_OSTIMER_OSTIMERCLKSEL_SHIFT; | ||
189 | } | ||
190 | else | ||
191 | { | ||
192 | actualSel = pClkSel[mux]; | ||
193 | } | ||
194 | |||
195 | /* Consider the combination of two registers */ | ||
196 | actualAttachId |= CLK_ATTACH_ID(mux, actualSel, i); | ||
197 | } | ||
198 | tmp32 = GET_ID_NEXT_ITEM(tmp32); /*!< pick up next descriptor */ | ||
199 | } | ||
200 | |||
201 | actualAttachId |= selector; | ||
202 | |||
203 | return (clock_attach_id_t)actualAttachId; | ||
204 | } | ||
205 | |||
206 | /* Set IP Clock Divider */ | ||
207 | /** | ||
208 | * brief Setup peripheral clock dividers. | ||
209 | * param div_name : Clock divider name | ||
210 | * param divided_by_value: Value to be divided | ||
211 | * param reset : Whether to reset the divider counter. | ||
212 | * return Nothing | ||
213 | */ | ||
214 | void CLOCK_SetClkDiv(clock_div_name_t div_name, uint32_t divided_by_value, bool reset) | ||
215 | { | ||
216 | volatile uint32_t *pClkDiv; | ||
217 | |||
218 | pClkDiv = &(SYSCON->SYSTICKCLKDIV0); | ||
219 | if ((div_name >= kCLOCK_DivFlexFrg0) && (div_name <= kCLOCK_DivFlexFrg7)) | ||
220 | { | ||
221 | /*!< Flexcomm Interface function clock = (clock selected via FCCLKSEL) / (1+ MULT /DIV), DIV = 0xFF */ | ||
222 | ((volatile uint32_t *)pClkDiv)[(uint8_t)div_name] = | ||
223 | SYSCON_FLEXFRG0CTRL_DIV_MASK | SYSCON_FLEXFRG0CTRL_MULT(divided_by_value); | ||
224 | } | ||
225 | else | ||
226 | { | ||
227 | if (reset) | ||
228 | { | ||
229 | ((volatile uint32_t *)pClkDiv)[(uint8_t)div_name] = 1UL << 29U; | ||
230 | } | ||
231 | if (divided_by_value == 0U) /*!< halt */ | ||
232 | { | ||
233 | ((volatile uint32_t *)pClkDiv)[(uint8_t)div_name] = 1UL << 30U; | ||
234 | } | ||
235 | else | ||
236 | { | ||
237 | ((volatile uint32_t *)pClkDiv)[(uint8_t)div_name] = (divided_by_value - 1U); | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | |||
242 | /* Set RTC 1KHz Clock Divider */ | ||
243 | /** | ||
244 | * brief Setup rtc 1khz clock divider. | ||
245 | * param divided_by_value: Value to be divided | ||
246 | * return Nothing | ||
247 | */ | ||
248 | void CLOCK_SetRtc1khzClkDiv(uint32_t divided_by_value) | ||
249 | { | ||
250 | PMC->RTCOSC32K = | ||
251 | (PMC->RTCOSC32K & ~PMC_RTCOSC32K_CLK1KHZDIV_MASK) | PMC_RTCOSC32K_CLK1KHZDIV(divided_by_value - 28U); | ||
252 | } | ||
253 | |||
254 | /* Set RTC 1KHz Clock Divider */ | ||
255 | /** | ||
256 | * brief Setup rtc 1hz clock divider. | ||
257 | * param divided_by_value: Value to be divided | ||
258 | * return Nothing | ||
259 | */ | ||
260 | void CLOCK_SetRtc1hzClkDiv(uint32_t divided_by_value) | ||
261 | { | ||
262 | if (divided_by_value == 0U) /*!< halt */ | ||
263 | { | ||
264 | PMC->RTCOSC32K |= (1UL << PMC_RTCOSC32K_CLK1HZDIVHALT_SHIFT); | ||
265 | } | ||
266 | else | ||
267 | { | ||
268 | PMC->RTCOSC32K = | ||
269 | (PMC->RTCOSC32K & ~PMC_RTCOSC32K_CLK1HZDIV_MASK) | PMC_RTCOSC32K_CLK1HZDIV(divided_by_value - 31744U); | ||
270 | } | ||
271 | } | ||
272 | |||
273 | /* Set FRO Clocking */ | ||
274 | /** | ||
275 | * brief Initialize the Core clock to given frequency (12, 48 or 96 MHz). | ||
276 | * Turns on FRO and uses default CCO, if freq is 12000000, then high speed output is off, else high speed output is | ||
277 | * enabled. | ||
278 | * param iFreq : Desired frequency (must be one of #CLK_FRO_12MHZ or #CLK_FRO_48MHZ or #CLK_FRO_96MHZ) | ||
279 | * return returns success or fail status. | ||
280 | */ | ||
281 | status_t CLOCK_SetupFROClocking(uint32_t iFreq) | ||
282 | { | ||
283 | if ((iFreq != 12000000U) && (iFreq != 96000000U)) | ||
284 | { | ||
285 | return kStatus_Fail; | ||
286 | } | ||
287 | /* Enable Analog Control module */ | ||
288 | SYSCON->PRESETCTRLCLR[2] = (1UL << SYSCON_PRESETCTRL2_ANALOG_CTRL_RST_SHIFT); | ||
289 | SYSCON->AHBCLKCTRLSET[2] = SYSCON_AHBCLKCTRL2_ANALOG_CTRL_MASK; | ||
290 | /* Power up the FRO192M */ | ||
291 | POWER_DisablePD(kPDRUNCFG_PD_FRO192M); | ||
292 | |||
293 | if (iFreq == 96000000U) | ||
294 | { | ||
295 | ANACTRL->FRO192M_CTRL |= ANACTRL_FRO192M_CTRL_ENA_96MHZCLK(1); | ||
296 | } | ||
297 | /* always enable | ||
298 | else if (iFreq == 48000000U) | ||
299 | { | ||
300 | ANACTRL->FRO192M_CTRL |= ANACTRL_FRO192M_CTRL_ENA_48MHZCLK(1); | ||
301 | }*/ | ||
302 | else | ||
303 | { | ||
304 | ANACTRL->FRO192M_CTRL |= ANACTRL_FRO192M_CTRL_ENA_12MHZCLK(1); | ||
305 | } | ||
306 | return kStatus_Success; | ||
307 | } | ||
308 | |||
309 | /* Set the FLASH wait states for the passed frequency */ | ||
310 | /** | ||
311 | * brief Set the flash wait states for the input freuqency. | ||
312 | * param iFreq: Input frequency | ||
313 | * return Nothing | ||
314 | */ | ||
315 | typedef struct | ||
316 | { | ||
317 | uint32_t waitstate; | ||
318 | uint32_t freqMax; | ||
319 | } WaitStateInterval_t; | ||
320 | |||
321 | /* Wait state if frequency is inferior to the one specified */ | ||
322 | static const WaitStateInterval_t IntervalList[] = { | ||
323 | {0, 11000000}, {1, 22000000}, {2, 33000000}, {3, 44000000}, {4, 55000000}, {5, 66000000}, {6, 84000000}, | ||
324 | {7, 104000000}, {8, 119000000}, {9, 129000000}, {10, 144000000}, {11, 150000000} /* Maximum allowed frequency (150 | ||
325 | MHz) */ | ||
326 | }; | ||
327 | |||
328 | void CLOCK_SetFLASHAccessCyclesForFreq(uint32_t system_freq_hz) | ||
329 | { | ||
330 | /* Flash Controller & FMC internal number of Wait States (minus 1) */ | ||
331 | uint32_t num_wait_states = 15UL; /* Default to the maximum number of wait states */ | ||
332 | |||
333 | for (size_t cnt = 0; cnt < (sizeof(IntervalList) / sizeof(WaitStateInterval_t)); cnt++) | ||
334 | { | ||
335 | if (system_freq_hz <= IntervalList[cnt].freqMax) | ||
336 | { | ||
337 | num_wait_states = IntervalList[cnt].waitstate; | ||
338 | break; | ||
339 | } | ||
340 | } | ||
341 | |||
342 | FLASH->INT_CLR_STATUS = 0x1F; /* Clear all status flags */ | ||
343 | |||
344 | FLASH->DATAW[0] = (FLASH->DATAW[0] & 0xFFFFFFF0UL) | | ||
345 | (num_wait_states & (SYSCON_FMCCR_FLASHTIM_MASK >> SYSCON_FMCCR_FLASHTIM_SHIFT)); | ||
346 | |||
347 | FLASH->CMD = 0x2; /* CMD_SET_READ_MODE */ | ||
348 | |||
349 | /* Wait until the cmd is completed (without error) */ | ||
350 | while ((FLASH->INT_STATUS & FLASH_INT_STATUS_DONE_MASK) == 0UL) | ||
351 | { | ||
352 | } | ||
353 | |||
354 | /* Adjust FMC waiting time cycles (num_wait_states) */ | ||
355 | SYSCON->FMCCR = (SYSCON->FMCCR & ~SYSCON_FMCCR_FLASHTIM_MASK) | | ||
356 | ((num_wait_states << SYSCON_FMCCR_FLASHTIM_SHIFT) & SYSCON_FMCCR_FLASHTIM_MASK); | ||
357 | } | ||
358 | |||
359 | /* Set EXT OSC Clk */ | ||
360 | /** | ||
361 | * brief Initialize the external osc clock to given frequency. | ||
362 | * param iFreq : Desired frequency (must be equal to exact rate in Hz) | ||
363 | * return returns success or fail status. | ||
364 | */ | ||
365 | status_t CLOCK_SetupExtClocking(uint32_t iFreq) | ||
366 | { | ||
367 | if (iFreq >= 32000000U) | ||
368 | { | ||
369 | return kStatus_Fail; | ||
370 | } | ||
371 | /* Turn on power for crystal 32 MHz */ | ||
372 | POWER_DisablePD(kPDRUNCFG_PD_XTAL32M); | ||
373 | POWER_DisablePD(kPDRUNCFG_PD_LDOXO32M); | ||
374 | /* Enable clock_in clock for clock module. */ | ||
375 | SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK; | ||
376 | |||
377 | s_Ext_Clk_Freq = iFreq; | ||
378 | return kStatus_Success; | ||
379 | } | ||
380 | |||
381 | /* Set I2S MCLK Clk */ | ||
382 | /** | ||
383 | * brief Initialize the I2S MCLK clock to given frequency. | ||
384 | * param iFreq : Desired frequency (must be equal to exact rate in Hz) | ||
385 | * return returns success or fail status. | ||
386 | */ | ||
387 | status_t CLOCK_SetupI2SMClkClocking(uint32_t iFreq) | ||
388 | { | ||
389 | s_I2S_Mclk_Freq = iFreq; | ||
390 | return kStatus_Success; | ||
391 | } | ||
392 | |||
393 | /* Set PLU CLKIN Clk */ | ||
394 | /** | ||
395 | * brief Initialize the PLU CLKIN clock to given frequency. | ||
396 | * param iFreq : Desired frequency (must be equal to exact rate in Hz) | ||
397 | * return returns success or fail status. | ||
398 | */ | ||
399 | status_t CLOCK_SetupPLUClkInClocking(uint32_t iFreq) | ||
400 | { | ||
401 | s_PLU_ClkIn_Freq = iFreq; | ||
402 | return kStatus_Success; | ||
403 | } | ||
404 | |||
405 | /* Get CLOCK OUT Clk */ | ||
406 | /*! brief Return Frequency of ClockOut | ||
407 | * return Frequency of ClockOut | ||
408 | */ | ||
409 | uint32_t CLOCK_GetClockOutClkFreq(void) | ||
410 | { | ||
411 | uint32_t freq = 0U; | ||
412 | |||
413 | switch (SYSCON->CLKOUTSEL) | ||
414 | { | ||
415 | case 0U: | ||
416 | freq = CLOCK_GetCoreSysClkFreq(); | ||
417 | break; | ||
418 | |||
419 | case 1U: | ||
420 | freq = CLOCK_GetPll0OutFreq(); | ||
421 | break; | ||
422 | |||
423 | case 2U: | ||
424 | freq = CLOCK_GetExtClkFreq(); | ||
425 | break; | ||
426 | |||
427 | case 3U: | ||
428 | freq = CLOCK_GetFroHfFreq(); | ||
429 | break; | ||
430 | |||
431 | case 4U: | ||
432 | freq = CLOCK_GetFro1MFreq(); | ||
433 | break; | ||
434 | |||
435 | case 5U: | ||
436 | freq = CLOCK_GetPll1OutFreq(); | ||
437 | break; | ||
438 | |||
439 | case 6U: | ||
440 | freq = CLOCK_GetOsc32KFreq(); | ||
441 | break; | ||
442 | |||
443 | case 7U: | ||
444 | freq = 0U; | ||
445 | break; | ||
446 | |||
447 | default: | ||
448 | freq = 0U; | ||
449 | break; | ||
450 | } | ||
451 | return freq / ((SYSCON->CLKOUTDIV & 0xffU) + 1U); | ||
452 | } | ||
453 | |||
454 | /* Get CAN Clk */ | ||
455 | /*! brief Return Frequency of Can Clock | ||
456 | * return Frequency of Can. | ||
457 | */ | ||
458 | uint32_t CLOCK_GetMCanClkFreq(void) | ||
459 | { | ||
460 | uint32_t freq = 0U; | ||
461 | |||
462 | switch (SYSCON->CANCLKSEL) | ||
463 | { | ||
464 | case 0U: | ||
465 | freq = CLOCK_GetCoreSysClkFreq() / ((SYSCON->CANCLKDIV & SYSCON_CANCLKDIV_DIV_MASK) + 1U); | ||
466 | break; | ||
467 | case 1U: | ||
468 | freq = CLOCK_GetFro1MFreq(); | ||
469 | break; | ||
470 | case 2U: | ||
471 | freq = CLOCK_GetOsc32KFreq(); | ||
472 | break; | ||
473 | case 7U: | ||
474 | freq = 0U; | ||
475 | break; | ||
476 | |||
477 | default: | ||
478 | freq = 0U; | ||
479 | break; | ||
480 | } | ||
481 | |||
482 | return freq; | ||
483 | } | ||
484 | |||
485 | /* Get ADC Clk */ | ||
486 | /*! brief Return Frequency of Adc Clock | ||
487 | * return Frequency of Adc. | ||
488 | */ | ||
489 | uint32_t CLOCK_GetAdcClkFreq(void) | ||
490 | { | ||
491 | uint32_t freq = 0U; | ||
492 | |||
493 | switch (SYSCON->ADCCLKSEL) | ||
494 | { | ||
495 | case 0U: | ||
496 | freq = CLOCK_GetCoreSysClkFreq(); | ||
497 | break; | ||
498 | case 1U: | ||
499 | freq = CLOCK_GetPll0OutFreq(); | ||
500 | break; | ||
501 | case 2U: | ||
502 | freq = CLOCK_GetFroHfFreq(); | ||
503 | break; | ||
504 | case 7U: | ||
505 | freq = 0U; | ||
506 | break; | ||
507 | |||
508 | default: | ||
509 | freq = 0U; | ||
510 | break; | ||
511 | } | ||
512 | |||
513 | return freq / ((SYSCON->ADCCLKDIV & SYSCON_ADCCLKDIV_DIV_MASK) + 1U); | ||
514 | } | ||
515 | |||
516 | /* Get USB0 Clk */ | ||
517 | /*! brief Return Frequency of Usb0 Clock | ||
518 | * return Frequency of Usb0 Clock. | ||
519 | */ | ||
520 | uint32_t CLOCK_GetUsb0ClkFreq(void) | ||
521 | { | ||
522 | uint32_t freq = 0U; | ||
523 | |||
524 | switch (SYSCON->USB0CLKSEL) | ||
525 | { | ||
526 | case 0U: | ||
527 | freq = CLOCK_GetCoreSysClkFreq(); | ||
528 | break; | ||
529 | case 1U: | ||
530 | freq = CLOCK_GetPll0OutFreq(); | ||
531 | break; | ||
532 | case 3U: | ||
533 | freq = CLOCK_GetFroHfFreq(); | ||
534 | break; | ||
535 | case 5U: | ||
536 | freq = CLOCK_GetPll1OutFreq(); | ||
537 | break; | ||
538 | case 7U: | ||
539 | freq = 0U; | ||
540 | break; | ||
541 | |||
542 | default: | ||
543 | freq = 0U; | ||
544 | break; | ||
545 | } | ||
546 | |||
547 | return freq / ((SYSCON->USB0CLKDIV & 0xffU) + 1U); | ||
548 | } | ||
549 | |||
550 | /* Get USB1 Clk */ | ||
551 | /*! brief Return Frequency of Usb1 Clock | ||
552 | * return Frequency of Usb1 Clock. | ||
553 | */ | ||
554 | uint32_t CLOCK_GetUsb1ClkFreq(void) | ||
555 | { | ||
556 | return ((ANACTRL->XO32M_CTRL & ANACTRL_XO32M_CTRL_ENABLE_PLL_USB_OUT_MASK) != 0UL) ? s_Ext_Clk_Freq : 0U; | ||
557 | } | ||
558 | |||
559 | /* Get MCLK Clk */ | ||
560 | /*! brief Return Frequency of MClk Clock | ||
561 | * return Frequency of MClk Clock. | ||
562 | */ | ||
563 | uint32_t CLOCK_GetMclkClkFreq(void) | ||
564 | { | ||
565 | uint32_t freq = 0U; | ||
566 | |||
567 | switch (SYSCON->MCLKCLKSEL) | ||
568 | { | ||
569 | case 0U: | ||
570 | freq = CLOCK_GetFroHfFreq(); | ||
571 | break; | ||
572 | case 1U: | ||
573 | freq = CLOCK_GetPll0OutFreq(); | ||
574 | break; | ||
575 | case 7U: | ||
576 | freq = 0U; | ||
577 | break; | ||
578 | |||
579 | default: | ||
580 | freq = 0U; | ||
581 | break; | ||
582 | } | ||
583 | |||
584 | return freq / ((SYSCON->MCLKDIV & 0xffU) + 1U); | ||
585 | } | ||
586 | |||
587 | /* Get SCTIMER Clk */ | ||
588 | /*! brief Return Frequency of SCTimer Clock | ||
589 | * return Frequency of SCTimer Clock. | ||
590 | */ | ||
591 | uint32_t CLOCK_GetSctClkFreq(void) | ||
592 | { | ||
593 | uint32_t freq = 0U; | ||
594 | |||
595 | switch (SYSCON->SCTCLKSEL) | ||
596 | { | ||
597 | case 0U: | ||
598 | freq = CLOCK_GetCoreSysClkFreq(); | ||
599 | break; | ||
600 | case 1U: | ||
601 | freq = CLOCK_GetPll0OutFreq(); | ||
602 | break; | ||
603 | case 2U: | ||
604 | freq = CLOCK_GetExtClkFreq(); | ||
605 | break; | ||
606 | case 3U: | ||
607 | freq = CLOCK_GetFroHfFreq(); | ||
608 | break; | ||
609 | case 5U: | ||
610 | freq = CLOCK_GetI2SMClkFreq(); | ||
611 | break; | ||
612 | case 7U: | ||
613 | freq = 0U; | ||
614 | break; | ||
615 | |||
616 | default: | ||
617 | freq = 0U; | ||
618 | break; | ||
619 | } | ||
620 | |||
621 | return freq / ((SYSCON->SCTCLKDIV & 0xffU) + 1U); | ||
622 | } | ||
623 | |||
624 | /* Get FRO 12M Clk */ | ||
625 | /*! brief Return Frequency of FRO 12MHz | ||
626 | * return Frequency of FRO 12MHz | ||
627 | */ | ||
628 | uint32_t CLOCK_GetFro12MFreq(void) | ||
629 | { | ||
630 | return ((ANACTRL->FRO192M_CTRL & ANACTRL_FRO192M_CTRL_ENA_12MHZCLK_MASK) != 0UL) ? 12000000U : 0U; | ||
631 | } | ||
632 | |||
633 | /* Get FRO 1M Clk */ | ||
634 | /*! brief Return Frequency of FRO 1MHz | ||
635 | * return Frequency of FRO 1MHz | ||
636 | */ | ||
637 | uint32_t CLOCK_GetFro1MFreq(void) | ||
638 | { | ||
639 | return ((SYSCON->CLOCK_CTRL & SYSCON_CLOCK_CTRL_FRO1MHZ_CLK_ENA_MASK) != 0UL) ? 1000000U : 0U; | ||
640 | } | ||
641 | |||
642 | /* Get EXT OSC Clk */ | ||
643 | /*! brief Return Frequency of External Clock | ||
644 | * return Frequency of External Clock. If no external clock is used returns 0. | ||
645 | */ | ||
646 | uint32_t CLOCK_GetExtClkFreq(void) | ||
647 | { | ||
648 | return ((ANACTRL->XO32M_CTRL & ANACTRL_XO32M_CTRL_ENABLE_SYSTEM_CLK_OUT_MASK) != 0UL) ? s_Ext_Clk_Freq : 0U; | ||
649 | } | ||
650 | |||
651 | /* Get WATCH DOG Clk */ | ||
652 | /*! brief Return Frequency of Watchdog | ||
653 | * return Frequency of Watchdog | ||
654 | */ | ||
655 | uint32_t CLOCK_GetWdtClkFreq(void) | ||
656 | { | ||
657 | return CLOCK_GetFro1MFreq() / ((SYSCON->WDTCLKDIV & SYSCON_WDTCLKDIV_DIV_MASK) + 1U); | ||
658 | } | ||
659 | |||
660 | /* Get HF FRO Clk */ | ||
661 | /*! brief Return Frequency of High-Freq output of FRO | ||
662 | * return Frequency of High-Freq output of FRO | ||
663 | */ | ||
664 | uint32_t CLOCK_GetFroHfFreq(void) | ||
665 | { | ||
666 | return ((ANACTRL->FRO192M_CTRL & ANACTRL_FRO192M_CTRL_ENA_96MHZCLK_MASK) != 0UL) ? 96000000U : 0U; | ||
667 | } | ||
668 | |||
669 | /* Get SYSTEM PLL Clk */ | ||
670 | /*! brief Return Frequency of PLL | ||
671 | * return Frequency of PLL | ||
672 | */ | ||
673 | uint32_t CLOCK_GetPll0OutFreq(void) | ||
674 | { | ||
675 | return s_Pll0_Freq; | ||
676 | } | ||
677 | |||
678 | /* Get USB PLL Clk */ | ||
679 | /*! brief Return Frequency of USB PLL | ||
680 | * return Frequency of PLL | ||
681 | */ | ||
682 | uint32_t CLOCK_GetPll1OutFreq(void) | ||
683 | { | ||
684 | return s_Pll1_Freq; | ||
685 | } | ||
686 | |||
687 | /* Get RTC OSC Clk */ | ||
688 | /*! brief Return Frequency of 32kHz osc | ||
689 | * return Frequency of 32kHz osc | ||
690 | */ | ||
691 | uint32_t CLOCK_GetOsc32KFreq(void) | ||
692 | { | ||
693 | return ((0UL == (PMC->PDRUNCFG0 & PMC_PDRUNCFG0_PDEN_FRO32K_MASK)) && | ||
694 | (0UL == (PMC->RTCOSC32K & PMC_RTCOSC32K_SEL_MASK))) ? | ||
695 | CLK_RTC_32K_CLK : | ||
696 | ((0UL == (PMC->PDRUNCFG0 & PMC_PDRUNCFG0_PDEN_XTAL32K_MASK)) && | ||
697 | ((PMC->RTCOSC32K & PMC_RTCOSC32K_SEL_MASK) != 0UL)) ? | ||
698 | CLK_RTC_32K_CLK : | ||
699 | 0UL; | ||
700 | } | ||
701 | |||
702 | /* Get MAIN Clk */ | ||
703 | /*! brief Return Frequency of Core System | ||
704 | * return Frequency of Core System | ||
705 | */ | ||
706 | uint32_t CLOCK_GetCoreSysClkFreq(void) | ||
707 | { | ||
708 | uint32_t freq = 0U; | ||
709 | |||
710 | switch (SYSCON->MAINCLKSELB) | ||
711 | { | ||
712 | case 0U: | ||
713 | if (SYSCON->MAINCLKSELA == 0U) | ||
714 | { | ||
715 | freq = CLOCK_GetFro12MFreq(); | ||
716 | } | ||
717 | else if (SYSCON->MAINCLKSELA == 1U) | ||
718 | { | ||
719 | freq = CLOCK_GetExtClkFreq(); | ||
720 | } | ||
721 | else if (SYSCON->MAINCLKSELA == 2U) | ||
722 | { | ||
723 | freq = CLOCK_GetFro1MFreq(); | ||
724 | } | ||
725 | else if (SYSCON->MAINCLKSELA == 3U) | ||
726 | { | ||
727 | freq = CLOCK_GetFroHfFreq(); | ||
728 | } | ||
729 | else | ||
730 | { | ||
731 | /* Added comments to avoid the violation of MISRA C-2012 rule 15.7 */ | ||
732 | } | ||
733 | break; | ||
734 | case 1U: | ||
735 | freq = CLOCK_GetPll0OutFreq(); | ||
736 | break; | ||
737 | case 2U: | ||
738 | freq = CLOCK_GetPll1OutFreq(); | ||
739 | break; | ||
740 | |||
741 | case 3U: | ||
742 | freq = CLOCK_GetOsc32KFreq(); | ||
743 | break; | ||
744 | |||
745 | default: | ||
746 | freq = 0U; | ||
747 | break; | ||
748 | } | ||
749 | |||
750 | return freq; | ||
751 | } | ||
752 | |||
753 | /* Get I2S MCLK Clk */ | ||
754 | /*! brief Return Frequency of I2S MCLK Clock | ||
755 | * return Frequency of I2S MCLK Clock | ||
756 | */ | ||
757 | uint32_t CLOCK_GetI2SMClkFreq(void) | ||
758 | { | ||
759 | return s_I2S_Mclk_Freq; | ||
760 | } | ||
761 | |||
762 | /* Get PLU CLKIN Clk */ | ||
763 | /*! brief Return Frequency of PLU CLKIN Clock | ||
764 | * return Frequency of PLU CLKIN Clock | ||
765 | */ | ||
766 | uint32_t CLOCK_GetPLUClkInFreq(void) | ||
767 | { | ||
768 | return s_PLU_ClkIn_Freq; | ||
769 | } | ||
770 | |||
771 | /* Get FLEXCOMM input clock */ | ||
772 | /*! brief Return Frequency of flexcomm input clock | ||
773 | * param id : flexcomm instance id | ||
774 | * return Frequency value | ||
775 | */ | ||
776 | uint32_t CLOCK_GetFlexCommInputClock(uint32_t id) | ||
777 | { | ||
778 | uint32_t freq = 0U; | ||
779 | |||
780 | switch (SYSCON->FCCLKSELX[id]) | ||
781 | { | ||
782 | case 0U: | ||
783 | freq = CLOCK_GetCoreSysClkFreq(); | ||
784 | break; | ||
785 | case 1U: | ||
786 | freq = CLOCK_GetPll0OutFreq() / ((SYSCON->PLL0CLKDIV & 0xffU) + 1U); | ||
787 | break; | ||
788 | case 2U: | ||
789 | freq = CLOCK_GetFro12MFreq(); | ||
790 | break; | ||
791 | case 3U: | ||
792 | freq = CLOCK_GetFroHfFreq() / ((SYSCON->FROHFDIV & 0xffU) + 1U); | ||
793 | break; | ||
794 | case 4U: | ||
795 | freq = CLOCK_GetFro1MFreq(); | ||
796 | break; | ||
797 | case 5U: | ||
798 | freq = CLOCK_GetI2SMClkFreq(); | ||
799 | break; | ||
800 | case 6U: | ||
801 | freq = CLOCK_GetOsc32KFreq(); | ||
802 | break; | ||
803 | case 7U: | ||
804 | freq = 0U; | ||
805 | break; | ||
806 | |||
807 | default: | ||
808 | freq = 0U; | ||
809 | break; | ||
810 | } | ||
811 | |||
812 | return freq; | ||
813 | } | ||
814 | |||
815 | /* Get FLEXCOMM Clk */ | ||
816 | uint32_t CLOCK_GetFlexCommClkFreq(uint32_t id) | ||
817 | { | ||
818 | uint32_t freq = 0U; | ||
819 | |||
820 | freq = CLOCK_GetFlexCommInputClock(id); | ||
821 | return freq / (1UL + (SYSCON->FLEXFRGXCTRL[id] & SYSCON_FLEXFRG0CTRL_MULT_MASK) / | ||
822 | ((SYSCON->FLEXFRGXCTRL[id] & SYSCON_FLEXFRG0CTRL_DIV_MASK) + 1UL)); | ||
823 | } | ||
824 | |||
825 | /* Get HS_LPSI Clk */ | ||
826 | uint32_t CLOCK_GetHsLspiClkFreq(void) | ||
827 | { | ||
828 | uint32_t freq = 0U; | ||
829 | |||
830 | switch (SYSCON->HSLSPICLKSEL) | ||
831 | { | ||
832 | case 0U: | ||
833 | freq = CLOCK_GetCoreSysClkFreq(); | ||
834 | break; | ||
835 | case 1U: | ||
836 | freq = CLOCK_GetPll0OutFreq() / ((SYSCON->PLL0CLKDIV & 0xffU) + 1U); | ||
837 | break; | ||
838 | case 2U: | ||
839 | freq = CLOCK_GetFro12MFreq(); | ||
840 | break; | ||
841 | case 3U: | ||
842 | freq = CLOCK_GetFroHfFreq() / ((SYSCON->FROHFDIV & 0xffU) + 1U); | ||
843 | break; | ||
844 | case 4U: | ||
845 | freq = CLOCK_GetFro1MFreq(); | ||
846 | break; | ||
847 | case 6U: | ||
848 | freq = CLOCK_GetOsc32KFreq(); | ||
849 | break; | ||
850 | case 7U: | ||
851 | freq = 0U; | ||
852 | break; | ||
853 | |||
854 | default: | ||
855 | freq = 0U; | ||
856 | break; | ||
857 | } | ||
858 | |||
859 | return freq; | ||
860 | } | ||
861 | |||
862 | /* Get CTimer Clk */ | ||
863 | /*! brief Return Frequency of CTimer functional Clock | ||
864 | * return Frequency of CTimer functional Clock | ||
865 | */ | ||
866 | uint32_t CLOCK_GetCTimerClkFreq(uint32_t id) | ||
867 | { | ||
868 | uint32_t freq = 0U; | ||
869 | |||
870 | switch (SYSCON->CTIMERCLKSELX[id]) | ||
871 | { | ||
872 | case 0U: | ||
873 | freq = CLOCK_GetCoreSysClkFreq(); | ||
874 | break; | ||
875 | case 1U: | ||
876 | freq = CLOCK_GetPll0OutFreq(); | ||
877 | break; | ||
878 | case 3U: | ||
879 | freq = CLOCK_GetFroHfFreq(); | ||
880 | break; | ||
881 | case 4U: | ||
882 | freq = CLOCK_GetFro1MFreq(); | ||
883 | break; | ||
884 | case 5U: | ||
885 | freq = CLOCK_GetI2SMClkFreq(); | ||
886 | break; | ||
887 | case 6U: | ||
888 | freq = CLOCK_GetOsc32KFreq(); | ||
889 | break; | ||
890 | case 7U: | ||
891 | freq = 0U; | ||
892 | break; | ||
893 | |||
894 | default: | ||
895 | freq = 0U; | ||
896 | break; | ||
897 | } | ||
898 | |||
899 | return freq; | ||
900 | } | ||
901 | |||
902 | /* Get Systick Clk */ | ||
903 | /*! brief Return Frequency of SystickClock | ||
904 | * return Frequency of Systick Clock | ||
905 | */ | ||
906 | uint32_t CLOCK_GetSystickClkFreq(uint32_t id) | ||
907 | { | ||
908 | uint32_t freq = 0U; | ||
909 | |||
910 | switch (SYSCON->SYSTICKCLKSELX[id]) | ||
911 | { | ||
912 | case 0U: | ||
913 | /*Niobe4mini just has one SYSTICKSEL and SYSTICKDIV register, Fix coverity problem in this way temporarily | ||
914 | */ | ||
915 | freq = CLOCK_GetCoreSysClkFreq() / (((SYSCON->SYSTICKCLKDIV0) & 0xffU) + 1U); | ||
916 | break; | ||
917 | case 1U: | ||
918 | freq = CLOCK_GetFro1MFreq(); | ||
919 | break; | ||
920 | case 2U: | ||
921 | freq = CLOCK_GetOsc32KFreq(); | ||
922 | break; | ||
923 | case 7U: | ||
924 | freq = 0U; | ||
925 | break; | ||
926 | |||
927 | default: | ||
928 | freq = 0U; | ||
929 | break; | ||
930 | } | ||
931 | |||
932 | return freq; | ||
933 | } | ||
934 | |||
935 | /* Set FlexComm Clock */ | ||
936 | /** | ||
937 | * brief Set the flexcomm output frequency. | ||
938 | * param id : flexcomm instance id | ||
939 | * freq : output frequency | ||
940 | * return 0 : the frequency range is out of range. | ||
941 | * 1 : switch successfully. | ||
942 | */ | ||
943 | uint32_t CLOCK_SetFlexCommClock(uint32_t id, uint32_t freq) | ||
944 | { | ||
945 | uint32_t input = CLOCK_GetFlexCommClkFreq(id); | ||
946 | uint32_t mul; | ||
947 | |||
948 | if ((freq > 48000000UL) || (freq > input) || (input / freq >= 2UL)) | ||
949 | { | ||
950 | /* FRG output frequency should be less than equal to 48MHz */ | ||
951 | return 0UL; | ||
952 | } | ||
953 | else | ||
954 | { | ||
955 | mul = (uint32_t)((((uint64_t)input - freq) * 256ULL) / ((uint64_t)freq)); | ||
956 | SYSCON->FLEXFRGXCTRL[id] = (mul << 8U) | 0xFFU; | ||
957 | return 1UL; | ||
958 | } | ||
959 | } | ||
960 | |||
961 | /* Get IP Clk */ | ||
962 | /*! brief Return Frequency of selected clock | ||
963 | * return Frequency of selected clock | ||
964 | */ | ||
965 | uint32_t CLOCK_GetFreq(clock_name_t clockName) | ||
966 | { | ||
967 | uint32_t freq; | ||
968 | switch (clockName) | ||
969 | { | ||
970 | case kCLOCK_CoreSysClk: | ||
971 | freq = CLOCK_GetCoreSysClkFreq(); | ||
972 | break; | ||
973 | case kCLOCK_BusClk: | ||
974 | freq = CLOCK_GetCoreSysClkFreq() / ((SYSCON->AHBCLKDIV & 0xffU) + 1U); | ||
975 | break; | ||
976 | case kCLOCK_ClockOut: | ||
977 | freq = CLOCK_GetClockOutClkFreq(); | ||
978 | break; | ||
979 | case kCLOCK_Pll1Out: | ||
980 | freq = CLOCK_GetPll1OutFreq(); | ||
981 | break; | ||
982 | case kCLOCK_Mclk: | ||
983 | freq = CLOCK_GetMclkClkFreq(); | ||
984 | break; | ||
985 | case kCLOCK_FroHf: | ||
986 | freq = CLOCK_GetFroHfFreq(); | ||
987 | break; | ||
988 | case kCLOCK_Fro12M: | ||
989 | freq = CLOCK_GetFro12MFreq(); | ||
990 | break; | ||
991 | case kCLOCK_Fro1M: | ||
992 | freq = CLOCK_GetFro1MFreq(); | ||
993 | break; | ||
994 | case kCLOCK_ExtClk: | ||
995 | freq = CLOCK_GetExtClkFreq(); | ||
996 | break; | ||
997 | case kCLOCK_Pll0Out: | ||
998 | freq = CLOCK_GetPll0OutFreq(); | ||
999 | break; | ||
1000 | case kCLOCK_FlexI2S: | ||
1001 | freq = CLOCK_GetI2SMClkFreq(); | ||
1002 | break; | ||
1003 | default: | ||
1004 | freq = 0U; | ||
1005 | break; | ||
1006 | } | ||
1007 | return freq; | ||
1008 | } | ||
1009 | |||
1010 | /* Find SELP, SELI, and SELR values for raw M value, max M = MVALMAX */ | ||
1011 | static void pllFindSel(uint32_t M, uint32_t *pSelP, uint32_t *pSelI, uint32_t *pSelR) | ||
1012 | { | ||
1013 | uint32_t seli, selp; | ||
1014 | /* bandwidth: compute selP from Multiplier */ | ||
1015 | if ((SYSCON->PLL0SSCG1 & SYSCON_PLL0SSCG1_MDIV_EXT_MASK) != 0UL) /* normal mode */ | ||
1016 | { | ||
1017 | selp = (M >> 2U) + 1U; | ||
1018 | if (selp >= 31U) | ||
1019 | { | ||
1020 | selp = 31U; | ||
1021 | } | ||
1022 | *pSelP = selp; | ||
1023 | |||
1024 | if (M >= 8000UL) | ||
1025 | { | ||
1026 | seli = 1UL; | ||
1027 | } | ||
1028 | else if (M >= 122UL) | ||
1029 | { | ||
1030 | seli = (uint32_t)(8000UL / M); /*floor(8000/M) */ | ||
1031 | } | ||
1032 | else | ||
1033 | { | ||
1034 | seli = 2UL * ((uint32_t)(M / 4UL)) + 3UL; /* 2*floor(M/4) + 3 */ | ||
1035 | } | ||
1036 | |||
1037 | if (seli >= 63UL) | ||
1038 | { | ||
1039 | seli = 63UL; | ||
1040 | } | ||
1041 | *pSelI = seli; | ||
1042 | |||
1043 | *pSelR = 0UL; | ||
1044 | } | ||
1045 | else | ||
1046 | { | ||
1047 | /* Note: If the spread spectrum mode, choose N to ensure 3 MHz < Fin/N < 5 MHz */ | ||
1048 | *pSelP = 3U; | ||
1049 | *pSelI = 4U; | ||
1050 | *pSelR = 4U; | ||
1051 | } | ||
1052 | } | ||
1053 | |||
1054 | /* Get predivider (N) from PLL0 NDEC setting */ | ||
1055 | static uint32_t findPll0PreDiv(void) | ||
1056 | { | ||
1057 | uint32_t preDiv = 1UL; | ||
1058 | |||
1059 | /* Direct input is not used? */ | ||
1060 | if ((SYSCON->PLL0CTRL & SYSCON_PLL0CTRL_BYPASSPREDIV_MASK) == 0UL) | ||
1061 | { | ||
1062 | preDiv = SYSCON->PLL0NDEC & SYSCON_PLL0NDEC_NDIV_MASK; | ||
1063 | if (preDiv == 0UL) | ||
1064 | { | ||
1065 | preDiv = 1UL; | ||
1066 | } | ||
1067 | } | ||
1068 | return preDiv; | ||
1069 | } | ||
1070 | |||
1071 | /* Get predivider (N) from PLL1 NDEC setting */ | ||
1072 | static uint32_t findPll1PreDiv(void) | ||
1073 | { | ||
1074 | uint32_t preDiv = 1UL; | ||
1075 | |||
1076 | /* Direct input is not used? */ | ||
1077 | if ((SYSCON->PLL1CTRL & SYSCON_PLL1CTRL_BYPASSPREDIV_MASK) == 0UL) | ||
1078 | { | ||
1079 | preDiv = SYSCON->PLL1NDEC & SYSCON_PLL1NDEC_NDIV_MASK; | ||
1080 | if (preDiv == 0UL) | ||
1081 | { | ||
1082 | preDiv = 1UL; | ||
1083 | } | ||
1084 | } | ||
1085 | return preDiv; | ||
1086 | } | ||
1087 | |||
1088 | /* Get postdivider (P) from PLL0 PDEC setting */ | ||
1089 | static uint32_t findPll0PostDiv(void) | ||
1090 | { | ||
1091 | uint32_t postDiv = 1UL; | ||
1092 | |||
1093 | if ((SYSCON->PLL0CTRL & SYSCON_PLL0CTRL_BYPASSPOSTDIV_MASK) == 0UL) | ||
1094 | { | ||
1095 | if ((SYSCON->PLL0CTRL & SYSCON_PLL0CTRL_BYPASSPOSTDIV2_MASK) != 0UL) | ||
1096 | { | ||
1097 | postDiv = SYSCON->PLL0PDEC & SYSCON_PLL0PDEC_PDIV_MASK; | ||
1098 | } | ||
1099 | else | ||
1100 | { | ||
1101 | postDiv = 2UL * (SYSCON->PLL0PDEC & SYSCON_PLL0PDEC_PDIV_MASK); | ||
1102 | } | ||
1103 | if (postDiv == 0UL) | ||
1104 | { | ||
1105 | postDiv = 2UL; | ||
1106 | } | ||
1107 | } | ||
1108 | return postDiv; | ||
1109 | } | ||
1110 | |||
1111 | /* Get postdivider (P) from PLL1 PDEC setting. */ | ||
1112 | static uint32_t findPll1PostDiv(void) | ||
1113 | { | ||
1114 | uint32_t postDiv = 1UL; | ||
1115 | |||
1116 | if ((SYSCON->PLL1CTRL & SYSCON_PLL1CTRL_BYPASSPOSTDIV_MASK) == 0UL) | ||
1117 | { | ||
1118 | if ((SYSCON->PLL1CTRL & SYSCON_PLL1CTRL_BYPASSPOSTDIV2_MASK) != 0UL) | ||
1119 | { | ||
1120 | postDiv = SYSCON->PLL1PDEC & SYSCON_PLL1PDEC_PDIV_MASK; | ||
1121 | } | ||
1122 | else | ||
1123 | { | ||
1124 | postDiv = 2UL * (SYSCON->PLL1PDEC & SYSCON_PLL1PDEC_PDIV_MASK); | ||
1125 | } | ||
1126 | if (postDiv == 0UL) | ||
1127 | { | ||
1128 | postDiv = 2UL; | ||
1129 | } | ||
1130 | } | ||
1131 | |||
1132 | return postDiv; | ||
1133 | } | ||
1134 | |||
1135 | /* Get multiplier (M) from PLL0 SSCG and SEL_EXT settings */ | ||
1136 | static float findPll0MMult(void) | ||
1137 | { | ||
1138 | float mMult = 1.0F; | ||
1139 | float mMult_fract; | ||
1140 | uint32_t mMult_int; | ||
1141 | |||
1142 | if ((SYSCON->PLL0SSCG1 & SYSCON_PLL0SSCG1_SEL_EXT_MASK) != 0UL) | ||
1143 | { | ||
1144 | mMult = | ||
1145 | (float)(uint32_t)((SYSCON->PLL0SSCG1 & SYSCON_PLL0SSCG1_MDIV_EXT_MASK) >> SYSCON_PLL0SSCG1_MDIV_EXT_SHIFT); | ||
1146 | } | ||
1147 | else | ||
1148 | { | ||
1149 | mMult_int = ((SYSCON->PLL0SSCG1 & SYSCON_PLL0SSCG1_MD_MBS_MASK) << 7U); | ||
1150 | mMult_int = mMult_int | ((SYSCON->PLL0SSCG0) >> PLL0_SSCG_MD_INT_P); | ||
1151 | mMult_fract = ((float)(uint32_t)((SYSCON->PLL0SSCG0) & PLL0_SSCG_MD_FRACT_M) / | ||
1152 | (float)(uint32_t)(1UL << PLL0_SSCG_MD_INT_P)); | ||
1153 | mMult = (float)mMult_int + mMult_fract; | ||
1154 | } | ||
1155 | if (mMult == 0.0F) | ||
1156 | { | ||
1157 | mMult = 1.0F; | ||
1158 | } | ||
1159 | return mMult; | ||
1160 | } | ||
1161 | |||
1162 | /* Get multiplier (M) from PLL1 MDEC. */ | ||
1163 | static uint32_t findPll1MMult(void) | ||
1164 | { | ||
1165 | uint32_t mMult = 1UL; | ||
1166 | |||
1167 | mMult = SYSCON->PLL1MDEC & SYSCON_PLL1MDEC_MDIV_MASK; | ||
1168 | |||
1169 | if (mMult == 0UL) | ||
1170 | { | ||
1171 | mMult = 1UL; | ||
1172 | } | ||
1173 | |||
1174 | return mMult; | ||
1175 | } | ||
1176 | |||
1177 | /* Find greatest common divisor between m and n */ | ||
1178 | static uint32_t FindGreatestCommonDivisor(uint32_t m, uint32_t n) | ||
1179 | { | ||
1180 | uint32_t tmp; | ||
1181 | |||
1182 | while (n != 0U) | ||
1183 | { | ||
1184 | tmp = n; | ||
1185 | n = m % n; | ||
1186 | m = tmp; | ||
1187 | } | ||
1188 | |||
1189 | return m; | ||
1190 | } | ||
1191 | |||
1192 | /* | ||
1193 | * Set PLL0 output based on desired output rate. | ||
1194 | * In this function, the it calculates the PLL0 setting for output frequency from input clock | ||
1195 | * frequency. The calculation would cost a few time. So it is not recommaned to use it frequently. | ||
1196 | * the "pllctrl", "pllndec", "pllpdec", "pllmdec" would updated in this function. | ||
1197 | */ | ||
1198 | static pll_error_t CLOCK_GetPll0ConfigInternal(uint32_t finHz, uint32_t foutHz, pll_setup_t *pSetup, bool useSS) | ||
1199 | { | ||
1200 | uint32_t nDivOutHz, fccoHz; | ||
1201 | uint32_t pllPreDivider, pllMultiplier, pllPostDivider; | ||
1202 | uint32_t pllDirectInput, pllDirectOutput; | ||
1203 | uint32_t pllSelP, pllSelI, pllSelR, uplimoff; | ||
1204 | |||
1205 | /* Baseline parameters (no input or output dividers) */ | ||
1206 | pllPreDivider = 1U; /* 1 implies pre-divider will be disabled */ | ||
1207 | pllPostDivider = 1U; /* 1 implies post-divider will be disabled */ | ||
1208 | pllDirectOutput = 1U; | ||
1209 | |||
1210 | /* Verify output rate parameter */ | ||
1211 | if (foutHz > PLL_MAX_CCO_FREQ_MHZ) | ||
1212 | { | ||
1213 | /* Maximum PLL output with post divider=1 cannot go above this frequency */ | ||
1214 | return kStatus_PLL_OutputTooHigh; | ||
1215 | } | ||
1216 | if (foutHz < (PLL_MIN_CCO_FREQ_MHZ / (PVALMAX << 1U))) | ||
1217 | { | ||
1218 | /* Minmum PLL output with maximum post divider cannot go below this frequency */ | ||
1219 | return kStatus_PLL_OutputTooLow; | ||
1220 | } | ||
1221 | |||
1222 | /* If using SS mode, input clock needs to be between 3MHz and 20MHz */ | ||
1223 | if (useSS) | ||
1224 | { | ||
1225 | /* Verify input rate parameter */ | ||
1226 | if (finHz < PLL_MIN_IN_SSMODE) | ||
1227 | { | ||
1228 | /* Input clock into the PLL cannot be lower than this */ | ||
1229 | return kStatus_PLL_InputTooLow; | ||
1230 | } | ||
1231 | /* PLL input in SS mode must be under 20MHz */ | ||
1232 | if (finHz > (PLL_MAX_IN_SSMODE * NVALMAX)) | ||
1233 | { | ||
1234 | return kStatus_PLL_InputTooHigh; | ||
1235 | } | ||
1236 | } | ||
1237 | else | ||
1238 | { | ||
1239 | /* Verify input rate parameter */ | ||
1240 | if (finHz < PLL_LOWER_IN_LIMIT) | ||
1241 | { | ||
1242 | /* Input clock into the PLL cannot be lower than this */ | ||
1243 | return kStatus_PLL_InputTooLow; | ||
1244 | } | ||
1245 | if (finHz > PLL_HIGHER_IN_LIMIT) | ||
1246 | { | ||
1247 | /* Input clock into the PLL cannot be higher than this */ | ||
1248 | return kStatus_PLL_InputTooHigh; | ||
1249 | } | ||
1250 | } | ||
1251 | |||
1252 | /* Find the optimal CCO frequency for the output and input that | ||
1253 | will keep it inside the PLL CCO range. This may require | ||
1254 | tweaking the post-divider for the PLL. */ | ||
1255 | fccoHz = foutHz; | ||
1256 | while (fccoHz < PLL_MIN_CCO_FREQ_MHZ) | ||
1257 | { | ||
1258 | /* CCO output is less than minimum CCO range, so the CCO output | ||
1259 | needs to be bumped up and the post-divider is used to bring | ||
1260 | the PLL output back down. */ | ||
1261 | pllPostDivider++; | ||
1262 | if (pllPostDivider > PVALMAX) | ||
1263 | { | ||
1264 | return kStatus_PLL_OutsideIntLimit; | ||
1265 | } | ||
1266 | |||
1267 | /* Target CCO goes up, PLL output goes down */ | ||
1268 | /* divide-by-2 divider in the post-divider is always work*/ | ||
1269 | fccoHz = foutHz * (pllPostDivider * 2U); | ||
1270 | pllDirectOutput = 0U; | ||
1271 | } | ||
1272 | |||
1273 | /* Determine if a pre-divider is needed to get the best frequency */ | ||
1274 | if ((finHz > PLL_LOWER_IN_LIMIT) && (fccoHz >= finHz) && (useSS == false)) | ||
1275 | { | ||
1276 | uint32_t a = FindGreatestCommonDivisor(fccoHz, finHz); | ||
1277 | |||
1278 | if (a > PLL_LOWER_IN_LIMIT) | ||
1279 | { | ||
1280 | a = finHz / a; | ||
1281 | if ((a != 0U) && (a < PLL_MAX_N_DIV)) | ||
1282 | { | ||
1283 | pllPreDivider = a; | ||
1284 | } | ||
1285 | } | ||
1286 | } | ||
1287 | |||
1288 | /* Bypass pre-divider hardware if pre-divider is 1 */ | ||
1289 | if (pllPreDivider > 1U) | ||
1290 | { | ||
1291 | pllDirectInput = 0U; | ||
1292 | } | ||
1293 | else | ||
1294 | { | ||
1295 | pllDirectInput = 1U; | ||
1296 | } | ||
1297 | |||
1298 | /* Determine PLL multipler */ | ||
1299 | nDivOutHz = (finHz / pllPreDivider); | ||
1300 | pllMultiplier = (fccoHz / nDivOutHz); | ||
1301 | |||
1302 | /* Find optimal values for filter */ | ||
1303 | if (useSS == false) | ||
1304 | { | ||
1305 | /* Will bumping up M by 1 get us closer to the desired CCO frequency? */ | ||
1306 | if ((nDivOutHz * ((pllMultiplier * 2U) + 1U)) < (fccoHz * 2U)) | ||
1307 | { | ||
1308 | pllMultiplier++; | ||
1309 | } | ||
1310 | |||
1311 | /* Setup filtering */ | ||
1312 | pllFindSel(pllMultiplier, &pllSelP, &pllSelI, &pllSelR); | ||
1313 | uplimoff = 0U; | ||
1314 | |||
1315 | /* Get encoded value for M (mult) and use manual filter, disable SS mode */ | ||
1316 | pSetup->pllsscg[1] = | ||
1317 | (uint32_t)((PLL_SSCG1_MDEC_VAL_SET(pllMultiplier)) | (1UL << SYSCON_PLL0SSCG1_SEL_EXT_SHIFT)); | ||
1318 | } | ||
1319 | else | ||
1320 | { | ||
1321 | uint64_t fc; | ||
1322 | |||
1323 | /* Filtering will be handled by SSC */ | ||
1324 | pllSelR = 0UL; | ||
1325 | pllSelI = 0UL; | ||
1326 | pllSelP = 0UL; | ||
1327 | uplimoff = 1U; | ||
1328 | |||
1329 | /* The PLL multiplier will get very close and slightly under the | ||
1330 | desired target frequency. A small fractional component can be | ||
1331 | added to fine tune the frequency upwards to the target. */ | ||
1332 | fc = ((uint64_t)(uint32_t)(fccoHz % nDivOutHz) << 25UL) / nDivOutHz; | ||
1333 | |||
1334 | /* Set multiplier */ | ||
1335 | pSetup->pllsscg[0] = (uint32_t)(PLL0_SSCG_MD_INT_SET(pllMultiplier) | PLL0_SSCG_MD_FRACT_SET((uint32_t)fc)); | ||
1336 | pSetup->pllsscg[1] = (uint32_t)(PLL0_SSCG_MD_INT_SET(pllMultiplier) >> 32U); | ||
1337 | } | ||
1338 | |||
1339 | /* Get encoded values for N (prediv) and P (postdiv) */ | ||
1340 | pSetup->pllndec = PLL_NDEC_VAL_SET(pllPreDivider); | ||
1341 | pSetup->pllpdec = PLL_PDEC_VAL_SET(pllPostDivider); | ||
1342 | |||
1343 | /* PLL control */ | ||
1344 | pSetup->pllctrl = (pllSelR << SYSCON_PLL0CTRL_SELR_SHIFT) | /* Filter coefficient */ | ||
1345 | (pllSelI << SYSCON_PLL0CTRL_SELI_SHIFT) | /* Filter coefficient */ | ||
1346 | (pllSelP << SYSCON_PLL0CTRL_SELP_SHIFT) | /* Filter coefficient */ | ||
1347 | (0UL << SYSCON_PLL0CTRL_BYPASSPLL_SHIFT) | /* PLL bypass mode disabled */ | ||
1348 | (uplimoff << SYSCON_PLL0CTRL_LIMUPOFF_SHIFT) | /* SS/fractional mode disabled */ | ||
1349 | (pllDirectInput << SYSCON_PLL0CTRL_BYPASSPREDIV_SHIFT) | /* Bypass pre-divider? */ | ||
1350 | (pllDirectOutput << SYSCON_PLL0CTRL_BYPASSPOSTDIV_SHIFT) | /* Bypass post-divider? */ | ||
1351 | (1UL << SYSCON_PLL0CTRL_CLKEN_SHIFT); /* Ensure the PLL clock output */ | ||
1352 | |||
1353 | return kStatus_PLL_Success; | ||
1354 | } | ||
1355 | |||
1356 | #if (defined(CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) && CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) | ||
1357 | /* Alloct the static buffer for cache. */ | ||
1358 | static pll_setup_t s_PllSetupCacheStruct[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT]; | ||
1359 | static uint32_t s_FinHzCache[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT] = {0}; | ||
1360 | static uint32_t s_FoutHzCache[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT] = {0}; | ||
1361 | static bool s_UseSSCache[CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT] = {false}; | ||
1362 | static uint32_t s_PllSetupCacheIdx = 0U; | ||
1363 | #endif /* CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT */ | ||
1364 | |||
1365 | /* | ||
1366 | * Calculate the PLL setting values from input clock freq to output freq. | ||
1367 | */ | ||
1368 | static pll_error_t CLOCK_GetPll0Config(uint32_t finHz, uint32_t foutHz, pll_setup_t *pSetup, bool useSS) | ||
1369 | { | ||
1370 | pll_error_t retErr; | ||
1371 | #if (defined(CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) && CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) | ||
1372 | uint32_t i; | ||
1373 | |||
1374 | for (i = 0U; i < CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT; i++) | ||
1375 | { | ||
1376 | if ((finHz == s_FinHzCache[i]) && (foutHz == s_FoutHzCache[i]) && (useSS == s_UseSSCache[i])) | ||
1377 | { | ||
1378 | /* Hit the target in cache buffer. */ | ||
1379 | pSetup->pllctrl = s_PllSetupCacheStruct[i].pllctrl; | ||
1380 | pSetup->pllndec = s_PllSetupCacheStruct[i].pllndec; | ||
1381 | pSetup->pllpdec = s_PllSetupCacheStruct[i].pllpdec; | ||
1382 | pSetup->pllsscg[0] = s_PllSetupCacheStruct[i].pllsscg[0]; | ||
1383 | pSetup->pllsscg[1] = s_PllSetupCacheStruct[i].pllsscg[1]; | ||
1384 | retErr = kStatus_PLL_Success; | ||
1385 | break; | ||
1386 | } | ||
1387 | } | ||
1388 | |||
1389 | if (i < CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) | ||
1390 | { | ||
1391 | return retErr; | ||
1392 | } | ||
1393 | #endif /* CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT */ | ||
1394 | |||
1395 | retErr = CLOCK_GetPll0ConfigInternal(finHz, foutHz, pSetup, useSS); | ||
1396 | |||
1397 | #if (defined(CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) && CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT) | ||
1398 | /* Cache the most recent calulation result into buffer. */ | ||
1399 | s_FinHzCache[s_PllSetupCacheIdx] = finHz; | ||
1400 | s_FoutHzCache[s_PllSetupCacheIdx] = foutHz; | ||
1401 | s_UseSSCache[s_PllSetupCacheIdx] = useSS; | ||
1402 | |||
1403 | s_PllSetupCacheStruct[s_PllSetupCacheIdx].pllctrl = pSetup->pllctrl; | ||
1404 | s_PllSetupCacheStruct[s_PllSetupCacheIdx].pllndec = pSetup->pllndec; | ||
1405 | s_PllSetupCacheStruct[s_PllSetupCacheIdx].pllpdec = pSetup->pllpdec; | ||
1406 | s_PllSetupCacheStruct[s_PllSetupCacheIdx].pllsscg[0] = pSetup->pllsscg[0]; | ||
1407 | s_PllSetupCacheStruct[s_PllSetupCacheIdx].pllsscg[1] = pSetup->pllsscg[1]; | ||
1408 | /* Update the index for next available buffer. */ | ||
1409 | s_PllSetupCacheIdx = (s_PllSetupCacheIdx + 1U) % CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT; | ||
1410 | #endif /* CLOCK_USR_CFG_PLL_CONFIG_CACHE_COUNT */ | ||
1411 | |||
1412 | return retErr; | ||
1413 | } | ||
1414 | |||
1415 | /* Update local PLL rate variable */ | ||
1416 | static void CLOCK_GetPLL0OutFromSetupUpdate(pll_setup_t *pSetup) | ||
1417 | { | ||
1418 | s_Pll0_Freq = CLOCK_GetPLL0OutFromSetup(pSetup); | ||
1419 | } | ||
1420 | |||
1421 | /* Update local PLL1 rate variable */ | ||
1422 | static void CLOCK_GetPLL1OutFromSetupUpdate(pll_setup_t *pSetup) | ||
1423 | { | ||
1424 | s_Pll1_Freq = CLOCK_GetPLL1OutFromSetup(pSetup); | ||
1425 | } | ||
1426 | |||
1427 | /* Return System PLL input clock rate */ | ||
1428 | /*! brief Return PLL0 input clock rate | ||
1429 | * return PLL0 input clock rate | ||
1430 | */ | ||
1431 | uint32_t CLOCK_GetPLL0InClockRate(void) | ||
1432 | { | ||
1433 | uint32_t clkRate = 0U; | ||
1434 | |||
1435 | switch ((SYSCON->PLL0CLKSEL & SYSCON_PLL0CLKSEL_SEL_MASK)) | ||
1436 | { | ||
1437 | case 0x00U: | ||
1438 | clkRate = CLK_FRO_12MHZ; | ||
1439 | break; | ||
1440 | |||
1441 | case 0x01U: | ||
1442 | clkRate = CLOCK_GetExtClkFreq(); | ||
1443 | break; | ||
1444 | |||
1445 | case 0x02U: | ||
1446 | clkRate = CLOCK_GetFro1MFreq(); | ||
1447 | break; | ||
1448 | |||
1449 | case 0x03U: | ||
1450 | clkRate = CLOCK_GetOsc32KFreq(); | ||
1451 | break; | ||
1452 | |||
1453 | default: | ||
1454 | clkRate = 0U; | ||
1455 | break; | ||
1456 | } | ||
1457 | |||
1458 | return clkRate; | ||
1459 | } | ||
1460 | |||
1461 | /* Return PLL1 input clock rate */ | ||
1462 | uint32_t CLOCK_GetPLL1InClockRate(void) | ||
1463 | { | ||
1464 | uint32_t clkRate = 0U; | ||
1465 | |||
1466 | switch ((SYSCON->PLL1CLKSEL & SYSCON_PLL1CLKSEL_SEL_MASK)) | ||
1467 | { | ||
1468 | case 0x00U: | ||
1469 | clkRate = CLK_FRO_12MHZ; | ||
1470 | break; | ||
1471 | |||
1472 | case 0x01U: | ||
1473 | clkRate = CLOCK_GetExtClkFreq(); | ||
1474 | break; | ||
1475 | |||
1476 | case 0x02U: | ||
1477 | clkRate = CLOCK_GetFro1MFreq(); | ||
1478 | break; | ||
1479 | |||
1480 | case 0x03U: | ||
1481 | clkRate = CLOCK_GetOsc32KFreq(); | ||
1482 | break; | ||
1483 | |||
1484 | default: | ||
1485 | clkRate = 0U; | ||
1486 | break; | ||
1487 | } | ||
1488 | |||
1489 | return clkRate; | ||
1490 | } | ||
1491 | |||
1492 | /* Return PLL0 output clock rate from setup structure */ | ||
1493 | /*! brief Return PLL0 output clock rate from setup structure | ||
1494 | * param pSetup : Pointer to a PLL setup structure | ||
1495 | * return PLL0 output clock rate the setup structure will generate | ||
1496 | */ | ||
1497 | uint32_t CLOCK_GetPLL0OutFromSetup(pll_setup_t *pSetup) | ||
1498 | { | ||
1499 | uint32_t clkRate = 0; | ||
1500 | uint32_t prediv, postdiv; | ||
1501 | float workRate = 0.0F; | ||
1502 | |||
1503 | /* Get the input clock frequency of PLL. */ | ||
1504 | clkRate = CLOCK_GetPLL0InClockRate(); | ||
1505 | |||
1506 | if (((pSetup->pllctrl & SYSCON_PLL0CTRL_BYPASSPLL_MASK) == 0UL) && | ||
1507 | ((pSetup->pllctrl & SYSCON_PLL0CTRL_CLKEN_MASK) != 0UL) && | ||
1508 | ((PMC->PDRUNCFG0 & PMC_PDRUNCFG0_PDEN_PLL0_MASK) == 0UL) && | ||
1509 | ((PMC->PDRUNCFG0 & PMC_PDRUNCFG0_PDEN_PLL0_SSCG_MASK) == 0UL)) | ||
1510 | { | ||
1511 | prediv = findPll0PreDiv(); | ||
1512 | postdiv = findPll0PostDiv(); | ||
1513 | /* Adjust input clock */ | ||
1514 | clkRate = clkRate / prediv; | ||
1515 | /* MDEC used for rate */ | ||
1516 | workRate = (float)clkRate * (float)findPll0MMult(); | ||
1517 | workRate /= (float)postdiv; | ||
1518 | } | ||
1519 | |||
1520 | return (uint32_t)workRate; | ||
1521 | } | ||
1522 | |||
1523 | /* Return PLL1 output clock rate from setup structure */ | ||
1524 | /*! brief Return PLL1 output clock rate from setup structure | ||
1525 | * param pSetup : Pointer to a PLL setup structure | ||
1526 | * return PLL0 output clock rate the setup structure will generate | ||
1527 | */ | ||
1528 | uint32_t CLOCK_GetPLL1OutFromSetup(pll_setup_t *pSetup) | ||
1529 | { | ||
1530 | uint32_t clkRate = 0; | ||
1531 | uint32_t prediv, postdiv; | ||
1532 | uint32_t workRate = 0UL; | ||
1533 | |||
1534 | /* Get the input clock frequency of PLL. */ | ||
1535 | clkRate = CLOCK_GetPLL1InClockRate(); | ||
1536 | |||
1537 | if (((pSetup->pllctrl & SYSCON_PLL1CTRL_BYPASSPLL_MASK) == 0UL) && | ||
1538 | ((pSetup->pllctrl & SYSCON_PLL1CTRL_CLKEN_MASK) != 0UL) && | ||
1539 | ((PMC->PDRUNCFG0 & PMC_PDRUNCFG0_PDEN_PLL1_MASK) == 0UL)) | ||
1540 | { | ||
1541 | prediv = findPll1PreDiv(); | ||
1542 | postdiv = findPll1PostDiv(); | ||
1543 | /* Adjust input clock */ | ||
1544 | clkRate = clkRate / prediv; | ||
1545 | /* MDEC used for rate */ | ||
1546 | workRate = clkRate * findPll1MMult(); | ||
1547 | workRate /= postdiv; | ||
1548 | } | ||
1549 | |||
1550 | return workRate; | ||
1551 | } | ||
1552 | |||
1553 | /* Set the current PLL0 Rate */ | ||
1554 | /*! brief Store the current PLL rate | ||
1555 | * param rate: Current rate of the PLL | ||
1556 | * return Nothing | ||
1557 | **/ | ||
1558 | void CLOCK_SetStoredPLL0ClockRate(uint32_t rate) | ||
1559 | { | ||
1560 | s_Pll0_Freq = rate; | ||
1561 | } | ||
1562 | |||
1563 | /* Return PLL0 output clock rate */ | ||
1564 | /*! brief Return PLL0 output clock rate | ||
1565 | * param recompute : Forces a PLL rate recomputation if true | ||
1566 | * return PLL0 output clock rate | ||
1567 | * note The PLL rate is cached in the driver in a variable as | ||
1568 | * the rate computation function can take some time to perform. It | ||
1569 | * is recommended to use 'false' with the 'recompute' parameter. | ||
1570 | */ | ||
1571 | uint32_t CLOCK_GetPLL0OutClockRate(bool recompute) | ||
1572 | { | ||
1573 | pll_setup_t Setup; | ||
1574 | uint32_t rate; | ||
1575 | |||
1576 | if ((recompute) || (s_Pll0_Freq == 0U)) | ||
1577 | { | ||
1578 | Setup.pllctrl = SYSCON->PLL0CTRL; | ||
1579 | Setup.pllndec = SYSCON->PLL0NDEC; | ||
1580 | Setup.pllpdec = SYSCON->PLL0PDEC; | ||
1581 | Setup.pllsscg[0] = SYSCON->PLL0SSCG0; | ||
1582 | Setup.pllsscg[1] = SYSCON->PLL0SSCG1; | ||
1583 | |||
1584 | CLOCK_GetPLL0OutFromSetupUpdate(&Setup); | ||
1585 | } | ||
1586 | |||
1587 | rate = s_Pll0_Freq; | ||
1588 | |||
1589 | return rate; | ||
1590 | } | ||
1591 | |||
1592 | /*! brief Return PLL1 output clock rate | ||
1593 | * param recompute : Forces a PLL rate recomputation if true | ||
1594 | * return PLL1 output clock rate | ||
1595 | * note The PLL rate is cached in the driver in a variable as | ||
1596 | * the rate computation function can take some time to perform. It | ||
1597 | * is recommended to use 'false' with the 'recompute' parameter. | ||
1598 | */ | ||
1599 | uint32_t CLOCK_GetPLL1OutClockRate(bool recompute) | ||
1600 | { | ||
1601 | pll_setup_t Setup; | ||
1602 | uint32_t rate; | ||
1603 | |||
1604 | if ((recompute) || (s_Pll1_Freq == 0U)) | ||
1605 | { | ||
1606 | Setup.pllctrl = SYSCON->PLL1CTRL; | ||
1607 | Setup.pllndec = SYSCON->PLL1NDEC; | ||
1608 | Setup.pllpdec = SYSCON->PLL1PDEC; | ||
1609 | Setup.pllmdec = SYSCON->PLL1MDEC; | ||
1610 | CLOCK_GetPLL1OutFromSetupUpdate(&Setup); | ||
1611 | } | ||
1612 | |||
1613 | rate = s_Pll1_Freq; | ||
1614 | |||
1615 | return rate; | ||
1616 | } | ||
1617 | |||
1618 | /* Set PLL0 output based on the passed PLL setup data */ | ||
1619 | /*! brief Set PLL output based on the passed PLL setup data | ||
1620 | * param pControl : Pointer to populated PLL control structure to generate setup with | ||
1621 | * param pSetup : Pointer to PLL setup structure to be filled | ||
1622 | * return PLL_ERROR_SUCCESS on success, or PLL setup error code | ||
1623 | * note Actual frequency for setup may vary from the desired frequency based on the | ||
1624 | * accuracy of input clocks, rounding, non-fractional PLL mode, etc. | ||
1625 | */ | ||
1626 | pll_error_t CLOCK_SetupPLL0Data(pll_config_t *pControl, pll_setup_t *pSetup) | ||
1627 | { | ||
1628 | uint32_t inRate; | ||
1629 | bool useSS = (bool)((pControl->flags & PLL_CONFIGFLAG_FORCENOFRACT) == 0UL); | ||
1630 | |||
1631 | pll_error_t pllError; | ||
1632 | |||
1633 | /* Determine input rate for the PLL */ | ||
1634 | if ((pControl->flags & PLL_CONFIGFLAG_USEINRATE) != 0UL) | ||
1635 | { | ||
1636 | inRate = pControl->inputRate; | ||
1637 | } | ||
1638 | else | ||
1639 | { | ||
1640 | inRate = CLOCK_GetPLL0InClockRate(); | ||
1641 | } | ||
1642 | |||
1643 | /* PLL flag options */ | ||
1644 | pllError = CLOCK_GetPll0Config(inRate, pControl->desiredRate, pSetup, useSS); | ||
1645 | if ((useSS) && (pllError == kStatus_PLL_Success)) | ||
1646 | { | ||
1647 | /* If using SS mode, then some tweaks are made to the generated setup */ | ||
1648 | pSetup->pllsscg[1] |= (uint32_t)pControl->ss_mf | (uint32_t)pControl->ss_mr | (uint32_t)pControl->ss_mc; | ||
1649 | if (pControl->mfDither) | ||
1650 | { | ||
1651 | pSetup->pllsscg[1] |= (1UL << SYSCON_PLL0SSCG1_DITHER_SHIFT); | ||
1652 | } | ||
1653 | } | ||
1654 | |||
1655 | return pllError; | ||
1656 | } | ||
1657 | |||
1658 | /* Set PLL0 output from PLL setup structure */ | ||
1659 | /*! brief Set PLL output from PLL setup structure (precise frequency) | ||
1660 | * param pSetup : Pointer to populated PLL setup structure | ||
1661 | * param flagcfg : Flag configuration for PLL config structure | ||
1662 | * return PLL_ERROR_SUCCESS on success, or PLL setup error code | ||
1663 | * note This function will power off the PLL, setup the PLL with the | ||
1664 | * new setup data, and then optionally powerup the PLL, wait for PLL lock, | ||
1665 | * and adjust system voltages to the new PLL rate. The function will not | ||
1666 | * alter any source clocks (ie, main systen clock) that may use the PLL, | ||
1667 | * so these should be setup prior to and after exiting the function. | ||
1668 | */ | ||
1669 | pll_error_t CLOCK_SetupPLL0Prec(pll_setup_t *pSetup, uint32_t flagcfg) | ||
1670 | { | ||
1671 | uint32_t inRate, clkRate, prediv; | ||
1672 | |||
1673 | /* Power off PLL during setup changes */ | ||
1674 | POWER_EnablePD(kPDRUNCFG_PD_PLL0); | ||
1675 | POWER_EnablePD(kPDRUNCFG_PD_PLL0_SSCG); | ||
1676 | |||
1677 | pSetup->flags = flagcfg; | ||
1678 | |||
1679 | /* Write PLL setup data */ | ||
1680 | SYSCON->PLL0CTRL = pSetup->pllctrl; | ||
1681 | SYSCON->PLL0NDEC = pSetup->pllndec; | ||
1682 | SYSCON->PLL0NDEC = pSetup->pllndec | (1UL << SYSCON_PLL0NDEC_NREQ_SHIFT); /* latch */ | ||
1683 | SYSCON->PLL0PDEC = pSetup->pllpdec; | ||
1684 | SYSCON->PLL0PDEC = pSetup->pllpdec | (1UL << SYSCON_PLL0PDEC_PREQ_SHIFT); /* latch */ | ||
1685 | SYSCON->PLL0SSCG0 = pSetup->pllsscg[0]; | ||
1686 | SYSCON->PLL0SSCG1 = pSetup->pllsscg[1]; | ||
1687 | SYSCON->PLL0SSCG1 = | ||
1688 | pSetup->pllsscg[1] | (1UL << SYSCON_PLL0SSCG1_MREQ_SHIFT) | (1UL << SYSCON_PLL0SSCG1_MD_REQ_SHIFT); /* latch */ | ||
1689 | |||
1690 | POWER_DisablePD(kPDRUNCFG_PD_PLL0); | ||
1691 | POWER_DisablePD(kPDRUNCFG_PD_PLL0_SSCG); | ||
1692 | |||
1693 | if ((pSetup->flags & PLL_SETUPFLAG_WAITLOCK) != 0UL) | ||
1694 | { | ||
1695 | if ((SYSCON->PLL0SSCG1 & SYSCON_PLL0SSCG1_MDIV_EXT_MASK) != 0UL) /* normal mode */ | ||
1696 | { | ||
1697 | inRate = CLOCK_GetPLL0InClockRate(); | ||
1698 | prediv = findPll0PreDiv(); | ||
1699 | /* Adjust input clock */ | ||
1700 | clkRate = inRate / prediv; | ||
1701 | /* The lock signal is only reliable between fref[2] :100 kHz to 20 MHz. */ | ||
1702 | if ((clkRate >= 100000UL) && (clkRate <= 20000000UL)) | ||
1703 | { | ||
1704 | while (CLOCK_IsPLL0Locked() == false) | ||
1705 | { | ||
1706 | } | ||
1707 | } | ||
1708 | else | ||
1709 | { | ||
1710 | SDK_DelayAtLeastUs(6000U, | ||
1711 | SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); /* software should use a 6 ms time interval | ||
1712 | to insure the PLL will be stable */ | ||
1713 | } | ||
1714 | } | ||
1715 | else /* spread spectrum mode */ | ||
1716 | { | ||
1717 | SDK_DelayAtLeastUs(6000U, | ||
1718 | SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); /* software should use a 6 ms time interval to | ||
1719 | insure the PLL will be stable */ | ||
1720 | } | ||
1721 | } | ||
1722 | |||
1723 | /* Update current programmed PLL rate var */ | ||
1724 | CLOCK_GetPLL0OutFromSetupUpdate(pSetup); | ||
1725 | |||
1726 | /* System voltage adjustment, occurs prior to setting main system clock */ | ||
1727 | if ((pSetup->flags & PLL_SETUPFLAG_ADGVOLT) != 0UL) | ||
1728 | { | ||
1729 | POWER_SetVoltageForFreq(s_Pll0_Freq); | ||
1730 | } | ||
1731 | |||
1732 | return kStatus_PLL_Success; | ||
1733 | } | ||
1734 | |||
1735 | /* Setup PLL Frequency from pre-calculated value */ | ||
1736 | /** | ||
1737 | * brief Set PLL0 output from PLL setup structure (precise frequency) | ||
1738 | * param pSetup : Pointer to populated PLL setup structure | ||
1739 | * return kStatus_PLL_Success on success, or PLL setup error code | ||
1740 | * note This function will power off the PLL, setup the PLL with the | ||
1741 | * new setup data, and then optionally powerup the PLL, wait for PLL lock, | ||
1742 | * and adjust system voltages to the new PLL rate. The function will not | ||
1743 | * alter any source clocks (ie, main systen clock) that may use the PLL, | ||
1744 | * so these should be setup prior to and after exiting the function. | ||
1745 | */ | ||
1746 | pll_error_t CLOCK_SetPLL0Freq(const pll_setup_t *pSetup) | ||
1747 | { | ||
1748 | uint32_t inRate, clkRate, prediv; | ||
1749 | /* Power off PLL during setup changes */ | ||
1750 | POWER_EnablePD(kPDRUNCFG_PD_PLL0); | ||
1751 | POWER_EnablePD(kPDRUNCFG_PD_PLL0_SSCG); | ||
1752 | |||
1753 | /* Write PLL setup data */ | ||
1754 | SYSCON->PLL0CTRL = pSetup->pllctrl; | ||
1755 | SYSCON->PLL0NDEC = pSetup->pllndec; | ||
1756 | SYSCON->PLL0NDEC = pSetup->pllndec | (1UL << SYSCON_PLL0NDEC_NREQ_SHIFT); /* latch */ | ||
1757 | SYSCON->PLL0PDEC = pSetup->pllpdec; | ||
1758 | SYSCON->PLL0PDEC = pSetup->pllpdec | (1UL << SYSCON_PLL0PDEC_PREQ_SHIFT); /* latch */ | ||
1759 | SYSCON->PLL0SSCG0 = pSetup->pllsscg[0]; | ||
1760 | SYSCON->PLL0SSCG1 = pSetup->pllsscg[1]; | ||
1761 | SYSCON->PLL0SSCG1 = | ||
1762 | pSetup->pllsscg[1] | (1UL << SYSCON_PLL0SSCG1_MD_REQ_SHIFT) | (1UL << SYSCON_PLL0SSCG1_MREQ_SHIFT); /* latch */ | ||
1763 | |||
1764 | POWER_DisablePD(kPDRUNCFG_PD_PLL0); | ||
1765 | POWER_DisablePD(kPDRUNCFG_PD_PLL0_SSCG); | ||
1766 | |||
1767 | if ((pSetup->flags & PLL_SETUPFLAG_WAITLOCK) != 0UL) | ||
1768 | { | ||
1769 | if ((SYSCON->PLL0SSCG1 & SYSCON_PLL0SSCG1_MDIV_EXT_MASK) != 0UL) /* normal mode */ | ||
1770 | { | ||
1771 | inRate = CLOCK_GetPLL0InClockRate(); | ||
1772 | prediv = findPll0PreDiv(); | ||
1773 | /* Adjust input clock */ | ||
1774 | clkRate = inRate / prediv; | ||
1775 | /* The lock signal is only reliable between fref[2] :100 kHz to 20 MHz. */ | ||
1776 | if ((clkRate >= 100000UL) && (clkRate <= 20000000UL)) | ||
1777 | { | ||
1778 | while (CLOCK_IsPLL0Locked() == false) | ||
1779 | { | ||
1780 | } | ||
1781 | } | ||
1782 | else | ||
1783 | { | ||
1784 | SDK_DelayAtLeastUs(6000U, | ||
1785 | SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); /* software should use a 6 ms time interval | ||
1786 | to insure the PLL will be stable */ | ||
1787 | } | ||
1788 | } | ||
1789 | else /* spread spectrum mode */ | ||
1790 | { | ||
1791 | SDK_DelayAtLeastUs(6000U, | ||
1792 | SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); /* software should use a 6 ms time interval to | ||
1793 | insure the PLL will be stable */ | ||
1794 | } | ||
1795 | } | ||
1796 | |||
1797 | /* Update current programmed PLL rate var */ | ||
1798 | s_Pll0_Freq = pSetup->pllRate; | ||
1799 | |||
1800 | return kStatus_PLL_Success; | ||
1801 | } | ||
1802 | |||
1803 | /* Setup PLL1 Frequency from pre-calculated value */ | ||
1804 | /** | ||
1805 | * brief Set PLL1 output from PLL setup structure (precise frequency) | ||
1806 | * param pSetup : Pointer to populated PLL setup structure | ||
1807 | * return kStatus_PLL_Success on success, or PLL setup error code | ||
1808 | * note This function will power off the PLL, setup the PLL with the | ||
1809 | * new setup data, and then optionally powerup the PLL, wait for PLL lock, | ||
1810 | * and adjust system voltages to the new PLL rate. The function will not | ||
1811 | * alter any source clocks (ie, main systen clock) that may use the PLL, | ||
1812 | * so these should be setup prior to and after exiting the function. | ||
1813 | */ | ||
1814 | pll_error_t CLOCK_SetPLL1Freq(const pll_setup_t *pSetup) | ||
1815 | { | ||
1816 | uint32_t inRate, clkRate, prediv; | ||
1817 | /* Power off PLL during setup changes */ | ||
1818 | POWER_EnablePD(kPDRUNCFG_PD_PLL1); | ||
1819 | |||
1820 | /* Write PLL setup data */ | ||
1821 | SYSCON->PLL1CTRL = pSetup->pllctrl; | ||
1822 | SYSCON->PLL1NDEC = pSetup->pllndec; | ||
1823 | SYSCON->PLL1NDEC = pSetup->pllndec | (1UL << SYSCON_PLL1NDEC_NREQ_SHIFT); /* latch */ | ||
1824 | SYSCON->PLL1PDEC = pSetup->pllpdec; | ||
1825 | SYSCON->PLL1PDEC = pSetup->pllpdec | (1UL << SYSCON_PLL1PDEC_PREQ_SHIFT); /* latch */ | ||
1826 | SYSCON->PLL1MDEC = pSetup->pllmdec; | ||
1827 | SYSCON->PLL1MDEC = pSetup->pllmdec | (1UL << SYSCON_PLL1MDEC_MREQ_SHIFT); /* latch */ | ||
1828 | |||
1829 | POWER_DisablePD(kPDRUNCFG_PD_PLL1); | ||
1830 | |||
1831 | if ((pSetup->flags & PLL_SETUPFLAG_WAITLOCK) != 0UL) | ||
1832 | { | ||
1833 | inRate = CLOCK_GetPLL1InClockRate(); | ||
1834 | prediv = findPll1PreDiv(); | ||
1835 | /* Adjust input clock */ | ||
1836 | clkRate = inRate / prediv; | ||
1837 | /* The lock signal is only reliable between fref[2] :100 kHz to 20 MHz. */ | ||
1838 | if ((clkRate >= 100000UL) && (clkRate <= 20000000UL)) | ||
1839 | { | ||
1840 | while (CLOCK_IsPLL1Locked() == false) | ||
1841 | { | ||
1842 | } | ||
1843 | } | ||
1844 | else | ||
1845 | { | ||
1846 | SDK_DelayAtLeastUs(6000U, | ||
1847 | SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); /* software should use a 6 ms time interval to | ||
1848 | insure the PLL will be stable */ | ||
1849 | } | ||
1850 | } | ||
1851 | |||
1852 | /* Update current programmed PLL rate var */ | ||
1853 | s_Pll1_Freq = pSetup->pllRate; | ||
1854 | |||
1855 | return kStatus_PLL_Success; | ||
1856 | } | ||
1857 | |||
1858 | /* Set PLL0 clock based on the input frequency and multiplier */ | ||
1859 | /*! brief Set PLL0 output based on the multiplier and input frequency | ||
1860 | * param multiply_by : multiplier | ||
1861 | * param input_freq : Clock input frequency of the PLL | ||
1862 | * return Nothing | ||
1863 | * note Unlike the Chip_Clock_SetupSystemPLLPrec() function, this | ||
1864 | * function does not disable or enable PLL power, wait for PLL lock, | ||
1865 | * or adjust system voltages. These must be done in the application. | ||
1866 | * The function will not alter any source clocks (ie, main systen clock) | ||
1867 | * that may use the PLL, so these should be setup prior to and after | ||
1868 | * exiting the function. | ||
1869 | */ | ||
1870 | void CLOCK_SetupPLL0Mult(uint32_t multiply_by, uint32_t input_freq) | ||
1871 | { | ||
1872 | uint32_t cco_freq = input_freq * multiply_by; | ||
1873 | uint32_t pdec = 1U; | ||
1874 | uint32_t selr; | ||
1875 | uint32_t seli; | ||
1876 | uint32_t selp; | ||
1877 | uint32_t mdec, ndec; | ||
1878 | |||
1879 | while (cco_freq < 275000000U) | ||
1880 | { | ||
1881 | multiply_by <<= 1U; /* double value in each iteration */ | ||
1882 | pdec <<= 1U; /* correspondingly double pdec to cancel effect of double msel */ | ||
1883 | cco_freq = input_freq * multiply_by; | ||
1884 | } | ||
1885 | |||
1886 | selr = 0U; | ||
1887 | |||
1888 | if (multiply_by >= 8000UL) | ||
1889 | { | ||
1890 | seli = 1UL; | ||
1891 | } | ||
1892 | else if (multiply_by >= 122UL) | ||
1893 | { | ||
1894 | seli = (uint32_t)(8000UL / multiply_by); /*floor(8000/M) */ | ||
1895 | } | ||
1896 | else | ||
1897 | { | ||
1898 | seli = 2UL * ((uint32_t)(multiply_by / 4UL)) + 3UL; /* 2*floor(M/4) + 3 */ | ||
1899 | } | ||
1900 | |||
1901 | if (seli >= 63U) | ||
1902 | { | ||
1903 | seli = 63U; | ||
1904 | } | ||
1905 | |||
1906 | { | ||
1907 | selp = 31U; | ||
1908 | } | ||
1909 | |||
1910 | if (pdec > 1U) | ||
1911 | { | ||
1912 | pdec = pdec / 2U; /* Account for minus 1 encoding */ | ||
1913 | /* Translate P value */ | ||
1914 | } | ||
1915 | |||
1916 | mdec = (uint32_t)PLL_SSCG1_MDEC_VAL_SET(multiply_by); | ||
1917 | ndec = 0x1U; /* pre divide by 1 (hardcoded) */ | ||
1918 | |||
1919 | SYSCON->PLL0CTRL = SYSCON_PLL0CTRL_CLKEN_MASK | SYSCON_PLL0CTRL_BYPASSPOSTDIV(0) | | ||
1920 | SYSCON_PLL0CTRL_BYPASSPOSTDIV2(0) | (selr << SYSCON_PLL0CTRL_SELR_SHIFT) | | ||
1921 | (seli << SYSCON_PLL0CTRL_SELI_SHIFT) | (selp << SYSCON_PLL0CTRL_SELP_SHIFT); | ||
1922 | SYSCON->PLL0PDEC = pdec | (1UL << SYSCON_PLL0PDEC_PREQ_SHIFT); /* set Pdec value and assert preq */ | ||
1923 | SYSCON->PLL0NDEC = ndec | (1UL << SYSCON_PLL0NDEC_NREQ_SHIFT); /* set Pdec value and assert preq */ | ||
1924 | SYSCON->PLL0SSCG1 = | ||
1925 | mdec | (1UL << SYSCON_PLL0SSCG1_MREQ_SHIFT); /* select non sscg MDEC value, assert mreq and select mdec value */ | ||
1926 | } | ||
1927 | |||
1928 | /* Enable USB DEVICE FULL SPEED clock */ | ||
1929 | /*! brief Enable USB Device FS clock. | ||
1930 | * param src : clock source | ||
1931 | * param freq: clock frequency | ||
1932 | * Enable USB Device Full Speed clock. | ||
1933 | */ | ||
1934 | bool CLOCK_EnableUsbfs0DeviceClock(clock_usbfs_src_t src, uint32_t freq) | ||
1935 | { | ||
1936 | bool ret = true; | ||
1937 | |||
1938 | CLOCK_DisableClock(kCLOCK_Usbd0); | ||
1939 | |||
1940 | if (kCLOCK_UsbfsSrcFro == src) | ||
1941 | { | ||
1942 | switch (freq) | ||
1943 | { | ||
1944 | case 96000000U: | ||
1945 | CLOCK_SetClkDiv(kCLOCK_DivUsb0Clk, 2, false); /*!< Div by 2 to get 48MHz, no divider reset */ | ||
1946 | break; | ||
1947 | |||
1948 | default: | ||
1949 | ret = false; | ||
1950 | break; | ||
1951 | } | ||
1952 | /* Turn ON FRO HF */ | ||
1953 | POWER_DisablePD(kPDRUNCFG_PD_FRO192M); | ||
1954 | /* Enable FRO 96MHz output */ | ||
1955 | ANACTRL->FRO192M_CTRL = ANACTRL->FRO192M_CTRL | ANACTRL_FRO192M_CTRL_ENA_96MHZCLK_MASK; | ||
1956 | /* Select FRO 96 or 48 MHz */ | ||
1957 | CLOCK_AttachClk(kFRO_HF_to_USB0_CLK); | ||
1958 | } | ||
1959 | else | ||
1960 | { | ||
1961 | /*!< Configure XTAL32M */ | ||
1962 | POWER_DisablePD(kPDRUNCFG_PD_XTAL32M); /* Ensure XTAL32M is powered */ | ||
1963 | POWER_DisablePD(kPDRUNCFG_PD_LDOXO32M); /* Ensure XTAL32M is powered */ | ||
1964 | (void)CLOCK_SetupExtClocking(16000000U); /* Enable clk_in clock */ | ||
1965 | SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK; /* Enable clk_in from XTAL32M clock */ | ||
1966 | ANACTRL->XO32M_CTRL |= ANACTRL_XO32M_CTRL_ENABLE_SYSTEM_CLK_OUT_MASK; /* Enable clk_in to system */ | ||
1967 | |||
1968 | /*!< Set up PLL1 */ | ||
1969 | POWER_DisablePD(kPDRUNCFG_PD_PLL1); | ||
1970 | CLOCK_AttachClk(kEXT_CLK_to_PLL1); /*!< Switch PLL1CLKSEL to EXT_CLK */ | ||
1971 | const pll_setup_t pll1Setup = { | ||
1972 | .pllctrl = SYSCON_PLL1CTRL_CLKEN_MASK | SYSCON_PLL1CTRL_SELI(19U) | SYSCON_PLL1CTRL_SELP(9U), | ||
1973 | .pllndec = SYSCON_PLL1NDEC_NDIV(1U), | ||
1974 | .pllpdec = SYSCON_PLL1PDEC_PDIV(5U), | ||
1975 | .pllmdec = SYSCON_PLL1MDEC_MDIV(30U), | ||
1976 | .pllRate = 48000000U, | ||
1977 | .flags = PLL_SETUPFLAG_WAITLOCK}; | ||
1978 | (void)CLOCK_SetPLL1Freq(&pll1Setup); | ||
1979 | |||
1980 | CLOCK_SetClkDiv(kCLOCK_DivUsb0Clk, 1U, false); | ||
1981 | CLOCK_AttachClk(kPLL1_to_USB0_CLK); | ||
1982 | SDK_DelayAtLeastUs(50U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); | ||
1983 | } | ||
1984 | CLOCK_EnableClock(kCLOCK_Usbd0); | ||
1985 | CLOCK_EnableClock(kCLOCK_UsbRam1); | ||
1986 | |||
1987 | return ret; | ||
1988 | } | ||
1989 | |||
1990 | /* Enable USB HOST FULL SPEED clock */ | ||
1991 | /*! brief Enable USB HOST FS clock. | ||
1992 | * param src : clock source | ||
1993 | * param freq: clock frequency | ||
1994 | * Enable USB HOST Full Speed clock. | ||
1995 | */ | ||
1996 | bool CLOCK_EnableUsbfs0HostClock(clock_usbfs_src_t src, uint32_t freq) | ||
1997 | { | ||
1998 | bool ret = true; | ||
1999 | |||
2000 | CLOCK_DisableClock(kCLOCK_Usbhmr0); | ||
2001 | CLOCK_DisableClock(kCLOCK_Usbhsl0); | ||
2002 | |||
2003 | if (kCLOCK_UsbfsSrcFro == src) | ||
2004 | { | ||
2005 | switch (freq) | ||
2006 | { | ||
2007 | case 96000000U: | ||
2008 | CLOCK_SetClkDiv(kCLOCK_DivUsb0Clk, 2, false); /*!< Div by 2 to get 48MHz, no divider reset */ | ||
2009 | break; | ||
2010 | |||
2011 | default: | ||
2012 | ret = false; | ||
2013 | break; | ||
2014 | } | ||
2015 | /* Turn ON FRO HF */ | ||
2016 | POWER_DisablePD(kPDRUNCFG_PD_FRO192M); | ||
2017 | /* Enable FRO 96MHz output */ | ||
2018 | ANACTRL->FRO192M_CTRL = ANACTRL->FRO192M_CTRL | ANACTRL_FRO192M_CTRL_ENA_96MHZCLK_MASK; | ||
2019 | /* Select FRO 96 MHz */ | ||
2020 | CLOCK_AttachClk(kFRO_HF_to_USB0_CLK); | ||
2021 | } | ||
2022 | else | ||
2023 | { | ||
2024 | /*!< Configure XTAL32M */ | ||
2025 | POWER_DisablePD(kPDRUNCFG_PD_XTAL32M); /* Ensure XTAL32M is powered */ | ||
2026 | POWER_DisablePD(kPDRUNCFG_PD_LDOXO32M); /* Ensure XTAL32M is powered */ | ||
2027 | (void)CLOCK_SetupExtClocking(16000000U); /* Enable clk_in clock */ | ||
2028 | SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK; /* Enable clk_in from XTAL32M clock */ | ||
2029 | ANACTRL->XO32M_CTRL |= ANACTRL_XO32M_CTRL_ENABLE_SYSTEM_CLK_OUT_MASK; /* Enable clk_in to system */ | ||
2030 | |||
2031 | /*!< Set up PLL1 */ | ||
2032 | POWER_DisablePD(kPDRUNCFG_PD_PLL1); | ||
2033 | CLOCK_AttachClk(kEXT_CLK_to_PLL1); /*!< Switch PLL1CLKSEL to EXT_CLK */ | ||
2034 | const pll_setup_t pll1Setup = { | ||
2035 | .pllctrl = SYSCON_PLL1CTRL_CLKEN_MASK | SYSCON_PLL1CTRL_SELI(19U) | SYSCON_PLL1CTRL_SELP(9U), | ||
2036 | .pllndec = SYSCON_PLL1NDEC_NDIV(1U), | ||
2037 | .pllpdec = SYSCON_PLL1PDEC_PDIV(5U), | ||
2038 | .pllmdec = SYSCON_PLL1MDEC_MDIV(30U), | ||
2039 | .pllRate = 48000000U, | ||
2040 | .flags = PLL_SETUPFLAG_WAITLOCK}; | ||
2041 | (void)CLOCK_SetPLL1Freq(&pll1Setup); | ||
2042 | |||
2043 | CLOCK_SetClkDiv(kCLOCK_DivUsb0Clk, 1U, false); | ||
2044 | CLOCK_AttachClk(kPLL1_to_USB0_CLK); | ||
2045 | SDK_DelayAtLeastUs(50U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); | ||
2046 | } | ||
2047 | CLOCK_EnableClock(kCLOCK_Usbhmr0); | ||
2048 | CLOCK_EnableClock(kCLOCK_Usbhsl0); | ||
2049 | CLOCK_EnableClock(kCLOCK_UsbRam1); | ||
2050 | |||
2051 | return ret; | ||
2052 | } | ||
2053 | |||
2054 | /* Enable USB PHY clock */ | ||
2055 | bool CLOCK_EnableUsbhs0PhyPllClock(clock_usb_phy_src_t src, uint32_t freq) | ||
2056 | { | ||
2057 | volatile uint32_t i; | ||
2058 | uint32_t phyPllDiv = 0U; | ||
2059 | uint16_t multiplier = 0U; | ||
2060 | |||
2061 | POWER_DisablePD(kPDRUNCFG_PD_XTAL32M); | ||
2062 | POWER_DisablePD(kPDRUNCFG_PD_LDOXO32M); | ||
2063 | POWER_DisablePD(kPDRUNCFG_PD_FRO32K); /*!< Ensure FRO32k is on */ | ||
2064 | POWER_DisablePD(kPDRUNCFG_PD_XTAL32K); /*!< Ensure xtal32k is on */ | ||
2065 | POWER_DisablePD(kPDRUNCFG_PD_USB1_PHY); /*!< Ensure xtal32k is on */ | ||
2066 | POWER_DisablePD(kPDRUNCFG_PD_LDOUSBHS); /*!< Ensure xtal32k is on */ | ||
2067 | |||
2068 | /* wait to make sure PHY power is fully up */ | ||
2069 | i = 100000U; | ||
2070 | while ((i--) != 0U) | ||
2071 | { | ||
2072 | __ASM("nop"); | ||
2073 | } | ||
2074 | |||
2075 | SYSCON->AHBCLKCTRLSET[2] = SYSCON_AHBCLKCTRL2_ANALOG_CTRL(1); | ||
2076 | SYSCON->AHBCLKCTRLSET[2] = SYSCON_AHBCLKCTRL2_USB1_PHY(1); | ||
2077 | |||
2078 | USBPHY->CTRL_CLR = USBPHY_CTRL_SFTRST_MASK; | ||
2079 | |||
2080 | multiplier = 480000000 / freq; | ||
2081 | |||
2082 | switch (multiplier) | ||
2083 | { | ||
2084 | case 15: | ||
2085 | { | ||
2086 | phyPllDiv = USBPHY_PLL_SIC_PLL_DIV_SEL(0U); | ||
2087 | break; | ||
2088 | } | ||
2089 | case 16: | ||
2090 | { | ||
2091 | phyPllDiv = USBPHY_PLL_SIC_PLL_DIV_SEL(1U); | ||
2092 | break; | ||
2093 | } | ||
2094 | case 20: | ||
2095 | { | ||
2096 | phyPllDiv = USBPHY_PLL_SIC_PLL_DIV_SEL(2U); | ||
2097 | break; | ||
2098 | } | ||
2099 | case 24: | ||
2100 | { | ||
2101 | phyPllDiv = USBPHY_PLL_SIC_PLL_DIV_SEL(4U); | ||
2102 | break; | ||
2103 | } | ||
2104 | case 25: | ||
2105 | { | ||
2106 | phyPllDiv = USBPHY_PLL_SIC_PLL_DIV_SEL(5U); | ||
2107 | break; | ||
2108 | } | ||
2109 | case 30: | ||
2110 | { | ||
2111 | phyPllDiv = USBPHY_PLL_SIC_PLL_DIV_SEL(6U); | ||
2112 | break; | ||
2113 | } | ||
2114 | default: | ||
2115 | { | ||
2116 | return false; | ||
2117 | } | ||
2118 | } | ||
2119 | USBPHY->PLL_SIC = (USBPHY->PLL_SIC & ~USBPHY_PLL_SIC_PLL_DIV_SEL(0x7)) | phyPllDiv; | ||
2120 | USBPHY->PLL_SIC_SET = USBPHY_PLL_SIC_SET_PLL_REG_ENABLE_MASK; | ||
2121 | USBPHY->PLL_SIC_CLR = (1UL << 16U); // Reserved. User must set this bit to 0x0 | ||
2122 | USBPHY->PLL_SIC_SET = USBPHY_PLL_SIC_SET_PLL_POWER_MASK; | ||
2123 | USBPHY->PLL_SIC_SET = USBPHY_PLL_SIC_SET_PLL_EN_USB_CLKS_MASK; | ||
2124 | |||
2125 | USBPHY->CTRL_CLR = USBPHY_CTRL_CLR_CLKGATE_MASK; | ||
2126 | USBPHY->PWD_SET = 0x0; | ||
2127 | |||
2128 | return true; | ||
2129 | } | ||
2130 | |||
2131 | /* Enable USB DEVICE HIGH SPEED clock */ | ||
2132 | bool CLOCK_EnableUsbhs0DeviceClock(clock_usbhs_src_t src, uint32_t freq) | ||
2133 | { | ||
2134 | SYSCON->AHBCLKCTRLSET[2] = SYSCON_AHBCLKCTRL2_USB1_RAM(1); | ||
2135 | SYSCON->AHBCLKCTRLSET[2] = SYSCON_AHBCLKCTRL2_USB1_DEV(1); | ||
2136 | |||
2137 | /* 16 MHz will be driven by the tb on the xtal1 pin of XTAL32M */ | ||
2138 | SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK; /* Enable clock_in clock for clock module. */ | ||
2139 | ANACTRL->XO32M_CTRL |= ANACTRL_XO32M_CTRL_ENABLE_PLL_USB_OUT(1); | ||
2140 | return true; | ||
2141 | } | ||
2142 | |||
2143 | /* Enable USB HOST HIGH SPEED clock */ | ||
2144 | bool CLOCK_EnableUsbhs0HostClock(clock_usbhs_src_t src, uint32_t freq) | ||
2145 | { | ||
2146 | SYSCON->AHBCLKCTRLSET[2] = SYSCON_AHBCLKCTRL2_USB1_RAM(1); | ||
2147 | SYSCON->AHBCLKCTRLSET[2] = SYSCON_AHBCLKCTRL2_USB1_HOST(1); | ||
2148 | |||
2149 | /* 16 MHz will be driven by the tb on the xtal1 pin of XTAL32M */ | ||
2150 | SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_CLKIN_ENA_MASK; /* Enable clock_in clock for clock module. */ | ||
2151 | ANACTRL->XO32M_CTRL |= ANACTRL_XO32M_CTRL_ENABLE_PLL_USB_OUT(1); | ||
2152 | |||
2153 | return true; | ||
2154 | } | ||