Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.
Upstream: https://github.com/ARMmbed/DAPLink
Diff: source/hic_hal/nxp/lpc4322/lpc43xx_cgu.c
- Revision:
- 0:01f31e923fe2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/hic_hal/nxp/lpc4322/lpc43xx_cgu.c Tue Apr 07 12:55:42 2020 +0200 @@ -0,0 +1,1132 @@ +/** + * @file lpc43xx_cgu.c + * @brief + * + * DAPLink Interface Firmware + * Copyright (c) 2009-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lpc_types.h" +#include "lpc43xx_scu.h" +#include "lpc43xx_cgu.h" + +/** This define used to fix mistake when run with IAR compiler */ +#ifdef __ICCARM__ +#define CGU_BRANCH_STATUS_ENABLE_MASK 0x80000001 +#else +#define CGU_BRANCH_STATUS_ENABLE_MASK 0x01 +#endif + +/*TODO List: + * SET PLL0 + * UPDATE Clock from PLL0 + * SetDIV uncheck value + * GetBaseStatus BASE_SAFE + * */ +/* Local definition */ +#define CGU_ADDRESS32(x,y) (*(uint32_t*)((uint32_t)x+y)) + +/* Local Variable */ +const int16_t CGU_Entity_ControlReg_Offset[CGU_ENTITY_NUM] = { + -1, //CGU_CLKSRC_32KHZ_OSC, + -1, //CGU_CLKSRC_IRC, + -1, //CGU_CLKSRC_ENET_RX_CLK, + -1, //CGU_CLKSRC_ENET_TX_CLK, + -1, //CGU_CLKSRC_GP_CLKIN, + -1, //CGU_CLKSRC_TCK, + 0x18, //CGU_CLKSRC_XTAL_OSC, + 0x20, //CGU_CLKSRC_PLL0, + 0x30, //CGU_CLKSRC_PLL0_AUDIO **REV A** + 0x44, //CGU_CLKSRC_PLL1, + -1, //CGU_CLKSRC_RESERVE, + -1, //CGU_CLKSRC_RESERVE, + 0x48, //CGU_CLKSRC_IDIVA,, + 0x4C, //CGU_CLKSRC_IDIVB, + 0x50, //CGU_CLKSRC_IDIVC, + 0x54, //CGU_CLKSRC_IDIVD, + 0x58, //CGU_CLKSRC_IDIVE, + + 0x5C, //CGU_BASE_SAFE, + 0x60, //CGU_BASE_USB0, + 0x64, //CGU_BASE_PERIPH, // used for SPGPIO, peripheral control + 0x68, //CGU_BASE_USB1, + 0x6C, //CGU_BASE_M4, + 0x70, //CGU_BASE_SPIFI, + -1, //CGU_BASE_RESERVE, + 0x78, //CGU_BASE_PHY_RX, + 0x7C, //CGU_BASE_PHY_TX, + 0x80, //CGU_BASE_APB1, + 0x84, //CGU_BASE_APB3, + 0x88, //CGU_BASE_LCD, + 0X8C, //CGU_BASE_ENET_CSR, **REV A** + 0x90, //CGU_BASE_SDIO, + 0x94, //CGU_BASE_SSP0, + 0x98, //CGU_BASE_SSP1, + 0x9C, //CGU_BASE_UART0, + 0xA0, //CGU_BASE_UART1, + 0xA4, //CGU_BASE_UART2, + 0xA8, //CGU_BASE_UART3, + 0xAC, //CGU_BASE_CLKOUT + -1, + -1, + -1, + -1, + 0xC0, //CGU_BASE_APLL + 0xC4, //CGU_BASE_OUT0 + 0xC8 //CGU_BASE_OUT1 +}; + +const uint8_t CGU_ConnectAlloc_Tbl[CGU_CLKSRC_NUM][CGU_ENTITY_NUM] = { +// 3 I E E G T X P P P x x D D D D D S U P U M S x P P A A L E S S S U U U U C x x x x A O O +// 2 R R T P C T L L L I I I I I A S E S 3 P H H P P C N D S S R R R R O P U U +// C X X I K A 0 A 1 A B C D E F B R B F RxTx1 3 D T I 0 1 0 1 2 3 L T T + {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1}, /*CGU_CLKSRC_32KHZ_OSC = 0,*/ + {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1}, /*CGU_CLKSRC_IRC,*/ + {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1}, /*CGU_CLKSRC_ENET_RX_CLK,*/ + {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1}, /*CGU_CLKSRC_ENET_TX_CLK,*/ + {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1}, /*CGU_CLKSRC_GP_CLKIN,*/ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0}, /*CGU_CLKSRC_TCK,*/ + {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1}, /*CGU_CLKSRC_XTAL_OSC,*/ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1}, /*CGU_CLKSRC_PLL0,*/ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1}, /*CGU_CLKSRC_PLL0_AUDIO,*/ + {0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1}, /*CGU_CLKSRC_PLL1,*/ + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1}, /*CGU_CLKSRC_IDIVA = CGU_CLKSRC_PLL1 + 3,*/ + {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1}, /*CGU_CLKSRC_IDIVB,*/ + {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1}, /*CGU_CLKSRC_IDIVC,*/ + {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1}, /*CGU_CLKSRC_IDIVD,*/ + {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1} /*CGU_CLKSRC_IDIVE,*/ +}; + +const CGU_PERIPHERAL_S CGU_PERIPHERAL_Info[CGU_PERIPHERAL_NUM] = { + /* Register Clock | Peripheral Clock + | BASE | BRANCH | BASE | BRANCH */ + {CGU_BASE_APB3, 0x1118, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_ADC0, + {CGU_BASE_APB3, 0x1120, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_ADC1, + {CGU_BASE_M4, 0x1460, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_AES, + //// CGU_PERIPHERAL_ALARMTIMER_CGU_RGU_RTC_WIC, + {CGU_BASE_APB1, 0x1200, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_APB1_BUS, + {CGU_BASE_APB3, 0x1100, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_APB3_BUS, + {CGU_BASE_APB3, 0x1128, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_CAN0, + {CGU_BASE_M4, 0x1538, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_CREG, + {CGU_BASE_APB3, 0x1110, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_DAC, + {CGU_BASE_M4, 0x1440, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_DMA, + {CGU_BASE_M4, 0x1430, CGU_BASE_M4, 0x1478, 0},//CGU_PERIPHERAL_EMC, + {CGU_BASE_M4, 0x1420, CGU_BASE_PHY_RX, 0x0000, CGU_PERIPHERAL_ETHERNET_TX},//CGU_PERIPHERAL_ETHERNET, + {CGU_ENTITY_NONE, 0x0000, CGU_BASE_PHY_TX, 0x0000, 0}, //CGU_PERIPHERAL_ETHERNET_TX + {CGU_BASE_M4, 0x1410, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_GPIO, + {CGU_BASE_APB1, 0x1210, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_I2C0, + {CGU_BASE_APB3, 0x1108, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_I2C1, + {CGU_BASE_APB1, 0x1218, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_I2S, + {CGU_BASE_M4, 0x1418, CGU_BASE_LCD, 0x0000, 0},//CGU_PERIPHERAL_LCD, + {CGU_BASE_M4, 0x1448, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_M3CORE, + {CGU_BASE_M4, 0x1400, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_M3_BUS, + {CGU_BASE_APB1, 0x1208, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_MOTOCON, + {CGU_BASE_M4, 0x1630, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_QEI, + {CGU_BASE_M4, 0x1600, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_RITIMER, + {CGU_BASE_M4, 0x1468, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_SCT, + {CGU_BASE_M4, 0x1530, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_SCU, + {CGU_BASE_M4, 0x1438, CGU_BASE_SDIO, 0x2800, 0},//CGU_PERIPHERAL_SDIO, + {CGU_BASE_M4, 0x1408, CGU_BASE_SPIFI, 0x1300, 0},//CGU_PERIPHERAL_SPIFI, + {CGU_BASE_M4, 0x1518, CGU_BASE_SSP0, 0x2700, 0},//CGU_PERIPHERAL_SSP0, + {CGU_BASE_M4, 0x1628, CGU_BASE_SSP1, 0x2600, 0},//CGU_PERIPHERAL_SSP1, + {CGU_BASE_M4, 0x1520, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_TIMER0, + {CGU_BASE_M4, 0x1528, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_TIMER1, + {CGU_BASE_M4, 0x1618, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_TIMER2, + {CGU_BASE_M4, 0x1620, CGU_ENTITY_NONE, 0x0000, 0},//CGU_PERIPHERAL_TIMER3, + {CGU_BASE_M4, 0x1508, CGU_BASE_UART0, 0x2500, 0},//CGU_PERIPHERAL_UART0, + {CGU_BASE_M4, 0x1510, CGU_BASE_UART1, 0x2400, 0},//CGU_PERIPHERAL_UART1, + {CGU_BASE_M4, 0x1608, CGU_BASE_UART2, 0x2300, 0},//CGU_PERIPHERAL_UART2, + {CGU_BASE_M4, 0x1610, CGU_BASE_UART3, 0x2200, 0},//CGU_PERIPHERAL_UART3, + {CGU_BASE_M4, 0x1428, CGU_BASE_USB0, 0x1800, 0},//CGU_PERIPHERAL_USB0, + {CGU_BASE_M4, 0x1470, CGU_BASE_USB1, 0x1900, 0},//CGU_PERIPHERAL_USB1, + {CGU_BASE_M4, 0x1500, CGU_BASE_SAFE, 0x0000, 0},//CGU_PERIPHERAL_WWDT, +}; + +uint32_t CGU_ClockSourceFrequency[CGU_CLKSRC_NUM] = {0, 12000000, 0, 0, 0, 0, 0, 480000000, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +#define CGU_CGU_ADDR ((uint32_t)LPC_CGU) +#define CGU_REG_BASE_CTRL(x) (*(uint32_t*)(CGU_CGU_ADDR+CGU_Entity_ControlReg_Offset[CGU_PERIPHERAL_Info[x].RegBaseEntity])) +#define CGU_REG_BRANCH_CTRL(x) (*(uint32_t*)(CGU_CGU_ADDR+CGU_PERIPHERAL_Info[x].RegBranchOffset)) +#define CGU_REG_BRANCH_STATUS(x) (*(volatile uint32_t*)(CGU_CGU_ADDR+CGU_PERIPHERAL_Info[x].RegBranchOffset+4)) + +#define CGU_PER_BASE_CTRL(x) (*(uint32_t*)(CGU_CGU_ADDR+CGU_Entity_ControlReg_Offset[CGU_PERIPHERAL_Info[x].PerBaseEntity])) +#define CGU_PER_BRANCH_CTRL(x) (*(uint32_t*)(CGU_CGU_ADDR+CGU_PERIPHERAL_Info[x].PerBranchOffset)) +#define CGU_PER_BRANCH_STATUS(x) (*(volatile uint32_t*)(CGU_CGU_ADDR+CGU_PERIPHERAL_Info[x].PerBranchOffset+4)) + +/**************************************************************************//** + * + * @brief Rough approximation of a delay function with microsecond resolution. + * + * Used during initial clock setup as the Timers are not configured yet. + * + * @param [in] us The number of microseconds to wait + * + *****************************************************************************/ +static void cgu_WaitUS(volatile uint32_t us) +{ + us *= (SystemCoreClock / 1000000) / 3; + + while (us--); +} + +/**************************************************************************//** + * + * @brief Simple lookup of best MSEL and NSEL values for wanted frequency + * + * Not optimized. + * + * @param [in] wantedFreq The wanted PLL1 frequency + * @param [out] pMsel The best MSEL value for the PLL1_CTRL register + * @param [out] pNsel The best NSEL value for the PLL1_CTRL register + * + *****************************************************************************/ +static void cgu_findMN(uint32_t wantedFreq, uint32_t *pMsel, uint32_t *pNsel) +{ + uint32_t besterr = wantedFreq; + uint32_t m, n, f, tmp, err; +#define ABSDIFF(__a, __b) ( ((__a) < (__b)) ? ((__b) - (__a)) : ((__a) - (__b)) ) + + for (n = 1; n <= 4; n++) { + f = 12000000 / n; + tmp = 0; + + for (m = 1; m <= 256; m++) { + tmp += f; + err = ABSDIFF(tmp, wantedFreq); + + if (err == 0) { + // found perfect match + *pMsel = m - 1; + *pNsel = n - 1; + return; + + } else if (err < besterr) { + *pMsel = m - 1; + *pNsel = n - 1; + besterr = err; + } + + if (tmp > wantedFreq) { + // no point in continuing to increase tmp as value is too high already + break; + } + } + } +} + +/*********************************************************************//** + * @brief Initialize default clock for LPC4300 Eval board + * @param[in] None + * @return Initialize status, could be: + * - CGU_ERROR_SUCCESS: successful + * - Other: error + **********************************************************************/ +uint32_t CGU_Init(uint32_t wantedFreq) +{ + uint32_t msel = 0; + uint32_t nsel = 0; + uint32_t tmp; + // Setup PLL1 to 204MHz + // 0. Select IRC as BASE_M4_CLK source + CGU_EntityConnect(CGU_CLKSRC_IRC, CGU_BASE_M4); + SystemCoreClock = 96000000; + // 1. Enable the crystal oscillator + CGU_SetXTALOSC(12000000); + CGU_EnableEntity(CGU_CLKSRC_XTAL_OSC, ENABLE); + // 2. Wait 250us + cgu_WaitUS(250); + // 3. Reconfigure PLL1 as follows: + // - Select the M and N divider values to produce the final desired + // PLL1 output frequency (204MHz => M=17,N=1 => msel=16,nsel=0) + // - Select the crystal oscillator as clock source for PLL1 + cgu_findMN(wantedFreq, &msel, &nsel); + tmp = LPC_CGU->PLL1_CTRL & ~((0xFF << 16) | (0x03 << 12)); + LPC_CGU->PLL1_CTRL = tmp | (msel << 16) | (nsel << 12); + CGU_EntityConnect(CGU_CLKSRC_XTAL_OSC, CGU_CLKSRC_PLL1); + + // 4. Wait for the PLL1 to lock + while ((LPC_CGU->PLL1_STAT & 1) == 0x0); + + // 5. Set PLL1 P-divider to divide by 2 (DIRECT=0 and PSEL=0) + LPC_CGU->PLL1_CTRL &= ~((0x03 << 8) | CGU_PLL1_DIRECT_MASK); + // 6. Select PLL1 as BASE_M4_CLK source. The BASE_M4_CLK now operates at + // the mid frequency range + CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_BASE_M4); + SystemCoreClock = (12000000 * (msel + 1)) / ((nsel + 1) * 2); + // 7. Wait 20us + cgu_WaitUS(20); + // 8. Set PLL P-divider to direct output mode (DIRECT=1) + LPC_CGU->PLL1_CTRL |= CGU_PLL1_DIRECT_MASK; + // The BASE_M4_CLK now operates in the high frequency range + CGU_UpdateClock(); + SystemCoreClock = (12000000 * (msel + 1)) / (nsel + 1); + return 0; +} + +/*********************************************************************//** + * @brief Configure power for individual peripheral + * @param[in] PPType peripheral type, should be: + * - CGU_PERIPHERAL_ADC0 :ADC0 + * - CGU_PERIPHERAL_ADC1 :ADC1 + * - CGU_PERIPHERAL_AES :AES + * - CGU_PERIPHERAL_APB1_BUS :APB1 bus + * - CGU_PERIPHERAL_APB3_BUS :APB3 bus + * - CGU_PERIPHERAL_CAN :CAN + * - CGU_PERIPHERAL_CREG :CREG + * - CGU_PERIPHERAL_DAC :DAC + * - CGU_PERIPHERAL_DMA :DMA + * - CGU_PERIPHERAL_EMC :EMC + * - CGU_PERIPHERAL_ETHERNET :ETHERNET + * - CGU_PERIPHERAL_GPIO :GPIO + * - CGU_PERIPHERAL_I2C0 :I2C0 + * - CGU_PERIPHERAL_I2C1 :I2C1 + * - CGU_PERIPHERAL_I2S :I2S + * - CGU_PERIPHERAL_LCD :LCD + * - CGU_PERIPHERAL_M3CORE :M3 core + * - CGU_PERIPHERAL_M3_BUS :M3 bus + * - CGU_PERIPHERAL_MOTOCON :Motor control + * - CGU_PERIPHERAL_QEI :QEI + * - CGU_PERIPHERAL_RITIMER :RIT timer + * - CGU_PERIPHERAL_SCT :SCT + * - CGU_PERIPHERAL_SCU :SCU + * - CGU_PERIPHERAL_SDIO :SDIO + * - CGU_PERIPHERAL_SPIFI :SPIFI + * - CGU_PERIPHERAL_SSP0 :SSP0 + * - CGU_PERIPHERAL_SSP1 :SSP1 + * - CGU_PERIPHERAL_TIMER0 :TIMER0 + * - CGU_PERIPHERAL_TIMER1 :TIMER1 + * - CGU_PERIPHERAL_TIMER2 :TIMER2 + * - CGU_PERIPHERAL_TIMER3 :TIMER3 + * - CGU_PERIPHERAL_UART0 :UART0 + * - CGU_PERIPHERAL_UART1 :UART1 + * - CGU_PERIPHERAL_UART2 :UART2 + * - CGU_PERIPHERAL_UART3 :UART3 + * - CGU_PERIPHERAL_USB0 :USB0 + * - CGU_PERIPHERAL_USB1 :USB1 + * - CGU_PERIPHERAL_WWDT :WWDT + * @param[in] en status, should be: + * - ENABLE: Enable power + * - DISABLE: Disable power + * @return Configure status, could be: + * - CGU_ERROR_SUCCESS: successful + * - Other: error + **********************************************************************/ +uint32_t CGU_ConfigPWR(CGU_PERIPHERAL_T PPType, FunctionalState en) +{ + if (PPType >= CGU_PERIPHERAL_WWDT && PPType <= CGU_PERIPHERAL_ADC0) { + return CGU_ERROR_INVALID_PARAM; + } + + if (en == DISABLE) { /* Going to disable clock */ + /*Get Reg branch status */ + if (CGU_PERIPHERAL_Info[PPType].RegBranchOffset != 0 && + CGU_REG_BRANCH_STATUS(PPType) & 1) { + CGU_REG_BRANCH_CTRL(PPType) &= ~1; /* Disable branch clock */ + + while (CGU_REG_BRANCH_STATUS(PPType) & 1); + } + + /* GetBase Status*/ + if ((CGU_PERIPHERAL_Info[PPType].RegBaseEntity != CGU_ENTITY_NONE) && + CGU_GetBaseStatus((CGU_ENTITY_T)CGU_PERIPHERAL_Info[PPType].RegBaseEntity) == 0) { + /* Disable Base */ + CGU_EnableEntity((CGU_ENTITY_T)CGU_PERIPHERAL_Info[PPType].RegBaseEntity, 0); + } + + /* Same for Peripheral */ + if ((CGU_PERIPHERAL_Info[PPType].PerBranchOffset != 0) && (CGU_PER_BRANCH_STATUS(PPType) & CGU_BRANCH_STATUS_ENABLE_MASK)) { + CGU_PER_BRANCH_CTRL(PPType) &= ~1; /* Disable branch clock */ + + while (CGU_PER_BRANCH_STATUS(PPType) & CGU_BRANCH_STATUS_ENABLE_MASK); + } + + /* GetBase Status*/ + if ((CGU_PERIPHERAL_Info[PPType].PerBaseEntity != CGU_ENTITY_NONE) && + CGU_GetBaseStatus((CGU_ENTITY_T)CGU_PERIPHERAL_Info[PPType].PerBaseEntity) == 0) { + /* Disable Base */ + CGU_EnableEntity((CGU_ENTITY_T)CGU_PERIPHERAL_Info[PPType].PerBaseEntity, 0); + } + + } else { + /* enable */ + /* GetBase Status*/ + if ((CGU_PERIPHERAL_Info[PPType].RegBaseEntity != CGU_ENTITY_NONE) && CGU_REG_BASE_CTRL(PPType) & CGU_BRANCH_STATUS_ENABLE_MASK) { + /* Enable Base */ + CGU_EnableEntity((CGU_ENTITY_T)CGU_PERIPHERAL_Info[PPType].RegBaseEntity, 1); + } + + /*Get Reg branch status */ + if ((CGU_PERIPHERAL_Info[PPType].RegBranchOffset != 0) && !(CGU_REG_BRANCH_STATUS(PPType) & CGU_BRANCH_STATUS_ENABLE_MASK)) { + CGU_REG_BRANCH_CTRL(PPType) |= 1; /* Enable branch clock */ + + while (!(CGU_REG_BRANCH_STATUS(PPType) & CGU_BRANCH_STATUS_ENABLE_MASK)); + } + + /* Same for Peripheral */ + /* GetBase Status*/ + if ((CGU_PERIPHERAL_Info[PPType].PerBaseEntity != CGU_ENTITY_NONE) && + (CGU_PER_BASE_CTRL(PPType) & 1)) { + /* Enable Base */ + CGU_EnableEntity((CGU_ENTITY_T)CGU_PERIPHERAL_Info[PPType].PerBaseEntity, 1); + } + + /*Get Reg branch status */ + if ((CGU_PERIPHERAL_Info[PPType].PerBranchOffset != 0) && !(CGU_PER_BRANCH_STATUS(PPType) & CGU_BRANCH_STATUS_ENABLE_MASK)) { + CGU_PER_BRANCH_CTRL(PPType) |= 1; /* Enable branch clock */ + + while (!(CGU_PER_BRANCH_STATUS(PPType) & CGU_BRANCH_STATUS_ENABLE_MASK)); + } + } + + if (CGU_PERIPHERAL_Info[PPType].next) { + return CGU_ConfigPWR((CGU_PERIPHERAL_T)CGU_PERIPHERAL_Info[PPType].next, en); + } + + return CGU_ERROR_SUCCESS; +} + + +/*********************************************************************//** + * @brief Get peripheral clock frequency + * @param[in] Clock Peripheral type, should be: + * - CGU_PERIPHERAL_ADC0 :ADC0 + * - CGU_PERIPHERAL_ADC1 :ADC1 + * - CGU_PERIPHERAL_AES :AES + * - CGU_PERIPHERAL_APB1_BUS :APB1 bus + * - CGU_PERIPHERAL_APB3_BUS :APB3 bus + * - CGU_PERIPHERAL_CAN :CAN + * - CGU_PERIPHERAL_CREG :CREG + * - CGU_PERIPHERAL_DAC :DAC + * - CGU_PERIPHERAL_DMA :DMA + * - CGU_PERIPHERAL_EMC :EMC + * - CGU_PERIPHERAL_ETHERNET :ETHERNET + * - CGU_PERIPHERAL_GPIO :GPIO + * - CGU_PERIPHERAL_I2C0 :I2C0 + * - CGU_PERIPHERAL_I2C1 :I2C1 + * - CGU_PERIPHERAL_I2S :I2S + * - CGU_PERIPHERAL_LCD :LCD + * - CGU_PERIPHERAL_M3CORE :M3 core + * - CGU_PERIPHERAL_M3_BUS :M3 bus + * - CGU_PERIPHERAL_MOTOCON :Motor control + * - CGU_PERIPHERAL_QEI :QEI + * - CGU_PERIPHERAL_RITIMER :RIT timer + * - CGU_PERIPHERAL_SCT :SCT + * - CGU_PERIPHERAL_SCU :SCU + * - CGU_PERIPHERAL_SDIO :SDIO + * - CGU_PERIPHERAL_SPIFI :SPIFI + * - CGU_PERIPHERAL_SSP0 :SSP0 + * - CGU_PERIPHERAL_SSP1 :SSP1 + * - CGU_PERIPHERAL_TIMER0 :TIMER0 + * - CGU_PERIPHERAL_TIMER1 :TIMER1 + * - CGU_PERIPHERAL_TIMER2 :TIMER2 + * - CGU_PERIPHERAL_TIMER3 :TIMER3 + * - CGU_PERIPHERAL_UART0 :UART0 + * - CGU_PERIPHERAL_UART1 :UART1 + * - CGU_PERIPHERAL_UART2 :UART2 + * - CGU_PERIPHERAL_UART3 :UART3 + * - CGU_PERIPHERAL_USB0 :USB0 + * - CGU_PERIPHERAL_USB1 :USB1 + * - CGU_PERIPHERAL_WWDT :WWDT + * @return Return frequently value + **********************************************************************/ +uint32_t CGU_GetPCLKFrequency(CGU_PERIPHERAL_T Clock) +{ + uint32_t ClkSrc; + + if (Clock >= CGU_PERIPHERAL_WWDT && Clock <= CGU_PERIPHERAL_ADC0) { + return CGU_ERROR_INVALID_PARAM; + } + + if (CGU_PERIPHERAL_Info[Clock].PerBaseEntity != CGU_ENTITY_NONE) { + /* Get Base Clock Source */ + ClkSrc = (CGU_PER_BASE_CTRL(Clock) & CGU_CTRL_SRC_MASK) >> 24; + + /* GetBase Status*/ + if (CGU_PER_BASE_CTRL(Clock) & 1) { + return 0; + } + + /* check Branch if it is enabled */ + if ((CGU_PERIPHERAL_Info[Clock].PerBranchOffset != 0) && !(CGU_PER_BRANCH_STATUS(Clock) & CGU_BRANCH_STATUS_ENABLE_MASK)) { + return 0; + } + + } else { + if (CGU_REG_BASE_CTRL(Clock) & 1) { + return 0; + } + + ClkSrc = (CGU_REG_BASE_CTRL(Clock) & CGU_CTRL_SRC_MASK) >> 24; + + /* check Branch if it is enabled */ + if ((CGU_PERIPHERAL_Info[Clock].RegBranchOffset != 0) && !(CGU_REG_BRANCH_STATUS(Clock) & CGU_BRANCH_STATUS_ENABLE_MASK)) { + return 0; + } + } + + return CGU_ClockSourceFrequency[ClkSrc]; +} + + +/*********************************************************************//** + * @brief Update clock + * @param[in] None + * @return None + **********************************************************************/ +void CGU_UpdateClock(void) +{ + uint32_t ClkSrc; + uint32_t div; + uint32_t divisor; + int32_t RegOffset; + + /* 32OSC */ + if (ISBITSET(LPC_CREG->CREG0, 1) && ISBITCLR(LPC_CREG->CREG0, 3)) { + CGU_ClockSourceFrequency[CGU_CLKSRC_32KHZ_OSC] = 32768; + + } else { + CGU_ClockSourceFrequency[CGU_CLKSRC_32KHZ_OSC] = 0; + } + + /*PLL0*/ + /* PLL1 */ + if (ISBITCLR(LPC_CGU->PLL1_CTRL, 0) /* Enabled */ /* EA ANDLI: Original code tested bit 1 which is BYPASS, not PD */ + && (LPC_CGU->PLL1_STAT & 1)) { /* Locked? */ + ClkSrc = (LPC_CGU->PLL1_CTRL & CGU_CTRL_SRC_MASK) >> 24; + CGU_ClockSourceFrequency[CGU_CLKSRC_PLL1] = CGU_ClockSourceFrequency[ClkSrc] * + (((LPC_CGU->PLL1_CTRL >> 16) & 0xFF) + 1); + + } else { + CGU_ClockSourceFrequency[CGU_CLKSRC_PLL1] = 0; + } + + /* DIV */ + for (div = CGU_CLKSRC_IDIVA; div <= CGU_CLKSRC_IDIVE; div++) { + RegOffset = CGU_Entity_ControlReg_Offset[div]; + + if (ISBITCLR(CGU_ADDRESS32(LPC_CGU, RegOffset), 1)) { + ClkSrc = (CGU_ADDRESS32(LPC_CGU, RegOffset) & CGU_CTRL_SRC_MASK) >> 24; + divisor = (CGU_ADDRESS32(LPC_CGU, RegOffset) >> 2) & 0xFF; + divisor ++; + CGU_ClockSourceFrequency[div] = CGU_ClockSourceFrequency[ClkSrc] / divisor; + + } else { + CGU_ClockSourceFrequency[div] = 0; + } + } +} + +/*********************************************************************//** + * @brief Set XTAL oscillator value + * @param[in] ClockFrequency XTAL Frequency value + * @return Setting status, could be: + * - CGU_ERROR_SUCCESS: successful + * - CGU_ERROR_FREQ_OUTOF_RANGE: XTAL value set is out of range + **********************************************************************/ +uint32_t CGU_SetXTALOSC(uint32_t ClockFrequency) +{ + if (ClockFrequency < 15000000) { + LPC_CGU->XTAL_OSC_CTRL &= ~(1 << 2); + + } else if (ClockFrequency < 25000000) { + LPC_CGU->XTAL_OSC_CTRL |= (1 << 2); + + } else { + return CGU_ERROR_FREQ_OUTOF_RANGE; + } + + CGU_ClockSourceFrequency[CGU_CLKSRC_XTAL_OSC] = ClockFrequency; + return CGU_ERROR_SUCCESS; +} + + +/*********************************************************************//** + * @brief Set clock divider + * @param[in] SelectDivider Clock source, should be: + * - CGU_CLKSRC_IDIVA :Integer divider register A + * - CGU_CLKSRC_IDIVB :Integer divider register B + * - CGU_CLKSRC_IDIVC :Integer divider register C + * - CGU_CLKSRC_IDIVD :Integer divider register D + * - CGU_CLKSRC_IDIVE :Integer divider register E + * @param[in] divisor Divisor value, should be: 0..255 + * @return Setting status, could be: + * - CGU_ERROR_SUCCESS: successful + * - CGU_ERROR_INVALID_ENTITY: Invalid entity + **********************************************************************/ +/* divisor number must >=1*/ +uint32_t CGU_SetDIV(CGU_ENTITY_T SelectDivider, uint32_t divisor) +{ + int32_t RegOffset; + uint32_t tempReg; + + if (SelectDivider >= CGU_CLKSRC_IDIVA && SelectDivider <= CGU_CLKSRC_IDIVE) { + RegOffset = CGU_Entity_ControlReg_Offset[SelectDivider]; + + if (RegOffset == -1) { + return CGU_ERROR_INVALID_ENTITY; + } + + tempReg = CGU_ADDRESS32(LPC_CGU, RegOffset); + tempReg &= ~(0xFF << 2); + tempReg |= ((divisor - 1) & 0xFF) << 2; + CGU_ADDRESS32(LPC_CGU, RegOffset) = tempReg; + return CGU_ERROR_SUCCESS; + } + + return CGU_ERROR_INVALID_ENTITY; +} + +/*********************************************************************//** + * @brief Enable clock entity + * @param[in] ClockEntity Clock entity, should be: + * - CGU_CLKSRC_32KHZ_OSC :32Khz oscillator + * - CGU_CLKSRC_IRC :IRC clock + * - CGU_CLKSRC_ENET_RX_CLK :Ethernet receive clock + * - CGU_CLKSRC_ENET_TX_CLK :Ethernet transmit clock + * - CGU_CLKSRC_GP_CLKIN :General purpose input clock + * - CGU_CLKSRC_XTAL_OSC :Crystal oscillator + * - CGU_CLKSRC_PLL0 :PLL0 clock + * - CGU_CLKSRC_PLL1 :PLL1 clock + * - CGU_CLKSRC_IDIVA :Integer divider register A + * - CGU_CLKSRC_IDIVB :Integer divider register B + * - CGU_CLKSRC_IDIVC :Integer divider register C + * - CGU_CLKSRC_IDIVD :Integer divider register D + * - CGU_CLKSRC_IDIVE :Integer divider register E + * - CGU_BASE_SAFE :Base safe clock (always on)for WDT + * - CGU_BASE_USB0 :Base clock for USB0 + * - CGU_BASE_PERIPH :Base clock for Peripheral bus + * - CGU_BASE_USB1 :Base clock for USB1 + * - CGU_BASE_M4 :System base clock for ARM Cortex-M3 core + * and APB peripheral blocks #0 and #2 + * - CGU_BASE_SPIFI :Base clock for SPIFI + * - CGU_BASE_PHY_RX :Base clock for Ethernet PHY Rx + * - CGU_BASE_PHY_TX :Base clock for Ethernet PHY Tx + * - CGU_BASE_APB1 :Base clock for APB peripheral block #1 + * - CGU_BASE_APB3 :Base clock for APB peripheral block #3 + * - CGU_BASE_LCD :Base clock for LCD + * - CGU_BASE_SDIO :Base clock for SDIO card reader + * - CGU_BASE_SSP0 :Base clock for SSP0 + * - CGU_BASE_SSP1 :Base clock for SSP1 + * - CGU_BASE_UART0 :Base clock for UART0 + * - CGU_BASE_UART1 :Base clock for UART1 + * - CGU_BASE_UART2 :Base clock for UART2 + * - CGU_BASE_UART3 :Base clock for UART3 + * - CGU_BASE_CLKOUT :Base clock for CLKOUT pin + * @param[in] en status, should be: + * - ENABLE: Enable power + * - DISABLE: Disable power + * @return Setting status, could be: + * - CGU_ERROR_SUCCESS: successful + * - CGU_ERROR_INVALID_ENTITY: Invalid entity + **********************************************************************/ +uint32_t CGU_EnableEntity(CGU_ENTITY_T ClockEntity, uint32_t en) +{ + int32_t RegOffset; + int32_t i; + + if (ClockEntity == CGU_CLKSRC_32KHZ_OSC) { + if (en) { + LPC_CREG->CREG0 &= ~((1 << 3) | (1 << 2)); + LPC_CREG->CREG0 |= (1 << 1) | (1 << 0); + + } else { + LPC_CREG->CREG0 &= ~((1 << 1) | (1 << 0)); + LPC_CREG->CREG0 |= (1 << 3); + } + + for (i = 0; i < 1000000; i++); + + } else if (ClockEntity == CGU_CLKSRC_ENET_RX_CLK) { + scu_pinmux(0xC , 0 , MD_PLN, FUNC3); + + } else if (ClockEntity == CGU_CLKSRC_ENET_TX_CLK) { + scu_pinmux(0x1 , 19 , MD_PLN, FUNC0); + + } else if (ClockEntity == CGU_CLKSRC_GP_CLKIN) { + } else if (ClockEntity == CGU_CLKSRC_TCK) { + } else if (ClockEntity == CGU_CLKSRC_XTAL_OSC) { + if (!en) { + LPC_CGU->XTAL_OSC_CTRL |= CGU_CTRL_EN_MASK; + + } else { + LPC_CGU->XTAL_OSC_CTRL &= ~CGU_CTRL_EN_MASK; + } + + /*Delay for stable clock*/ + for (i = 0; i < 1000000; i++); + + } else { + RegOffset = CGU_Entity_ControlReg_Offset[ClockEntity]; + + if (RegOffset == -1) { + return CGU_ERROR_INVALID_ENTITY; + } + + if (!en) { + CGU_ADDRESS32(CGU_CGU_ADDR, RegOffset) |= CGU_CTRL_EN_MASK; + + } else { + CGU_ADDRESS32(CGU_CGU_ADDR, RegOffset) &= ~CGU_CTRL_EN_MASK; + + /*if PLL is selected check if it is locked */ + if (ClockEntity == CGU_CLKSRC_PLL0) { + while ((LPC_CGU->PLL0USB_STAT & 1) == 0x0); + } + + if (ClockEntity == CGU_CLKSRC_PLL0_AUDIO) { + while ((LPC_CGU->PLL0AUDIO_STAT & 1) == 0x0); + } + + if (ClockEntity == CGU_CLKSRC_PLL1) { + while ((LPC_CGU->PLL1_STAT & 1) == 0x0); + + /*post check lock status */ + if (!(LPC_CGU->PLL1_STAT & 1)) + while (1); + } + } + } + + return CGU_ERROR_SUCCESS; +} + +/*********************************************************************//** + * @brief Connect entity clock source + * @param[in] ClockSource Clock source, should be: + * - CGU_CLKSRC_32KHZ_OSC :32Khz oscillator + * - CGU_CLKSRC_IRC :IRC clock + * - CGU_CLKSRC_ENET_RX_CLK :Ethernet receive clock + * - CGU_CLKSRC_ENET_TX_CLK :Ethernet transmit clock + * - CGU_CLKSRC_GP_CLKIN :General purpose input clock + * - CGU_CLKSRC_XTAL_OSC :Crystal oscillator + * - CGU_CLKSRC_PLL0 :PLL0 clock + * - CGU_CLKSRC_PLL1 :PLL1 clock + * - CGU_CLKSRC_IDIVA :Integer divider register A + * - CGU_CLKSRC_IDIVB :Integer divider register B + * - CGU_CLKSRC_IDIVC :Integer divider register C + * - CGU_CLKSRC_IDIVD :Integer divider register D + * - CGU_CLKSRC_IDIVE :Integer divider register E + * @param[in] ClockEntity Clock entity, should be: + * - CGU_CLKSRC_PLL0 :PLL0 clock + * - CGU_CLKSRC_PLL1 :PLL1 clock + * - CGU_CLKSRC_IDIVA :Integer divider register A + * - CGU_CLKSRC_IDIVB :Integer divider register B + * - CGU_CLKSRC_IDIVC :Integer divider register C + * - CGU_CLKSRC_IDIVD :Integer divider register D + * - CGU_CLKSRC_IDIVE :Integer divider register E + * - CGU_BASE_SAFE :Base safe clock (always on)for WDT + * - CGU_BASE_USB0 :Base clock for USB0 + * - CGU_BASE_USB1 :Base clock for USB1 + * - CGU_BASE_M4 :System base clock for ARM Cortex-M3 core + * and APB peripheral blocks #0 and #2 + * - CGU_BASE_SPIFI :Base clock for SPIFI + * - CGU_BASE_PHY_RX :Base clock for Ethernet PHY Rx + * - CGU_BASE_PHY_TX :Base clock for Ethernet PHY Tx + * - CGU_BASE_APB1 :Base clock for APB peripheral block #1 + * - CGU_BASE_APB3 :Base clock for APB peripheral block #3 + * - CGU_BASE_LCD :Base clock for LCD + * - CGU_BASE_SDIO :Base clock for SDIO card reader + * - CGU_BASE_SSP0 :Base clock for SSP0 + * - CGU_BASE_SSP1 :Base clock for SSP1 + * - CGU_BASE_UART0 :Base clock for UART0 + * - CGU_BASE_UART1 :Base clock for UART1 + * - CGU_BASE_UART2 :Base clock for UART2 + * - CGU_BASE_UART3 :Base clock for UART3 + * - CGU_BASE_CLKOUT :Base clock for CLKOUT pin + * @return Setting status, could be: + * - CGU_ERROR_SUCCESS: successful + * - CGU_ERROR_CONNECT_TOGETHER: Error when 2 clock source connect together + * - CGU_ERROR_INVALID_CLOCK_SOURCE: Invalid clock source error + * - CGU_ERROR_INVALID_ENTITY: Invalid entity error + **********************************************************************/ +/* Connect one entity into clock source */ +uint32_t CGU_EntityConnect(CGU_ENTITY_T ClockSource, CGU_ENTITY_T ClockEntity) +{ + int32_t RegOffset; + uint32_t tempReg; + + if (ClockSource > CGU_CLKSRC_IDIVE) { + return CGU_ERROR_INVALID_CLOCK_SOURCE; + } + + if (ClockEntity >= CGU_CLKSRC_PLL0 && ClockEntity <= CGU_BASE_CLKOUT) { + if (CGU_ConnectAlloc_Tbl[ClockSource][ClockEntity]) { + RegOffset = CGU_Entity_ControlReg_Offset[ClockSource]; + + if (RegOffset != -1) { + if (ClockEntity <= CGU_CLKSRC_IDIVE && + ClockEntity >= CGU_CLKSRC_PLL0) { + //RegOffset = (CGU_ADDRESS32(LPC_CGU,RegOffset)>>24)&0xF; + if (((CGU_ADDRESS32(LPC_CGU, RegOffset) >> 24) & 0xF) == ClockEntity) { + return CGU_ERROR_CONNECT_TOGETHER; + } + } + } + + RegOffset = CGU_Entity_ControlReg_Offset[ClockEntity]; + + if (RegOffset == -1) { + return CGU_ERROR_INVALID_ENTITY; + } + + tempReg = CGU_ADDRESS32(LPC_CGU, RegOffset); + tempReg &= ~CGU_CTRL_SRC_MASK; + tempReg |= ClockSource << 24 | CGU_CTRL_AUTOBLOCK_MASK; + CGU_ADDRESS32(LPC_CGU, RegOffset) = tempReg; + return CGU_ERROR_SUCCESS; + + } else { + return CGU_ERROR_INVALID_CLOCK_SOURCE; + } + + } else { + return CGU_ERROR_INVALID_ENTITY; + } +} + + +/*********************************************************************//** + * @brief Get current USB PLL clock from XTAL + * @param[in] None + * @return Returned clock value + **********************************************************************/ +uint32_t CGU_SetPLL0(void) +{ + // Setup PLL550 to generate 480MHz from 12 MHz crystal + LPC_CGU->PLL0USB_CTRL |= 1; // Power down PLL + // P N + LPC_CGU->PLL0USB_NP_DIV = (98 << 0) | (514 << 12); + // SELP SELI SELR MDEC + LPC_CGU->PLL0USB_MDIV = (0xB << 17) | (0x10 << 22) | (0 << 28) | (0x7FFA << 0); + LPC_CGU->PLL0USB_CTRL = (CGU_CLKSRC_XTAL_OSC << 24) | (0x3 << 2) | (1 << 4); + return CGU_ERROR_SUCCESS; +} + + + +/*********************************************************************//** + * @brief Get current Audio PLL clock from XTAL + * @param[in] None + * @return Returned clock value + **********************************************************************/ +uint32_t CGU_SetPLL0audio(void) +{ + /* disable clock, disable skew enable, power down pll, + * (dis/en)able post divider, (dis/en)able pre-divider, + * disable free running mode, disable bandsel, + * enable up limmiter, disable bypass + */ + LPC_CGU->PLL0AUDIO_CTRL = (6 << 24) /* source = XTAL OSC 12 MHz */ + | _BIT(0); /* power down */ + /* PLL should be set to 512fs rate 512 * 48000 = 24576000 Hz */ + /* set mdec register */ +#if 1 // results from gcc program + LPC_CGU->PLL0AUDIO_MDIV = 0x23e34d3; + LPC_CGU->PLL0AUDIO_NP_DIV = 0x3f00e; + LPC_CGU->PLL0AUDIO_CTRL = (6 << 24) /* source = XTAL OSC 12 MHz */ + | (6 << 12) // fractional divider off and bypassed + | _BIT(4); /* CLKEN */ +#else + LPC_CGU->PLL0AUDIO_MDIV = (0 << 28) /* SELR */ + | (40 << 22) /* SELI */ + | (31 << 17) /* SELP */ + | 11372; /* MDEC */ + /* set ndec, pdec register */ + LPC_CGU->PLL0AUDIO_NP_DIV = (22 << 12) /* ndec */ + | (10); /* pdec */ + /* set fraction divider register. [21:15] = m, [14:0] = fractional value */ + LPC_CGU->PLL0AUDIO_FRAC = (86 << 15) | 0x1B7; + LPC_CGU->PLL0AUDIO_CTRL = (6 << 24) /* source = XTAL OSC 12 MHz */ + | _BIT(12) /* enable SD modulator to update mdec*/ + | _BIT(4); /* CLKEN */ +#endif + + /* wait for lock */ + while (!(LPC_CGU->PLL0AUDIO_STAT & 1)); + + return CGU_ERROR_SUCCESS; +} + + +/*********************************************************************//** + * @brief Setting PLL1 + * @param[in] mult Multiple value + * @return Setting status, could be: + * - CGU_ERROR_SUCCESS: successful + * - CGU_ERROR_INVALID_PARAM: Invalid parameter error + **********************************************************************/ +uint32_t CGU_SetPLL1(uint32_t mult) +{ + uint32_t msel = 0, nsel = 0, psel = 0, pval = 1; + uint32_t freq; + uint32_t ClkSrc = (LPC_CGU->PLL1_CTRL & CGU_CTRL_SRC_MASK) >> 24; + freq = CGU_ClockSourceFrequency[ClkSrc]; + freq *= mult; + msel = mult - 1; + LPC_CGU->PLL1_CTRL &= ~(CGU_PLL1_FBSEL_MASK | + CGU_PLL1_BYPASS_MASK | + CGU_PLL1_DIRECT_MASK | + (0x03 << 8) | (0xFF << 16) | (0x03 << 12)); + + if (freq < 156000000) { + //psel is encoded such that 0=1, 1=2, 2=4, 3=8 + while (2 * (pval)*freq < 156000000) { + psel++; + pval *= 2; + } + +// if(2*(pval)*freq > 320000000) { +// //THIS IS OUT OF RANGE!!! +// //HOW DO WE ASSERT IN SAMPLE CODE? +// //__breakpoint(0); +// return CGU_ERROR_INVALID_PARAM; +// } + LPC_CGU->PLL1_CTRL |= (msel << 16) | (nsel << 12) | (psel << 8) | CGU_PLL1_FBSEL_MASK; + + } else if (freq < 320000000) { + LPC_CGU->PLL1_CTRL |= (msel << 16) | (nsel << 12) | (psel << 8) | CGU_PLL1_DIRECT_MASK | CGU_PLL1_FBSEL_MASK; + + } else { + return CGU_ERROR_INVALID_PARAM; + } + + return CGU_ERROR_SUCCESS; +} + + +/*********************************************************************//** + * @brief Get current base status + * @param[in] Base Base type, should be: + * - CGU_BASE_USB0 :Base clock for USB0 + * - CGU_BASE_USB1 :Base clock for USB1 + * - CGU_BASE_M4 :System base clock for ARM Cortex-M3 core + * and APB peripheral blocks #0 and #2 + * - CGU_BASE_SPIFI :Base clock for SPIFI + * - CGU_BASE_APB1 :Base clock for APB peripheral block #1 + * - CGU_BASE_APB3 :Base clock for APB peripheral block #3 + * - CGU_BASE_SDIO :Base clock for SDIO card reader + * - CGU_BASE_SSP0 :Base clock for SSP0 + * - CGU_BASE_SSP1 :Base clock for SSP1 + * - CGU_BASE_UART0 :Base clock for UART0 + * - CGU_BASE_UART1 :Base clock for UART1 + * - CGU_BASE_UART2 :Base clock for UART2 + * - CGU_BASE_UART3 :Base clock for UART3 + * @return Always return 0 + **********************************************************************/ +uint32_t CGU_GetBaseStatus(CGU_ENTITY_T Base) +{ + switch (Base) { + /*CCU1*/ + case CGU_BASE_APB3: + return LPC_CCU1->BASE_STAT & 1; + + case CGU_BASE_APB1: + return (LPC_CCU1->BASE_STAT >> 1) & 1; + + case CGU_BASE_SPIFI: + return (LPC_CCU1->BASE_STAT >> 2) & 1; + + case CGU_BASE_M4: + return (LPC_CCU1->BASE_STAT >> 3) & 1; + + case CGU_BASE_USB0: + return (LPC_CCU1->BASE_STAT >> 7) & 1; + + case CGU_BASE_USB1: + return (LPC_CCU1->BASE_STAT >> 8) & 1; + + /*CCU2*/ + case CGU_BASE_UART3: + return (LPC_CCU2->BASE_STAT >> 1) & 1; + + case CGU_BASE_UART2: + return (LPC_CCU2->BASE_STAT >> 2) & 1; + + case CGU_BASE_UART1: + return (LPC_CCU2->BASE_STAT >> 3) & 1; + + case CGU_BASE_UART0: + return (LPC_CCU2->BASE_STAT >> 4) & 1; + + case CGU_BASE_SSP1: + return (LPC_CCU2->BASE_STAT >> 5) & 1; + + case CGU_BASE_SSP0: + return (LPC_CCU2->BASE_STAT >> 6) & 1; + + case CGU_BASE_SDIO: + return (LPC_CCU2->BASE_STAT >> 7) & 1; + + /*BASE SAFE is used by WWDT and RGU*/ + case CGU_BASE_SAFE: + break; + + default: + break; + } + + return 0; +} + + +/*********************************************************************//** + * @brief Compare one source clock to IRC clock + * @param[in] Clock Clock entity that will be compared to IRC, should be: + * - CGU_CLKSRC_32KHZ_OSC :32Khz crystal oscillator + * - CGU_CLKSRC_ENET_RX_CLK :Ethernet receive clock + * - CGU_CLKSRC_ENET_TX_CLK :Ethernet transmit clock + * - CGU_CLKSRC_GP_CLKIN :General purpose input clock + * - CGU_CLKSRC_XTAL_OSC :Crystal oscillator + * - CGU_CLKSRC_PLL0 :PLL0 clock + * - CGU_CLKSRC_PLL1 :PLL1 clock + * - CGU_CLKSRC_IDIVA :Integer divider register A + * - CGU_CLKSRC_IDIVB :Integer divider register B + * - CGU_CLKSRC_IDIVC :Integer divider register C + * - CGU_CLKSRC_IDIVD :Integer divider register D + * - CGU_CLKSRC_IDIVE :Integer divider register E + * - CGU_BASE_SAFE :Base safe clock (always on)for WDT + * - CGU_BASE_USB0 :Base clock for USB0 + * - CGU_BASE_USB1 :Base clock for USB1 + * - CGU_BASE_M4 :System base clock for ARM Cortex-M3 core + * and APB peripheral blocks #0 and #2 + * - CGU_BASE_SPIFI :Base clock for SPIFI + * - CGU_BASE_PHY_RX :Base clock for Ethernet PHY Rx + * - CGU_BASE_PHY_TX :Base clock for Ethernet PHY Tx + * - CGU_BASE_APB1 :Base clock for APB peripheral block #1 + * - CGU_BASE_APB3 :Base clock for APB peripheral block #3 + * - CGU_BASE_LCD :Base clock for LCD + * - CGU_BASE_SDIO :Base clock for SDIO card reader + * - CGU_BASE_SSP0 :Base clock for SSP0 + * - CGU_BASE_SSP1 :Base clock for SSP1 + * - CGU_BASE_UART0 :Base clock for UART0 + * - CGU_BASE_UART1 :Base clock for UART1 + * - CGU_BASE_UART2 :Base clock for UART2 + * - CGU_BASE_UART3 :Base clock for UART3 + * - CGU_BASE_CLKOUT :Base clock for CLKOUT pin + * @param[in] m Multiple value pointer + * @param[in] d Divider value pointer + * @return Compare status, could be: + * - (-1): fail + * - 0: successful + * @note Formula used to compare: + * FClock = F_IRC* m / d + **********************************************************************/ +int CGU_FrequencyMonitor(CGU_ENTITY_T Clock, uint32_t *m, uint32_t *d) +{ + uint32_t n, c, temp; + int i; + /* Maximum allow RCOUNT number */ + c = 511; + /* Check Source Clock Freq is larger or smaller */ + LPC_CGU->FREQ_MON = (Clock << 24) | 1 << 23 | c; + + while (LPC_CGU->FREQ_MON & (1 << 23)); + + for (i = 0; i < 10000; i++); + + temp = (LPC_CGU->FREQ_MON >> 9) & 0x3FFF; + + if (temp == 0) { /* too low F < 12000000/511*/ + return -1; + } + + if (temp > 511) { /* larger */ + c = 511 - (LPC_CGU->FREQ_MON & 0x1FF); + + } else { + do { + c--; + LPC_CGU->FREQ_MON = (Clock << 24) | 1 << 23 | c; + + while (LPC_CGU->FREQ_MON & (1 << 23)); + + for (i = 0; i < 10000; i++); + + n = (LPC_CGU->FREQ_MON >> 9) & 0x3FFF; + } while (n == temp); + + c++; + } + + *m = temp; + *d = c; + return 0; +} + +/*********************************************************************//** + * @brief Compare one source clock to another source clock + * @param[in] Clock Clock entity that will be compared to second source, should be: + * - CGU_CLKSRC_32KHZ_OSC :32Khz crystal oscillator + * - CGU_CLKSRC_ENET_RX_CLK :Ethernet receive clock + * - CGU_CLKSRC_ENET_TX_CLK :Ethernet transmit clock + * - CGU_CLKSRC_GP_CLKIN :General purpose input clock + * - CGU_CLKSRC_XTAL_OSC :Crystal oscillator + * - CGU_CLKSRC_PLL0 :PLL0 clock + * - CGU_CLKSRC_PLL1 :PLL1 clock + * - CGU_CLKSRC_IDIVA :Integer divider register A + * - CGU_CLKSRC_IDIVB :Integer divider register B + * - CGU_CLKSRC_IDIVC :Integer divider register C + * - CGU_CLKSRC_IDIVD :Integer divider register D + * - CGU_CLKSRC_IDIVE :Integer divider register E + * - CGU_BASE_SAFE :Base safe clock (always on)for WDT + * - CGU_BASE_USB0 :Base clock for USB0 + * - CGU_BASE_USB1 :Base clock for USB1 + * - CGU_BASE_M4 :System base clock for ARM Cortex-M3 core + * and APB peripheral blocks #0 and #2 + * - CGU_BASE_SPIFI :Base clock for SPIFI + * - CGU_BASE_PHY_RX :Base clock for Ethernet PHY Rx + * - CGU_BASE_PHY_TX :Base clock for Ethernet PHY Tx + * - CGU_BASE_APB1 :Base clock for APB peripheral block #1 + * - CGU_BASE_APB3 :Base clock for APB peripheral block #3 + * - CGU_BASE_LCD :Base clock for LCD + * - CGU_BASE_SDIO :Base clock for SDIO card reader + * - CGU_BASE_SSP0 :Base clock for SSP0 + * - CGU_BASE_SSP1 :Base clock for SSP1 + * - CGU_BASE_UART0 :Base clock for UART0 + * - CGU_BASE_UART1 :Base clock for UART1 + * - CGU_BASE_UART2 :Base clock for UART2 + * - CGU_BASE_UART3 :Base clock for UART3 + * - CGU_BASE_CLKOUT :Base clock for CLKOUT pin + * @param[in] CompareToClock Clock source that to be compared to first source, should be different + * to first source. + * @param[in] m Multiple value pointer + * @param[in] d Divider value pointer + * @return Compare status, could be: + * - (-1): fail + * - 0: successful + * @note Formula used to compare: + * FClock = m*FCompareToClock/d + **********************************************************************/ +uint32_t CGU_RealFrequencyCompare(CGU_ENTITY_T Clock, CGU_ENTITY_T CompareToClock, uint32_t *m, uint32_t *d) +{ + uint32_t m1, m2, d1, d2; + + /* Check Parameter */ + if ((Clock > CGU_CLKSRC_IDIVE) || (CompareToClock > CGU_CLKSRC_IDIVE)) { + return CGU_ERROR_INVALID_PARAM; + } + + /* Check for Clock Enable - Not yet implement + * The Comparator will hang if Clock has not been set*/ + CGU_FrequencyMonitor(Clock, &m1, &d1); + CGU_FrequencyMonitor(CompareToClock, &m2, &d2); + *m = m1 * d2; + *d = d1 * m2; + return 0; +} +