/**************************************************************************************************/ /** * @file clock_drv.c * @brief CLOCK module driver file. * @version V1.0.0 * @date December-2022 * @author Zhixin Semiconductor * * @note * Copyright (C) 2021-2022 Zhixin Semiconductor Ltd. All rights reserved. * **************************************************************************************************/ #include "clock_drv.h" /** @addtogroup Z20K14XM_Peripheral_Driver * @{ */ /** @defgroup Clock * @brief Clock driver modules * @{ */ /** @defgroup Clock_Private_Type * @{ */ typedef volatile union { struct { uint32_t PCKMD : 2; /* [1:0] r/w */ uint32_t RSVD_3_2 : 2; /* [3:2] r */ uint32_t CLKMUX : 3; /* [6:4] r/w */ uint32_t RSVD_7 : 1; /* [7] r */ uint32_t CLKDIV : 4; /* [11:8] r/w */ uint32_t RSVD_15_12 : 4; /* [15:12] r */ uint32_t PWLK : 1; /* [16] r/w */ uint32_t RSVD_19_17 : 3; /* [19:17] r */ uint32_t PSUPVACEN : 1; /* [20] r/w */ uint32_t PRSTB : 1; /* [21] r/w */ uint32_t RSVD_23_22 : 2; /* [23:22] r */ uint32_t PPR : 1; /* [24] r/w */ uint32_t PCLKMUXPR : 1; /* [25] r/w */ uint32_t PCLKDIVPR : 1; /* [26] r/w */ uint32_t PSUPVACPR : 1; /* [27] r/w */ uint32_t RSVD_30_28 : 3; /* [30:28] r */ uint32_t LOCK : 1; /* [31] r/w */ } BF; uint32_t WORDVAL; } ModuleClk_t; /** @} end of group Clock_Private_Type*/ /** @defgroup Clock_PLL_Configure_Private_Defines * @{ */ /** @} end of group Clock_PLL_Configure_Private_Type*/ /** @defgroup Clock_Private_Defines * @{ */ #define PMU_UNLOCK_SEQUENCE (0x94730000UL) #define CLK_WAIT_CNT 100000U #define CLK_OSC32K_WAIT_CNT 5000000U /** @} end of group Clock_Private_Defines */ /** @defgroup Clock_Private_Variables * @{ */ /** * @brief RTC Register address array */ static rtc_reg_t * const rtcRegPtr = (rtc_reg_t *)RTC_BASE_ADDR; static rtc_reg_w_t * const rtcRegWPtr = (rtc_reg_w_t *)RTC_BASE_ADDR; /** * @brief PARCC Register address array */ static ModuleClk_t *parccRegPtr[]= { (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_WDOG), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_EWDT), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_STIM), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_TIM0), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_TIM1), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_TIM2), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_TIM3), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_MCPWM0), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_MCPWM1), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_TDG0), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_TDG1), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_CAN0), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_CAN1), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_CAN2), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_CAN3), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_CAN4), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_CAN5), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_CAN6), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_CAN7), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_UART0), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_UART1), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_UART2), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_UART3), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_UART4), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_UART5), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_SPI0), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_SPI1), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_SPI2), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_SPI3), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_I2C0), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_I2C1), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_I2S0), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_I2S1), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_I2S1+0x4), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_ADC0), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_ADC1), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_CMP), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_CRC), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_AES), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_TRNG), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_FLASH), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_FLASH+0x4), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_DMA), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_DMAMUX), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_PORTA), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_PORTB), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_PORTC), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_PORTD), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_PORTE), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_TMU), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_REGFILE), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_SMPU), (ModuleClk_t *)(PARCC_BASE_ADDR+CLK_GPIO), }; /** * @brief SCM Register address array */ static scm_reg_t * const scmRegPtr = (scm_reg_t *)SCM_BASE_ADDR; /** * @brief SCC Register address array */ static scc_reg_t * const sccRegPtr = (scc_reg_t *)SCC_BASE_ADDR; static scc_reg_w_t * const sccRegWPtr = (scc_reg_w_t *)SCC_BASE_ADDR; /** * @brief PMU Register address array */ static pmu_reg_t * const pmuRegPtr = (pmu_reg_t *)PMU_BASE_ADDR; static pmu_reg_w_t * const pmuRegWPtr = (pmu_reg_w_t *)PMU_BASE_ADDR; /** * @brief SCC IRQHandler callback function pointer array */ static isr_cb_t * sccIsrCbFunc[CLK_INT_ALL]= {NULL, NULL}; /** @} end of group Clock_Private_Variables */ /** @defgroup Clock_Global_Variables * @{ */ /** @} end of group Clock_Global_Variables */ /** @defgroup Clock_Private_FunctionDeclaration * @{ */ void SCC_DriverIRQHandler(void); /** @} end of group Clock_Private_FunctionDeclaration */ /** @defgroup Clock_Private_Functions * @{ */ static uint32_t CLK_GetSysClkFreq(uint32_t oscFreq); /** * @brief SCC IRQHandler function * * @param none * * @return none * */ void SCC_DriverIRQHandler(void) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scc_reg_w_t * SCCxw = (scc_reg_w_t *)(sccRegWPtr); if(SCCx->SCC_OSCCS.OSCLOC != 0U) { if(SCCx->SCC_OSCCS.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_OSCCS = 0x5B000000U; } /* clear int status */ SCCx->SCC_OSCCS.OSCLOC = 1U; /* lock */ SCCx->SCC_OSCCS.LOCK = 1U; if(sccIsrCbFunc[CLK_INT_OSCLOC] != NULL) { sccIsrCbFunc[CLK_INT_OSCLOC](); } else { CLK_OSC40MMonitorDisable(); } } if(SCCx->SCC_FIRCCS.FIRCLOC != 0U) { if(SCCx->SCC_FIRCCS.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_FIRCCS = 0x5B000000U; } /* clear int status */ SCCx->SCC_FIRCCS.FIRCLOC = 1U; /* lock */ SCCx->SCC_FIRCCS.LOCK = 1U; if(sccIsrCbFunc[CLK_INT_FIRCLOC] != NULL) { sccIsrCbFunc[CLK_INT_FIRCLOC](); } else { CLK_FIRC64MMonitorDisable(); } } COMMON_DSB(); } /** * @brief get system clock frequency before divider * * @param[in] oscFreq: frequency of the OSC clock * * @return ret the clock frequency. If return 0, there is some error. * */ static uint32_t CLK_GetSysClkFreq(uint32_t oscFreq) { uint32_t ret = 0U; scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); if(2U == SCCx->SCC_CST.SCS) { ret = oscFreq; } else if(1U == SCCx->SCC_CST.SCS) { ret = 64000000UL; } else if(3U == SCCx->SCC_CST.SCS) { if(0U == SCCx->SCC_SPLLCFG1.REFCKS) { ret = CLK_GetPLLFreq(PLL_FIRC64M_CLK, oscFreq); } /* 1U == SCCx->SCC_SPLLCFG1.REFCKS */ else { ret = CLK_GetPLLFreq(PLL_OSC_CLK, oscFreq); } } else { /* Do nothing */ } return ret; } /** @} end of group Clock_Private_Functions */ /** @defgroup Clock_Public_Functions * @{ */ /** * @brief Config and enable FIRC64M clock * * @param[in] stopModeEn: Enable/Disable FIRC64M in stop mode * -ENABLE * -DISABLE * * @return none * */ void CLK_FIRC64MEnable(ControlState_t stopModeEn) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scc_reg_w_t * SCCxw = (scc_reg_w_t *)(sccRegWPtr); if(SCCx->SCC_FIRCCS.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_FIRCCS = 0x5B000000U; } SCCx->SCC_FIRCCS.FIRCSTOPEN = (uint32_t)stopModeEn; SCCx->SCC_FIRCCS.FIRCEN = 1U; /* lock this register */ SCCx->SCC_FIRCCS.LOCK = 1U; } /** * @brief Config and enable PLL clock * * @param[in] stopModeEn: Enable/Disable PLL in stop mode. * -ENABLE * -DISABLE * * @return none * */ void CLK_PLLEnable(ControlState_t stopModeEn) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scc_reg_w_t * SCCxw = (scc_reg_w_t *)(sccRegWPtr); if(SCCx->SCC_SPLLCS.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_SPLLCS = 0x5B000000U; } SCCx->SCC_SPLLCS.RDYEN = 1U; SCCx->SCC_SPLLCS.SPLLSTOPEN = (uint32_t)stopModeEn; SCCx->SCC_SPLLCS.SPLLEN = 1U; /* lock this register */ SCCx->SCC_SPLLCS.LOCK = 1U; if (SUCC == CLK_WaitClkReady(CLK_SRC_PLL)) { SCCxw->SCC_SPLLCS = 0x5B000000U; SCCx->SCC_SPLLCS.OUTEN = 1U; SCCx->SCC_SPLLCS.RDYEN = 0U; SCCx->SCC_SPLLCS.LOCK = 1U; } } /** * @brief Config and enable OSC40M clock * * @param[in] freqMode: It selects the frequency mode of OSC40M * @param[in] stopModeEn: Enable/Disable OSC40M in stop mode. * @param[in] mode: select OSC mode. It selects from crystal oscillator or * external square wave clock source. * * @return status * ERR - some error. * SUCC - successful * */ ResultStatus_t CLK_OSC40MEnable(CLK_OscFreqMode_t freqMode, ControlState_t stopModeEn, CLK_OscMode_t mode) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scc_reg_w_t * SCCxw = (scc_reg_w_t *)(sccRegWPtr); if(SCCx->SCC_OSCCFG.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_OSCCFG = 0x5B000000U; } SCCx->SCC_OSCCFG.HFREQ = (uint32_t)freqMode; SCCx->SCC_OSCCFG.EXCLKS = (uint32_t)mode; SCCx->SCC_OSCCFG.OLMEN = 1U; /* lock */ SCCx->SCC_OSCCFG.LOCK = 1U; if(SCCx->SCC_OSCCS.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_OSCCS = 0x5B000000U; } SCCx->SCC_OSCCS.OSCSTOPEN = (uint32_t)stopModeEn; SCCx->SCC_OSCCS.OSCEN = 1U; SCCx->SCC_OSCCS.LOCK = 1U; /* wait for clock ready */ return CLK_WaitClkReady(CLK_SRC_OSC40M); } /** * @brief Select system clock. * * @param[in] clk: select the clock source * -CLK_SYS_OSC40M * -CLK_SYS_FIRC64M * -CLK_SYS_PLL * * @return * SUCC: the system clock is selected successfully * ERR: fail * @note The selected clock source has to be ready * before call this function. * */ ResultStatus_t CLK_SysClkSrc(CLK_System_t clk) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scc_reg_w_t * SCCxw = (scc_reg_w_t *)(sccRegWPtr); if(CLK_SYS_FIRC64M == clk) { if(CLK_WaitClkReady(CLK_SRC_FIRC64M) != SUCC) { return ERR; } if(SCCx->SCC_CFG.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_CFG = 0x5B000000U; } /* select sys clock source */ SCCxw->SCC_CFG = (SCCxw->SCC_CFG & 0xFFF8FFFFU) | (1UL << 16U); SCCx->SCC_CFG.LOCK = 1U; return SUCC; } else if(CLK_SYS_OSC40M == clk) { if(CLK_WaitClkReady(CLK_SRC_OSC40M) != SUCC) { return ERR; } if(SCCx->SCC_CFG.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_CFG = 0x5B000000U; } /* select sys clock source */ SCCxw->SCC_CFG = (SCCxw->SCC_CFG & 0xFFF8FFFFU) | (1UL << 17U); SCCx->SCC_CFG.LOCK = 1; return SUCC; } else if(CLK_SYS_PLL == clk) { if(CLK_WaitClkReady(CLK_SRC_PLL) != SUCC) { return ERR; } if(SCCx->SCC_CFG.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_CFG = 0x5B000000U; } /* select sys clock source */ SCCxw->SCC_CFG = (SCCxw->SCC_CFG & 0xFFF8FFFFU) | (3UL << 16U); SCCx->SCC_CFG.LOCK = 1; return SUCC; } else { return ERR; } } /** * @brief Get system clock source. * * @param[in] none. * * @return * -CLK_SYS_FIRC64M * -CLK_SYS_OSC40M * -CLK_SYS_PLL * */ CLK_System_t CLK_GetSysClkSrc(void) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); if(SCCx->SCC_CST.SCS == (uint32_t)CLK_SYS_FIRC64M) { return CLK_SYS_FIRC64M; } else if(SCCx->SCC_CST.SCS == (uint32_t)CLK_SYS_OSC40M) { return CLK_SYS_OSC40M; } /* SCCx->SCC_CST.SCS == CLK_SYS_PLL */ else { return CLK_SYS_PLL; } } /** * @brief Disable FIRC64M clock * * @param[in] none. * * @return none * */ void CLK_FIRC64MDisable(void) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scc_reg_w_t * SCCxw = (scc_reg_w_t *)(sccRegWPtr); if(SCCx->SCC_FIRCCS.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_FIRCCS = 0x5B000000; } SCCx->SCC_FIRCCS.FIRCEN = 0; /* lock this register */ SCCx->SCC_FIRCCS.LOCK = 1; } /** * @brief Disable PLL clock * * @param[in] none. * * @return none * */ void CLK_PLLDisable(void) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scc_reg_w_t * SCCxw = (scc_reg_w_t *)(sccRegWPtr); if(SCCx->SCC_SPLLCS.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_SPLLCS = 0x5B000000; } SCCx->SCC_SPLLCS.SPLLEN = 0; SCCx->SCC_SPLLCS.OUTEN = 0; /* lock this register */ SCCx->SCC_SPLLCS.LOCK = 1; } /** * @brief Select PLL reference clock * * @param[in] pll_ref_clk: PLL reference clock * -PLL_OSC_CLK * -PLL_FIRC64M_CLK * * @return none * */ void CLK_PLLRefClockSelect(CLK_PLLRefClk_t pll_ref_clk) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scc_reg_w_t * SCCxw = (scc_reg_w_t *)(sccRegWPtr); if(SCCx->SCC_SPLLCFG1.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_SPLLCFG1 = 0x5B000000; } /*Select OSC or FIRC as PLL reference clock*/ SCCx->SCC_SPLLCFG1.REFCKS = (uint32_t)pll_ref_clk; /* lock this register */ SCCx->SCC_SPLLCFG1.LOCK = 1; } /** * @brief Get PLL output freqency * * @param[in] pll_ref_clk: PLL reference clock * -PLL_OSC_CLK * -PLL_FIRC64M_CLK * * @return * PLL output freqency. * */ uint32_t CLK_GetPLLFreq(CLK_PLLRefClk_t pll_ref_clk, uint32_t oscFreq) { uint32_t postDiv; uint32_t preDiv; uint32_t mult; uint32_t preScaler = 0U; uint32_t pllOutFreq = 0U; scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scc_reg_w_t * SCCxw = (scc_reg_w_t *)(sccRegWPtr); if(SCCx->SCC_SPLLCFG1.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_SPLLCFG1 = 0x5B000000; } postDiv = SCCx->SCC_SPLLCFG1.POSTDIV; preDiv = SCCx->SCC_SPLLCFG1.PREDIV; mult = SCCx->SCC_SPLLCFG1.MULT; if(SCCx->SCC_SPLLCFG1.FBPRESEN == 1U) { preScaler = 2; } /* SCC_SPLLCFG1.FBPRESEN == 0U */ else { preScaler = 1; } /* lock this register */ SCCx->SCC_SPLLCFG1.LOCK = 1; if(pll_ref_clk == PLL_OSC_CLK) { pllOutFreq = oscFreq*mult*preScaler/((postDiv*2U)*((uint32_t)1U<SCC_SPLLCFG1.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_SPLLCFG1 = 0x5B000000; } /*Set up the PLL configuration register*/ SCCx->SCC_SPLLCFG1.POSTDIV = (uint32_t)(pll_config->pllPostDivider); SCCx->SCC_SPLLCFG1.PREDIV = (uint32_t)(pll_config->pllPreDivider); SCCx->SCC_SPLLCFG1.MULT = pll_config->pllMultiplier; SCCx->SCC_SPLLCFG1.FBPRESEN = (uint32_t)(pll_config->pllPreScaler); SCCx->SCC_SPLLCFG1.REFCKS = (uint32_t)(pll_config->pllRefClock); /* lock this register */ SCCx->SCC_SPLLCFG1.LOCK = 1; } /** * @brief Disable OSC40M clock * * @param[in] none. * * @return none * */ void CLK_OSC40MDisable(void) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scc_reg_w_t * SCCxw = (scc_reg_w_t *)(sccRegWPtr); if(SCCx->SCC_OSCCS.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_OSCCS = 0x5B000000; } if(SCCx->SCC_OSCCFG.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_OSCCFG = 0x5B000000U; } SCCx->SCC_OSCCS.OSCEN = 0U; SCCx->SCC_OSCCFG.OLMEN = 0U; /* lock */ SCCx->SCC_OSCCS.LOCK = 1U; SCCx->SCC_OSCCFG.LOCK = 1U; } /** * @brief Config and Enable OSC40M loss of clock monitor * * @param[in] act: select the action when loss of clock is detected. * -CLK_MON_INT * -CLK_MON_RST * * @return none * */ void CLK_OSC40MMonitorEnable(CLK_MonitorAct_t act) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scc_reg_w_t * SCCxw = (scc_reg_w_t *)(sccRegWPtr); if(SCCx->SCC_OSCCS.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_OSCCS = 0x5B000000; } SCCx->SCC_OSCCS.OSCCMRE = (uint32_t)act; SCCx->SCC_OSCCS.OSCCME = 1; SCCx->SCC_OSCCS.OSCLOCINTEN = 1; /* lock */ SCCx->SCC_OSCCS.LOCK = 1; } /** * @brief Disable OSC40M loss of clock monitor * * @param[in] none. * * @return none * */ void CLK_OSC40MMonitorDisable(void) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scc_reg_w_t * SCCxw = (scc_reg_w_t *)(sccRegWPtr); if(SCCx->SCC_OSCCS.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_OSCCS = 0x5B000000; } SCCx->SCC_OSCCS.OSCCME = 0; /* lock */ SCCx->SCC_OSCCS.LOCK = 1; } /** * @brief Config and Enable FIRC64M loss of clock monitor * * @param[in] act: select the action when loss of clock is detected. * -CLK_MON_INT * -CLK_MON_RST * * @return none * */ void CLK_FIRC64MMonitorEnable(CLK_MonitorAct_t act) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scc_reg_w_t * SCCxw = (scc_reg_w_t *)(sccRegWPtr); if(SCCx->SCC_FIRCCS.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_FIRCCS = 0x5B000000; } SCCx->SCC_FIRCCS.FIRCCMRE = (uint32_t)act; SCCx->SCC_FIRCCS.FIRCCME = 1; SCCx->SCC_FIRCCS.FIRCLOCINTEN = 1; /* lock */ SCCx->SCC_FIRCCS.LOCK = 1; } /** * @brief Config and Enable FIRC64M loss of clock monitor * * @param[in] none * * @return none * */ void CLK_FIRC64MMonitorDisable(void) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scc_reg_w_t * SCCxw = (scc_reg_w_t *)(sccRegWPtr); if(SCCx->SCC_FIRCCS.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_FIRCCS = 0x5B000000; } SCCx->SCC_FIRCCS.FIRCCME = 0; /* lock */ SCCx->SCC_FIRCCS.LOCK = 1; } /** * @brief Config and Enable LPO32K clock * * @param[in] none * * @return none * */ void CLK_LPO32KEnable(void) { pmu_reg_t * PMUx = (pmu_reg_t *)(pmuRegPtr); pmu_reg_w_t * PMUxw = (pmu_reg_w_t *)(pmuRegWPtr); PMUxw->PMU_LOCK = PMU_UNLOCK_SEQUENCE; PMUx->PMU_LPO_32K_CFG.LPO_CLK_DIS = 0; PMUx->PMU_LOCK.LOCK = 1U; } /** * @brief Disable LPO32K clock * * @param[in] none. * * @return none * */ void CLK_LPO32KDisable(void) { pmu_reg_t * PMUx = (pmu_reg_t *)(pmuRegPtr); pmu_reg_w_t * PMUxw = (pmu_reg_w_t *)(pmuRegWPtr); PMUxw->PMU_LOCK = PMU_UNLOCK_SEQUENCE; PMUx->PMU_LPO_32K_CFG.LPO_CLK_DIS = 1; PMUx->PMU_LOCK.LOCK = 1U; } /** * @brief Config and Enable OSC32K clock * * @param[in] mode: Select internal/external mode. * -CLK_OSC_XTAL * -CLK_OSC_EXT_SRC * * @return none * */ void CLK_OSC32KEnable(CLK_OscMode_t mode) { rtc_reg_t * RTCx = (rtc_reg_t *)(rtcRegPtr); rtc_reg_w_t * RTCxw = (rtc_reg_w_t *)(rtcRegWPtr); if(RTCx->RTC_LOCKR.LOCK != 0U) { RTCxw->RTC_LOCKR = 0x98670000U; } if( CLK_OSC_XTAL == mode) { RTCx->RTC_CSR.EXTAL_32K_EN = 0U; RTCx->RTC_CSR.CRYSTAL_EN = 1U; } else { RTCx->RTC_CSR.EXTAL_32K_EN = 1U; RTCx->RTC_CSR.CRYSTAL_EN = 0U; } RTCx->RTC_LOCKR.LOCK = 1U; } /** * @brief Disable OSC32K clock * * @param[in] none * * @return none * */ void CLK_OSC32KDisable(void) { rtc_reg_t * RTCx = (rtc_reg_t *)(rtcRegPtr); rtc_reg_w_t * RTCxw = (rtc_reg_w_t *)(rtcRegWPtr); if(RTCx->RTC_LOCKR.LOCK != 0U) { RTCxw->RTC_LOCKR = 0x98670000U; } RTCx->RTC_CSR.EXTAL_32K_EN = 0U; RTCx->RTC_CSR.CRYSTAL_EN = 0U; RTCx->RTC_LOCKR.LOCK = 1U; } /** * @brief Set clock divider * * @param[in] module: select which module clock to enable. * * @param[in] divider: Select the clock divider: CLK_DIV_1...CLK_DIV_16. * @return none * */ void CLK_SetClkDivider(CLK_Module_t module, CLK_Divider_t divider) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scc_reg_w_t * SCCxw = (scc_reg_w_t *)(sccRegWPtr); ModuleClk_t *mod_p = (ModuleClk_t *)(parccRegPtr[module/4]); switch(module) { case CLK_EWDT: case CLK_STIM: case CLK_TIM0: case CLK_TIM1: case CLK_TIM2: case CLK_TIM3: case CLK_MCPWM0: case CLK_MCPWM1: case CLK_TDG0: case CLK_TDG1: case CLK_CAN0: case CLK_CAN1: case CLK_CAN2: case CLK_CAN3: #if (CAN_INSTANCE_NUM == 6) || (CAN_INSTANCE_NUM == 8) case CLK_CAN4: case CLK_CAN5: #endif #if (CAN_INSTANCE_NUM == 8) case CLK_CAN6: case CLK_CAN7: #endif case CLK_UART0: case CLK_UART1: case CLK_UART2: case CLK_UART3: case CLK_UART4: case CLK_UART5: case CLK_SPI0: case CLK_SPI1: case CLK_SPI2: case CLK_SPI3: case CLK_I2C0: #if (I2C_INSTANCE_NUM == 2) case CLK_I2C1: #endif case CLK_I2S0: #if (I2S_INSTANCE_NUM == 2) case CLK_I2S1: #endif case CLK_ADC0: case CLK_ADC1: case CLK_FLASH: case CLK_PORTA: case CLK_PORTB: case CLK_PORTC: case CLK_PORTD: case CLK_PORTE: if(mod_p->BF.LOCK != 0U) { /* unlock this register */ mod_p->WORDVAL = 0x5B000000U; } mod_p->BF.CLKDIV = (uint32_t)divider; mod_p->BF.LOCK = 1U; break; case CLK_CORE: if(SCCx->SCC_CFG.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_CFG = 0x5B000000U; } SCCxw->SCC_CFG = (SCCxw->SCC_CFG & 0xFFFFF0FFU) | ((uint32_t)divider << 8U); SCCx->SCC_CFG.LOCK = 1; break; case CLK_BUS: if(SCCx->SCC_CFG.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_CFG = 0x5B000000U; } SCCxw->SCC_CFG = (SCCxw->SCC_CFG & 0xFFFFFF0FU) | ((uint32_t)divider << 4U); SCCx->SCC_CFG.LOCK = 1U; break; case CLK_SLOW: if(SCCx->SCC_CFG.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_CFG = 0x5B000000U; } SCCxw->SCC_CFG = (SCCxw->SCC_CFG & 0xFFFFFFF0U) | (uint32_t)divider; SCCx->SCC_CFG.LOCK = 1U; break; default: break; } } /** * @brief Select clock source for module * * @param[in] module: select which module clock to enable. * * @param[in] clockSource: select clock source * -CLK_SRC_NO * -CLK_SRC_LPO32K * -CLK_SRC_OSC32K * -CLK_SRC_FIRC64M * -CLK_SRC_OSC40M * -CLK_SRC_PLL * @return * - SUCC * - ERR: the input parameter is unreasonable. * */ ResultStatus_t CLK_ModuleSrc(CLK_Module_t module, CLK_Src_t clockSource) { ModuleClk_t *mod_p = (ModuleClk_t *)(parccRegPtr[module/4]); volatile ResultStatus_t res = SUCC; switch(module) { case CLK_STIM: case CLK_TIM0: case CLK_TIM1: case CLK_TIM2: case CLK_TIM3: case CLK_MCPWM0: case CLK_MCPWM1: case CLK_TDG0: case CLK_TDG1: case CLK_UART0: case CLK_UART1: case CLK_UART2: case CLK_UART3: case CLK_UART4: case CLK_UART5: case CLK_SPI0: case CLK_SPI1: case CLK_SPI2: case CLK_SPI3: case CLK_I2C0: #if (I2C_INSTANCE_NUM == 2) case CLK_I2C1: #endif case CLK_I2S0: #if (I2S_INSTANCE_NUM == 2) case CLK_I2S1: #endif if(mod_p->BF.LOCK != 0U) { /* unlock this register */ mod_p->WORDVAL = 0x5B000000U; } if(CLK_SRC_LPO32K == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else if(CLK_SRC_OSC32K == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else if(CLK_SRC_FIRC64M == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else if(CLK_SRC_OSC40M == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else if(CLK_SRC_PLL == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else if(CLK_SRC_NO == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else { res = ERR; } mod_p->BF.LOCK = 1U; break; case CLK_CAN0: case CLK_CAN1: case CLK_CAN2: case CLK_CAN3: #if (CAN_INSTANCE_NUM == 6) || (CAN_INSTANCE_NUM == 8) case CLK_CAN4: case CLK_CAN5: #endif #if (CAN_INSTANCE_NUM == 8) case CLK_CAN6: case CLK_CAN7: #endif if(mod_p->BF.LOCK != 0U) { /* unlock this register */ mod_p->WORDVAL = 0x5B000000U; } if(CLK_SRC_FIRC64M == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else if(CLK_SRC_OSC40M == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else if(CLK_SRC_PLL == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else if(CLK_SRC_NO == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else { res = ERR; } mod_p->BF.LOCK = 1U; break; case CLK_FLASH: if(mod_p->BF.LOCK != 0U) { /* unlock this register */ mod_p->WORDVAL = 0x5B000000U; } if(CLK_SRC_FIRC64M == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else if(CLK_SRC_OSC40M == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else if(CLK_SRC_PLL == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else if(CLK_SRC_SLOW == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else if(CLK_SRC_NO == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else { res = ERR; } mod_p->BF.LOCK = 1U; break; case CLK_EWDT: case CLK_ADC0: case CLK_ADC1: case CLK_PORTA: case CLK_PORTB: case CLK_PORTC: case CLK_PORTD: case CLK_PORTE: if(mod_p->BF.LOCK != 0U) { /* unlock this register */ mod_p->WORDVAL = 0x5B000000U; } if(CLK_SRC_LPO32K == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else if(CLK_SRC_OSC32K == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else if(CLK_SRC_FIRC64M == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else if(CLK_SRC_OSC40M == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else if(CLK_SRC_NO == clockSource) { mod_p->BF.CLKMUX = (uint32_t)clockSource; } else { res = ERR; } mod_p->BF.LOCK = 1U; break; default: res = ERR; break; } return res; } /** * @brief get module clock frequency before divider * * @param[in] module: select the module * @param[in] oscFreq: frequency of the OSC clock * * @return The clock frequency. If return 0, there is some error. * */ uint32_t CLK_GetModuleClkFreq(CLK_Module_t module,uint32_t oscFreq) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); ModuleClk_t *mod_p = (ModuleClk_t *)(parccRegPtr[(module/4)]); uint32_t freq = 0,div = 1; switch(module) { case CLK_EWDT: case CLK_STIM: case CLK_TIM0: case CLK_TIM1: case CLK_TIM2: case CLK_TIM3: case CLK_MCPWM0: case CLK_MCPWM1: case CLK_TDG0: case CLK_TDG1: case CLK_CAN0: case CLK_CAN1: case CLK_CAN2: case CLK_CAN3: #if (CAN_INSTANCE_NUM == 6) || (CAN_INSTANCE_NUM == 8) case CLK_CAN4: case CLK_CAN5: #endif #if (CAN_INSTANCE_NUM == 8) case CLK_CAN6: case CLK_CAN7: #endif case CLK_UART0: case CLK_UART1: case CLK_UART2: case CLK_UART3: case CLK_UART4: case CLK_UART5: case CLK_SPI0: case CLK_SPI1: case CLK_SPI2: case CLK_SPI3: case CLK_I2C0: #if (I2C_INSTANCE_NUM == 2) case CLK_I2C1: #endif case CLK_I2S0: #if (I2S_INSTANCE_NUM == 2) case CLK_I2S1: #endif case CLK_ADC0: case CLK_ADC1: case CLK_FLASH: case CLK_PORTA: case CLK_PORTB: case CLK_PORTC: case CLK_PORTD: case CLK_PORTE: div = (mod_p->BF.CLKDIV + 1U); switch(mod_p->BF.CLKMUX) { case CLK_SRC_LPO32K: freq = 32000U; break; case CLK_SRC_OSC32K: freq = 32768U; break; case CLK_SRC_FIRC64M: freq = 64000000U; break; case CLK_SRC_OSC40M: freq = oscFreq; break; case CLK_SRC_PLL: freq = CLK_GetPLLFreq(PLL_OSC_CLK, oscFreq); break; case CLK_SRC_SLOW: div = (SCCx->SCC_CST.DIVCORE + 1U); div *= (SCCx->SCC_CST.DIVSLOW + 1U); freq = CLK_GetSysClkFreq(oscFreq); break; default: break; } break; case CLK_CORE: div = (SCCx->SCC_CST.DIVCORE + 1U); freq = CLK_GetSysClkFreq(oscFreq); break; case CLK_BUS: div = (SCCx->SCC_CST.DIVCORE + 1U); div *= (SCCx->SCC_CST.DIVBUS + 1U); freq = CLK_GetSysClkFreq(oscFreq); break; case CLK_SLOW: div = (SCCx->SCC_CST.DIVCORE + 1U); div *= (SCCx->SCC_CST.DIVSLOW + 1U); freq = CLK_GetSysClkFreq(oscFreq); break; default: break; } return freq/div; } /** * @brief Get the clock source status * * @param[in] clockSource: clock source * -CLK_SRC_NO * -CLK_SRC_LPO32K * -CLK_SRC_OSC32K * -CLK_SRC_FIRC64M * -CLK_SRC_OSC40M * -CLK_SRC_PLL * * @return The clock source status * */ FlagStatus_t CLK_GetClkStatus(CLK_Src_t clockSource) { pmu_reg_t * PMUx = (pmu_reg_t *)(pmuRegPtr); scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); rtc_reg_t * RTCx = (rtc_reg_t *)(rtcRegPtr); FlagStatus_t bitStatus = RESET; switch(clockSource) { case CLK_SRC_LPO32K: bitStatus = ((PMUx->PMU_LPO_32K_CFG.LPO_CLK_READY != 0U) ? SET : RESET); break; case CLK_SRC_FIRC64M: bitStatus = ((SCCx->SCC_FIRCCS.FIRCRDY != 0U) ? SET : RESET); break; case CLK_SRC_OSC32K: bitStatus = ((RTCx->RTC_CSR.OSC_RDY != 0U) ? SET : RESET); break; case CLK_SRC_OSC40M: bitStatus = ((SCCx->SCC_OSCCS.OSCRDY != 0U) ? SET : RESET); break; case CLK_SRC_PLL: bitStatus = ((SCCx->SCC_SPLLCS.SPLLRDY != 0U) ? SET : RESET); break; default: break; } return bitStatus; } /** * @brief Wait the clock source status until it is ready * * @param[in] clockSource: the clock source to be waited * -CLK_SRC_NO * -CLK_SRC_LPO32K * -CLK_SRC_OSC32K * -CLK_SRC_FIRC64M * -CLK_SRC_OSC40M * -CLK_SRC_PLL * * @return SUCC -- the clock is ready * ERR -- time out * */ ResultStatus_t CLK_WaitClkReady(CLK_Src_t clockSource) { pmu_reg_t * PMUx = (pmu_reg_t *)(pmuRegPtr); scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); rtc_reg_t * RTCx = (rtc_reg_t *)(rtcRegPtr); volatile uint32_t localCnt = 0; ResultStatus_t retVal = SUCC; switch(clockSource) { case CLK_SRC_LPO32K: while(PMUx->PMU_LPO_32K_CFG.LPO_CLK_READY == 0U) { if(localCnt > CLK_WAIT_CNT) { retVal = ERR; break; } else { localCnt++; } } break; case CLK_SRC_FIRC64M: while(SCCx->SCC_FIRCCS.FIRCRDY == 0U) { if(localCnt > CLK_WAIT_CNT) { retVal = ERR; break; } else { localCnt++; } } break; case CLK_SRC_OSC32K: while(RTCx->RTC_CSR.OSC_RDY == 0U) { if(localCnt > CLK_OSC32K_WAIT_CNT) { retVal = ERR; break; } else { localCnt++; } } break; case CLK_SRC_OSC40M: while(SCCx->SCC_OSCCS.OSCRDY == 0U) { if(localCnt > CLK_WAIT_CNT) { retVal = ERR; break; } else { localCnt++; } } break; case CLK_SRC_PLL: while(SCCx->SCC_SPLLCS.SPLLRDY == 0U) { if(localCnt > CLK_WAIT_CNT) { retVal = ERR; break; } else { localCnt++; } } break; default: retVal = ERR; break; } return retVal; } /** * @brief Config and Enable clock output * * @param[in] outSrc: Select the clock source to be output. * -CLK_OUT_FIRC64M * -CLK_OUT_OSC40M * -CLK_OUT_PLL * -CLK_OUT_SLOW * -CLK_OUT_BUS * -CLK_OUT_CORE * -CLK_OUT_OSC32K * -CLK_OUT_LPO32K * @param[in] divider: output clock divider * -CLK_OUT_DIV_1 * -CLK_OUT_DIV_2 * -CLK_OUT_DIV_4 * -CLK_OUT_DIV_8 * * @return none * */ void CLK_ClkOutEnable(CLK_OutSrc_t outSrc, CLK_OutDiv_t divider) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scm_reg_t * SCMx = (scm_reg_t *)(scmRegPtr); /*Disable clock out first before switching*/ SCMx->SCM_CHIPCTL.CLKOUTEN = 0; switch(outSrc) { case CLK_OUT_OSC40M: case CLK_OUT_FIRC64M: case CLK_OUT_PLL: case CLK_OUT_SLOW: case CLK_OUT_BUS: case CLK_OUT_CORE: SCMx->SCM_CHIPCTL.CLKOUTSEL = 0; SCCx->SCC_CLKOUTCFG.CLKOUTSEL = (uint32_t)outSrc; break; case CLK_OUT_OSC32K: SCMx->SCM_CHIPCTL.CLKOUTSEL = 1; break; case CLK_OUT_LPO32K: SCMx->SCM_CHIPCTL.CLKOUTSEL = 2; break; default: break; } SCMx->SCM_CHIPCTL.CLKOUTDIV = (uint32_t)divider; /* Enable clock out */ SCMx->SCM_CHIPCTL.CLKOUTEN = 1; } /** * @brief Disable clock output * * @param[in] none * * @return none * */ void CLK_ClkOutDisable(void) { scm_reg_t * SCMx = (scm_reg_t *)(scmRegPtr); SCMx->SCM_CHIPCTL.CLKOUTEN = 0U; } /** * @brief install call back function * * @param[in] intId: select the interrupt * -CLK_INT_OSCLOC * -CLK_INT_FIRCLOC * -CLK_INT_ALL * @param[in] cbFun: pointer to callback function * * @return none * */ void CLK_InstallCallBackFunc(CLK_Int_t intId,isr_cb_t * cbFun) { sccIsrCbFunc[intId] = cbFun; } /** * @brief Clear Interrupt status * * @param[in] intId: select the interrupt * -CLK_INT_OSCLOC * -CLK_INT_FIRCLOC * -CLK_INT_ALL * * @return none * */ void CLK_IntClear(CLK_Int_t intId) { scc_reg_t * SCCx = (scc_reg_t *)(sccRegPtr); scc_reg_w_t * SCCxw = (scc_reg_w_t *)(sccRegWPtr); if(intId == CLK_INT_OSCLOC) { if(SCCx->SCC_OSCCS.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_OSCCS = 0x5B000000U; } /* clear int status */ SCCx->SCC_OSCCS.OSCLOC = 1U; /* lock */ SCCx->SCC_OSCCS.LOCK = 1U; } else if(intId == CLK_INT_FIRCLOC) { if(SCCx->SCC_FIRCCS.LOCK != 0U) { /* unlock this register */ SCCxw->SCC_FIRCCS = 0x5B000000U; } /* clear int status */ SCCx->SCC_FIRCCS.FIRCLOC = 1U; /* lock */ SCCx->SCC_FIRCCS.LOCK = 1U; } else { /* Do nothing */ } } /** @} end of group Clock_Public_Functions */ /** @} end of group Clock */ /** @} end of group Z20K14XM_Peripheral_Driver */