diff options
Diffstat (limited to 'lib/chibios-contrib/ext/mcux-sdk/devices/K32L2A41A/drivers/fsl_clock.c')
-rw-r--r-- | lib/chibios-contrib/ext/mcux-sdk/devices/K32L2A41A/drivers/fsl_clock.c | 1214 |
1 files changed, 1214 insertions, 0 deletions
diff --git a/lib/chibios-contrib/ext/mcux-sdk/devices/K32L2A41A/drivers/fsl_clock.c b/lib/chibios-contrib/ext/mcux-sdk/devices/K32L2A41A/drivers/fsl_clock.c new file mode 100644 index 000000000..c2b032d18 --- /dev/null +++ b/lib/chibios-contrib/ext/mcux-sdk/devices/K32L2A41A/drivers/fsl_clock.c | |||
@@ -0,0 +1,1214 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015, Freescale Semiconductor, Inc. | ||
3 | * Copyright 2016 - 2019, NXP | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * SPDX-License-Identifier: BSD-3-Clause | ||
7 | */ | ||
8 | |||
9 | #include "fsl_clock.h" | ||
10 | |||
11 | /******************************************************************************* | ||
12 | * Definitions | ||
13 | ******************************************************************************/ | ||
14 | |||
15 | /* Component ID definition, used by tools. */ | ||
16 | #ifndef FSL_COMPONENT_ID | ||
17 | #define FSL_COMPONENT_ID "platform.drivers.clock" | ||
18 | #endif | ||
19 | |||
20 | #define SCG_SIRC_LOW_RANGE_FREQ 2000000U /* Slow IRC low range clock frequency. */ | ||
21 | #define SCG_SIRC_HIGH_RANGE_FREQ 8000000U /* Slow IRC high range clock frequency. */ | ||
22 | |||
23 | #define SCG_FIRC_FREQ0 48000000U /* Fast IRC trimed clock frequency(48MHz). */ | ||
24 | #define SCG_FIRC_FREQ1 52000000U /* Fast IRC trimed clock frequency(52MHz). */ | ||
25 | #define SCG_FIRC_FREQ2 56000000U /* Fast IRC trimed clock frequency(56MHz). */ | ||
26 | #define SCG_FIRC_FREQ3 60000000U /* Fast IRC trimed clock frequency(60MHz). */ | ||
27 | |||
28 | /* | ||
29 | * System PLL base divider value, it is the PLL reference clock divider | ||
30 | * value when SCG_SPLLCFG[PREDIV]=0. | ||
31 | */ | ||
32 | #define SCG_SPLL_PREDIV_BASE_VALUE 1U | ||
33 | |||
34 | /* | ||
35 | * System PLL base multiplier value, it is the PLL multiplier value | ||
36 | * when SCG_SPLLCFG[MULT]=0. | ||
37 | */ | ||
38 | #define SCG_SPLL_MULT_BASE_VALUE 16U | ||
39 | |||
40 | #define SCG_SPLL_PREDIV_MAX_VALUE 7U /* Max value of SCG_SPLLCFG[PREDIV]. */ | ||
41 | #define SCG_SPLL_MULT_MAX_VALUE 31U /* Max value of SCG_SPLLCFG[MULT]. */ | ||
42 | |||
43 | /* | ||
44 | * System PLL reference clock after SCG_SPLLCFG[PREDIV] should be in | ||
45 | * the range of SCG_SPLL_REF_MIN to SCG_SPLL_REF_MAX. | ||
46 | */ | ||
47 | #define SCG_SPLL_REF_MIN 8000000UL | ||
48 | #define SCG_SPLL_REF_MAX 32000000UL | ||
49 | |||
50 | #define SCG_CSR_SCS_VAL ((SCG->CSR & SCG_CSR_SCS_MASK) >> SCG_CSR_SCS_SHIFT) | ||
51 | #define SCG_SOSCDIV_SOSCDIV1_VAL ((SCG->SOSCDIV & SCG_SOSCDIV_SOSCDIV1_MASK) >> SCG_SOSCDIV_SOSCDIV1_SHIFT) | ||
52 | #define SCG_SOSCDIV_SOSCDIV2_VAL ((SCG->SOSCDIV & SCG_SOSCDIV_SOSCDIV2_MASK) >> SCG_SOSCDIV_SOSCDIV2_SHIFT) | ||
53 | #define SCG_SOSCDIV_SOSCDIV3_VAL ((SCG->SOSCDIV & SCG_SOSCDIV_SOSCDIV3_MASK) >> SCG_SOSCDIV_SOSCDIV3_SHIFT) | ||
54 | #define SCG_SIRCDIV_SIRCDIV1_VAL ((SCG->SIRCDIV & SCG_SIRCDIV_SIRCDIV1_MASK) >> SCG_SIRCDIV_SIRCDIV1_SHIFT) | ||
55 | #define SCG_SIRCDIV_SIRCDIV2_VAL ((SCG->SIRCDIV & SCG_SIRCDIV_SIRCDIV2_MASK) >> SCG_SIRCDIV_SIRCDIV2_SHIFT) | ||
56 | #define SCG_SIRCDIV_SIRCDIV3_VAL ((SCG->SIRCDIV & SCG_SIRCDIV_SIRCDIV3_MASK) >> SCG_SIRCDIV_SIRCDIV3_SHIFT) | ||
57 | #define SCG_FIRCDIV_FIRCDIV1_VAL ((SCG->FIRCDIV & SCG_FIRCDIV_FIRCDIV1_MASK) >> SCG_FIRCDIV_FIRCDIV1_SHIFT) | ||
58 | #define SCG_FIRCDIV_FIRCDIV2_VAL ((SCG->FIRCDIV & SCG_FIRCDIV_FIRCDIV2_MASK) >> SCG_FIRCDIV_FIRCDIV2_SHIFT) | ||
59 | #define SCG_FIRCDIV_FIRCDIV3_VAL ((SCG->FIRCDIV & SCG_FIRCDIV_FIRCDIV3_MASK) >> SCG_FIRCDIV_FIRCDIV3_SHIFT) | ||
60 | |||
61 | #define SCG_SPLLDIV_SPLLDIV1_VAL ((SCG->SPLLDIV & SCG_SPLLDIV_SPLLDIV1_MASK) >> SCG_SPLLDIV_SPLLDIV1_SHIFT) | ||
62 | #define SCG_SPLLDIV_SPLLDIV2_VAL ((SCG->SPLLDIV & SCG_SPLLDIV_SPLLDIV2_MASK) >> SCG_SPLLDIV_SPLLDIV2_SHIFT) | ||
63 | #define SCG_SPLLDIV_SPLLDIV3_VAL ((SCG->SPLLDIV & SCG_SPLLDIV_SPLLDIV3_MASK) >> SCG_SPLLDIV_SPLLDIV3_SHIFT) | ||
64 | |||
65 | #define SCG_SIRCCFG_RANGE_VAL ((SCG->SIRCCFG & SCG_SIRCCFG_RANGE_MASK) >> SCG_SIRCCFG_RANGE_SHIFT) | ||
66 | #define SCG_FIRCCFG_RANGE_VAL ((SCG->FIRCCFG & SCG_FIRCCFG_RANGE_MASK) >> SCG_FIRCCFG_RANGE_SHIFT) | ||
67 | |||
68 | #define SCG_SPLLCFG_PREDIV_VAL ((SCG->SPLLCFG & SCG_SPLLCFG_PREDIV_MASK) >> SCG_SPLLCFG_PREDIV_SHIFT) | ||
69 | #define SCG_SPLLCFG_MULT_VAL ((SCG->SPLLCFG & SCG_SPLLCFG_MULT_MASK) >> SCG_SPLLCFG_MULT_SHIFT) | ||
70 | |||
71 | #define PCC_PCS_VAL(reg) (((reg)&PCC_CLKCFG_PCS_MASK) >> PCC_CLKCFG_PCS_SHIFT) | ||
72 | #define PCC_FRAC_VAL(reg) (((reg)&PCC_CLKCFG_FRAC_MASK) >> PCC_CLKCFG_FRAC_SHIFT) | ||
73 | #define PCC_PCD_VAL(reg) (((reg)&PCC_CLKCFG_PCD_MASK) >> PCC_CLKCFG_PCD_SHIFT) | ||
74 | |||
75 | /******************************************************************************* | ||
76 | * Variables | ||
77 | ******************************************************************************/ | ||
78 | |||
79 | /* External XTAL0 (OSC0) clock frequency. */ | ||
80 | volatile uint32_t g_xtal0Freq; | ||
81 | |||
82 | /******************************************************************************* | ||
83 | * Prototypes | ||
84 | ******************************************************************************/ | ||
85 | |||
86 | /*! | ||
87 | * @brief Get the common System PLL frequency for both RAW SPLL output and SPLL PFD output. | ||
88 | * | ||
89 | * The "raw" SPLL output is the clkout divided by postdiv1-2 of SAPLL. | ||
90 | * The "common" System PLL frequency is the common part for both RAW SPLL and SPLL PFD output. | ||
91 | * That is the frequency calculated based on the clock source which passes through POSTDIV & MULT. | ||
92 | * "Common" SPLL Frequency = Divided Reference Frequency * MULT | ||
93 | * | ||
94 | * @return Clock frequency; If the clock is invalid, returns 0. | ||
95 | */ | ||
96 | static uint32_t CLOCK_GetSysPllCommonFreq(void); | ||
97 | |||
98 | /******************************************************************************* | ||
99 | * Code | ||
100 | ******************************************************************************/ | ||
101 | |||
102 | /*! | ||
103 | * brief Get the external reference clock frequency (ERCLK). | ||
104 | * | ||
105 | * return Clock frequency in Hz. | ||
106 | */ | ||
107 | uint32_t CLOCK_GetErClkFreq(void) | ||
108 | { | ||
109 | uint32_t freq; | ||
110 | |||
111 | if ((SCG->SOSCCSR & SCG_SOSCCSR_SOSCEN_MASK) != 0UL) | ||
112 | { | ||
113 | /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */ | ||
114 | assert(g_xtal0Freq); | ||
115 | freq = g_xtal0Freq; | ||
116 | } | ||
117 | else | ||
118 | { | ||
119 | freq = 0U; | ||
120 | } | ||
121 | |||
122 | return freq; | ||
123 | } | ||
124 | |||
125 | /*! | ||
126 | * brief Get the OSC 32K clock frequency (OSC32KCLK). | ||
127 | * | ||
128 | * return Clock frequency in Hz. | ||
129 | */ | ||
130 | uint32_t CLOCK_GetOsc32kClkFreq(void) | ||
131 | { | ||
132 | return (CLOCK_GetErClkFreq() == 32768U) ? 32768U : 0U; | ||
133 | } | ||
134 | |||
135 | /*! | ||
136 | * brief Get the flash clock frequency. | ||
137 | * | ||
138 | * return Clock frequency in Hz. | ||
139 | */ | ||
140 | uint32_t CLOCK_GetFlashClkFreq(void) | ||
141 | { | ||
142 | return CLOCK_GetSysClkFreq(kSCG_SysClkSlow); | ||
143 | } | ||
144 | |||
145 | /*! | ||
146 | * brief Get the bus clock frequency. | ||
147 | * | ||
148 | * return Clock frequency in Hz. | ||
149 | */ | ||
150 | uint32_t CLOCK_GetBusClkFreq(void) | ||
151 | { | ||
152 | return CLOCK_GetSysClkFreq(kSCG_SysClkSlow); | ||
153 | } | ||
154 | |||
155 | /*! | ||
156 | * brief Get the platform clock frequency. | ||
157 | * | ||
158 | * return Clock frequency in Hz. | ||
159 | */ | ||
160 | uint32_t CLOCK_GetPlatClkFreq(void) | ||
161 | { | ||
162 | return CLOCK_GetSysClkFreq(kSCG_SysClkCore); | ||
163 | } | ||
164 | |||
165 | /*! | ||
166 | * brief Get the core clock or system clock frequency. | ||
167 | * | ||
168 | * return Clock frequency in Hz. | ||
169 | */ | ||
170 | uint32_t CLOCK_GetCoreSysClkFreq(void) | ||
171 | { | ||
172 | return CLOCK_GetSysClkFreq(kSCG_SysClkCore); | ||
173 | } | ||
174 | |||
175 | /*! | ||
176 | * brief Gets the clock frequency for a specific clock name. | ||
177 | * | ||
178 | * This function checks the current clock configurations and then calculates | ||
179 | * the clock frequency for a specific clock name defined in clock_name_t. | ||
180 | * | ||
181 | * param clockName Clock names defined in clock_name_t | ||
182 | * return Clock frequency value in hertz | ||
183 | */ | ||
184 | uint32_t CLOCK_GetFreq(clock_name_t clockName) | ||
185 | { | ||
186 | uint32_t freq; | ||
187 | |||
188 | switch (clockName) | ||
189 | { | ||
190 | case kCLOCK_CoreSysClk: | ||
191 | case kCLOCK_PlatClk: | ||
192 | freq = CLOCK_GetSysClkFreq(kSCG_SysClkCore); | ||
193 | break; | ||
194 | case kCLOCK_BusClk: | ||
195 | case kCLOCK_FlashClk: | ||
196 | freq = CLOCK_GetSysClkFreq(kSCG_SysClkSlow); | ||
197 | break; | ||
198 | case kCLOCK_ScgSysOscClk: | ||
199 | freq = CLOCK_GetSysOscFreq(); | ||
200 | break; | ||
201 | case kCLOCK_ScgSircClk: | ||
202 | freq = CLOCK_GetSircFreq(); | ||
203 | break; | ||
204 | case kCLOCK_ScgFircClk: | ||
205 | freq = CLOCK_GetFircFreq(); | ||
206 | break; | ||
207 | case kCLOCK_ScgSysPllClk: | ||
208 | freq = CLOCK_GetSysPllFreq(); | ||
209 | break; | ||
210 | case kCLOCK_ScgSysOscAsyncDiv1Clk: | ||
211 | freq = CLOCK_GetSysOscAsyncFreq(kSCG_AsyncDiv1Clk); | ||
212 | break; | ||
213 | case kCLOCK_ScgSysOscAsyncDiv2Clk: | ||
214 | freq = CLOCK_GetSysOscAsyncFreq(kSCG_AsyncDiv2Clk); | ||
215 | break; | ||
216 | case kCLOCK_ScgSysOscAsyncDiv3Clk: | ||
217 | freq = CLOCK_GetSysOscAsyncFreq(kSCG_AsyncDiv3Clk); | ||
218 | break; | ||
219 | case kCLOCK_ScgSircAsyncDiv1Clk: | ||
220 | freq = CLOCK_GetSircAsyncFreq(kSCG_AsyncDiv1Clk); | ||
221 | break; | ||
222 | case kCLOCK_ScgSircAsyncDiv2Clk: | ||
223 | freq = CLOCK_GetSircAsyncFreq(kSCG_AsyncDiv2Clk); | ||
224 | break; | ||
225 | case kCLOCK_ScgSircAsyncDiv3Clk: | ||
226 | freq = CLOCK_GetSircAsyncFreq(kSCG_AsyncDiv3Clk); | ||
227 | break; | ||
228 | case kCLOCK_ScgFircAsyncDiv1Clk: | ||
229 | freq = CLOCK_GetFircAsyncFreq(kSCG_AsyncDiv1Clk); | ||
230 | break; | ||
231 | case kCLOCK_ScgFircAsyncDiv2Clk: | ||
232 | freq = CLOCK_GetFircAsyncFreq(kSCG_AsyncDiv2Clk); | ||
233 | break; | ||
234 | case kCLOCK_ScgFircAsyncDiv3Clk: | ||
235 | freq = CLOCK_GetFircAsyncFreq(kSCG_AsyncDiv3Clk); | ||
236 | break; | ||
237 | case kCLOCK_ScgSysPllAsyncDiv1Clk: | ||
238 | freq = CLOCK_GetSysPllAsyncFreq(kSCG_AsyncDiv1Clk); | ||
239 | break; | ||
240 | case kCLOCK_ScgSysPllAsyncDiv2Clk: | ||
241 | freq = CLOCK_GetSysPllAsyncFreq(kSCG_AsyncDiv2Clk); | ||
242 | break; | ||
243 | case kCLOCK_ScgSysPllAsyncDiv3Clk: | ||
244 | freq = CLOCK_GetSysPllAsyncFreq(kSCG_AsyncDiv3Clk); | ||
245 | break; | ||
246 | case kCLOCK_LpoClk: | ||
247 | freq = LPO_CLK_FREQ; | ||
248 | break; | ||
249 | case kCLOCK_Osc32kClk: | ||
250 | freq = (CLOCK_GetErClkFreq() == 32768U) ? 32768U : 0U; | ||
251 | break; | ||
252 | case kCLOCK_ErClk: | ||
253 | freq = CLOCK_GetErClkFreq(); | ||
254 | break; | ||
255 | default: | ||
256 | freq = 0U; | ||
257 | break; | ||
258 | } | ||
259 | return freq; | ||
260 | } | ||
261 | |||
262 | /*! | ||
263 | * brief Gets the clock frequency for a specific IP module. | ||
264 | * | ||
265 | * This function gets the IP module clock frequency based on PCC registers. It is | ||
266 | * only used for the IP modules which could select clock source by PCC[PCS]. | ||
267 | * | ||
268 | * param name Which peripheral to get, see \ref clock_ip_name_t. | ||
269 | * return Clock frequency value in hertz | ||
270 | */ | ||
271 | uint32_t CLOCK_GetIpFreq(clock_ip_name_t name) | ||
272 | { | ||
273 | uint32_t reg = (*(volatile uint32_t *)(uint32_t)name); | ||
274 | |||
275 | scg_async_clk_t asycClk; | ||
276 | uint32_t freq; | ||
277 | uint32_t ret; | ||
278 | |||
279 | assert(reg & PCC_CLKCFG_PR_MASK); | ||
280 | |||
281 | /* USB uses SCG DIV1 clock, others use SCG DIV3 clock. */ | ||
282 | if (kCLOCK_Usbfs0 == name) | ||
283 | { | ||
284 | asycClk = kSCG_AsyncDiv1Clk; | ||
285 | } | ||
286 | else | ||
287 | { | ||
288 | asycClk = kSCG_AsyncDiv3Clk; | ||
289 | } | ||
290 | |||
291 | switch (PCC_PCS_VAL(reg)) | ||
292 | { | ||
293 | case (uint32_t)kCLOCK_IpSrcSysOscAsync: | ||
294 | freq = CLOCK_GetSysOscAsyncFreq(asycClk); | ||
295 | break; | ||
296 | case (uint32_t)kCLOCK_IpSrcSircAsync: | ||
297 | freq = CLOCK_GetSircAsyncFreq(asycClk); | ||
298 | break; | ||
299 | case (uint32_t)kCLOCK_IpSrcFircAsync: | ||
300 | freq = CLOCK_GetFircAsyncFreq(asycClk); | ||
301 | break; | ||
302 | case (uint32_t)kCLOCK_IpSrcSysPllAsync: | ||
303 | freq = CLOCK_GetSysPllAsyncFreq(asycClk); | ||
304 | break; | ||
305 | default: | ||
306 | freq = 0U; | ||
307 | break; | ||
308 | } | ||
309 | |||
310 | if ((reg & (PCC_CLKCFG_PCD_MASK | PCC_CLKCFG_FRAC_MASK)) != 0UL) | ||
311 | { | ||
312 | ret = freq * (PCC_FRAC_VAL(reg) + 1U) / (PCC_PCD_VAL(reg) + 1U); | ||
313 | } | ||
314 | else | ||
315 | { | ||
316 | ret = freq; | ||
317 | } | ||
318 | |||
319 | return ret; | ||
320 | } | ||
321 | |||
322 | /*! brief Enable USB FS clock. | ||
323 | * | ||
324 | * param src USB FS clock source. | ||
325 | * param freq The frequency specified by src. | ||
326 | * retval true The clock is set successfully. | ||
327 | * retval false The clock source is invalid to get proper USB FS clock. | ||
328 | */ | ||
329 | bool CLOCK_EnableUsbfs0Clock(clock_ip_src_t src, uint32_t freq) | ||
330 | { | ||
331 | bool ret = true; | ||
332 | |||
333 | CLOCK_DisableClock(kCLOCK_Usbfs0); | ||
334 | |||
335 | if (kCLOCK_IpSrcNoneOrExt == src) | ||
336 | { | ||
337 | CLOCK_SetIpSrc(kCLOCK_Usbfs0, kCLOCK_IpSrcNoneOrExt); | ||
338 | } | ||
339 | else | ||
340 | { | ||
341 | switch (freq) | ||
342 | { | ||
343 | case 120000000U: | ||
344 | CLOCK_SetIpSrcDiv(kCLOCK_Usbfs0, src, 4U, 1U); | ||
345 | break; | ||
346 | case 96000000U: | ||
347 | CLOCK_SetIpSrcDiv(kCLOCK_Usbfs0, src, 1U, 0U); | ||
348 | break; | ||
349 | case 72000000U: | ||
350 | CLOCK_SetIpSrcDiv(kCLOCK_Usbfs0, src, 2U, 1U); | ||
351 | break; | ||
352 | case 48000000U: | ||
353 | CLOCK_SetIpSrcDiv(kCLOCK_Usbfs0, src, 0U, 0U); | ||
354 | break; | ||
355 | default: | ||
356 | ret = false; | ||
357 | break; | ||
358 | } | ||
359 | } | ||
360 | |||
361 | CLOCK_EnableClock(kCLOCK_Usbfs0); | ||
362 | |||
363 | return ret; | ||
364 | } | ||
365 | |||
366 | /*! | ||
367 | * brief Gets the SCG system clock frequency. | ||
368 | * | ||
369 | * This function gets the SCG system clock frequency. These clocks are used for | ||
370 | * core, platform, external, and bus clock domains. | ||
371 | * | ||
372 | * param type Which type of clock to get, core clock or slow clock. | ||
373 | * return Clock frequency. | ||
374 | */ | ||
375 | uint32_t CLOCK_GetSysClkFreq(scg_sys_clk_t type) | ||
376 | { | ||
377 | uint32_t freq; | ||
378 | |||
379 | scg_sys_clk_config_t sysClkConfig; | ||
380 | |||
381 | CLOCK_GetCurSysClkConfig(&sysClkConfig); /* Get the main clock for SoC platform. */ | ||
382 | |||
383 | switch (sysClkConfig.src) | ||
384 | { | ||
385 | case (uint8_t)kSCG_SysClkSrcSysOsc: | ||
386 | freq = CLOCK_GetSysOscFreq(); | ||
387 | break; | ||
388 | case (uint8_t)kSCG_SysClkSrcSirc: | ||
389 | freq = CLOCK_GetSircFreq(); | ||
390 | break; | ||
391 | case (uint8_t)kSCG_SysClkSrcFirc: | ||
392 | freq = CLOCK_GetFircFreq(); | ||
393 | break; | ||
394 | case (uint8_t)kSCG_SysClkSrcSysPll: | ||
395 | freq = CLOCK_GetSysPllFreq(); | ||
396 | break; | ||
397 | default: | ||
398 | freq = 0U; | ||
399 | break; | ||
400 | } | ||
401 | |||
402 | freq /= ((uint32_t)sysClkConfig.divCore + 1UL); /* divided by the DIVCORE firstly. */ | ||
403 | |||
404 | if (kSCG_SysClkSlow == type) | ||
405 | { | ||
406 | freq /= ((uint32_t)sysClkConfig.divSlow + 1UL); | ||
407 | } | ||
408 | else | ||
409 | { | ||
410 | /* Add comment to prevent the case of MISRA C-2012 rule 15.7 */ | ||
411 | } | ||
412 | |||
413 | return freq; | ||
414 | } | ||
415 | |||
416 | /*! | ||
417 | * brief Initializes the SCG system OSC. | ||
418 | * | ||
419 | * This function enables the SCG system OSC clock according to the | ||
420 | * configuration. | ||
421 | * | ||
422 | * param config Pointer to the configuration structure. | ||
423 | * retval kStatus_Success System OSC is initialized. | ||
424 | * retval kStatus_SCG_Busy System OSC has been enabled and is used by the system clock. | ||
425 | * retval kStatus_ReadOnly System OSC control register is locked. | ||
426 | * | ||
427 | * note This function can't detect whether the system OSC has been enabled and | ||
428 | * used by an IP. | ||
429 | */ | ||
430 | status_t CLOCK_InitSysOsc(const scg_sosc_config_t *config) | ||
431 | { | ||
432 | assert(config); | ||
433 | uint8_t range = 0U; /* SCG_SOSCCFG[RANGE] */ | ||
434 | status_t status; | ||
435 | uint8_t tmp8; | ||
436 | |||
437 | /* If crystal oscillator used, need to get RANGE value base on frequency. */ | ||
438 | if (kSCG_SysOscModeExt != config->workMode) | ||
439 | { | ||
440 | if ((config->freq >= 32768U) && (config->freq <= 40000U)) | ||
441 | { | ||
442 | range = 1U; | ||
443 | } | ||
444 | else if ((config->freq >= 1000000U) && (config->freq <= 8000000U)) | ||
445 | { | ||
446 | range = 2U; | ||
447 | } | ||
448 | else if ((config->freq >= 8000000U) && (config->freq <= 32000000U)) | ||
449 | { | ||
450 | range = 3U; | ||
451 | } | ||
452 | else | ||
453 | { | ||
454 | return kStatus_InvalidArgument; | ||
455 | } | ||
456 | } | ||
457 | |||
458 | /* De-init the SOSC first. */ | ||
459 | status = CLOCK_DeinitSysOsc(); | ||
460 | |||
461 | if (kStatus_Success != status) | ||
462 | { | ||
463 | return status; | ||
464 | } | ||
465 | |||
466 | /* Now start to set up OSC clock. */ | ||
467 | /* Step 1. Setup dividers. */ | ||
468 | SCG->SOSCDIV = | ||
469 | SCG_SOSCDIV_SOSCDIV1(config->div1) | SCG_SOSCDIV_SOSCDIV2(config->div2) | SCG_SOSCDIV_SOSCDIV3(config->div3); | ||
470 | |||
471 | /* Step 2. Set OSC configuration. */ | ||
472 | SCG->SOSCCFG = config->capLoad | (uint32_t)config->workMode | SCG_SOSCCFG_RANGE(range); | ||
473 | |||
474 | /* Step 3. Enable clock. */ | ||
475 | /* SCG->SOSCCSR = SCG_SOSCCSR_SOSCEN_MASK | (config->enableMode); */ | ||
476 | tmp8 = config->enableMode; | ||
477 | tmp8 |= SCG_SOSCCSR_SOSCEN_MASK; | ||
478 | SCG->SOSCCSR = tmp8; | ||
479 | |||
480 | /* Step 4. Wait for OSC clock to be valid. */ | ||
481 | while (0UL == (SCG->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK)) | ||
482 | { | ||
483 | } | ||
484 | |||
485 | /* Step 5. Enabe monitor. */ | ||
486 | SCG->SOSCCSR |= (uint32_t)config->monitorMode; | ||
487 | |||
488 | return kStatus_Success; | ||
489 | } | ||
490 | |||
491 | /*! | ||
492 | * brief De-initializes the SCG system OSC. | ||
493 | * | ||
494 | * This function disables the SCG system OSC clock. | ||
495 | * | ||
496 | * retval kStatus_Success System OSC is deinitialized. | ||
497 | * retval kStatus_SCG_Busy System OSC is used by the system clock. | ||
498 | * retval kStatus_ReadOnly System OSC control register is locked. | ||
499 | * | ||
500 | * note This function can't detect whether the system OSC is used by an IP. | ||
501 | */ | ||
502 | status_t CLOCK_DeinitSysOsc(void) | ||
503 | { | ||
504 | uint32_t reg = SCG->SOSCCSR; | ||
505 | status_t status; | ||
506 | |||
507 | /* If clock is used by system, return error. */ | ||
508 | if ((reg & SCG_SOSCCSR_SOSCSEL_MASK) != 0UL) | ||
509 | { | ||
510 | status = kStatus_SCG_Busy; | ||
511 | } | ||
512 | |||
513 | /* If configure register is locked, return error. */ | ||
514 | else if ((reg & SCG_SOSCCSR_LK_MASK) != 0UL) | ||
515 | { | ||
516 | status = kStatus_ReadOnly; | ||
517 | } | ||
518 | else | ||
519 | { | ||
520 | SCG->SOSCCSR = SCG_SOSCCSR_SOSCERR_MASK; | ||
521 | status = kStatus_Success; | ||
522 | } | ||
523 | |||
524 | return status; | ||
525 | } | ||
526 | |||
527 | /*! | ||
528 | * brief Gets the SCG system OSC clock frequency (SYSOSC). | ||
529 | * | ||
530 | * return Clock frequency; If the clock is invalid, returns 0. | ||
531 | */ | ||
532 | uint32_t CLOCK_GetSysOscFreq(void) | ||
533 | { | ||
534 | uint32_t freq; | ||
535 | |||
536 | if ((SCG->SOSCCSR & SCG_SOSCCSR_SOSCVLD_MASK) != 0UL) /* System OSC clock is valid. */ | ||
537 | { | ||
538 | /* Please call CLOCK_SetXtal0Freq base on board setting before using OSC0 clock. */ | ||
539 | assert(g_xtal0Freq); | ||
540 | freq = g_xtal0Freq; | ||
541 | } | ||
542 | else | ||
543 | { | ||
544 | freq = 0U; | ||
545 | } | ||
546 | |||
547 | return freq; | ||
548 | } | ||
549 | |||
550 | /*! | ||
551 | * brief Gets the SCG asynchronous clock frequency from the system OSC. | ||
552 | * | ||
553 | * param type The asynchronous clock type. | ||
554 | * return Clock frequency; If the clock is invalid, returns 0. | ||
555 | */ | ||
556 | uint32_t CLOCK_GetSysOscAsyncFreq(scg_async_clk_t type) | ||
557 | { | ||
558 | uint32_t oscFreq = CLOCK_GetSysOscFreq(); | ||
559 | uint32_t divider = 0U; | ||
560 | uint32_t freq; | ||
561 | |||
562 | /* Get divider. */ | ||
563 | if (oscFreq != 0UL) | ||
564 | { | ||
565 | switch (type) | ||
566 | { | ||
567 | case kSCG_AsyncDiv3Clk: /* SOSCDIV3_CLK. */ | ||
568 | divider = SCG_SOSCDIV_SOSCDIV3_VAL; | ||
569 | break; | ||
570 | case kSCG_AsyncDiv2Clk: /* SOSCDIV2_CLK. */ | ||
571 | divider = SCG_SOSCDIV_SOSCDIV2_VAL; | ||
572 | break; | ||
573 | case kSCG_AsyncDiv1Clk: /* SOSCDIV1_CLK. */ | ||
574 | divider = SCG_SOSCDIV_SOSCDIV1_VAL; | ||
575 | break; | ||
576 | default: | ||
577 | divider = 0U; | ||
578 | break; | ||
579 | } | ||
580 | } | ||
581 | if (divider != 0U) | ||
582 | { | ||
583 | freq = (oscFreq >> (divider - 1U)); | ||
584 | } | ||
585 | else /* Output disabled. */ | ||
586 | { | ||
587 | freq = 0U; | ||
588 | } | ||
589 | |||
590 | return freq; | ||
591 | } | ||
592 | |||
593 | /*! | ||
594 | * brief Initializes the SCG slow IRC clock. | ||
595 | * | ||
596 | * This function enables the SCG slow IRC clock according to the | ||
597 | * configuration. | ||
598 | * | ||
599 | * param config Pointer to the configuration structure. | ||
600 | * retval kStatus_Success SIRC is initialized. | ||
601 | * retval kStatus_SCG_Busy SIRC has been enabled and is used by system clock. | ||
602 | * retval kStatus_ReadOnly SIRC control register is locked. | ||
603 | * | ||
604 | * note This function can't detect whether the system OSC has been enabled and | ||
605 | * used by an IP. | ||
606 | */ | ||
607 | status_t CLOCK_InitSirc(const scg_sirc_config_t *config) | ||
608 | { | ||
609 | assert(config); | ||
610 | |||
611 | status_t status; | ||
612 | |||
613 | /* De-init the SIRC first. */ | ||
614 | status = CLOCK_DeinitSirc(); | ||
615 | |||
616 | if (status == kStatus_Success) | ||
617 | { | ||
618 | /* Now start to set up SIRC clock. */ | ||
619 | /* Step 1. Setup dividers. */ | ||
620 | SCG->SIRCDIV = SCG_SIRCDIV_SIRCDIV1(config->div1) | SCG_SIRCDIV_SIRCDIV2(config->div2) | | ||
621 | SCG_SIRCDIV_SIRCDIV3(config->div3); | ||
622 | |||
623 | /* Step 2. Set SIRC configuration. */ | ||
624 | SCG->SIRCCFG = SCG_SIRCCFG_RANGE(config->range); | ||
625 | |||
626 | /* Step 3. Enable clock. */ | ||
627 | SCG->SIRCCSR = SCG_SIRCCSR_SIRCEN_MASK | config->enableMode; | ||
628 | |||
629 | /* Step 4. Wait for SIRC clock to be valid. */ | ||
630 | while (0UL == (SCG->SIRCCSR & SCG_SIRCCSR_SIRCVLD_MASK)) | ||
631 | { | ||
632 | } | ||
633 | } | ||
634 | |||
635 | return status; | ||
636 | } | ||
637 | |||
638 | /*! | ||
639 | * brief De-initializes the SCG slow IRC. | ||
640 | * | ||
641 | * This function disables the SCG slow IRC. | ||
642 | * | ||
643 | * retval kStatus_Success SIRC is deinitialized. | ||
644 | * retval kStatus_SCG_Busy SIRC is used by system clock. | ||
645 | * retval kStatus_ReadOnly SIRC control register is locked. | ||
646 | * | ||
647 | * note This function can't detect whether the SIRC is used by an IP. | ||
648 | */ | ||
649 | status_t CLOCK_DeinitSirc(void) | ||
650 | { | ||
651 | uint32_t reg = SCG->SIRCCSR; | ||
652 | status_t status; | ||
653 | |||
654 | /* If clock is used by system, return error. */ | ||
655 | if ((reg & SCG_SIRCCSR_SIRCSEL_MASK) != 0UL) | ||
656 | { | ||
657 | status = kStatus_SCG_Busy; | ||
658 | } | ||
659 | /* If configure register is locked, return error. */ | ||
660 | else if ((reg & SCG_SIRCCSR_LK_MASK) != 0UL) | ||
661 | { | ||
662 | status = kStatus_ReadOnly; | ||
663 | } | ||
664 | else | ||
665 | { | ||
666 | SCG->SIRCCSR = 0U; | ||
667 | status = kStatus_Success; | ||
668 | } | ||
669 | |||
670 | return status; | ||
671 | } | ||
672 | |||
673 | /*! | ||
674 | * brief Gets the SCG SIRC clock frequency. | ||
675 | * | ||
676 | * return Clock frequency; If the clock is invalid, returns 0. | ||
677 | */ | ||
678 | uint32_t CLOCK_GetSircFreq(void) | ||
679 | { | ||
680 | static const uint32_t sircFreq[] = {SCG_SIRC_LOW_RANGE_FREQ, SCG_SIRC_HIGH_RANGE_FREQ}; | ||
681 | uint32_t freq; | ||
682 | |||
683 | if ((SCG->SIRCCSR & SCG_SIRCCSR_SIRCVLD_MASK) != 0UL) /* SIRC is valid. */ | ||
684 | { | ||
685 | freq = sircFreq[SCG_SIRCCFG_RANGE_VAL]; | ||
686 | } | ||
687 | else | ||
688 | { | ||
689 | freq = 0U; | ||
690 | } | ||
691 | |||
692 | return freq; | ||
693 | } | ||
694 | |||
695 | /*! | ||
696 | * brief Gets the SCG asynchronous clock frequency from the SIRC. | ||
697 | * | ||
698 | * param type The asynchronous clock type. | ||
699 | * return Clock frequency; If the clock is invalid, returns 0. | ||
700 | */ | ||
701 | uint32_t CLOCK_GetSircAsyncFreq(scg_async_clk_t type) | ||
702 | { | ||
703 | uint32_t sircFreq = CLOCK_GetSircFreq(); | ||
704 | uint32_t divider = 0U; | ||
705 | uint32_t freq; | ||
706 | |||
707 | /* Get divider. */ | ||
708 | if (sircFreq != 0UL) | ||
709 | { | ||
710 | switch (type) | ||
711 | { | ||
712 | case kSCG_AsyncDiv3Clk: /* SIRCDIV3_CLK. */ | ||
713 | divider = SCG_SIRCDIV_SIRCDIV3_VAL; | ||
714 | break; | ||
715 | case kSCG_AsyncDiv2Clk: /* SIRCDIV2_CLK. */ | ||
716 | divider = SCG_SIRCDIV_SIRCDIV2_VAL; | ||
717 | break; | ||
718 | case kSCG_AsyncDiv1Clk: /* SIRCDIV2_CLK. */ | ||
719 | divider = SCG_SIRCDIV_SIRCDIV1_VAL; | ||
720 | break; | ||
721 | default: | ||
722 | divider = 0U; | ||
723 | break; | ||
724 | } | ||
725 | } | ||
726 | if (divider != 0UL) | ||
727 | { | ||
728 | freq = (sircFreq >> (divider - 1U)); | ||
729 | } | ||
730 | else /* Output disabled. */ | ||
731 | { | ||
732 | freq = 0U; | ||
733 | } | ||
734 | |||
735 | return freq; | ||
736 | } | ||
737 | |||
738 | /*! | ||
739 | * brief Initializes the SCG fast IRC clock. | ||
740 | * | ||
741 | * This function enables the SCG fast IRC clock according to the configuration. | ||
742 | * | ||
743 | * param config Pointer to the configuration structure. | ||
744 | * retval kStatus_Success FIRC is initialized. | ||
745 | * retval kStatus_SCG_Busy FIRC has been enabled and is used by the system clock. | ||
746 | * retval kStatus_ReadOnly FIRC control register is locked. | ||
747 | * | ||
748 | * note This function can't detect whether the FIRC has been enabled and | ||
749 | * used by an IP. | ||
750 | */ | ||
751 | status_t CLOCK_InitFirc(const scg_firc_config_t *config) | ||
752 | { | ||
753 | assert(config); | ||
754 | |||
755 | status_t status; | ||
756 | |||
757 | /* De-init the FIRC first. */ | ||
758 | status = CLOCK_DeinitFirc(); | ||
759 | |||
760 | if (kStatus_Success != status) | ||
761 | { | ||
762 | return status; | ||
763 | } | ||
764 | |||
765 | /* Now start to set up FIRC clock. */ | ||
766 | /* Step 1. Setup dividers. */ | ||
767 | SCG->FIRCDIV = | ||
768 | SCG_FIRCDIV_FIRCDIV1(config->div1) | SCG_FIRCDIV_FIRCDIV2(config->div2) | SCG_FIRCDIV_FIRCDIV3(config->div3); | ||
769 | |||
770 | /* Step 2. Set FIRC configuration. */ | ||
771 | SCG->FIRCCFG = SCG_FIRCCFG_RANGE(config->range); | ||
772 | |||
773 | /* Step 3. Set trimming configuration. */ | ||
774 | if ((config->trimConfig) != NULL) | ||
775 | { | ||
776 | SCG->FIRCTCFG = | ||
777 | SCG_FIRCTCFG_TRIMDIV(config->trimConfig->trimDiv) | SCG_FIRCTCFG_TRIMSRC(config->trimConfig->trimSrc); | ||
778 | |||
779 | /* TODO: Write FIRCSTAT cause bus error: TKT266932. */ | ||
780 | if (kSCG_FircTrimNonUpdate == config->trimConfig->trimMode) | ||
781 | { | ||
782 | SCG->FIRCSTAT = SCG_FIRCSTAT_TRIMCOAR(config->trimConfig->trimCoar) | | ||
783 | SCG_FIRCSTAT_TRIMFINE(config->trimConfig->trimFine); | ||
784 | } | ||
785 | |||
786 | /* trim mode. */ | ||
787 | SCG->FIRCCSR = (uint32_t)(config->trimConfig->trimMode); | ||
788 | |||
789 | if ((SCG->FIRCCSR & SCG_FIRCCSR_FIRCERR_MASK) != 0UL) | ||
790 | { | ||
791 | return kStatus_Fail; | ||
792 | } | ||
793 | } | ||
794 | |||
795 | /* Step 4. Enable clock. */ | ||
796 | SCG->FIRCCSR |= (SCG_FIRCCSR_FIRCEN_MASK | config->enableMode); | ||
797 | |||
798 | /* Step 5. Wait for FIRC clock to be valid. */ | ||
799 | while (0UL == (SCG->FIRCCSR & SCG_FIRCCSR_FIRCVLD_MASK)) | ||
800 | { | ||
801 | } | ||
802 | |||
803 | return kStatus_Success; | ||
804 | } | ||
805 | |||
806 | /*! | ||
807 | * brief De-initializes the SCG fast IRC. | ||
808 | * | ||
809 | * This function disables the SCG fast IRC. | ||
810 | * | ||
811 | * retval kStatus_Success FIRC is deinitialized. | ||
812 | * retval kStatus_SCG_Busy FIRC is used by the system clock. | ||
813 | * retval kStatus_ReadOnly FIRC control register is locked. | ||
814 | * | ||
815 | * note This function can't detect whether the FIRC is used by an IP. | ||
816 | */ | ||
817 | status_t CLOCK_DeinitFirc(void) | ||
818 | { | ||
819 | uint32_t reg = SCG->FIRCCSR; | ||
820 | status_t status = kStatus_Success; | ||
821 | |||
822 | /* If clock is used by system, return error. */ | ||
823 | if ((reg & SCG_FIRCCSR_FIRCSEL_MASK) != 0UL) | ||
824 | { | ||
825 | status = kStatus_SCG_Busy; | ||
826 | } | ||
827 | /* If configure register is locked, return error. */ | ||
828 | else if ((reg & SCG_FIRCCSR_LK_MASK) != 0UL) | ||
829 | { | ||
830 | status = kStatus_ReadOnly; | ||
831 | } | ||
832 | else | ||
833 | { | ||
834 | SCG->FIRCCSR = SCG_FIRCCSR_FIRCERR_MASK; | ||
835 | } | ||
836 | |||
837 | return status; | ||
838 | } | ||
839 | |||
840 | /*! | ||
841 | * brief Gets the SCG FIRC clock frequency. | ||
842 | * | ||
843 | * return Clock frequency; If the clock is invalid, returns 0. | ||
844 | */ | ||
845 | uint32_t CLOCK_GetFircFreq(void) | ||
846 | { | ||
847 | uint32_t freq; | ||
848 | |||
849 | static const uint32_t fircFreq[] = { | ||
850 | SCG_FIRC_FREQ0, | ||
851 | SCG_FIRC_FREQ1, | ||
852 | SCG_FIRC_FREQ2, | ||
853 | SCG_FIRC_FREQ3, | ||
854 | }; | ||
855 | |||
856 | if ((SCG->FIRCCSR & SCG_FIRCCSR_FIRCVLD_MASK) != 0UL) /* FIRC is valid. */ | ||
857 | { | ||
858 | freq = fircFreq[SCG_FIRCCFG_RANGE_VAL]; | ||
859 | } | ||
860 | else | ||
861 | { | ||
862 | freq = 0U; | ||
863 | } | ||
864 | |||
865 | return freq; | ||
866 | } | ||
867 | |||
868 | /*! | ||
869 | * brief Gets the SCG asynchronous clock frequency from the FIRC. | ||
870 | * | ||
871 | * param type The asynchronous clock type. | ||
872 | * return Clock frequency; If the clock is invalid, returns 0. | ||
873 | */ | ||
874 | uint32_t CLOCK_GetFircAsyncFreq(scg_async_clk_t type) | ||
875 | { | ||
876 | uint32_t fircFreq = CLOCK_GetFircFreq(); | ||
877 | uint32_t divider = 0U; | ||
878 | uint32_t freq; | ||
879 | |||
880 | /* Get divider. */ | ||
881 | if (fircFreq != 0UL) | ||
882 | { | ||
883 | switch (type) | ||
884 | { | ||
885 | case kSCG_AsyncDiv3Clk: /* FIRCDIV3_CLK. */ | ||
886 | divider = SCG_FIRCDIV_FIRCDIV3_VAL; | ||
887 | break; | ||
888 | case kSCG_AsyncDiv2Clk: /* FIRCDIV2_CLK. */ | ||
889 | divider = SCG_FIRCDIV_FIRCDIV2_VAL; | ||
890 | break; | ||
891 | case kSCG_AsyncDiv1Clk: /* FIRCDIV1_CLK. */ | ||
892 | divider = SCG_FIRCDIV_FIRCDIV1_VAL; | ||
893 | break; | ||
894 | default: | ||
895 | divider = 0U; | ||
896 | break; | ||
897 | } | ||
898 | } | ||
899 | if (divider != 0U) | ||
900 | { | ||
901 | freq = (fircFreq >> (divider - 1U)); | ||
902 | } | ||
903 | else /* Output disabled. */ | ||
904 | { | ||
905 | freq = 0U; | ||
906 | } | ||
907 | |||
908 | return freq; | ||
909 | } | ||
910 | |||
911 | /*! | ||
912 | * brief Calculates the MULT and PREDIV for the PLL. | ||
913 | * | ||
914 | * This function calculates the proper MULT and PREDIV to generate the desired PLL | ||
915 | * output frequency with the input reference clock frequency. It returns the closest | ||
916 | * frequency match that the PLL can generate. The corresponding MULT/PREDIV are returned with | ||
917 | * parameters. If the desired frequency is not valid, this function returns 0. | ||
918 | * | ||
919 | * param refFreq The input reference clock frequency. | ||
920 | * param desireFreq The desired output clock frequency. | ||
921 | * param mult The value of MULT. | ||
922 | * param prediv The value of PREDIV. | ||
923 | * return The PLL output frequency with the MULT and PREDIV; If | ||
924 | * the desired frequency can't be generated, this function returns 0U. | ||
925 | */ | ||
926 | uint32_t CLOCK_GetSysPllMultDiv(uint32_t refFreq, uint32_t desireFreq, uint8_t *mult, uint8_t *prediv) | ||
927 | { | ||
928 | uint8_t ret_prediv; /* PREDIV to return */ | ||
929 | uint8_t ret_mult; /* MULT to return */ | ||
930 | uint8_t prediv_min; /* Minimal PREDIV value to make reference clock in allowed range. */ | ||
931 | uint8_t prediv_max; /* Max PREDIV value to make reference clock in allowed range. */ | ||
932 | uint8_t prediv_cur; /* PREDIV value for iteration. */ | ||
933 | uint8_t mult_cur; /* MULT value for iteration. */ | ||
934 | uint32_t ret_freq = 0U; /* Output frequency to return .*/ | ||
935 | uint32_t diff = 0xFFFFFFFFU; /* Difference between desireFreq and return frequency. */ | ||
936 | uint32_t ref_div; /* Reference frequency after PREDIV. */ | ||
937 | |||
938 | /* | ||
939 | * Steps: | ||
940 | * 1. Get allowed prediv with such rules: | ||
941 | * 1). refFreq / prediv >= SCG_PLL_REF_MIN. | ||
942 | * 2). refFreq / prediv <= SCG_PLL_REF_MAX. | ||
943 | * 2. For each allowed prediv, there are two candidate mult values: | ||
944 | * 1). (desireFreq / (refFreq / prediv)). | ||
945 | * 2). (desireFreq / (refFreq / prediv)) + 1. | ||
946 | * If could get the precise desired frequency, return current prediv and | ||
947 | * mult directly. Otherwise choose the one which is closer to desired | ||
948 | * frequency. | ||
949 | */ | ||
950 | |||
951 | /* Reference frequency is out of range. */ | ||
952 | if ((refFreq < SCG_SPLL_REF_MIN) || | ||
953 | (refFreq > (SCG_SPLL_REF_MAX * (SCG_SPLL_PREDIV_MAX_VALUE + SCG_SPLL_PREDIV_BASE_VALUE)))) | ||
954 | { | ||
955 | return 0U; | ||
956 | } | ||
957 | |||
958 | /* refFreq/PREDIV must in a range. First get the allowed PREDIV range. */ | ||
959 | prediv_max = (uint8_t)(refFreq / SCG_SPLL_REF_MIN); | ||
960 | prediv_min = (uint8_t)((refFreq + SCG_SPLL_REF_MAX - 1UL) / SCG_SPLL_REF_MAX); | ||
961 | |||
962 | desireFreq *= 2U; | ||
963 | |||
964 | /* PREDIV traversal. */ | ||
965 | for (prediv_cur = prediv_max; prediv_cur >= prediv_min; prediv_cur--) | ||
966 | { | ||
967 | /* | ||
968 | * For each PREDIV, the available MULT is (desireFreq*PREDIV/refFreq) | ||
969 | * or (desireFreq*PREDIV/refFreq + 1U). This function chooses the closer | ||
970 | * one. | ||
971 | */ | ||
972 | /* Reference frequency after PREDIV. */ | ||
973 | ref_div = refFreq / prediv_cur; | ||
974 | |||
975 | mult_cur = (uint8_t)(desireFreq / ref_div); | ||
976 | |||
977 | if ((mult_cur < SCG_SPLL_MULT_BASE_VALUE - 1U) || | ||
978 | (mult_cur > SCG_SPLL_MULT_BASE_VALUE + SCG_SPLL_MULT_MAX_VALUE)) | ||
979 | { | ||
980 | /* No MULT is available with this PREDIV. */ | ||
981 | continue; | ||
982 | } | ||
983 | |||
984 | ret_freq = mult_cur * ref_div; | ||
985 | |||
986 | if (mult_cur >= SCG_SPLL_MULT_BASE_VALUE) | ||
987 | { | ||
988 | if (ret_freq == desireFreq) /* If desire frequency is got. */ | ||
989 | { | ||
990 | *prediv = prediv_cur - SCG_SPLL_PREDIV_BASE_VALUE; | ||
991 | *mult = mult_cur - SCG_SPLL_MULT_BASE_VALUE; | ||
992 | return ret_freq / 2U; | ||
993 | } | ||
994 | if (diff > desireFreq - ret_freq) /* New PRDIV/VDIV is closer. */ | ||
995 | { | ||
996 | diff = desireFreq - ret_freq; | ||
997 | ret_prediv = prediv_cur; | ||
998 | ret_mult = mult_cur; | ||
999 | } | ||
1000 | } | ||
1001 | mult_cur++; | ||
1002 | if (mult_cur <= (SCG_SPLL_MULT_BASE_VALUE + SCG_SPLL_MULT_MAX_VALUE)) | ||
1003 | { | ||
1004 | ret_freq += ref_div; | ||
1005 | if (diff > ret_freq - desireFreq) /* New PRDIV/VDIV is closer. */ | ||
1006 | { | ||
1007 | diff = ret_freq - desireFreq; | ||
1008 | ret_prediv = prediv_cur; | ||
1009 | ret_mult = mult_cur; | ||
1010 | } | ||
1011 | } | ||
1012 | } | ||
1013 | |||
1014 | if (0xFFFFFFFFU != diff) | ||
1015 | { | ||
1016 | /* PREDIV/MULT found. */ | ||
1017 | *prediv = ret_prediv - SCG_SPLL_PREDIV_BASE_VALUE; | ||
1018 | *mult = ret_mult - SCG_SPLL_MULT_BASE_VALUE; | ||
1019 | return ((refFreq / ret_prediv) * ret_mult) / 2U; | ||
1020 | } | ||
1021 | else | ||
1022 | { | ||
1023 | return 0U; /* No proper PREDIV/MULT found. */ | ||
1024 | } | ||
1025 | } | ||
1026 | |||
1027 | /*! | ||
1028 | * brief Initializes the SCG system PLL. | ||
1029 | * | ||
1030 | * This function enables the SCG system PLL clock according to the | ||
1031 | * configuration. The system PLL can use the system OSC or FIRC as | ||
1032 | * the clock source. Ensure that the source clock is valid before | ||
1033 | * calling this function. | ||
1034 | * | ||
1035 | * Example code for initializing SPLL clock output: | ||
1036 | * code | ||
1037 | * const scg_spll_config_t g_scgSysPllConfig = {.enableMode = kSCG_SysPllEnable, | ||
1038 | * .monitorMode = kSCG_SysPllMonitorDisable, | ||
1039 | * .div1 = kSCG_AsyncClkDivBy1, | ||
1040 | * .div2 = kSCG_AsyncClkDisable, | ||
1041 | * .div3 = kSCG_AsyncClkDivBy2, | ||
1042 | * .src = kSCG_SysPllSrcFirc, | ||
1043 | * .isBypassSelected = false, | ||
1044 | * .isPfdSelected = false, | ||
1045 | * .prediv = 5U, | ||
1046 | * .pfdClkout = kSCG_AuxPllPfd0Clk, | ||
1047 | * endcode | ||
1048 | * | ||
1049 | * param config Pointer to the configuration structure. | ||
1050 | * retval kStatus_Success System PLL is initialized. | ||
1051 | * retval kStatus_SCG_Busy System PLL has been enabled and is used by the system clock. | ||
1052 | * retval kStatus_ReadOnly System PLL control register is locked. | ||
1053 | * | ||
1054 | * note This function can't detect whether the system PLL has been enabled and | ||
1055 | * used by an IP. | ||
1056 | */ | ||
1057 | status_t CLOCK_InitSysPll(const scg_spll_config_t *config) | ||
1058 | { | ||
1059 | assert(config); | ||
1060 | |||
1061 | status_t status; | ||
1062 | |||
1063 | /* De-init the SPLL first. */ | ||
1064 | status = CLOCK_DeinitSysPll(); | ||
1065 | |||
1066 | if (kStatus_Success != status) | ||
1067 | { | ||
1068 | return status; | ||
1069 | } | ||
1070 | |||
1071 | /* Now start to set up PLL clock. */ | ||
1072 | /* Step 1. Setup dividers. */ | ||
1073 | SCG->SPLLDIV = | ||
1074 | SCG_SPLLDIV_SPLLDIV1(config->div1) | SCG_SPLLDIV_SPLLDIV2(config->div2) | SCG_SPLLDIV_SPLLDIV3(config->div3); | ||
1075 | |||
1076 | /* Step 2. Set PLL configuration. */ | ||
1077 | SCG->SPLLCFG = | ||
1078 | SCG_SPLLCFG_SOURCE(config->src) | SCG_SPLLCFG_PREDIV(config->prediv) | SCG_SPLLCFG_MULT(config->mult); | ||
1079 | |||
1080 | /* Step 3. Enable clock. */ | ||
1081 | SCG->SPLLCSR = (uint32_t)SCG_SPLLCSR_SPLLEN_MASK | config->enableMode; | ||
1082 | |||
1083 | /* Step 4. Wait for PLL clock to be valid. */ | ||
1084 | while (0UL == (SCG->SPLLCSR & SCG_SPLLCSR_SPLLVLD_MASK)) | ||
1085 | { | ||
1086 | } | ||
1087 | |||
1088 | /* Step 5. Enabe monitor. */ | ||
1089 | SCG->SPLLCSR |= (uint32_t)config->monitorMode; | ||
1090 | |||
1091 | return kStatus_Success; | ||
1092 | } | ||
1093 | |||
1094 | /*! | ||
1095 | * brief De-initializes the SCG system PLL. | ||
1096 | * | ||
1097 | * This function disables the SCG system PLL. | ||
1098 | * | ||
1099 | * retval kStatus_Success system PLL is deinitialized. | ||
1100 | * retval kStatus_SCG_Busy system PLL is used by the system clock. | ||
1101 | * retval kStatus_ReadOnly System PLL control register is locked. | ||
1102 | * | ||
1103 | * note This function can't detect whether the system PLL is used by an IP. | ||
1104 | */ | ||
1105 | status_t CLOCK_DeinitSysPll(void) | ||
1106 | { | ||
1107 | uint32_t reg = SCG->SPLLCSR; | ||
1108 | status_t status; | ||
1109 | |||
1110 | /* If clock is used by system, return error. */ | ||
1111 | if ((reg & SCG_SPLLCSR_SPLLSEL_MASK) != 0UL) | ||
1112 | { | ||
1113 | status = kStatus_SCG_Busy; | ||
1114 | } | ||
1115 | /* If configure register is locked, return error. */ | ||
1116 | else if ((reg & SCG_SPLLCSR_LK_MASK) != 0UL) | ||
1117 | { | ||
1118 | status = kStatus_ReadOnly; | ||
1119 | } | ||
1120 | else | ||
1121 | { | ||
1122 | /* Deinit and clear the error. */ | ||
1123 | SCG->SPLLCSR = SCG_SPLLCSR_SPLLERR_MASK; | ||
1124 | status = kStatus_Success; | ||
1125 | } | ||
1126 | |||
1127 | return status; | ||
1128 | } | ||
1129 | |||
1130 | static uint32_t CLOCK_GetSysPllCommonFreq(void) | ||
1131 | { | ||
1132 | uint32_t freq = 0U; | ||
1133 | |||
1134 | if ((SCG->SPLLCFG & SCG_SPLLCFG_SOURCE_MASK) != 0UL) /* If use FIRC */ | ||
1135 | { | ||
1136 | freq = CLOCK_GetFircFreq(); | ||
1137 | } | ||
1138 | else /* Use System OSC. */ | ||
1139 | { | ||
1140 | freq = CLOCK_GetSysOscFreq(); | ||
1141 | } | ||
1142 | |||
1143 | if (freq != 0UL) /* If source is valid. */ | ||
1144 | { | ||
1145 | freq /= (SCG_SPLLCFG_PREDIV_VAL + SCG_SPLL_PREDIV_BASE_VALUE); /* Pre-divider. */ | ||
1146 | freq *= (SCG_SPLLCFG_MULT_VAL + SCG_SPLL_MULT_BASE_VALUE); /* Multiplier. */ | ||
1147 | } | ||
1148 | |||
1149 | return freq; | ||
1150 | } | ||
1151 | |||
1152 | /*! | ||
1153 | * brief Gets the SCG system PLL clock frequency. | ||
1154 | * | ||
1155 | * return Clock frequency; If the clock is invalid, returns 0. | ||
1156 | */ | ||
1157 | uint32_t CLOCK_GetSysPllFreq(void) | ||
1158 | { | ||
1159 | uint32_t freq; | ||
1160 | |||
1161 | if ((SCG->SPLLCSR & SCG_SPLLCSR_SPLLVLD_MASK) != 0UL) /* System PLL is valid. */ | ||
1162 | { | ||
1163 | freq = CLOCK_GetSysPllCommonFreq(); | ||
1164 | |||
1165 | return freq >> 1U; | ||
1166 | } | ||
1167 | else | ||
1168 | { | ||
1169 | return 0U; | ||
1170 | } | ||
1171 | } | ||
1172 | |||
1173 | /*! | ||
1174 | * brief Gets the SCG asynchronous clock frequency from the system PLL. | ||
1175 | * | ||
1176 | * param type The asynchronous clock type. | ||
1177 | * return Clock frequency; If the clock is invalid, returns 0. | ||
1178 | */ | ||
1179 | uint32_t CLOCK_GetSysPllAsyncFreq(scg_async_clk_t type) | ||
1180 | { | ||
1181 | uint32_t pllFreq = CLOCK_GetSysPllFreq(); | ||
1182 | uint32_t divider = 0U; | ||
1183 | uint32_t freq; | ||
1184 | |||
1185 | /* Get divider. */ | ||
1186 | if (pllFreq != 0UL) | ||
1187 | { | ||
1188 | switch (type) | ||
1189 | { | ||
1190 | case kSCG_AsyncDiv3Clk: /* SPLLDIV3_CLK. */ | ||
1191 | divider = SCG_SPLLDIV_SPLLDIV3_VAL; | ||
1192 | break; | ||
1193 | case kSCG_AsyncDiv2Clk: /* SPLLDIV2_CLK. */ | ||
1194 | divider = SCG_SPLLDIV_SPLLDIV2_VAL; | ||
1195 | break; | ||
1196 | case kSCG_AsyncDiv1Clk: /* SPLLDIV1_CLK. */ | ||
1197 | divider = SCG_SPLLDIV_SPLLDIV1_VAL; | ||
1198 | break; | ||
1199 | default: | ||
1200 | divider = 0U; | ||
1201 | break; | ||
1202 | } | ||
1203 | } | ||
1204 | if (divider != 0UL) | ||
1205 | { | ||
1206 | freq = (pllFreq >> (divider - 1U)); | ||
1207 | } | ||
1208 | else /* Output disabled. */ | ||
1209 | { | ||
1210 | freq = 0U; | ||
1211 | } | ||
1212 | |||
1213 | return freq; | ||
1214 | } | ||