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