LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 
32 #include "chip.h"
33 
34 /*****************************************************************************
35  * Private types/enumerations/variables
36  ****************************************************************************/
37 
38 /* Maps a peripheral clock to it's base clock */
39 typedef struct {
49 #if 0
50 #if defined(CHIP_LPC43XX)
51  {CLK_PERIPH_BUS, CLK_PERIPH_SGPIO, CLK_BASE_PERIPH},
52 #endif
55 #if defined(CHIP_LPC43XX)
56  {CLK_SPI, CLK_SPI, CLK_BASE_SPI},
57  {CLK_VADC, CLK_VADC, CLK_BASE_VADC},
58 #endif
62  {CLK_APB2_UART1, CLK_APB2_UART1, CLK_BASE_UART1},
63  {CLK_APB2_UART0, CLK_APB2_UART0, CLK_BASE_UART0},
65  {CLK_APB2_SSP0, CLK_APB2_SSP0, CLK_BASE_SSP0},
68 #endif
69 };
70 
71 /*****************************************************************************
72  * Public types/enumerations/variables
73  ****************************************************************************/
74 
75 /*****************************************************************************
76  * Private functions
77  ****************************************************************************/
78 
79 /* Test PLL input values for a specific frequency range */
81 {
82  uint32_t TestHz = TestMult * InputHz;
83 
84  if ((TestHz < MinHz) || (TestHz > MAX_CLOCK_FREQ) || (TestHz > MaxHz)) {
85  TestHz = 0;
86  }
87 
88  return TestHz;
89 }
90 
91 /* Returns clock rate out of a divider */
93 {
94  CHIP_CGU_CLKIN_T input;
95  uint32_t div;
96 
97  input = Chip_Clock_GetDividerSource(divider);
98  div = Chip_Clock_GetDividerDivisor(divider);
99  return Chip_Clock_GetClockInputHz(input) / (div + 1);
100 }
101 
102 /* Finds the base clock for the peripheral clock */
104 {
106  int i = 0;
107 
108  while ((baseclk == CLK_BASE_NONE) && (periph_to_base[i].clkbase != baseclk)) {
109  if ((clk >= periph_to_base[i].clkstart) && (clk <= periph_to_base[i].clkend)) {
110  baseclk = periph_to_base[i].clkbase;
111  }
112  else {
113  i++;
114  }
115  }
116 
117  return baseclk;
118 }
119 
120 /*****************************************************************************
121  * Public functions
122  ****************************************************************************/
123 
124 /* Enables the crystal oscillator */
126 {
127  uint32_t OldCrystalConfig = LPC_CGU->XTAL_OSC_CTRL;
128 
129  /* Clear bypass mode */
130  OldCrystalConfig &= (~2);
131  if (OldCrystalConfig != LPC_CGU->XTAL_OSC_CTRL) {
132  LPC_CGU->XTAL_OSC_CTRL = OldCrystalConfig;
133  }
134 
135  /* Enable crystal oscillator */
136  OldCrystalConfig &= (~1);
137  if (CRYSTAL_MAIN_FREQ_IN >= 20000000) {
138  OldCrystalConfig |= 4; /* Set high frequency mode */
139 
140  }
141  LPC_CGU->XTAL_OSC_CTRL = OldCrystalConfig;
142 }
143 
144 /* Disables the crystal oscillator */
146 {
147  /* Disable crystal oscillator */
148  LPC_CGU->XTAL_OSC_CTRL &= (~1);
149 }
150 
151 /* Configures the main PLL */
153 {
154  uint32_t freqin = Chip_Clock_GetClockInputHz(Input);
155  uint32_t Mult, LastMult, MultEnd;
156  uint32_t freqout, freqout2;
157 
158  if (DesiredHz != 0xFFFFFFFF) {
159  /* Test DesiredHz rounded down */
160  Mult = DesiredHz / freqin;
161  freqout = Chip_Clock_TestMainPLLMultiplier(freqin, Mult, MinHz, MaxHz);
162 
163  /* Test DesiredHz rounded up */
164  Mult++;
165  freqout2 = Chip_Clock_TestMainPLLMultiplier(freqin, Mult, MinHz, MaxHz);
166 
167  if (freqout && !freqout2) { /* rounding up is no good? set first multiplier */
168  Mult--;
169  return Chip_Clock_SetupMainPLLMult(Input, Mult);
170  }
171  if (!freqout && freqout2) { /* didn't work until rounded up? set 2nd multiplier */
172  return Chip_Clock_SetupMainPLLMult(Input, Mult);
173  }
174 
175  if (freqout && freqout2) { /* either multiplier okay? choose closer one */
176  if ((DesiredHz - freqout) > (freqout2 - DesiredHz)) {
177  Mult--;
178  return Chip_Clock_SetupMainPLLMult(Input, Mult);
179  }
180  else {
181  return Chip_Clock_SetupMainPLLMult(Input, Mult);
182  }
183  }
184  }
185 
186  /* Neither multiplier okay? Try to start at MinHz and increment.
187  This should find the highest multiplier that is still good */
188  Mult = MinHz / freqin;
189  MultEnd = MaxHz / freqin;
190  LastMult = 0;
191  while (1) {
192  freqout = Chip_Clock_TestMainPLLMultiplier(freqin, Mult, MinHz, MaxHz);
193 
194  if (freqout) {
195  LastMult = Mult;
196  }
197 
198  if (Mult >= MultEnd) {
199  break;
200  }
201  Mult++;
202  }
203 
204  if (LastMult) {
205  return Chip_Clock_SetupMainPLLMult(Input, LastMult);
206  }
207 
208  return 0;
209 }
210 
211 /* Directly set the PLL multipler */
213 {
214  uint32_t freq = Chip_Clock_GetClockInputHz(Input);
215  uint32_t msel = 0, nsel = 0, psel = 0, pval = 1;
216  uint32_t PLLReg = LPC_CGU->PLL1_CTRL;
217 
218  freq *= mult;
219  msel = mult - 1;
220 
221  PLLReg &= ~(0x1F << 24);/* clear input source bits */
222  PLLReg |= Input << 24; /* set input source bits to parameter */
223 
224  /* Clear other PLL input bits */
225  PLLReg &= ~((1 << 6) | /* FBSEL */
226  (1 << 1) | /* BYPASS */
227  (1 << 7) | /* DIRECT */
228  (0x03 << 8) | (0xFF << 16) | (0x03 << 12)); /* PSEL, MSEL, NSEL- divider ratios */
229 
230  if (freq < 156000000) {
231  /* psel is encoded such that 0=1, 1=2, 2=4, 3=8 */
232  while ((2 * (pval) * freq) < 156000000) {
233  psel++;
234  pval *= 2;
235  }
236 
237  PLLReg |= (msel << 16) | (nsel << 12) | (psel << 8) | (1 << 6); /* dividers + FBSEL */
238  }
239  else if (freq < 320000000) {
240  PLLReg |= (msel << 16) | (nsel << 12) | (psel << 8) | (1 << 7) | (1 << 6); /* dividers + DIRECT + FBSEL */
241  }
242  else {
244  return 0;
245  }
246  LPC_CGU->PLL1_CTRL = PLLReg & ~(1 << 0);
247 
248  return freq;
249 }
250 
251 /* Returns the frequency of the main PLL */
253 {
254  uint32_t PLLReg = LPC_CGU->PLL1_CTRL;
255  uint32_t freq = Chip_Clock_GetClockInputHz((CHIP_CGU_CLKIN_T) ((PLLReg >> 24) & 0xF));
256  uint32_t msel, nsel, psel, direct, fbsel;
257  uint32_t m, n, p;
258  const uint8_t ptab[] = {1, 2, 4, 8};
259 
260  /* No lock? */
261  if (!(LPC_CGU->PLL1_STAT & 1)) {
262  return 0;
263  }
264 
265  msel = (PLLReg >> 16) & 0xFF;
266  nsel = (PLLReg >> 12) & 0x3;
267  psel = (PLLReg >> 8) & 0x3;
268  direct = (PLLReg >> 7) & 0x1;
269  fbsel = (PLLReg >> 6) & 0x1;
270 
271  m = msel + 1;
272  n = nsel + 1;
273  p = ptab[psel];
274 
275  if (direct || fbsel) {
276  return m * (freq / n);
277  }
278 
279  return (m / (2 * p)) * (freq / n);
280 }
281 
282 /* Disables the main PLL */
284 {
285  /* power down main PLL */
286  LPC_CGU->PLL1_CTRL |= 1;
287 }
288 
289 /* Disables the main PLL */
291 {
292  /* power down main PLL */
293  LPC_CGU->PLL1_CTRL &= ~1;
294 }
295 
296 /* Returns the lock status of the main PLL */
298 {
299  /* Return true if locked */
300  return (bool) (LPC_CGU->PLL1_STAT & 1);
301 }
302 
303 /* Sets up a CGU clock divider and it's input clock */
305 {
306  uint32_t reg = LPC_CGU->IDIV_CTRL[Divider];
307 
308  Divisor--;
309 
310  if (Input != CLKINPUT_PD) {
311  /* Mask off bits that need to changes */
312  reg &= ~((0x1F << 24) | 1 | (0xF << 2));
313 
314  /* Enable autoblocking, clear PD, and set clock source & divisor */
315  LPC_CGU->IDIV_CTRL[Divider] = reg | (1 << 11) | (Input << 24) | (Divisor << 2);
316  }
317  else {
318  LPC_CGU->IDIV_CTRL[Divider] = reg | 1; /* Power down this divider */
319  }
320 }
321 
322 /* Gets a CGU clock divider source */
324 {
325  uint32_t reg = LPC_CGU->IDIV_CTRL[Divider];
326 
327  if (reg & 1) { /* divider is powered down */
328  return CLKINPUT_PD;
329  }
330 
331  return (CHIP_CGU_CLKIN_T) ((reg >> 24) & 0x1F);
332 }
333 
334 /* Gets a CGU clock divider divisor */
336 {
337  return (CHIP_CGU_CLKIN_T) ((LPC_CGU->IDIV_CTRL[Divider] >> 2) & 0xF);
338 }
339 
340 /* Returns the frequency of the specified input clock source */
342 {
343  uint32_t rate = 0;
344 
345  switch (input) {
346  case CLKIN_32K:
347  rate = CRYSTAL_32K_FREQ_IN;
348  break;
349 
350  case CLKIN_IRC:
351  rate = CGU_IRC_FREQ;
352  break;
353 
354  case CLKIN_ENET_RX:
355 #if defined(USE_RMII)
356  /* In RMII mode, this clock is not attached */
357 #else
358  /* MII mode requires 25MHz clock */
359  rate = 25000000;
360 #endif
361  break;
362 
363  case CLKIN_ENET_TX:
364 #if defined(USE_RMII)
365  /* MII mode requires 50MHz clock */
366  rate = 50000000;
367 #else
368  /* MII mode requires 25MHz clock */
369  rate = 25000000;
370 #endif
371  break;
372 
373  case CLKIN_CLKIN:
374 #if defined(EXTERNAL_CLKIN_FREQ_IN)
375  rate = EXTERNAL_CLKIN_FREQ_IN;
376 #else
377  /* Assume no clock in if a rate wasn't defined */
378 #endif
379  break;
380 
381  case CLKIN_CRYSTAL:
382  rate = CRYSTAL_MAIN_FREQ_IN;
383  break;
384 
385  case CLKIN_USBPLL:
386  rate = CGU_USB_PLL_RATE;
387  break;
388 
389  case CLKIN_AUDIOPLL:
390  rate = CGU_AUDIO_PLL_RATE;
391  break;
392 
393  case CLKIN_MAINPLL:
394  rate = Chip_Clock_GetMainPLLHz();
395  break;
396 
397  case CLKIN_IDIVA:
398  rate = Chip_Clock_GetDivRate(input, CLK_IDIV_A);
399  break;
400 
401  case CLKIN_IDIVB:
402  rate = Chip_Clock_GetDivRate(input, CLK_IDIV_B);
403  break;
404 
405  case CLKIN_IDIVC:
406  rate = Chip_Clock_GetDivRate(input, CLK_IDIV_C);
407  break;
408 
409  case CLKIN_IDIVD:
410  rate = Chip_Clock_GetDivRate(input, CLK_IDIV_D);
411  break;
412 
413  case CLKIN_IDIVE:
414  rate = Chip_Clock_GetDivRate(input, CLK_IDIV_E);
415  break;
416 
417  case CLKINPUT_PD:
418  rate = 0;
419  break;
420 
421  default:
422  break;
423  }
424 
425  return rate;
426 }
427 
428 /* Returns the frequency of the specified base clock source */
430 {
432 }
433 
434 /* Sets a CGU Base Clock clock source */
435 void Chip_Clock_SetBaseClock(CHIP_CGU_BASE_CLK_T BaseClock, CHIP_CGU_CLKIN_T Input, bool autoblocken, bool powerdn)
436 {
437  uint32_t reg = LPC_CGU->BASE_CLK[BaseClock];
438 
439  if (BaseClock < CLK_BASE_NONE) {
440  if (Input != CLKINPUT_PD) {
441  /* Mask off fields we plan to update */
442  reg &= ~((0x1F << 24) | 1 | (1 << 11));
443 
444  if (autoblocken) {
445  reg |= (1 << 11);
446  }
447  if (powerdn) {
448  reg |= (1 << 0);
449  }
450 
451  /* Set clock source */
452  reg |= (Input << 24);
453 
454  LPC_CGU->BASE_CLK[BaseClock] = reg;
455  }
456  }
457  else {
458  LPC_CGU->BASE_CLK[BaseClock] = reg | 1; /* Power down this base clock */
459  }
460 }
461 
462 /* Reads CGU Base Clock clock source information */
463 void Chip_Clock_GetBaseClockOpts(CHIP_CGU_BASE_CLK_T BaseClock, CHIP_CGU_CLKIN_T *Input, bool *autoblocken,
464  bool *powerdn)
465 {
466  uint32_t reg = LPC_CGU->BASE_CLK[BaseClock];
467  CHIP_CGU_CLKIN_T ClkIn = (CHIP_CGU_CLKIN_T) ((reg >> 24) & 0x1F );
468 
469  if (BaseClock < CLK_BASE_NONE) {
470  /* Get settings */
471  *Input = ClkIn;
472  *autoblocken = (reg & (1 << 11)) ? true : false;
473  *powerdn = (reg & (1 << 0)) ? true : false;
474  }
475  else {
476  *Input = CLKINPUT_PD;
477  *powerdn = true;
478  *autoblocken = true;
479  }
480 }
481 
482 /*Enables a base clock source */
484 {
485  if (BaseClock < CLK_BASE_NONE) {
486  LPC_CGU->BASE_CLK[BaseClock] &= ~1;
487  }
488 }
489 
490 /* Disables a base clock source */
492 {
493  if (BaseClock < CLK_BASE_NONE) {
494  LPC_CGU->BASE_CLK[BaseClock] |= 1;
495  }
496 }
497 
498 /* Returns base clock enable state */
500 {
501  bool enabled;
502 
503  if (BaseClock < CLK_BASE_NONE) {
504  enabled = (bool) ((LPC_CGU->BASE_CLK[BaseClock] & 1) == 0);
505  }
506  else {
507  enabled = false;
508  }
509 
510  return enabled;
511 }
512 
513 /* Gets a CGU Base Clock clock source */
515 {
516  uint32_t reg;
517 
518  if (BaseClock >= CLK_BASE_NONE) {
519  return CLKINPUT_PD;
520  }
521 
522  reg = LPC_CGU->BASE_CLK[BaseClock];
523 
524  /* base clock is powered down? */
525  if (reg & 1) {
526  return CLKINPUT_PD;
527  }
528 
529  return (CHIP_CGU_CLKIN_T) ((reg >> 24) & 0x1F);
530 }
531 
532 /* Enables a peripheral clock and sets clock states */
533 void Chip_Clock_EnableOpts(CHIP_CCU_CLK_T clk, bool autoen, bool wakeupen, int div)
534 {
535  uint32_t reg = 1;
536 
537  if (autoen) {
538  reg |= (1 << 1);
539  }
540  if (wakeupen) {
541  reg |= (1 << 2);
542  }
543 
544  /* Not all clocks support a divider, but we won't check that here. Only
545  dividers of 1 and 2 are allowed. Assume 1 if not 2 */
546  if (div == 2) {
547  reg |= (1 << 5);
548  }
549 
550  /* Setup peripheral clock and start running */
551  if (clk >= CLK_CCU2_START) {
552  LPC_CCU2->CLKCCU[clk - CLK_CCU2_START].CFG = reg;
553  }
554  else {
555  LPC_CCU1->CLKCCU[clk].CFG = reg;
556  }
557 }
558 
559 /* Enables a peripheral clock */
561 {
562  /* Start peripheral clock running */
563  if (clk >= CLK_CCU2_START) {
564  LPC_CCU2->CLKCCU[clk - CLK_CCU2_START].CFG |= 1;
565  }
566  else {
567  LPC_CCU1->CLKCCU[clk].CFG |= 1;
568  }
569 }
570 
571 /* Disables a peripheral clock */
573 {
574  /* Stop peripheral clock */
575  if (clk >= CLK_CCU2_START) {
576  LPC_CCU2->CLKCCU[clk - CLK_CCU2_START].CFG &= ~1;
577  }
578  else {
579  LPC_CCU1->CLKCCU[clk].CFG &= ~1;
580  }
581 }
582 
589 {
590  /* Set Power Down bit */
591  LPC_CCU1->PM = 1;
592  LPC_CCU2->PM = 1;
593 }
594 
600 {
601  /* Clear Power Down bit */
602  LPC_CCU1->PM = 0;
603  LPC_CCU2->PM = 0;
604 }
605 
606 /* Returns a peripheral clock rate */
608 {
609  CHIP_CGU_BASE_CLK_T baseclk;
610  uint32_t reg, div, rate;
611 
612  /* Get CCU config register for clock */
613  if (clk >= CLK_CCU2_START) {
614  reg = LPC_CCU2->CLKCCU[clk - CLK_CCU2_START].CFG;
615  }
616  else {
617  reg = LPC_CCU1->CLKCCU[clk].CFG;
618  }
619 
620  /* Is the clock enabled? */
621  if (reg & 1) {
622  /* Get base clock for this peripheral clock */
623  baseclk = Chip_Clock_FindBaseClock(clk);
624 
625  /* Get base clock rate */
626  rate = Chip_Clock_GetBaseClocktHz(baseclk);
627 
628  /* Get divider for this clock */
629  if (((reg >> 5) & 0x7) == 0) {
630  div = 1;
631  }
632  else {
633  div = 2;/* No other dividers supported */
634 
635  }
636  rate = rate / div;
637  }
638  else {
639  rate = 0;
640  }
641 
642  return rate;
643 }
644 
645 /* Sets up the audio or USB PLL */
647  const CGU_USBAUDIO_PLL_SETUP_T *pPLLSetup)
648 {
649  uint32_t reg = pPLLSetup->ctrl | (Input << 24);
650  /* Setup from passed values */
651  LPC_CGU->PLL[pllnum].PLL_CTRL = reg;
652  LPC_CGU->PLL[pllnum].PLL_MDIV = pPLLSetup->mdiv;
653  LPC_CGU->PLL[pllnum].PLL_NP_DIV = pPLLSetup->ndiv;
654 
655  /* Fractional divider is for audio PLL only */
656  if (pllnum == pllnum) {
657  LPC_CGU->PLL0AUDIO_FRAC = pPLLSetup->fract;
658  }
659 }
660 
661 /* Enables the audio or USB PLL */
663 {
664  LPC_CGU->PLL[pllnum].PLL_CTRL &= ~1;
665 }
666 
667 /* Disables the audio or USB PLL */
669 {
670  LPC_CGU->PLL[pllnum].PLL_CTRL |= 1;
671 }
672 
673 /* Returns the PLL status */
675 {
676  return LPC_CGU->PLL[pllnum].PLL_STAT;
677 }