LPCOpen Platform for LPC18XX/43XX microcontrollers: C:/w/lpcopen_docs/software/lpc_core/lpc_chip/chip_18xx_43xx/clock_18xx_43xx.c Source File

| LPCOpen Platform for LPC18XX/43XX microcontrollers 18XX43XX LPCOpen Platform for the NXP LPC18XX/43XX family of Microcontrollers

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

clock_18xx_43xx.c
Go to the documentation of this file.
1 /*
2 * @brief LPC18xx/43xx clock driver
3 *
4 * @note
5 * Copyright(C) NXP Semiconductors, 2012
6 * All rights reserved.
7 *
8 * @par
9 * Software that is described herein is for illustrative purposes only
10 * which provides customers with programming information regarding the
11 * LPC products. This software is supplied "AS IS" without any warranties of
12 * any kind, and NXP Semiconductors and its licenser disclaim any and
13 * all warranties, express or implied, including all implied warranties of
14 * merchantability, fitness for a particular purpose and non-infringement of
15 * intellectual property rights. NXP Semiconductors assumes no responsibility
16 * or liability for the use of the software, conveys no license or rights under any
17 * patent, copyright, mask work right, or any other intellectual property rights in
18 * or to any products. NXP Semiconductors reserves the right to make changes
19 * in the software without notification. NXP Semiconductors also makes no
20 * representation or warranty that such application will be suitable for the
21 * specified use without further testing or modification.
22 *
23 * @par
24 * Permission to use, copy, modify, and distribute this software and its
25 * documentation is hereby granted, under NXP Semiconductors' and its
26 * licensor's relevant copyrights in the software, without fee, provided that it
27 * is used in conjunction with NXP Semiconductors microcontrollers. This
28 * copyright, permission, and disclaimer notice must appear in all copies of
29 * this code.
30 */
31 #include "chip.h"
32
33 /*****************************************************************************
34 * Private types/enumerations/variables
35 ****************************************************************************/
36
37 /* Maps a peripheral clock to it's base clock */
38 typedef struct {
39 CHIP_CCU_CLK_T clkstart;
40 CHIP_CCU_CLK_T clkend;
41 CHIP_CGU_BASE_CLK_T clkbase;
42 } CLK_PERIPH_TO_BASE_T;
43 static const CLK_PERIPH_TO_BASE_T periph_to_base[] = {
44 {CLK_APB3_BUS, CLK_APB3_CAN0, CLK_BASE_APB3},
45 {CLK_APB1_BUS, CLK_APB1_CAN1, CLK_BASE_APB1},
46 {CLK_SPIFI, CLK_SPIFI, CLK_BASE_SPIFI},
47 {CLK_MX_BUS, CLK_MX_QEI, CLK_BASE_MX},
48 #if defined(CHIP_LPC43XX)
49 {CLK_PERIPH_BUS, CLK_PERIPH_SGPIO, CLK_BASE_PERIPH},
50 #endif
51 {CLK_USB0, CLK_USB0, CLK_BASE_USB0},
52 {CLK_USB1, CLK_USB1, CLK_BASE_USB1},
53 #if defined(CHIP_LPC43XX)
54 {CLK_SPI, CLK_SPI, CLK_BASE_SPI},
55 {CLK_ADCHS, CLK_ADCHS, CLK_BASE_ADCHS},
56 #endif
57 {CLK_APLL, CLK_APLL, CLK_BASE_APLL},
58 {CLK_APB2_UART3, CLK_APB2_UART3, CLK_BASE_UART3},
59 {CLK_APB2_UART2, CLK_APB2_UART2, CLK_BASE_UART2},
60 {CLK_APB0_UART1, CLK_APB0_UART1, CLK_BASE_UART1},
61 {CLK_APB0_UART0, CLK_APB0_UART0, CLK_BASE_UART0},
62 {CLK_APB2_SSP1, CLK_APB2_SSP1, CLK_BASE_SSP1},
63 {CLK_APB0_SSP0, CLK_APB0_SSP0, CLK_BASE_SSP0},
64 {CLK_APB2_SDIO, CLK_APB2_SDIO, CLK_BASE_SDIO},
65 {CLK_CCU2_LAST, CLK_CCU2_LAST, CLK_BASE_NONE}
66 };
67
68 #define CRYSTAL_32K_FREQ_IN (32 * 1024)
69
70 /* Variables to use audio and usb pll frequency */
71 static uint32_t audio_usb_pll_freq[CGU_AUDIO_PLL+1];
72
73 /*****************************************************************************
74 * Public types/enumerations/variables
75 ****************************************************************************/
76
77 /*****************************************************************************
78 * Private functions
79 ****************************************************************************/
80 __STATIC_INLINE uint32_t ABS(int val)
81 {
82 if (val < 0)
83 return -val;
84 return val;
85 }
86
87 static void pll_calc_divs(uint32_t freq, PLL_PARAM_T *ppll)
88 {
89
90 uint32_t prev = freq;
91 int n, m, p;
92
93 /* When direct mode is set FBSEL should be a don't care */
94 if (ppll->ctrl & (1 << 7)) {
95 ppll->ctrl &= ~(1 << 6);
96 }
97 for (n = 1; n <= 4; n++) {
98 for (p = 0; p < 4; p ++) {
99 for (m = 1; m <= 256; m++) {
100 uint32_t fcco, fout;
101 if (ppll->ctrl & (1 << 6)) {
102 fcco = ((m << (p + 1)) * ppll->fin) / n;
103 } else {
104 fcco = (m * ppll->fin) / n;
105 }
106 if (fcco < PLL_MIN_CCO_FREQ) continue;
107 if (fcco > PLL_MAX_CCO_FREQ) break;
108 if (ppll->ctrl & (1 << 7)) {
109 fout = fcco;
110 } else {
111 fout = fcco >> (p + 1);
112 }
113
114 if (ABS(freq - fout) < prev) {
115 ppll->nsel = n;
116 ppll->psel = p + 1;
117 ppll->msel = m;
118 ppll->fout = fout;
119 ppll->fcco = fcco;
120 prev = ABS(freq - fout);
121 }
122 }
123 }
124 }
125 }
126
127 static void pll_get_frac(uint32_t freq, PLL_PARAM_T *ppll)
128 {
129 int diff[3];
130 PLL_PARAM_T pll[3] = {{0},{0},{0}};
131
132 /* Try direct mode */
133 pll[0].ctrl |= (1 << 7);
134 pll[0].fin = ppll->fin;
135 pll[0].srcin = ppll->srcin;
136 pll_calc_divs(freq, &pll[0]);
137 if (pll[0].fout == freq) {
138 *ppll = pll[0];
139 return ;
140 }
141 diff[0] = ABS(freq - pll[0].fout);
142
143 /* Try non-Integer mode */
144 pll[2].ctrl = (1 << 6);
145 pll[2].fin = ppll->fin;
146 pll[2].srcin = ppll->srcin;
147 pll_calc_divs(freq, &pll[2]);
148 if (pll[2].fout == freq) {
149 *ppll = pll[2];
150 return ;
151 }
152
153 diff[2] = ABS(freq - pll[2].fout);
154 /* Try integer mode */
155 pll[1].ctrl = (1 << 6);
156 pll[1].fin = ppll->fin;
157 pll[1].srcin = ppll->srcin;
158 pll_calc_divs(freq, &pll[1]);
159 if (pll[1].fout == freq) {
160 *ppll = pll[1];
161 return ;
162 }
163 diff[1] = ABS(freq - pll[1].fout);
164
165 /* Find the min of 3 and return */
166 if (diff[0] <= diff[1]) {
167 if (diff[0] <= diff[2]) {
168 *ppll = pll[0];
169 } else {
170 *ppll = pll[2];
171 }
172 } else {
173 if (diff[1] <= diff[2]) {
174 *ppll = pll[1];
175 } else {
176 *ppll = pll[2];
177 }
178 }
179 }
180
181 /* Test PLL input values for a specific frequency range */
182 static uint32_t Chip_Clock_TestMainPLLMultiplier(uint32_t InputHz, uint32_t TestMult, uint32_t MinHz, uint32_t MaxHz)
183 {
184 uint32_t TestHz = TestMult * InputHz;
185
186 if ((TestHz < MinHz) || (TestHz > MAX_CLOCK_FREQ) || (TestHz > MaxHz)) {
187 TestHz = 0;
188 }
189
190 return TestHz;
191 }
192
193 /* Returns clock rate out of a divider */
194 static uint32_t Chip_Clock_GetDivRate(CHIP_CGU_CLKIN_T clock, CHIP_CGU_IDIV_T divider)
195 {
196 CHIP_CGU_CLKIN_T input;
197 uint32_t div;
198
199 input = Chip_Clock_GetDividerSource(divider);
200 div = Chip_Clock_GetDividerDivisor(divider);
201 return Chip_Clock_GetClockInputHz(input) / (div + 1);
202 }
203
204 /* Finds the base clock for the peripheral clock */
205 static CHIP_CGU_BASE_CLK_T Chip_Clock_FindBaseClock(CHIP_CCU_CLK_T clk)
206 {
207 CHIP_CGU_BASE_CLK_T baseclk = CLK_BASE_NONE;
208 int i = 0;
209
210 while ((baseclk == CLK_BASE_NONE) && (periph_to_base[i].clkbase != baseclk)) {
211 if ((clk >= periph_to_base[i].clkstart) && (clk <= periph_to_base[i].clkend)) {
212 baseclk = periph_to_base[i].clkbase;
213 }
214 else {
215 i++;
216 }
217 }
218
219 return baseclk;
220 }
221
222 /*****************************************************************************
223 * Public functions
224 ****************************************************************************/
225
226 /* Enables the crystal oscillator */
227 void Chip_Clock_EnableCrystal(void)
228 {
229 volatile uint32_t delay = 1000;
230
231 uint32_t OldCrystalConfig = LPC_CGU->XTAL_OSC_CTRL;
232
233 /* Clear bypass mode */
234 OldCrystalConfig &= (~2);
235 if (OldCrystalConfig != LPC_CGU->XTAL_OSC_CTRL) {
236 LPC_CGU->XTAL_OSC_CTRL = OldCrystalConfig;
237 }
238
239 /* Enable crystal oscillator */
240 OldCrystalConfig &= (~1);
241 if (OscRateIn >= 20000000) {
242 OldCrystalConfig |= 4; /* Set high frequency mode */
243
244 }
245 LPC_CGU->XTAL_OSC_CTRL = OldCrystalConfig;
246
247 /* Delay for 250uSec */
248 while(delay--) {}
249 }
250
251 /* Calculate the Main PLL div values */
252 int Chip_Clock_CalcMainPLLValue(uint32_t freq, PLL_PARAM_T *ppll)
253 {
254 ppll->fin = Chip_Clock_GetClockInputHz(ppll->srcin);
255
256 /* Do sanity check on frequency */
257 if (freq > MAX_CLOCK_FREQ || freq < (PLL_MIN_CCO_FREQ / 16) || !ppll->fin) {
258 return -1;
259 }
260
261 ppll->ctrl = 1 << 7; /* Enable direct mode [If possible] */
262 ppll->nsel = 0;
263 ppll->psel = 0;
264 ppll->msel = freq / ppll->fin;
265
266 if (freq < PLL_MIN_CCO_FREQ || ppll->msel * ppll->fin != freq) {
267 pll_get_frac(freq, ppll);
268 if (!ppll->nsel) {
269 return -1;
270 }
271 ppll->nsel --;
272 }
273
274 if (ppll->msel == 0) {
275 return - 1;
276 }
277
278 if (ppll->psel) {
279 ppll->psel --;
280 }
281
282 ppll->msel --;
283
284 return 0;
285 }
286
287 /* Disables the crystal oscillator */
288 void Chip_Clock_DisableCrystal(void)
289 {
290 /* Disable crystal oscillator */
291 LPC_CGU->XTAL_OSC_CTRL |= 1;
292 }
293
294 /* Configures the main PLL */
295 uint32_t Chip_Clock_SetupMainPLLHz(CHIP_CGU_CLKIN_T Input, uint32_t MinHz, uint32_t DesiredHz, uint32_t MaxHz)
296 {
297 uint32_t freqin = Chip_Clock_GetClockInputHz(Input);
298 uint32_t Mult, LastMult, MultEnd;
299 uint32_t freqout, freqout2;
300
301 if (DesiredHz != 0xFFFFFFFF) {
302 /* Test DesiredHz rounded down */
303 Mult = DesiredHz / freqin;
304 freqout = Chip_Clock_TestMainPLLMultiplier(freqin, Mult, MinHz, MaxHz);
305
306 /* Test DesiredHz rounded up */
307 Mult++;
308 freqout2 = Chip_Clock_TestMainPLLMultiplier(freqin, Mult, MinHz, MaxHz);
309
310 if (freqout && !freqout2) { /* rounding up is no good? set first multiplier */
311 Mult--;
312 return Chip_Clock_SetupMainPLLMult(Input, Mult);
313 }
314 if (!freqout && freqout2) { /* didn't work until rounded up? set 2nd multiplier */
315 return Chip_Clock_SetupMainPLLMult(Input, Mult);
316 }
317
318 if (freqout && freqout2) { /* either multiplier okay? choose closer one */
319 if ((DesiredHz - freqout) > (freqout2 - DesiredHz)) {
320 Mult--;
321 return Chip_Clock_SetupMainPLLMult(Input, Mult);
322 }
323 else {
324 return Chip_Clock_SetupMainPLLMult(Input, Mult);
325 }
326 }
327 }
328
329 /* Neither multiplier okay? Try to start at MinHz and increment.
330 This should find the highest multiplier that is still good */
331 Mult = MinHz / freqin;
332 MultEnd = MaxHz / freqin;
333 LastMult = 0;
334 while (1) {
335 freqout = Chip_Clock_TestMainPLLMultiplier(freqin, Mult, MinHz, MaxHz);
336
337 if (freqout) {
338 LastMult = Mult;
339 }
340
341 if (Mult >= MultEnd) {
342 break;
343 }
344 Mult++;
345 }
346
347 if (LastMult) {
348 return Chip_Clock_SetupMainPLLMult(Input, LastMult);
349 }
350
351 return 0;
352 }
353
354 /* Directly set the PLL multipler */
355 uint32_t Chip_Clock_SetupMainPLLMult(CHIP_CGU_CLKIN_T Input, uint32_t mult)
356 {
357 volatile uint32_t delay = 250;
358 uint32_t freq = Chip_Clock_GetClockInputHz(Input);
359 uint32_t msel = 0, nsel = 0, psel = 0, pval = 1;
360 uint32_t PLLReg = LPC_CGU->PLL1_CTRL;
361
362 freq *= mult;
363 msel = mult - 1;
364
365 PLLReg &= ~(0x1F << 24);/* clear input source bits */
366 PLLReg |= Input << 24; /* set input source bits to parameter */
367
368 /* Clear other PLL input bits */
369 PLLReg &= ~((1 << 6) | /* FBSEL */
370 (1 << 1) | /* BYPASS */
371 (1 << 7) | /* DIRECT */
372 (0x03 << 8) | (0xFF << 16) | (0x03 << 12)); /* PSEL, MSEL, NSEL- divider ratios */
373
374 if (freq < 156000000) {
375 /* psel is encoded such that 0=1, 1=2, 2=4, 3=8 */
376 while ((2 * (pval) * freq) < 156000000) {
377 psel++;
378 pval *= 2;
379 }
380
381 PLLReg |= (msel << 16) | (nsel << 12) | (psel << 8) | (1 << 6); /* dividers + FBSEL */
382 }
383 else if (freq < 320000000) {
384 PLLReg |= (msel << 16) | (nsel << 12) | (psel << 8) | (1 << 7) | (1 << 6); /* dividers + DIRECT + FBSEL */
385 }
386 else {
387 Chip_Clock_DisableMainPLL();
388 return 0;
389 }
390 LPC_CGU->PLL1_CTRL = PLLReg & ~(1 << 0);
391
392 /* Wait for 50uSec */
393 while(delay--) {}
394
395 return freq;
396 }
397
398 /* Returns the frequency of the main PLL */
399 uint32_t Chip_Clock_GetMainPLLHz(void)
400 {
401 uint32_t PLLReg = LPC_CGU->PLL1_CTRL;
402 uint32_t freq = Chip_Clock_GetClockInputHz((CHIP_CGU_CLKIN_T) ((PLLReg >> 24) & 0xF));
403 uint32_t msel, nsel, psel, direct, fbsel;
404 uint32_t m, n, p;
405 const uint8_t ptab[] = {1, 2, 4, 8};
406
407 /* No lock? */
408 if (!(LPC_CGU->PLL1_STAT & 1)) {
409 return 0;
410 }
411
412 msel = (PLLReg >> 16) & 0xFF;
413 nsel = (PLLReg >> 12) & 0x3;
414 psel = (PLLReg >> 8) & 0x3;
415 direct = (PLLReg >> 7) & 0x1;
416 fbsel = (PLLReg >> 6) & 0x1;
417
418 m = msel + 1;
419 n = nsel + 1;
420 p = ptab[psel];
421
422 if (direct || fbsel) {
423 return m * (freq / n);
424 }
425
426 return (m / (2 * p)) * (freq / n);
427 }
428
429 /* Sets up a CGU clock divider and it's input clock */
430 void Chip_Clock_SetDivider(CHIP_CGU_IDIV_T Divider, CHIP_CGU_CLKIN_T Input, uint32_t Divisor)
431 {
432 uint32_t reg = LPC_CGU->IDIV_CTRL[Divider];
433
434 Divisor--;
435
436 if (Input != CLKINPUT_PD) {
437 /* Mask off bits that need to changes */
438 reg &= ~((0x1F << 24) | 1 | (CHIP_CGU_IDIV_MASK(Divider) << 2));
439
440 /* Enable autoblocking, clear PD, and set clock source & divisor */
441 LPC_CGU->IDIV_CTRL[Divider] = reg | (1 << 11) | (Input << 24) | (Divisor << 2);
442 }
443 else {
444 LPC_CGU->IDIV_CTRL[Divider] = reg | 1; /* Power down this divider */
445 }
446 }
447
448 /* Gets a CGU clock divider source */
449 CHIP_CGU_CLKIN_T Chip_Clock_GetDividerSource(CHIP_CGU_IDIV_T Divider)
450 {
451 uint32_t reg = LPC_CGU->IDIV_CTRL[Divider];
452
453 if (reg & 1) { /* divider is powered down */
454 return CLKINPUT_PD;
455 }
456
457 return (CHIP_CGU_CLKIN_T) ((reg >> 24) & 0x1F);
458 }
459
460 /* Gets a CGU clock divider divisor */
461 uint32_t Chip_Clock_GetDividerDivisor(CHIP_CGU_IDIV_T Divider)
462 {
463 return (CHIP_CGU_CLKIN_T) ((LPC_CGU->IDIV_CTRL[Divider] >> 2) & CHIP_CGU_IDIV_MASK(Divider));
464 }
465
466 /* Returns the frequency of the specified input clock source */
467 uint32_t Chip_Clock_GetClockInputHz(CHIP_CGU_CLKIN_T input)
468 {
469 uint32_t rate = 0;
470
471 switch (input) {
472 case CLKIN_32K:
473 rate = CRYSTAL_32K_FREQ_IN;
474 break;
475
476 case CLKIN_IRC:
477 rate = CGU_IRC_FREQ;
478 break;
479
480 case CLKIN_ENET_RX:
481 if ((LPC_CREG->CREG6 & 0x07) != 0x4) {
482 /* MII mode requires 25MHz clock */
483 rate = 25000000;
484 }
485 break;
486
487 case CLKIN_ENET_TX:
488 if ((LPC_CREG->CREG6 & 0x07) != 0x4) {
489 rate = 25000000; /* MII uses 25 MHz */
490 } else {
491 rate = 50000000; /* RMII uses 50 MHz */
492 }
493 break;
494
495 case CLKIN_CLKIN:
496 rate = ExtRateIn;
497 break;
498
499 case CLKIN_CRYSTAL:
500 rate = OscRateIn;
501 break;
502
503 case CLKIN_USBPLL:
504 rate = audio_usb_pll_freq[CGU_USB_PLL];
505 break;
506
507 case CLKIN_AUDIOPLL:
508 rate = audio_usb_pll_freq[CGU_AUDIO_PLL];
509 break;
510
511 case CLKIN_MAINPLL:
512 rate = Chip_Clock_GetMainPLLHz();
513 break;
514
515 case CLKIN_IDIVA:
516 rate = Chip_Clock_GetDivRate(input, CLK_IDIV_A);
517 break;
518
519 case CLKIN_IDIVB:
520 rate = Chip_Clock_GetDivRate(input, CLK_IDIV_B);
521 break;
522
523 case CLKIN_IDIVC:
524 rate = Chip_Clock_GetDivRate(input, CLK_IDIV_C);
525 break;
526
527 case CLKIN_IDIVD:
528 rate = Chip_Clock_GetDivRate(input, CLK_IDIV_D);
529 break;
530
531 case CLKIN_IDIVE:
532 rate = Chip_Clock_GetDivRate(input, CLK_IDIV_E);
533 break;
534
535 case CLKINPUT_PD:
536 rate = 0;
537 break;
538
539 default:
540 break;
541 }
542
543 return rate;
544 }
545
546 /* Returns the frequency of the specified base clock source */
547 uint32_t Chip_Clock_GetBaseClocktHz(CHIP_CGU_BASE_CLK_T clock)
548 {
549 return Chip_Clock_GetClockInputHz(Chip_Clock_GetBaseClock(clock));
550 }
551
552 /* Sets a CGU Base Clock clock source */
553 void Chip_Clock_SetBaseClock(CHIP_CGU_BASE_CLK_T BaseClock, CHIP_CGU_CLKIN_T Input, bool autoblocken, bool powerdn)
554 {
555 uint32_t reg = LPC_CGU->BASE_CLK[BaseClock];
556
557 if (BaseClock < CLK_BASE_NONE) {
558 if (Input != CLKINPUT_PD) {
559 /* Mask off fields we plan to update */
560 reg &= ~((0x1F << 24) | 1 | (1 << 11));
561
562 if (autoblocken) {
563 reg |= (1 << 11);
564 }
565 if (powerdn) {
566 reg |= (1 << 0);
567 }
568
569 /* Set clock source */
570 reg |= (Input << 24);
571
572 LPC_CGU->BASE_CLK[BaseClock] = reg;
573 }
574 }
575 else {
576 LPC_CGU->BASE_CLK[BaseClock] = reg | 1; /* Power down this base clock */
577 }
578 }
579
580 /* Reads CGU Base Clock clock source information */
581 void Chip_Clock_GetBaseClockOpts(CHIP_CGU_BASE_CLK_T BaseClock, CHIP_CGU_CLKIN_T *Input, bool *autoblocken,
582 bool *powerdn)
583 {
584 uint32_t reg = LPC_CGU->BASE_CLK[BaseClock];
585 CHIP_CGU_CLKIN_T ClkIn = (CHIP_CGU_CLKIN_T) ((reg >> 24) & 0x1F );
586
587 if (BaseClock < CLK_BASE_NONE) {
588 /* Get settings */
589 *Input = ClkIn;
590 *autoblocken = (reg & (1 << 11)) ? true : false;
591 *powerdn = (reg & (1 << 0)) ? true : false;
592 }
593 else {
594 *Input = CLKINPUT_PD;
595 *powerdn = true;
596 *autoblocken = true;
597 }
598 }
599
600 /*Enables a base clock source */
601 void Chip_Clock_EnableBaseClock(CHIP_CGU_BASE_CLK_T BaseClock)
602 {
603 if (BaseClock < CLK_BASE_NONE) {
604 LPC_CGU->BASE_CLK[BaseClock] &= ~1;
605 }
606 }
607
608 /* Disables a base clock source */
609 void Chip_Clock_DisableBaseClock(CHIP_CGU_BASE_CLK_T BaseClock)
610 {
611 if (BaseClock < CLK_BASE_NONE) {
612 LPC_CGU->BASE_CLK[BaseClock] |= 1;
613 }
614 }
615
616 /* Returns base clock enable state */
617 bool Chip_Clock_IsBaseClockEnabled(CHIP_CGU_BASE_CLK_T BaseClock)
618 {
619 bool enabled;
620
621 if (BaseClock < CLK_BASE_NONE) {
622 enabled = (bool) ((LPC_CGU->BASE_CLK[BaseClock] & 1) == 0);
623 }
624 else {
625 enabled = false;
626 }
627
628 return enabled;
629 }
630
631 /* Gets a CGU Base Clock clock source */
632 CHIP_CGU_CLKIN_T Chip_Clock_GetBaseClock(CHIP_CGU_BASE_CLK_T BaseClock)
633 {
634 uint32_t reg;
635
636 if (BaseClock >= CLK_BASE_NONE) {
637 return CLKINPUT_PD;
638 }
639
640 reg = LPC_CGU->BASE_CLK[BaseClock];
641
642 /* base clock is powered down? */
643 if (reg & 1) {
644 return CLKINPUT_PD;
645 }
646
647 return (CHIP_CGU_CLKIN_T) ((reg >> 24) & 0x1F);
648 }
649
650 /* Enables a peripheral clock and sets clock states */
651 void Chip_Clock_EnableOpts(CHIP_CCU_CLK_T clk, bool autoen, bool wakeupen, int div)
652 {
653 uint32_t reg = 1;
654
655 if (autoen) {
656 reg |= (1 << 1);
657 }
658 if (wakeupen) {
659 reg |= (1 << 2);
660 }
661
662 /* Not all clocks support a divider, but we won't check that here. Only
663 dividers of 1 and 2 are allowed. Assume 1 if not 2 */
664 if (div == 2) {
665 reg |= (1 << 5);
666 }
667
668 /* Setup peripheral clock and start running */
669 if (clk >= CLK_CCU2_START) {
670 LPC_CCU2->CLKCCU[clk - CLK_CCU2_START].CFG = reg;
671 }
672 else {
673 LPC_CCU1->CLKCCU[clk].CFG = reg;
674 }
675 }
676
677 /* Enables a peripheral clock */
678 void Chip_Clock_Enable(CHIP_CCU_CLK_T clk)
679 {
680 /* Start peripheral clock running */
681 if (clk >= CLK_CCU2_START) {
682 LPC_CCU2->CLKCCU[clk - CLK_CCU2_START].CFG |= 1;
683 }
684 else {
685 LPC_CCU1->CLKCCU[clk].CFG |= 1;
686 }
687 }
688
689 /* Enable RTC Clock */
690 void Chip_Clock_RTCEnable(void)
691 {
692 LPC_CREG->CREG0 &= ~((1 << 3) | (1 << 2)); /* Reset 32Khz oscillator */
693 LPC_CREG->CREG0 |= (1 << 1) | (1 << 0); /* Enable 32 kHz & 1 kHz on osc32k and release reset */
694 }
695
696 /* Disables a peripheral clock */
697 void Chip_Clock_Disable(CHIP_CCU_CLK_T clk)
698 {
699 /* Stop peripheral clock */
700 if (clk >= CLK_CCU2_START) {
701 LPC_CCU2->CLKCCU[clk - CLK_CCU2_START].CFG &= ~1;
702 }
703 else {
704 LPC_CCU1->CLKCCU[clk].CFG &= ~1;
705 }
706 }
707
713 void Chip_Clock_StartPowerDown(void)
714 {
715 /* Set Power Down bit */
716 LPC_CCU1->PM = 1;
717 LPC_CCU2->PM = 1;
718 }
719
724 void Chip_Clock_ClearPowerDown(void)
725 {
726 /* Clear Power Down bit */
727 LPC_CCU1->PM = 0;
728 LPC_CCU2->PM = 0;
729 }
730
731 /* Returns a peripheral clock rate */
732 uint32_t Chip_Clock_GetRate(CHIP_CCU_CLK_T clk)
733 {
734 CHIP_CGU_BASE_CLK_T baseclk;
735 uint32_t reg, div, rate;
736
737 /* Get CCU config register for clock */
738 if (clk >= CLK_CCU2_START) {
739 reg = LPC_CCU2->CLKCCU[clk - CLK_CCU2_START].CFG;
740 }
741 else {
742 reg = LPC_CCU1->CLKCCU[clk].CFG;
743 }
744
745 /* Is the clock enabled? */
746 if (reg & 1) {
747 /* Get base clock for this peripheral clock */
748 baseclk = Chip_Clock_FindBaseClock(clk);
749
750 /* Get base clock rate */
751 rate = Chip_Clock_GetBaseClocktHz(baseclk);
752
753 /* Get divider for this clock */
754 if (((reg >> 5) & 0x7) == 0) {
755 div = 1;
756 }
757 else {
758 div = 2;/* No other dividers supported */
759
760 }
761 rate = rate / div;
762 }
763 else {
764 rate = 0;
765 }
766
767 return rate;
768 }
769
770 /* Get EMC Clock Rate */
771 uint32_t Chip_Clock_GetEMCRate(void)
772
773 {
774 uint32_t ClkFreq;
775 uint32_t EMCDiv;
776 ClkFreq = Chip_Clock_GetRate(CLK_MX_EMC);
777
778 /* EMC Divider readback at pos 27
779 TODO: just checked but dont mention in UM */
780 EMCDiv = (LPC_CCU1->CLKCCU[CLK_MX_EMC_DIV].CFG >> 27) & 0x07;
781
782 /* Check EMC Divider to get real EMC clock out */
783 if ((EMCDiv == 1) && (LPC_CREG->CREG6 & (1 << 16))) {
784 ClkFreq >>= 1;
785 }
786 return ClkFreq;
787 }
788
789 /* Sets up the audio or USB PLL */
790 void Chip_Clock_SetupPLL(CHIP_CGU_CLKIN_T Input, CHIP_CGU_USB_AUDIO_PLL_T pllnum,
791 const CGU_USBAUDIO_PLL_SETUP_T *pPLLSetup)
792 {
793 uint32_t reg = pPLLSetup->ctrl | (Input << 24);
794
795 /* Setup from passed values */
796 LPC_CGU->PLL[pllnum].PLL_CTRL = reg;
797 LPC_CGU->PLL[pllnum].PLL_MDIV = pPLLSetup->mdiv;
798 LPC_CGU->PLL[pllnum].PLL_NP_DIV = pPLLSetup->ndiv;
799
800 /* Fractional divider is for audio PLL only */
801 if (pllnum == CGU_AUDIO_PLL) {
802 LPC_CGU->PLL0AUDIO_FRAC = pPLLSetup->fract;
803 }
804 audio_usb_pll_freq[pllnum] = pPLLSetup->freq;
805 }
806
807 /* Enables the audio or USB PLL */
808 void Chip_Clock_EnablePLL(CHIP_CGU_USB_AUDIO_PLL_T pllnum)
809 {
810 LPC_CGU->PLL[pllnum].PLL_CTRL &= ~1;
811 }
812
813 /* Disables the audio or USB PLL */
814 void Chip_Clock_DisablePLL(CHIP_CGU_USB_AUDIO_PLL_T pllnum)
815 {
816 LPC_CGU->PLL[pllnum].PLL_CTRL |= 1;
817 }
818
819 /* Returns the PLL status */
820 uint32_t Chip_Clock_GetPLLStatus(CHIP_CGU_USB_AUDIO_PLL_T pllnum)
821 {
822 return LPC_CGU->PLL[pllnum].PLL_STAT;
823 }