1 /*
2 * @brief LPC15XX System clock control functions
3 *
4 * Copyright(C) NXP Semiconductors, 2013
5 * All rights reserved.
6 *
7 * Software that is described herein is for illustrative purposes only
8 * which provides customers with programming information regarding the
9 * LPC products. This software is supplied "AS IS" without any warranties of
10 * any kind, and NXP Semiconductors and its licensor disclaim any and
11 * all warranties, express or implied, including all implied warranties of
12 * merchantability, fitness for a particular purpose and non-infringement of
13 * intellectual property rights. NXP Semiconductors assumes no responsibility
14 * or liability for the use of the software, conveys no license or rights under any
15 * patent, copyright, mask work right, or any other intellectual property rights in
16 * or to any products. NXP Semiconductors reserves the right to make changes
17 * in the software without notification. NXP Semiconductors also makes no
18 * representation or warranty that such application will be suitable for the
19 * specified use without further testing or modification.
20 *
21 * Permission to use, copy, modify, and distribute this software and its
22 * documentation is hereby granted, under NXP Semiconductors' and its
23 * licensor's relevant copyrights in the software, without fee, provided that it
24 * is used in conjunction with NXP Semiconductors microcontrollers. This
25 * copyright, permission, and disclaimer notice must appear in all copies of
26 * this code.
27 */
28
29 #include "chip.h"
30
31 /*****************************************************************************
32 * Private types/enumerations/variables
33 ****************************************************************************/
34
35 /*****************************************************************************
36 * Public types/enumerations/variables
37 ****************************************************************************/
38
39 /*****************************************************************************
40 * Private functions
41 ****************************************************************************/
42
43 /* Compute a PLL frequency */
Chip_Clock_GetPLLFreq(uint32_t PLLReg,uint32_t inputRate)44 STATIC uint32_t Chip_Clock_GetPLLFreq(uint32_t PLLReg, uint32_t inputRate)
45 {
46 uint32_t msel = ((PLLReg & 0x3F) + 1);
47
48 return inputRate * msel;
49 }
50
51 /* Return a PLL input (common) */
Chip_Clock_GetPLLInClockRate(uint32_t reg)52 STATIC uint32_t Chip_Clock_GetPLLInClockRate(uint32_t reg)
53 {
54 uint32_t clkRate;
55
56 switch ((CHIP_SYSCTL_PLLCLKSRC_T) (reg & 0x3)) {
57 case SYSCTL_PLLCLKSRC_IRC:
58 clkRate = Chip_Clock_GetIntOscRate();
59 break;
60
61 case SYSCTL_PLLCLKSRC_MAINOSC:
62 clkRate = Chip_Clock_GetMainOscRate();
63 break;
64
65 default:
66 clkRate = 0;
67 }
68
69 return clkRate;
70 }
71
72 /*****************************************************************************
73 * Public functions
74 ****************************************************************************/
75
76 /* Return System PLL input clock rate */
Chip_Clock_GetSystemPLLInClockRate(void)77 uint32_t Chip_Clock_GetSystemPLLInClockRate(void)
78 {
79 return Chip_Clock_GetPLLInClockRate(LPC_SYSCTL->SYSPLLCLKSEL);
80 }
81
82 /* Return System PLL output clock rate */
Chip_Clock_GetSystemPLLOutClockRate(void)83 uint32_t Chip_Clock_GetSystemPLLOutClockRate(void)
84 {
85 return Chip_Clock_GetPLLFreq(LPC_SYSCTL->SYSPLLCTRL,
86 Chip_Clock_GetSystemPLLInClockRate());
87 }
88
89 /* Return USB PLL input clock rate */
Chip_Clock_GetUSBPLLInClockRate(void)90 uint32_t Chip_Clock_GetUSBPLLInClockRate(void)
91 {
92 return Chip_Clock_GetPLLInClockRate(LPC_SYSCTL->USBPLLCLKSEL);
93 }
94
95 /* Return USB PLL output clock rate */
Chip_Clock_GetUSBPLLOutClockRate(void)96 uint32_t Chip_Clock_GetUSBPLLOutClockRate(void)
97 {
98 return Chip_Clock_GetPLLFreq(LPC_SYSCTL->USBPLLCTRL,
99 Chip_Clock_GetUSBPLLInClockRate());
100 }
101
102 /* Return SCT PLL input clock rate */
Chip_Clock_GetSCTPLLInClockRate(void)103 uint32_t Chip_Clock_GetSCTPLLInClockRate(void)
104 {
105 return Chip_Clock_GetPLLInClockRate(LPC_SYSCTL->SCTPLLCLKSEL);
106 }
107
108 /* Return SCT PLL output clock rate */
Chip_Clock_GetSCTPLLOutClockRate(void)109 uint32_t Chip_Clock_GetSCTPLLOutClockRate(void)
110 {
111 return Chip_Clock_GetPLLFreq(LPC_SYSCTL->SCTPLLCTRL,
112 Chip_Clock_GetSCTPLLInClockRate());
113 }
114
115 /* Return main A clock rate */
Chip_Clock_GetMain_A_ClockRate(void)116 uint32_t Chip_Clock_GetMain_A_ClockRate(void)
117 {
118 uint32_t clkRate = 0;
119
120 switch (Chip_Clock_GetMain_A_ClockSource()) {
121 case SYSCTL_MAIN_A_CLKSRC_IRC:
122 clkRate = Chip_Clock_GetIntOscRate();
123 break;
124
125 case SYSCTL_MAIN_A_CLKSRCA_MAINOSC:
126 clkRate = Chip_Clock_GetMainOscRate();
127 break;
128
129 case SYSCTL_MAIN_A_CLKSRCA_WDTOSC:
130 clkRate = Chip_Clock_GetWDTOSCRate();
131 break;
132
133 default:
134 clkRate = 0;
135 break;
136 }
137
138 return clkRate;
139 }
140
141 /* Return main B clock rate */
Chip_Clock_GetMain_B_ClockRate(void)142 uint32_t Chip_Clock_GetMain_B_ClockRate(void)
143 {
144 uint32_t clkRate = 0;
145
146 switch (Chip_Clock_GetMain_B_ClockSource()) {
147 case SYSCTL_MAIN_B_CLKSRC_MAINCLKSELA:
148 clkRate = Chip_Clock_GetMain_A_ClockRate();
149 break;
150
151 case SYSCTL_MAIN_B_CLKSRC_SYSPLLIN:
152 clkRate = Chip_Clock_GetSystemPLLInClockRate();
153 break;
154
155 case SYSCTL_MAIN_B_CLKSRC_SYSPLLOUT:
156 clkRate = Chip_Clock_GetSystemPLLOutClockRate();
157 break;
158
159 case SYSCTL_MAIN_B_CLKSRC_RTC:
160 clkRate = Chip_Clock_GetRTCOscRate();
161 break;
162 }
163
164 return clkRate;
165 }
166
167 /* Set main system clock source */
Chip_Clock_SetMainClockSource(CHIP_SYSCTL_MAINCLKSRC_T src)168 void Chip_Clock_SetMainClockSource(CHIP_SYSCTL_MAINCLKSRC_T src)
169 {
170 uint32_t clkSrc = (uint32_t) src;
171
172 if (clkSrc >= 4) {
173 /* Main B source only, not using main A */
174 Chip_Clock_SetMain_B_ClockSource((CHIP_SYSCTL_MAIN_B_CLKSRC_T) (clkSrc - 4));
175 }
176 else {
177 /* Select main A clock source and set main B source to use main A */
178 Chip_Clock_SetMain_A_ClockSource((CHIP_SYSCTL_MAIN_A_CLKSRC_T) clkSrc);
179 Chip_Clock_SetMain_B_ClockSource(SYSCTL_MAIN_B_CLKSRC_MAINCLKSELA);
180 }
181 }
182
183 /* Returns the main clock source */
Chip_Clock_GetMainClockSource(void)184 CHIP_SYSCTL_MAINCLKSRC_T Chip_Clock_GetMainClockSource(void)
185 {
186 CHIP_SYSCTL_MAIN_B_CLKSRC_T srcB;
187 uint32_t clkSrc;
188
189 /* Get main B clock source */
190 srcB = Chip_Clock_GetMain_B_ClockSource();
191 if (srcB == SYSCTL_MAIN_B_CLKSRC_MAINCLKSELA) {
192 /* Using source A, so return source A */
193 clkSrc = (uint32_t) Chip_Clock_GetMain_A_ClockSource();
194 }
195 else {
196 /* Using source B */
197 clkSrc = 4 + (uint32_t) srcB;
198 }
199
200 return (CHIP_SYSCTL_MAINCLKSRC_T) clkSrc;
201 }
202
203 /* Return main clock rate */
Chip_Clock_GetMainClockRate(void)204 uint32_t Chip_Clock_GetMainClockRate(void)
205 {
206 uint32_t clkRate;
207
208 if (Chip_Clock_GetMain_B_ClockSource() == SYSCTL_MAIN_B_CLKSRC_MAINCLKSELA) {
209 /* Return main A clock rate */
210 clkRate = Chip_Clock_GetMain_A_ClockRate();
211 }
212 else {
213 /* Return main B clock rate */
214 clkRate = Chip_Clock_GetMain_B_ClockRate();
215 }
216
217 return clkRate;
218 }
219
220 /* Return ADC asynchronous clock rate */
Chip_Clock_GetADCASYNCRate(void)221 uint32_t Chip_Clock_GetADCASYNCRate(void)
222 {
223 uint32_t clkRate = 0;
224
225 switch (Chip_Clock_GetADCASYNCSource()) {
226 case SYSCTL_ADCASYNCCLKSRC_IRC:
227 clkRate = Chip_Clock_GetIntOscRate();
228 break;
229
230 case SYSCTL_ADCASYNCCLKSRC_SYSPLLOUT:
231 clkRate = Chip_Clock_GetSystemPLLOutClockRate();
232 break;
233
234 case SYSCTL_ADCASYNCCLKSRC_USBPLLOUT:
235 clkRate = Chip_Clock_GetUSBPLLOutClockRate();
236 break;
237
238 case SYSCTL_ADCASYNCCLKSRC_SCTPLLOUT:
239 clkRate = Chip_Clock_GetSCTPLLOutClockRate();
240 break;
241 }
242
243 return clkRate;
244 }
245
246 /**
247 * @brief Set CLKOUT clock source and divider
248 * @param src : Clock source for CLKOUT
249 * @param div : divider for CLKOUT clock
250 * @return Nothing
251 * @note Use 0 to disable, or a divider value of 1 to 255. The CLKOUT clock
252 * rate is the clock source divided by the divider. This function will
253 * also toggle the clock source update register to update the clock
254 * source.
255 */
Chip_Clock_SetCLKOUTSource(CHIP_SYSCTL_CLKOUTSRC_T src,uint32_t div)256 void Chip_Clock_SetCLKOUTSource(CHIP_SYSCTL_CLKOUTSRC_T src, uint32_t div)
257 {
258 uint32_t srcClk = (uint32_t) src;
259
260 /* Use a clock A source? */
261 if (src >= 4) {
262 /* Not using a CLKOUT A source */
263 LPC_SYSCTL->CLKOUTSEL[1] = srcClk - 4;
264 }
265 else {
266 /* Using a clock A source, select A and then switch B to A */
267 LPC_SYSCTL->CLKOUTSEL[0] = srcClk;
268 LPC_SYSCTL->CLKOUTSEL[1] = 0;
269 }
270
271 LPC_SYSCTL->CLKOUTDIV = div;
272 }
273
274 /* Enable a system or peripheral clock */
Chip_Clock_EnablePeriphClock(CHIP_SYSCTL_CLOCK_T clk)275 void Chip_Clock_EnablePeriphClock(CHIP_SYSCTL_CLOCK_T clk)
276 {
277 uint32_t clkEnab = (uint32_t) clk;
278
279 if (clkEnab >= 32) {
280 LPC_SYSCTL->SYSAHBCLKCTRL[1] |= (1 << (clkEnab - 32));
281 }
282 else {
283 LPC_SYSCTL->SYSAHBCLKCTRL[0] |= (1 << clkEnab);
284 }
285 }
286
287 /* Disable a system or peripheral clock */
Chip_Clock_DisablePeriphClock(CHIP_SYSCTL_CLOCK_T clk)288 void Chip_Clock_DisablePeriphClock(CHIP_SYSCTL_CLOCK_T clk)
289 {
290 uint32_t clkEnab = (uint32_t) clk;
291
292 if (clkEnab >= 32) {
293 LPC_SYSCTL->SYSAHBCLKCTRL[1] &= ~(1 << (clkEnab - 32));
294 }
295 else {
296 LPC_SYSCTL->SYSAHBCLKCTRL[0] &= ~(1 << clkEnab);
297 }
298 }
299
300 /* Returns the system tick rate as used with the system tick divider */
Chip_Clock_GetSysTickClockRate(void)301 uint32_t Chip_Clock_GetSysTickClockRate(void)
302 {
303 uint32_t sysRate, div;
304
305 div = Chip_Clock_GetSysTickClockDiv();
306
307 /* If divider is 0, the system tick clock is disabled */
308 if (div == 0) {
309 sysRate = 0;
310 }
311 else {
312 sysRate = Chip_Clock_GetMainClockRate() / div;
313 }
314
315 return sysRate;
316 }
317
318 /* Get UART base rate */
Chip_Clock_GetUARTBaseClockRate(void)319 uint32_t Chip_Clock_GetUARTBaseClockRate(void)
320 {
321 uint64_t inclk;
322 uint32_t div;
323
324 div = (uint32_t) Chip_Clock_GetUARTFRGDivider();
325 if (div == 0) {
326 /* Divider is 0 so UART clock is disabled */
327 inclk = 0;
328 }
329 else {
330 uint32_t mult, divmult;
331
332 /* Input clock into FRG block is the divided main system clock */
333 inclk = (uint64_t) (Chip_Clock_GetMainClockRate() / div);
334
335 divmult = LPC_SYSCTL->FRGCTRL & 0xFFFF;
336 if ((divmult & 0xFF) == 0xFF) {
337 /* Fractional part is enabled, get multiplier */
338 mult = (divmult >> 8) & 0xFF;
339
340 /* Get fractional error */
341 inclk = (inclk * 256) / (uint64_t) (256 + mult);
342 }
343 }
344
345 return (uint32_t) inclk;
346 }
347
348 /* Set UART base rate */
Chip_Clock_SetUARTBaseClockRate(uint32_t rate,bool fEnable)349 uint32_t Chip_Clock_SetUARTBaseClockRate(uint32_t rate, bool fEnable)
350 {
351 uint32_t div, inclk;
352
353 /* Input clock into FRG block is the main system cloock */
354 inclk = Chip_Clock_GetMainClockRate();
355
356 /* Get integer divider for coarse rate */
357 div = inclk / rate;
358 if (div == 0) {
359 div = 1;
360 }
361
362 /* Approximated rate with only integer divider */
363 Chip_Clock_SetUARTFRGDivider((uint8_t) div);
364
365 if (fEnable) {
366 uint32_t err;
367 uint64_t uart_fra_multiplier;
368
369 err = inclk - (rate * div);
370 uart_fra_multiplier = ((uint64_t) err * 256) / (uint64_t) (rate * div);
371
372 /* Enable fractional divider and set multiplier */
373 LPC_SYSCTL->FRGCTRL = 0xFF | ((uart_fra_multiplier & 0xFF) << 8);
374 }
375 else {
376 /* Disable fractional generator and use integer divider only */
377 LPC_SYSCTL->FRGCTRL = 0;
378 }
379
380 return Chip_Clock_GetUARTBaseClockRate();
381 }
382
383 /* Bypass System Oscillator and set oscillator frequency range */
Chip_Clock_SetPLLBypass(bool bypass,bool highfr)384 void Chip_Clock_SetPLLBypass(bool bypass, bool highfr)
385 {
386 uint32_t ctrl = 0;
387
388 if (bypass) {
389 ctrl |= (1 << 0);
390 }
391 if (highfr) {
392 ctrl |= (1 << 1);
393 }
394
395 LPC_SYSCTL->SYSOSCCTRL = ctrl;
396 }
397
398 /* Return system clock rate */
Chip_Clock_GetSystemClockRate(void)399 uint32_t Chip_Clock_GetSystemClockRate(void)
400 {
401 /* No point in checking for divide by 0 */
402 return Chip_Clock_GetMainClockRate() / LPC_SYSCTL->SYSAHBCLKDIV;
403 }
404