LPCOpen Platform
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 "clock_18xx_43xx.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  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 {
105  CGU_BASE_CLK_T baseclk = CLK_BASE_NONE;
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((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 /* Returns the lock status of the main PLL */
291 {
292  /* Return true if locked */
293  return (bool) (LPC_CGU->PLL1_STAT & 1);
294 }
295 
296 /* Sets up a CGU clock divider and it's input clock */
298 {
299  uint32_t reg = LPC_CGU->IDIV_CTRL[Divider];
300 
301  Divisor--;
302 
303  if (Input != CLKINPUT_PD) {
304  /* Mask off bits that need to changes */
305  reg &= ~((0x1F << 24) | 1 | (0xF << 2));
306 
307  /* Enable autoblocking, clear PD, and set clock source & divisor */
308  LPC_CGU->IDIV_CTRL[Divider] = reg | (1 << 11) | (Input << 24) | (Divisor << 2);
309  }
310  else {
311  LPC_CGU->IDIV_CTRL[Divider] = reg | 1; /* Power down this divider */
312  }
313 }
314 
315 /* Gets a CGU clock divider source */
317 {
318  uint32_t reg = LPC_CGU->IDIV_CTRL[Divider];
319 
320  if (reg & 1) { /* divider is powered down */
321  return CLKINPUT_PD;
322  }
323 
324  return (CGU_CLKIN_T) ((reg >> 24) & 0x1F);
325 }
326 
327 /* Gets a CGU clock divider divisor */
329 {
330  return (CGU_CLKIN_T) ((LPC_CGU->IDIV_CTRL[Divider] >> 2) & 0xF);
331 }
332 
333 /* Returns the frequency of the specified input clock source */
335 {
336  uint32_t rate = 0;
337 
338  switch (input) {
339  case CLKIN_32K:
340  rate = CRYSTAL_32K_FREQ_IN;
341  break;
342 
343  case CLKIN_IRC:
344  rate = CGU_IRC_FREQ;
345  break;
346 
347  case CLKIN_ENET_RX:
348 #if defined(USE_RMII)
349  /* In RMII mode, this clock is not attached */
350 #else
351  /* MII mode requires 25MHz clock */
352  rate = 25000000;
353 #endif
354  break;
355 
356  case CLKIN_ENET_TX:
357 #if defined(USE_RMII)
358  /* MII mode requires 50MHz clock */
359  rate = 50000000;
360 #else
361  /* MII mode requires 25MHz clock */
362  rate = 25000000;
363 #endif
364  break;
365 
366  case CLKIN_CLKIN:
367 #if defined(EXTERNAL_CLKIN_FREQ_IN)
368  rate = EXTERNAL_CLKIN_FREQ_IN;
369 #else
370  /* Assume no clock in if a rate wasn't defined */
371 #endif
372  break;
373 
374  case CLKIN_CRYSTAL:
375  rate = CRYSTAL_MAIN_FREQ_IN;
376  break;
377 
378  case CLKIN_USBPLL:
379  rate = 0; // FIXME
380  break;
381 
382  case CLKIN_AUDIOPLL:
383  rate = 0; // FIXME
384  break;
385 
386  case CLKIN_MAINPLL:
387  rate = Chip_Clock_GetMainPLLHz();
388  break;
389 
390  case CLKIN_IDIVA:
391  rate = Chip_Clock_GetDivRate(input, CLK_IDIV_A);
392  break;
393 
394  case CLKIN_IDIVB:
395  rate = Chip_Clock_GetDivRate(input, CLK_IDIV_B);
396  break;
397 
398  case CLKIN_IDIVC:
399  rate = Chip_Clock_GetDivRate(input, CLK_IDIV_C);
400  break;
401 
402  case CLKIN_IDIVD:
403  rate = Chip_Clock_GetDivRate(input, CLK_IDIV_D);
404  break;
405 
406  case CLKIN_IDIVE:
407  rate = Chip_Clock_GetDivRate(input, CLK_IDIV_E);
408  break;
409 
410  case CLKINPUT_PD:
411  rate = 0;
412  break;
413 
414  default:
415  break;
416  }
417 
418  return rate;
419 }
420 
421 /* Returns the frequency of the specified base clock source */
423 {
425 }
426 
427 /* Sets a CGU Base Clock clock source */
428 void Chip_Clock_SetBaseClock(CGU_BASE_CLK_T BaseClock, CGU_CLKIN_T Input, bool autoblocken, bool powerdn)
429 {
430  uint32_t reg = LPC_CGU->BASE_CLK[BaseClock];
431 
432  if (BaseClock < CLK_BASE_NONE) {
433  if (Input != CLKINPUT_PD) {
434  /* Mask off fields we plan to update */
435  reg &= ~((0x1F << 24) | 1 | (1 << 11));
436 
437  if (autoblocken) {
438  reg |= (1 << 11);
439  }
440  if (powerdn) {
441  reg |= (1 << 0);
442  }
443 
444  /* Set clock source */
445  reg |= (Input << 24);
446 
447  LPC_CGU->BASE_CLK[BaseClock] = reg;
448  }
449  }
450  else {
451  LPC_CGU->BASE_CLK[BaseClock] = reg | 1; /* Power down this base clock */
452  }
453 }
454 
455 /*Enables a base clock source */
457 {
458  if (BaseClock < CLK_BASE_NONE) {
459  LPC_CGU->BASE_CLK[BaseClock] &= ~1;
460  }
461 }
462 
463 /* Disables a base clock source */
465 {
466  if (BaseClock < CLK_BASE_NONE) {
467  LPC_CGU->BASE_CLK[BaseClock] |= 1;
468  }
469 }
470 
471 /* Gets a CGU Base Clock clock source */
473 {
474  uint32_t reg = LPC_CGU->BASE_CLK[BaseClock];
475 
476  if (BaseClock >= CLK_BASE_NONE) {
477  return CLKINPUT_PD;
478  }
479 
480  /* base clock is powered down? */
481  if (reg & 1) {
482  return CLKINPUT_PD;
483  }
484 
485  return (CGU_CLKIN_T) ((reg >> 24) & 0x1F);
486 }
487 
488 /* Enables a peripheral clock and sets clock states */
489 void Chip_Clock_EnableOpts(CCU_CLK_T clk, bool autoen, bool wakeupen, int div)
490 {
491  uint32_t reg = 1;
492 
493  if (autoen) {
494  reg |= (1 << 1);
495  }
496  if (wakeupen) {
497  reg |= (1 << 2);
498  }
499 
500  /* Not all clocks support a divider, but we won't check that here. Only
501  dividers of 1 and 2 are allowed. Assume 1 if not 2 */
502  if (div == 2) {
503  reg |= (1 << 5);
504  }
505 
506  /* Setup peripheral clock and start running */
507  if (clk >= CLK_CCU2_START) {
508  LPC_CCU2->CLKCCU[clk - CLK_CCU2_START].CFG = reg;
509  }
510  else {
511  LPC_CCU1->CLKCCU[clk].CFG = reg;
512  }
513 }
514 
515 /* Enables a peripheral clock */
517 {
518  /* Start peripheral clock running */
519  if (clk >= CLK_CCU2_START) {
520  LPC_CCU2->CLKCCU[clk - CLK_CCU2_START].CFG |= 1;
521  }
522  else {
523  LPC_CCU1->CLKCCU[clk].CFG |= 1;
524  }
525 }
526 
527 /* Disables a peripheral clock */
529 {
530  /* Stop peripheral clock */
531  if (clk >= CLK_CCU2_START) {
532  LPC_CCU2->CLKCCU[clk - CLK_CCU2_START].CFG &= ~1;
533  }
534  else {
535  LPC_CCU1->CLKCCU[clk].CFG &= ~1;
536  }
537 }
538 
539 /* Returns a peripheral clock rate */
541 {
542  CGU_BASE_CLK_T baseclk;
543  uint32_t reg, div, rate;
544 
545  /* Get CCU config register for clock */
546  if (clk >= CLK_CCU2_START) {
547  reg = LPC_CCU2->CLKCCU[clk - CLK_CCU2_START].CFG;
548  }
549  else {
550  reg = LPC_CCU1->CLKCCU[clk].CFG;
551  }
552 
553  /* Is the clock enabled? */
554  if (reg & 1) {
555  /* Get base clock for this peripheral clock */
556  baseclk = Chip_Clock_FindBseClock(clk);
557 
558  /* Get base clock rate */
559  rate = Chip_Clock_GetBaseClocktHz(baseclk);
560 
561  /* Get divider for this clock */
562  if (((reg >> 5) & 0x7) == 0) {
563  div = 1;
564  }
565  else {
566  div = 2;/* No other dividers supported */
567 
568  }
569  rate = rate / div;
570  }
571  else {
572  rate = 0;
573  }
574 
575  return rate;
576 }