LPCOpen Platform for LPC18XX/43XX microcontrollers  18XX43XX
LPCOpen Platform for the NXP LPC18XX/43XX family of Microcontrollers
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 {
48 #if defined(CHIP_LPC43XX)
49  {CLK_PERIPH_BUS, CLK_PERIPH_SGPIO, CLK_BASE_PERIPH},
50 #endif
53 #if defined(CHIP_LPC43XX)
54  {CLK_SPI, CLK_SPI, CLK_BASE_SPI},
55  {CLK_ADCHS, CLK_ADCHS, CLK_BASE_ADCHS},
56 #endif
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 */
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 */
206 {
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 */
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 */
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 {
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 */
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 */
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 */
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 */
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:
505  break;
506 
507  case CLKIN_AUDIOPLL:
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 */
548 {
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 */
602 {
603  if (BaseClock < CLK_BASE_NONE) {
604  LPC_CGU->BASE_CLK[BaseClock] &= ~1;
605  }
606 }
607 
608 /* Disables a base clock source */
610 {
611  if (BaseClock < CLK_BASE_NONE) {
612  LPC_CGU->BASE_CLK[BaseClock] |= 1;
613  }
614 }
615 
616 /* Returns base clock enable state */
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 */
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 */
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 */
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 */
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 
714 {
715  /* Set Power Down bit */
716  LPC_CCU1->PM = 1;
717  LPC_CCU2->PM = 1;
718 }
719 
725 {
726  /* Clear Power Down bit */
727  LPC_CCU1->PM = 0;
728  LPC_CCU2->PM = 0;
729 }
730 
731 /* Returns a peripheral clock rate */
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 */
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 */
809 {
810  LPC_CGU->PLL[pllnum].PLL_CTRL &= ~1;
811 }
812 
813 /* Disables the audio or USB PLL */
815 {
816  LPC_CGU->PLL[pllnum].PLL_CTRL |= 1;
817 }
818 
819 /* Returns the PLL status */
821 {
822  return LPC_CGU->PLL[pllnum].PLL_STAT;
823 }