aboutsummaryrefslogtreecommitdiff
path: root/lib/chibios-contrib/ext/mcux-sdk/devices/LPC832/drivers/fsl_clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chibios-contrib/ext/mcux-sdk/devices/LPC832/drivers/fsl_clock.c')
-rw-r--r--lib/chibios-contrib/ext/mcux-sdk/devices/LPC832/drivers/fsl_clock.c458
1 files changed, 458 insertions, 0 deletions
diff --git a/lib/chibios-contrib/ext/mcux-sdk/devices/LPC832/drivers/fsl_clock.c b/lib/chibios-contrib/ext/mcux-sdk/devices/LPC832/drivers/fsl_clock.c
new file mode 100644
index 000000000..9016f71af
--- /dev/null
+++ b/lib/chibios-contrib/ext/mcux-sdk/devices/LPC832/drivers/fsl_clock.c
@@ -0,0 +1,458 @@
1/*
2 * Copyright 2017-2019 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8#include "fsl_clock.h"
9/*******************************************************************************
10 * Definitions
11 ******************************************************************************/
12/* Component ID definition, used by tools. */
13#ifndef FSL_COMPONENT_ID
14#define FSL_COMPONENT_ID "platform.drivers.clock"
15#endif
16#define SYSPLL_MIN_INPUT_FREQ_HZ (10000000U) /*!< Minimum PLL input rate */
17#define SYSPLL_MAX_INPUT_FREQ_HZ (25000000U) /*!< Maximum PLL input rate */
18#define SYSPLL_MAX_OUTPUT_FREQ_HZ (100000000U) /*!< Maximum PLL output rate */
19#define SYSPLL_MIN_FCCO_FREQ_HZ (156000000U) /*!< Maximum FCCO output rate */
20#define SYSPLL_MAX_FCCO_FREQ_HZ (320000000U) /*!< Maximum FCCO output rate */
21#define SYSOSC_BOUNDARY_FREQ_HZ (15000000U) /*!< boundary frequency value */
22
23/* External clock rate.
24 * Either external clk in rate or system oscillator frequency.
25 */
26uint32_t g_Ext_Clk_Freq = 0U;
27uint32_t g_Wdt_Osc_Freq = 0U;
28
29/** Sys pll freq.*/
30uint32_t g_Sys_Pll_Freq = 0U;
31/*******************************************************************************
32 * Variables
33 ******************************************************************************/
34
35/*******************************************************************************
36 * Prototypes
37 ******************************************************************************/
38/*
39 * @brief select post divider for system pll according to the target frequency.
40 * @param outFreq: Value to be output
41 * @return post divider
42 */
43static uint32_t findSyestemPllPsel(uint32_t outFreq);
44
45/*
46 * @brief Update clock source.
47 * @param base clock register base address.
48 * @param mask clock source update enable bit mask value.
49 */
50static void CLOCK_UpdateClkSrc(volatile uint32_t *base, uint32_t mask);
51
52/*******************************************************************************
53 * Code
54 ******************************************************************************/
55static void CLOCK_UpdateClkSrc(volatile uint32_t *base, uint32_t mask)
56{
57 assert(base);
58
59 *base &= ~mask;
60 *base |= mask;
61 while ((*base & mask) == 0U)
62 {
63 }
64}
65
66/*! brief Return Frequency of IRC
67 * return Frequency of IRC
68 */
69uint32_t CLOCK_GetIrcFreq(void)
70{
71 return 12000000U;
72}
73
74/*! brief Return Frequency of SYSOSC
75 * return Frequency of SYSOSC
76 */
77uint32_t CLOCK_GetSysOscFreq(void)
78{
79 uint32_t freq = 0U;
80 if ((SYSCON->PDRUNCFG & SYSCON_PDRUNCFG_SYSOSC_PD_MASK) == 0U)
81 {
82 freq = CLOCK_GetExtClkFreq();
83 }
84 return freq;
85}
86
87/*! brief Return Frequency of Main Clock.
88 * return Frequency of Main Clock.
89 */
90uint32_t CLOCK_GetMainClkFreq(void)
91{
92 uint32_t freq = 0U;
93
94 switch (SYSCON->MAINCLKSEL)
95 {
96 case 0U:
97 freq = CLOCK_GetIrcFreq();
98 break;
99
100 case 1U:
101 freq = CLOCK_GetSystemPLLInClockRate();
102 break;
103
104 case 2U:
105 freq = CLOCK_GetWdtOscFreq();
106 break;
107
108 case 3U:
109 freq = CLOCK_GetSystemPLLFreq();
110 break;
111 default:
112 assert(false);
113 break;
114 }
115
116 return freq;
117}
118
119/*! brief Return Frequency of ClockOut
120 * return Frequency of ClockOut
121 */
122uint32_t CLOCK_GetClockOutClkFreq(void)
123{
124 uint32_t div = SYSCON->CLKOUTDIV & 0xffU, freq = 0U;
125
126 switch (SYSCON->CLKOUTSEL)
127 {
128 case 0U:
129 freq = CLOCK_GetIrcFreq();
130 break;
131
132 case 1U:
133 freq = CLOCK_GetSysOscFreq();
134 break;
135
136 case 2U:
137 freq = CLOCK_GetWdtOscFreq();
138 break;
139
140 case 3U:
141 freq = CLOCK_GetMainClkFreq();
142 break;
143
144 default:
145 assert(false);
146 break;
147 }
148
149 return div == 0U ? 0U : (freq / div);
150}
151
152/*! brief Return Frequency of UART
153 * return Frequency of UART
154 */
155uint32_t CLOCK_GetUartClkFreq(void)
156{
157 uint32_t freq = CLOCK_GetMainClkFreq();
158 uint32_t uartDiv = SYSCON->UARTCLKDIV & 0xffU;
159
160 return uartDiv == 0U ? 0U :
161 (uint32_t)((uint64_t)(freq << 8U) /
162 (uartDiv * (256U + ((SYSCON->UARTFRGMULT) & SYSCON_UARTFRGMULT_MULT_MASK))));
163}
164
165/*! brief Return Frequency of UART0
166 * return Frequency of UART0
167 */
168uint32_t CLOCK_GetUart0ClkFreq(void)
169{
170 return CLOCK_GetUartClkFreq();
171}
172
173/*! brief Return Frequency of UART1
174 * return Frequency of UART1
175 */
176uint32_t CLOCK_GetUart1ClkFreq(void)
177{
178 return CLOCK_GetUartClkFreq();
179}
180
181/*! brief Return Frequency of UART2
182 * return Frequency of UART2
183 */
184uint32_t CLOCK_GetUart2ClkFreq(void)
185{
186 return CLOCK_GetUartClkFreq();
187}
188
189/*! brief Return Frequency of selected clock
190 * return Frequency of selected clock
191 */
192uint32_t CLOCK_GetFreq(clock_name_t clockName)
193{
194 uint32_t freq;
195
196 switch (clockName)
197 {
198 case kCLOCK_CoreSysClk:
199 freq = CLOCK_GetCoreSysClkFreq();
200 break;
201 case kCLOCK_MainClk:
202 freq = CLOCK_GetMainClkFreq();
203 break;
204 case kCLOCK_Irc:
205 freq = CLOCK_GetIrcFreq();
206 break;
207 case kCLOCK_ExtClk:
208 freq = CLOCK_GetExtClkFreq();
209 break;
210 case kCLOCK_WdtOsc:
211 freq = CLOCK_GetWdtOscFreq();
212 break;
213 case kCLOCK_PllOut:
214 freq = CLOCK_GetSystemPLLFreq();
215 break;
216
217 default:
218 freq = 0U;
219 break;
220 }
221
222 return freq;
223}
224
225/*! brief Return System PLL input clock rate
226 * return System PLL input clock rate
227 */
228uint32_t CLOCK_GetSystemPLLInClockRate(void)
229{
230 uint32_t freq = 0U;
231
232 switch ((SYSCON->SYSPLLCLKSEL & SYSCON_SYSPLLCLKSEL_SEL_MASK))
233 {
234 /* source from external clock in */
235 case 0x00U:
236 freq = CLOCK_GetIrcFreq();
237 break;
238 /* source from the IRC clock */
239 case 0x01U:
240 freq = CLOCK_GetSysOscFreq();
241 break;
242 /* source from external clock clock */
243 case 0x03U:
244 freq = CLOCK_GetExtClkFreq();
245 break;
246
247 default:
248 assert(false);
249 break;
250 }
251
252 return freq;
253}
254
255static uint32_t findSyestemPllPsel(uint32_t outFreq)
256{
257 uint32_t pSel = 0U;
258
259 if (outFreq > (SYSPLL_MIN_FCCO_FREQ_HZ >> 1U))
260 {
261 pSel = 0U;
262 }
263 else if (outFreq > (SYSPLL_MIN_FCCO_FREQ_HZ >> 2U))
264 {
265 pSel = 1U;
266 }
267 else if (outFreq > (SYSPLL_MIN_FCCO_FREQ_HZ >> 3U))
268 {
269 pSel = 2U;
270 }
271 else
272 {
273 pSel = 3U;
274 }
275
276 return pSel;
277}
278
279/*! brief System PLL initialize.
280 * param config System PLL configurations.
281 */
282void CLOCK_InitSystemPll(const clock_sys_pll_t *config)
283{
284 assert(config->targetFreq <= SYSPLL_MAX_OUTPUT_FREQ_HZ);
285
286 uint32_t mSel = 0U, pSel = 0U, inputFreq = 0U;
287 uint32_t syspllclkseltmp;
288 /* Power off PLL during setup changes */
289 SYSCON->PDRUNCFG |= SYSCON_PDRUNCFG_SYSPLL_PD_MASK;
290
291 /*set system pll clock source select register */
292 syspllclkseltmp = (SYSCON->SYSPLLCLKSEL & (~SYSCON_SYSPLLCLKSEL_SEL_MASK)) | (uint32_t)config->src;
293 SYSCON->SYSPLLCLKSEL |= syspllclkseltmp;
294 /* system pll clock source update */
295 CLOCK_UpdateClkSrc((volatile uint32_t *)(&(SYSCON->SYSPLLCLKUEN)), SYSCON_SYSPLLCLKSEL_SEL_MASK);
296
297 inputFreq = CLOCK_GetSystemPLLInClockRate();
298 assert(inputFreq != 0U);
299
300 /* calucate the feedback divider value and post divider value*/
301 mSel = config->targetFreq / inputFreq;
302 pSel = findSyestemPllPsel(config->targetFreq);
303
304 /* configure PSEL and MSEL */
305 SYSCON->SYSPLLCTRL = (SYSCON->SYSPLLCTRL & (~(SYSCON_SYSPLLCTRL_MSEL_MASK | SYSCON_SYSPLLCTRL_PSEL_MASK))) |
306 SYSCON_SYSPLLCTRL_MSEL(mSel - 1U) | SYSCON_SYSPLLCTRL_PSEL(pSel);
307
308 /* Power up PLL after setup changes */
309 SYSCON->PDRUNCFG &= ~SYSCON_PDRUNCFG_SYSPLL_PD_MASK;
310
311 /* wait pll lock */
312 while ((SYSCON->SYSPLLSTAT & SYSCON_SYSPLLSTAT_LOCK_MASK) == 0U)
313 {
314 }
315
316 g_Sys_Pll_Freq = inputFreq * mSel;
317}
318
319/*! brief Init external CLK IN, select the CLKIN as the external clock source.
320 * param clkInFreq external clock in frequency.
321 */
322void CLOCK_InitExtClkin(uint32_t clkInFreq)
323{
324 /* remove the pull up and pull down resistors in the IOCON */
325 IOCON->PIO[IOCON_INDEX_PIO0_1] &= ~IOCON_PIO_MODE_MASK;
326 /* enable the 1 bit functions for CLKIN */
327 SWM0->PINENABLE0 &= ~SWM_PINENABLE0_CLKIN_MASK;
328 /* record the external clock rate */
329 g_Ext_Clk_Freq = clkInFreq;
330}
331
332/*! brief XTALIN init function
333 * system oscillator is bypassed, sys_osc_clk is fed driectly from the XTALIN.
334 * param xtalInFreq XTALIN frequency value
335 * return Frequency of PLL
336 */
337void CLOCK_InitXtalin(uint32_t xtalInFreq)
338{
339 /* remove the pull up and pull down resistors in the IOCON */
340 IOCON->PIO[IOCON_INDEX_PIO0_8] &= ~IOCON_PIO_MODE_MASK;
341 /* enable the 1 bit functions for XTALIN and XTALOUT */
342 SWM0->PINENABLE0 &= ~SWM_PINENABLE0_XTALIN_MASK;
343
344 /* system osc configure */
345 SYSCON->SYSOSCCTRL |= SYSCON_SYSOSCCTRL_BYPASS_MASK;
346 /* enable system osc power first */
347 SYSCON->PDRUNCFG &= ~SYSCON_PDRUNCFG_SYSOSC_PD_MASK;
348
349 /* software delay 500USs */
350 SDK_DelayAtLeastUs(500U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
351
352 /* record the external clock rate */
353 g_Ext_Clk_Freq = xtalInFreq;
354}
355
356/*! brief Init SYS OSC
357 * param oscFreq oscillator frequency value.
358 */
359void CLOCK_InitSysOsc(uint32_t oscFreq)
360{
361 uint32_t sysoscctrltmp;
362 /* remove the pull up and pull down resistors in the IOCON */
363 IOCON->PIO[IOCON_INDEX_PIO0_9] &= ~IOCON_PIO_MODE_MASK;
364 IOCON->PIO[IOCON_INDEX_PIO0_8] &= ~IOCON_PIO_MODE_MASK;
365 /* enable the 1 bit functions for XTALIN and XTALOUT */
366 SWM0->PINENABLE0 &= ~(SWM_PINENABLE0_XTALIN_MASK | SWM_PINENABLE0_XTALOUT_MASK);
367
368 /* system osc configure */
369 sysoscctrltmp = (SYSCON->SYSOSCCTRL & (~(SYSCON_SYSOSCCTRL_BYPASS_MASK | SYSCON_SYSOSCCTRL_FREQ_RANGE_MASK))) |
370 (oscFreq > SYSOSC_BOUNDARY_FREQ_HZ ? SYSCON_SYSOSCCTRL_FREQ_RANGE_MASK : 0U);
371 SYSCON->SYSOSCCTRL |= sysoscctrltmp;
372
373 /* enable system osc power first */
374 SYSCON->PDRUNCFG &= ~SYSCON_PDRUNCFG_SYSOSC_PD_MASK;
375
376 /* software delay 500USs */
377 SDK_DelayAtLeastUs(500U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
378
379 /* record the external clock rate */
380 g_Ext_Clk_Freq = oscFreq;
381}
382
383/*! brief Init watch dog OSC
384 * Any setting of the FREQSEL bits will yield a Fclkana value within 40% of the
385 * listed frequency value. The watchdog oscillator is the clock source with the lowest power
386 * consumption. If accurate timing is required, use the FRO or system oscillator.
387 * The frequency of the watchdog oscillator is undefined after reset. The watchdog
388 * oscillator frequency must be programmed by writing to the WDTOSCCTRL register before
389 * using the watchdog oscillator.
390 * Watchdog osc output frequency = wdtOscFreq / wdtOscDiv, should in range 9.3KHZ to 2.3MHZ.
391 * param wdtOscFreq watch dog analog part output frequency, reference _wdt_analog_output_freq.
392 * param wdtOscDiv watch dog analog part output frequency divider, shoule be a value >= 2U and multiple of 2
393 */
394void CLOCK_InitWdtOsc(clock_wdt_analog_freq_t wdtOscFreq, uint32_t wdtOscDiv)
395{
396 assert(wdtOscDiv >= 2U);
397
398 uint32_t wdtOscCtrl = SYSCON->WDTOSCCTRL;
399
400 wdtOscCtrl &= ~(SYSCON_WDTOSCCTRL_DIVSEL_MASK | SYSCON_WDTOSCCTRL_FREQSEL_MASK);
401
402 wdtOscCtrl |=
403 SYSCON_WDTOSCCTRL_DIVSEL((wdtOscDiv >> 1U) - 1U) | SYSCON_WDTOSCCTRL_FREQSEL(CLK_WDT_OSC_GET_REG(wdtOscFreq));
404
405 SYSCON->WDTOSCCTRL = wdtOscCtrl;
406
407 /* power up watchdog oscillator */
408 SYSCON->PDRUNCFG &= ~SYSCON_PDRUNCFG_WDTOSC_PD_MASK;
409 /* update watch dog oscillator value */
410 g_Wdt_Osc_Freq = CLK_WDT_OSC_GET_FREQ(wdtOscFreq) / wdtOscDiv;
411}
412
413/*! brief Set main clock reference source.
414 * param src, reference clock_main_clk_src_t to set the main clock source.
415 */
416void CLOCK_SetMainClkSrc(clock_main_clk_src_t src)
417{
418 uint32_t mainMux = CLK_MAIN_CLK_MUX_GET_MUX(src), mainPreMux = CLK_MAIN_CLK_MUX_GET_PRE_MUX(src);
419
420 if (((SYSCON->MAINCLKSEL & SYSCON_MAINCLKSEL_SEL_MASK) != mainPreMux) && (mainMux == 0U))
421 {
422 SYSCON->MAINCLKSEL = (SYSCON->MAINCLKSEL & (~SYSCON_MAINCLKSEL_SEL_MASK)) | SYSCON_MAINCLKSEL_SEL(mainPreMux);
423 CLOCK_UpdateClkSrc((volatile uint32_t *)(&(SYSCON->MAINCLKUEN)), SYSCON_MAINCLKUEN_ENA_MASK);
424 }
425}
426
427/*! brief Set UARTFRG
428 * param target UART clock src.
429 */
430bool CLOCK_SetUARTFRGClkFreq(uint32_t freq)
431{
432 uint32_t input = CLOCK_GetMainClkFreq();
433 uint32_t mul;
434
435 freq *= SYSCON->UARTCLKDIV;
436
437 /* The given frequency should not be 0. */
438 assert(0UL != freq);
439
440 if ((freq > input) || (input / freq >= 2U))
441 {
442 return false;
443 }
444
445 mul = (uint32_t)(((uint64_t)((uint64_t)input - freq) << 8U) / ((uint64_t)freq));
446
447 SYSCON->UARTFRGDIV = SYSCON_UARTFRGDIV_DIV_MASK;
448 SYSCON->UARTFRGMULT = SYSCON_UARTFRGMULT_MULT(mul);
449
450 return true;
451}
452
453/*! brief updates the clock source of the CLKOUT
454 */
455void CLOCK_UpdateClkOUTsrc(void)
456{
457 CLOCK_UpdateClkSrc((volatile uint32_t *)(&(SYSCON->CLKOUTUEN)), SYSCON_CLKOUTUEN_ENA_MASK);
458}