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