1942 lines
61 KiB
C
1942 lines
61 KiB
C
/**
|
|
* @file fc7xxx_driver_scg.c
|
|
* @author Flagchip
|
|
* @brief FC7xxx SCG driver type definition and API
|
|
* @version 0.1.0
|
|
* @date 2024-01-12
|
|
*
|
|
* @copyright Copyright (c) 2024 Flagchip Semiconductors Co., Ltd.
|
|
*
|
|
*/
|
|
|
|
/********************************************************************************
|
|
* Revision History:
|
|
*
|
|
* Version Date Initials CR# Descriptions
|
|
* --------- ---------- ------------ ---------- ---------------
|
|
* 0.1.0 2024-01-12 Flagchip085 N/A First version for FC7240
|
|
********************************************************************************/
|
|
#include "fc7xxx_driver_scg.h"
|
|
#include "fc7xxx_board_conf.h"
|
|
|
|
#if ((FOSC_FREQUENCY < 16000000U) || (FOSC_FREQUENCY > 48000000U))
|
|
#error "FOSC is not in range 16M ~ 48 M"
|
|
#endif
|
|
|
|
/***************** Macros *********************/
|
|
#define SIRC_CLOCK 12000000U
|
|
#define SIRC32K_CLOCK 32000U
|
|
#define FIRC_CLOCK 96000000U
|
|
#define NVM_CLOCK 12000000U
|
|
#define FOSC_STABILIZATION_TIMEOUT 96000U
|
|
#define FIRC_STABILIZATION_TIMEOUT 20U
|
|
#define SIRC_STABILIZATION_TIMEOUT 100U
|
|
#define SOSC_STABILIZATION_TIMEOUT 320500U
|
|
#define PLL_STABILIZATION_TIMEOUT 320500U
|
|
#define SCG_CLKSRC_STABILIZATION_TIMEOUT 1000U
|
|
#define CLOCK_OFF_STABILIZATION_TIMEOUT 1000U /* clock out time is about 1us */
|
|
#define CLOCK_DIV_STABILIZATION_TIMEOUT 1000U
|
|
|
|
#define PLL0_CLK_MAX 240000000U
|
|
#define PLL1_CLK_MAX 320000000U
|
|
#define PLL_VCO_CLK_MAX 800000000U
|
|
#define PLL_VCO_CLK_MIN 300000000U
|
|
#define PLL_FEEDBACK_CLK_MAX 4000000U
|
|
#define PLL_FEEDBACK_CLK_MIN 2000000U
|
|
#define SYS_CORE_CLK_MAX 240000000U
|
|
#define SYS_BUS_CLK_MAX 120000000U
|
|
#define SYS_SLOW_CLK_MAX 60000000U
|
|
|
|
#define FOSC_DIVH_MAX_CLOCK 48000000U
|
|
#define FOSC_DIVM_MAX_CLOCK 48000000U
|
|
#define FOSC_DIVL_MAX_CLOCK 48000000U
|
|
#define FIRC_DIVH_MAX_CLOCK 96000000U
|
|
#define FIRC_DIVM_MAX_CLOCK 96000000U
|
|
#define FIRC_DIVL_MAX_CLOCK 48000000U
|
|
#define PLL0_DIVH_MAX_CLOCK 240000000U
|
|
#define PLL0_DIVM_MAX_CLOCK 120000000U
|
|
#define PLL0_DIVL_MAX_CLOCK 60000000U
|
|
#define PLL1_DIVH_MAX_CLOCK 320000000U
|
|
#define PLL1_DIVM_MAX_CLOCK 160000000U
|
|
#define PLL1_DIVL_MAX_CLOCK 80000000U
|
|
|
|
/***************** mcaro function *********************/
|
|
#define SCG_CheckClockAckStatus(x, timeout, returnVal) \
|
|
while ((x) && (timeout > 0U)) \
|
|
{ \
|
|
timeout--; \
|
|
} \
|
|
if (timeout != 0U) \
|
|
{ \
|
|
returnVal = SCG_STATUS_SUCCESS; \
|
|
} \
|
|
else \
|
|
{ \
|
|
returnVal = SCG_STATUS_TIMEOUT; \
|
|
}
|
|
|
|
|
|
#define SCG_GetDivHClock(_clock_, input_freq, ouput_freq) \
|
|
{ \
|
|
uint32_t u32DivRegVal; \
|
|
\
|
|
u32DivRegVal = SCG_HWA_GetClockDiv(_clock_); \
|
|
ouput_freq = SCG_CALCULATE_DIVH_FREQ(input_freq, u32DivRegVal); \
|
|
}
|
|
|
|
#define SCG_GetDivMClock(_clock_, input_freq, ouput_freq) \
|
|
{ \
|
|
uint32_t u32DivRegVal; \
|
|
u32DivRegVal = SCG_HWA_GetClockDiv(_clock_); \
|
|
ouput_freq = SCG_CALCULATE_DIVM_FREQ(input_freq, u32DivRegVal); \
|
|
}
|
|
|
|
#define SCG_GetDivLClock(_clock_, input_freq, ouput_freq) \
|
|
{ \
|
|
uint32_t u32DivRegVal; \
|
|
u32DivRegVal = SCG_HWA_GetClockDiv(_clock_); \
|
|
ouput_freq = SCG_CALCULATE_DIVL_FREQ(input_freq, u32DivRegVal); \
|
|
}
|
|
|
|
/***************** Local Functions *********************/
|
|
|
|
static uint32_t SCG_CalculateSircFreq(const SCG_ClkSrcType eScgClockName)
|
|
{
|
|
uint32_t u32Freq;
|
|
|
|
if (SCG_SIRC_CLK == eScgClockName)
|
|
{
|
|
u32Freq = SIRC_CLOCK;
|
|
}
|
|
else if (SCG_SIRCDIVH_CLK == eScgClockName)
|
|
{
|
|
SCG_GetDivHClock(SCG_SIRC_CLOCK_SYMBOL, SIRC_CLOCK, u32Freq);
|
|
}
|
|
else if (SCG_SIRCDIVM_CLK == eScgClockName)
|
|
{
|
|
SCG_GetDivMClock(SCG_SIRC_CLOCK_SYMBOL, SIRC_CLOCK, u32Freq);
|
|
}
|
|
else if (SCG_SIRCDIVL_CLK == eScgClockName)
|
|
{
|
|
SCG_GetDivLClock(SCG_SIRC_CLOCK_SYMBOL, SIRC_CLOCK, u32Freq);
|
|
}
|
|
else
|
|
{
|
|
u32Freq = UNKNOWN_CLOCK;
|
|
}
|
|
|
|
return u32Freq;
|
|
}
|
|
|
|
static uint32_t SCG_CalculateFircFreq(const SCG_ClkSrcType eScgClockName)
|
|
{
|
|
uint32_t u32Freq;
|
|
|
|
if (true == SCG_HWA_GetClockVliad(SCG_FIRC_CLOCK_SYMBOL))
|
|
{
|
|
if (SCG_FIRC_CLK == eScgClockName)
|
|
{
|
|
u32Freq = FIRC_CLOCK;
|
|
}
|
|
else if (SCG_FIRCDIVH_CLK == eScgClockName)
|
|
{
|
|
SCG_GetDivHClock(SCG_FIRC_CLOCK_SYMBOL, FIRC_CLOCK, u32Freq);
|
|
}
|
|
else if (SCG_FIRCDIVM_CLK == eScgClockName)
|
|
{
|
|
SCG_GetDivMClock(SCG_FIRC_CLOCK_SYMBOL, FIRC_CLOCK, u32Freq);
|
|
}
|
|
else if (SCG_FIRCDIVL_CLK == eScgClockName)
|
|
{
|
|
SCG_GetDivLClock(SCG_FIRC_CLOCK_SYMBOL, FIRC_CLOCK, u32Freq);
|
|
}
|
|
else
|
|
{
|
|
u32Freq = UNKNOWN_CLOCK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
u32Freq = UNKNOWN_CLOCK;
|
|
}
|
|
|
|
return u32Freq;
|
|
}
|
|
|
|
static uint32_t SCG_CalculateFoscFreq(const SCG_ClkSrcType eScgClockName)
|
|
{
|
|
uint32_t u32Freq;
|
|
|
|
if (true == SCG_HWA_GetClockVliad(SCG_FOSC_CLOCK_SYMBOL))
|
|
{
|
|
if (SCG_FOSC_CLK == eScgClockName)
|
|
{
|
|
u32Freq = FOSC_FREQUENCY;
|
|
}
|
|
else if (SCG_FOSCDIVH_CLK == eScgClockName)
|
|
{
|
|
SCG_GetDivHClock(SCG_FOSC_CLOCK_SYMBOL, FOSC_FREQUENCY, u32Freq);
|
|
}
|
|
else if (SCG_FOSCDIVM_CLK == eScgClockName)
|
|
{
|
|
SCG_GetDivMClock(SCG_FOSC_CLOCK_SYMBOL, FOSC_FREQUENCY, u32Freq);
|
|
}
|
|
else if (SCG_FOSCDIVL_CLK == eScgClockName)
|
|
{
|
|
SCG_GetDivLClock(SCG_FOSC_CLOCK_SYMBOL, FOSC_FREQUENCY, u32Freq);
|
|
}
|
|
else
|
|
{
|
|
u32Freq = UNKNOWN_CLOCK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
u32Freq = UNKNOWN_CLOCK;
|
|
}
|
|
|
|
return u32Freq;
|
|
}
|
|
|
|
static uint32_t SCG_CalculatePll0Freq(const SCG_ClkSrcType eScgClockName)
|
|
{
|
|
uint32_t u32Freq, u32ClkFreq;
|
|
uint32_t u32Temp, u32PreDiv, u32PstDiv;
|
|
uint32_t u32Mult;
|
|
|
|
if (true == SCG_HWA_GetClockVliad(SCG_PLL0_CLOCK_SYMBOL))
|
|
{
|
|
u32Temp = SCG_HWA_GetPllSrc(SCG_PLL0_CLOCK_SYMBOL);
|
|
if (u32Temp == (uint32_t)SCG_PLLSOURCE_FIRC)
|
|
{
|
|
|
|
u32ClkFreq = FIRC_CLOCK / 2U;
|
|
}
|
|
else
|
|
{
|
|
/* (u32Temp == (uint32_t)SCG_PLLSOURCE_FOSC) */
|
|
u32ClkFreq = FOSC_FREQUENCY;
|
|
}
|
|
u32PreDiv = SCG_HWA_GetPllPrediv(SCG_PLL0_CLOCK_SYMBOL) + 1U;
|
|
u32Mult = SCG_HWA_GetPllMult(SCG_PLL0_CLOCK_SYMBOL) + 1U;
|
|
u32PstDiv = SCG_HWA_GetPllPstdiv(SCG_PLL0_CLOCK_SYMBOL);
|
|
if(u32PstDiv == 0U)
|
|
{
|
|
u32PstDiv = 1U;
|
|
}
|
|
u32ClkFreq = (u32ClkFreq / (u32PreDiv) * (u32Mult)) >> (u32PstDiv);
|
|
|
|
if (SCG_PLL0_CLK == eScgClockName)
|
|
{
|
|
u32Freq = u32ClkFreq;
|
|
}
|
|
else if (SCG_PLL0DIVH_CLK == eScgClockName)
|
|
{
|
|
SCG_GetDivHClock(SCG_PLL0_CLOCK_SYMBOL, u32ClkFreq, u32Freq);
|
|
}
|
|
else if (SCG_PLL0DIVM_CLK == eScgClockName)
|
|
{
|
|
SCG_GetDivMClock(SCG_PLL0_CLOCK_SYMBOL, u32ClkFreq, u32Freq);
|
|
}
|
|
else if (SCG_PLL0DIVL_CLK == eScgClockName)
|
|
{
|
|
SCG_GetDivLClock(SCG_PLL0_CLOCK_SYMBOL, u32ClkFreq, u32Freq);
|
|
}
|
|
else
|
|
{
|
|
u32Freq = UNKNOWN_CLOCK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
u32Freq = UNKNOWN_CLOCK;
|
|
}
|
|
|
|
return u32Freq;
|
|
}
|
|
|
|
static uint32_t SCG_CalculatePll1Freq(const SCG_ClkSrcType eScgClockName)
|
|
{
|
|
uint32_t u32Freq, u32ClkFreq;
|
|
uint32_t u32Temp, u32PreDiv, u32PstDiv;
|
|
uint32_t u32Mult;
|
|
|
|
if (true == SCG_HWA_GetClockVliad(SCG_PLL1_CLOCK_SYMBOL))
|
|
{
|
|
u32Temp = SCG_HWA_GetPllSrc(SCG_PLL1_CLOCK_SYMBOL);
|
|
if (u32Temp == (uint32_t)SCG_PLLSOURCE_FIRC)
|
|
{
|
|
u32ClkFreq = FIRC_CLOCK / 2U;
|
|
}
|
|
else
|
|
{
|
|
/* (u32Temp == (uint32_t)SCG_PLLSOURCE_FOSC) */
|
|
u32ClkFreq = FOSC_FREQUENCY;
|
|
}
|
|
u32PreDiv = SCG_HWA_GetPllPrediv(SCG_PLL1_CLOCK_SYMBOL) + 1U;
|
|
u32Mult = SCG_HWA_GetPllMult(SCG_PLL1_CLOCK_SYMBOL) + 1U;
|
|
u32PstDiv = SCG_HWA_GetPllPstdiv(SCG_PLL1_CLOCK_SYMBOL);
|
|
if(u32PstDiv == 0U)
|
|
{
|
|
u32PstDiv = 1U;
|
|
}
|
|
u32ClkFreq = (u32ClkFreq / (u32PreDiv) * (u32Mult)) >> (u32PstDiv);
|
|
|
|
if (SCG_PLL1_CLK == eScgClockName)
|
|
{
|
|
u32Freq = u32ClkFreq;
|
|
}
|
|
else if (SCG_PLL1DIVH_CLK == eScgClockName)
|
|
{
|
|
SCG_GetDivHClock(SCG_PLL1_CLOCK_SYMBOL, u32ClkFreq, u32Freq);
|
|
}
|
|
else if (SCG_PLL1DIVM_CLK == eScgClockName)
|
|
{
|
|
SCG_GetDivMClock(SCG_PLL1_CLOCK_SYMBOL, u32ClkFreq, u32Freq);
|
|
}
|
|
else if (SCG_PLL1DIVL_CLK == eScgClockName)
|
|
{
|
|
SCG_GetDivLClock(SCG_PLL1_CLOCK_SYMBOL, u32ClkFreq, u32Freq);
|
|
}
|
|
else
|
|
{
|
|
u32Freq = UNKNOWN_CLOCK;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
u32Freq = UNKNOWN_CLOCK;
|
|
}
|
|
|
|
return u32Freq;
|
|
}
|
|
|
|
static uint32_t SCG_CalculateSystemFreq(const SCG_ClkSrcType eScgClockName)
|
|
{
|
|
uint32_t u32Freq, u32ClkFreq;
|
|
uint32_t u32Temp, u32DivCore, u32DivBus, u32DivSlow;
|
|
|
|
u32Temp = (uint32_t)SCG_HWA_GetSysClkSrc();
|
|
|
|
if ((uint32_t)SCG_CLOCK_SRC_FOSC == u32Temp)
|
|
{
|
|
u32ClkFreq = FOSC_FREQUENCY;
|
|
}
|
|
else if ((uint32_t)SCG_CLOCK_SRC_FIRC == u32Temp)
|
|
{
|
|
u32ClkFreq = FIRC_CLOCK;
|
|
}
|
|
else if ((uint32_t)SCG_CLOCK_SRC_PLL0 == u32Temp)
|
|
{
|
|
u32ClkFreq = SCG_CalculatePll0Freq(SCG_PLL0_CLK);
|
|
}
|
|
else if ((uint32_t)SCG_CLOCK_SRC_SIRC == u32Temp)
|
|
{
|
|
u32ClkFreq = SCG_CalculateSircFreq(SCG_SIRC_CLK);
|
|
}
|
|
else
|
|
{
|
|
u32ClkFreq = UNKNOWN_CLOCK;
|
|
}
|
|
|
|
u32DivCore = (uint32_t)(SCG_HWA_GetSysClkDivCore() + 1U);
|
|
u32DivBus = (uint32_t)(SCG_HWA_GetSysClkDivBus() + 1U);
|
|
u32DivSlow = (uint32_t)(SCG_HWA_GetSysClkDivSlow() + 1U);
|
|
|
|
u32ClkFreq = (uint32_t)(u32ClkFreq / u32DivCore);
|
|
|
|
if (SCG_CORE_CLK == eScgClockName)
|
|
{
|
|
u32Freq = u32ClkFreq;
|
|
}
|
|
else if (SCG_BUS_CLK == eScgClockName)
|
|
{
|
|
u32Freq = (uint32_t)(u32ClkFreq / u32DivBus);
|
|
}
|
|
else
|
|
{
|
|
/* (SCG_SLOW_CLK == eScgClockName) */
|
|
u32Freq = (uint32_t)((u32ClkFreq / u32DivBus) / u32DivSlow);
|
|
}
|
|
|
|
return u32Freq;
|
|
}
|
|
|
|
static uint32_t SCG_CalculateClkOutFreq(void)
|
|
{
|
|
uint8_t u8ClockoutSrc;
|
|
uint32_t u32Freq;
|
|
/* check clock out configuration */
|
|
u8ClockoutSrc = SCG_HWA_GetClkOutSel();
|
|
|
|
if ((uint8_t)SCG_CLOCKOUT_SRC_OFF == u8ClockoutSrc)
|
|
{
|
|
u32Freq = 0U;
|
|
}
|
|
else if ((uint8_t)SCG_CLOCKOUT_SRC_FOSC == u8ClockoutSrc)
|
|
{
|
|
u32Freq = FOSC_FREQUENCY;
|
|
}
|
|
else if ((uint8_t)SCG_CLOCKOUT_SRC_SIRC == u8ClockoutSrc)
|
|
{
|
|
u32Freq = SCG_CalculateSircFreq(SCG_SIRC_CLK);
|
|
}
|
|
else if ((uint8_t)SCG_CLOCKOUT_SRC_FIRC == u8ClockoutSrc)
|
|
{
|
|
u32Freq = SCG_CalculateFircFreq(SCG_FIRC_CLK);
|
|
}
|
|
else if ((uint8_t)SCG_CLOCKOUT_SRC_SOSC == u8ClockoutSrc)
|
|
{
|
|
u32Freq = SOSC_FREQUENCY;
|
|
}
|
|
else if ((uint8_t)SCG_CLOCKOUT_SRC_PLL1 == u8ClockoutSrc)
|
|
{
|
|
u32Freq = SCG_CalculatePll1Freq(SCG_PLL1_CLK);
|
|
}
|
|
else if ((uint8_t)SCG_CLOCKOUT_SRC_PLL0 == u8ClockoutSrc)
|
|
{
|
|
u32Freq = SCG_CalculatePll0Freq(SCG_PLL0_CLK);
|
|
}
|
|
else if ((uint8_t)SCG_CLOCKOUT_SRC_SIRC32K == u8ClockoutSrc)
|
|
{
|
|
u32Freq = SIRC32K_CLOCK;
|
|
}
|
|
else
|
|
{
|
|
u32Freq = UNKNOWN_CLOCK;
|
|
}
|
|
|
|
return u32Freq;
|
|
}
|
|
|
|
static uint32_t SCG_CalculateCMU4RefFreq(void)
|
|
{
|
|
uint32_t u32Freq,u32Temp;
|
|
|
|
u32Temp = SCG_HWA_GetClkOutCfg();
|
|
|
|
if((u32Temp & SCG_CLKOUTCFG_CMU4CLK_FOSC_MASK) != 0U)
|
|
{
|
|
u32Freq = FOSC_FREQUENCY;
|
|
}
|
|
else if((u32Temp & SCG_CLKOUTCFG_CMU4CLK_SIRC_MASK) != 0U)
|
|
{
|
|
u32Freq = SIRC_CLOCK;
|
|
}
|
|
else
|
|
{
|
|
u32Freq = UNKNOWN_CLOCK;
|
|
}
|
|
|
|
return u32Freq;
|
|
}
|
|
|
|
static SCG_StatusType SCG_EnablePLL0(const SCG_PllType *const pPllConfig)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
uint32_t u32TempVal;
|
|
uint32_t u32Freq;
|
|
uint32_t u32FeedBackFreq,u32VcoFreq;
|
|
uint32_t u32DivHClockFreq = 0u;
|
|
uint32_t u32DivMClockFreq = 0u;
|
|
uint32_t u32DivLClockFreq = 0u;
|
|
uint32_t u32Pll0DivEn = 0u;
|
|
|
|
/* check pll is valid, if valid, do not configure PLL */
|
|
if (true == SCG_HWA_GetClockVliad(SCG_PLL0_CLOCK_SYMBOL))
|
|
{
|
|
eStatusVal = SCG_STATUS_SEQUENCE_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* PLL input is FOSC or FIRC clock/2 */
|
|
u32Freq = (SCG_PLLSOURCE_FOSC == pPllConfig->eSrc) ? (FOSC_FREQUENCY) : (FIRC_CLOCK / 2U);
|
|
|
|
/* Check the PLL feedback clock range */
|
|
u32FeedBackFreq = u32Freq / (pPllConfig->u8Prediv + 1U);
|
|
if(u32FeedBackFreq < PLL_FEEDBACK_CLK_MIN || u32FeedBackFreq > PLL_FEEDBACK_CLK_MAX)
|
|
{
|
|
eStatusVal = SCG_STATUS_PARAM_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* Check the PLL VCO clock range */
|
|
u32VcoFreq = u32FeedBackFreq * (pPllConfig->u16Mult + 1U);
|
|
if((u32VcoFreq < PLL_VCO_CLK_MIN) || (u32VcoFreq > PLL_VCO_CLK_MAX))
|
|
{
|
|
eStatusVal = SCG_STATUS_PARAM_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* Check the PLL out clock range */
|
|
u32Freq = u32VcoFreq >> (uint32_t)pPllConfig->ePstDiv;
|
|
if (u32Freq > PLL0_CLK_MAX)
|
|
{
|
|
eStatusVal = SCG_STATUS_PARAM_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Check DIV clock frequency is valid or not */
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
if(pPllConfig->eDivH != SCG_ASYNC_CLOCK_DISABLE)
|
|
{
|
|
u32DivHClockFreq = (uint32_t)(u32Freq >> ((uint32_t)pPllConfig->eDivH - 1u));
|
|
u32Pll0DivEn |= (uint32_t)SCG_CLOCK_DIV_H;
|
|
}
|
|
if(pPllConfig->eDivM != SCG_ASYNC_CLOCK_DISABLE)
|
|
{
|
|
u32DivMClockFreq = (uint32_t)(u32Freq >> ((uint32_t)pPllConfig->eDivM - 1u));
|
|
u32Pll0DivEn |= (uint32_t)SCG_CLOCK_DIV_M;
|
|
}
|
|
if(pPllConfig->eDivL != SCG_ASYNC_CLOCK_DISABLE)
|
|
{
|
|
u32DivLClockFreq = (uint32_t)(u32Freq >> ((uint32_t)pPllConfig->eDivL - 1u));
|
|
u32Pll0DivEn |= (uint32_t)SCG_CLOCK_DIV_L;
|
|
}
|
|
if ((u32DivHClockFreq > PLL0_DIVH_MAX_CLOCK) || (u32DivMClockFreq > PLL0_DIVM_MAX_CLOCK) || (u32DivLClockFreq > PLL0_DIVL_MAX_CLOCK))
|
|
{
|
|
eStatusVal = SCG_STATUS_PARAM_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* unlock PLL CSR register */
|
|
SCG_HWA_UnlockPllCsr(SCG_PLL0_CLOCK_SYMBOL);
|
|
|
|
/* Configure PLLCFG register */
|
|
u32TempVal = SCG_PLLCFG_PREDIV(pPllConfig->u8Prediv) | SCG_PLLCFG_MULT(pPllConfig->u16Mult) | SCG_PLLCFG_PSTDIV(
|
|
pPllConfig->ePstDiv) | SCG_PLLCFG_SOURCE(pPllConfig->eSrc) ;
|
|
SCG_HWA_SetPllCfg(SCG_PLL0_CLOCK_SYMBOL, u32TempVal);
|
|
|
|
/* Configure PLLCSR register */
|
|
u32TempVal = SCG_PLLCSR_STEN(pPllConfig->bSten);
|
|
SCG_HWA_SetPllCsr(SCG_PLL0_CLOCK_SYMBOL, u32TempVal);
|
|
|
|
/* Configure PLLDIV */
|
|
SCG_HWA_DiablePll0Div(SCG_CLOCK_DIV_ALL);
|
|
u32TempVal = SCG_HWA_GetClockDiv(SCG_PLL0_CLOCK_SYMBOL);
|
|
u32TempVal &= ~(uint32_t)(SCG_PLLDIV_DIVL_MASK | SCG_PLLDIV_DIVM_MASK | SCG_PLLDIV_DIVH_MASK);
|
|
u32TempVal |= (SCG_PLLDIV_DIVH(pPllConfig->eDivH) | SCG_PLLDIV_DIVM(pPllConfig->eDivM) | SCG_PLLDIV_DIVL(
|
|
pPllConfig->eDivL));
|
|
SCG_HWA_SetPllDiv(SCG_PLL0_CLOCK_SYMBOL, u32TempVal) ;
|
|
|
|
/* Set CSR[EN] bit to 1 */
|
|
SCG_HWA_EnablePll(SCG_PLL0_CLOCK_SYMBOL);
|
|
|
|
/* Wait PLL valid */
|
|
u32TempVal = PLL_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((false == SCG_HWA_GetClockVliad(SCG_PLL0_CLOCK_SYMBOL)), u32TempVal, eStatusVal)
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* Enable PLLDIV */
|
|
SCG_HWA_EnablePll0Div((SCG_DivEnableType)u32Pll0DivEn);
|
|
|
|
if (pPllConfig->bCm)
|
|
{
|
|
SCG_HWA_EnablePllClockMonitor(SCG_PLL0_CLOCK_SYMBOL);
|
|
}
|
|
|
|
if (pPllConfig->bCmre)
|
|
{
|
|
SCG_HWA_EnablePllClockMonitorReset(SCG_PLL0_CLOCK_SYMBOL);
|
|
}
|
|
|
|
if (pPllConfig->bLock)
|
|
{
|
|
/* lock CSR register */
|
|
SCG_HWA_LockPllCsr(SCG_PLL0_CLOCK_SYMBOL);
|
|
}
|
|
|
|
/* Wait DIV[ACK] change to 1 */
|
|
u32TempVal = CLOCK_DIV_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((SCG_HWA_GetPll0DivAck((SCG_DivEnableType)u32Pll0DivEn) != true), u32TempVal, eStatusVal)
|
|
}
|
|
else
|
|
{
|
|
/* Clear CFG configuration */
|
|
SCG_HWA_SetPllCfg(SCG_PLL0_CLOCK_SYMBOL, 0U);
|
|
|
|
/* Clear CSR configuration */
|
|
SCG_HWA_SetPllCsr(SCG_PLL0_CLOCK_SYMBOL, 0U);
|
|
|
|
/* Clear DIV configuration*/
|
|
SCG_HWA_SetPllDiv(SCG_PLL0_CLOCK_SYMBOL, 0U);
|
|
}
|
|
|
|
}
|
|
|
|
return eStatusVal;
|
|
}
|
|
|
|
static SCG_StatusType SCG_EnablePLL1(const SCG_PllType *const pPllConfig)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
uint32_t u32TempVal;
|
|
uint32_t u32Freq;
|
|
uint32_t u32FeedBackFreq,u32VcoFreq;
|
|
uint32_t u32DivHClockFreq = 0u;
|
|
uint32_t u32DivMClockFreq = 0u;
|
|
uint32_t u32DivLClockFreq = 0u;
|
|
uint32_t u32Pll1DivEn = 0u;
|
|
|
|
/* check pll is valid, if valid, do not configure PLL */
|
|
if (true == SCG_HWA_GetClockVliad(SCG_PLL1_CLOCK_SYMBOL))
|
|
{
|
|
eStatusVal = SCG_STATUS_SEQUENCE_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* PLL input is FOSC or FIRC clock/2 */
|
|
u32Freq = (SCG_PLLSOURCE_FOSC == pPllConfig->eSrc) ? (FOSC_FREQUENCY) : (FIRC_CLOCK / 2U);
|
|
|
|
/* Check the PLL feedback clock range */
|
|
u32FeedBackFreq = u32Freq / (pPllConfig->u8Prediv + 1U);
|
|
if(u32FeedBackFreq < PLL_FEEDBACK_CLK_MIN || u32FeedBackFreq > PLL_FEEDBACK_CLK_MAX)
|
|
{
|
|
eStatusVal = SCG_STATUS_PARAM_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* Check the PLL VCO clock range */
|
|
u32VcoFreq = u32FeedBackFreq * (pPllConfig->u16Mult + 1U);
|
|
if((u32VcoFreq < PLL_VCO_CLK_MIN) || (u32VcoFreq > PLL_VCO_CLK_MAX))
|
|
{
|
|
eStatusVal = SCG_STATUS_PARAM_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* Check the PLL out clock range */
|
|
u32Freq = u32VcoFreq >> (uint32_t)pPllConfig->ePstDiv;
|
|
if (u32Freq > PLL1_CLK_MAX)
|
|
{
|
|
eStatusVal = SCG_STATUS_PARAM_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Check DIV clock frequency is valid or not */
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
if(pPllConfig->eDivH != SCG_ASYNC_CLOCK_DISABLE)
|
|
{
|
|
u32DivHClockFreq = (uint32_t)(u32Freq >> ((uint32_t)pPllConfig->eDivH - 1u));
|
|
u32Pll1DivEn |= (uint32_t)SCG_CLOCK_DIV_H;
|
|
}
|
|
if(pPllConfig->eDivM != SCG_ASYNC_CLOCK_DISABLE)
|
|
{
|
|
u32DivMClockFreq = (uint32_t)(u32Freq >> ((uint32_t)pPllConfig->eDivM - 1u));
|
|
u32Pll1DivEn |= (uint32_t)SCG_CLOCK_DIV_M;
|
|
}
|
|
if(pPllConfig->eDivL != SCG_ASYNC_CLOCK_DISABLE)
|
|
{
|
|
u32DivLClockFreq = (uint32_t)(u32Freq >> ((uint32_t)pPllConfig->eDivL - 1u));
|
|
u32Pll1DivEn |= (uint32_t)SCG_CLOCK_DIV_L;
|
|
}
|
|
if ((u32DivHClockFreq > PLL1_DIVH_MAX_CLOCK) || (u32DivMClockFreq > PLL1_DIVM_MAX_CLOCK) || (u32DivLClockFreq > PLL1_DIVL_MAX_CLOCK))
|
|
{
|
|
eStatusVal = SCG_STATUS_PARAM_ERROR;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* unlock PLL CSR register */
|
|
SCG_HWA_UnlockPllCsr(SCG_PLL1_CLOCK_SYMBOL);
|
|
|
|
/* Configure PLLCFG register */
|
|
u32TempVal = SCG_PLLCFG_PREDIV(pPllConfig->u8Prediv) | SCG_PLLCFG_MULT(pPllConfig->u16Mult) | SCG_PLLCFG_PSTDIV(
|
|
pPllConfig->ePstDiv) | SCG_PLLCFG_SOURCE(pPllConfig->eSrc) ;
|
|
SCG_HWA_SetPllCfg(SCG_PLL1_CLOCK_SYMBOL, u32TempVal);
|
|
|
|
/* Configure PLLCSR register */
|
|
u32TempVal = SCG_PLLCSR_STEN(pPllConfig->bSten);
|
|
SCG_HWA_SetPllCsr(SCG_PLL1_CLOCK_SYMBOL, u32TempVal);
|
|
|
|
/* Configure PLLDIV */
|
|
SCG_HWA_DiablePll1Div(SCG_CLOCK_DIV_ALL);
|
|
u32TempVal = SCG_HWA_GetClockDiv(SCG_PLL1_CLOCK_SYMBOL);
|
|
u32TempVal &= ~(uint32_t)(SCG_PLLDIV_DIVL_MASK | SCG_PLLDIV_DIVM_MASK | SCG_PLLDIV_DIVH_MASK);
|
|
u32TempVal |= (SCG_PLLDIV_DIVH(pPllConfig->eDivH) | SCG_PLLDIV_DIVM(pPllConfig->eDivM) | SCG_PLLDIV_DIVL(
|
|
pPllConfig->eDivL));
|
|
SCG_HWA_SetPllDiv(SCG_PLL1_CLOCK_SYMBOL, u32TempVal) ;
|
|
|
|
/* Set CSR[EN] bit to 1 */
|
|
SCG_HWA_EnablePll(SCG_PLL1_CLOCK_SYMBOL);
|
|
|
|
/* Wait PLL valid */
|
|
u32TempVal = PLL_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((false == SCG_HWA_GetClockVliad(SCG_PLL1_CLOCK_SYMBOL)), u32TempVal, eStatusVal)
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* Enable PLLDIV */
|
|
SCG_HWA_EnablePll1Div((SCG_DivEnableType)u32Pll1DivEn);
|
|
|
|
if (pPllConfig->bCm)
|
|
{
|
|
SCG_HWA_EnablePllClockMonitor(SCG_PLL1_CLOCK_SYMBOL);
|
|
}
|
|
|
|
if (pPllConfig->bCmre)
|
|
{
|
|
SCG_HWA_EnablePllClockMonitorReset(SCG_PLL1_CLOCK_SYMBOL);
|
|
}
|
|
|
|
if (pPllConfig->bLock)
|
|
{
|
|
/* lock CSR register */
|
|
SCG_HWA_LockPllCsr(SCG_PLL1_CLOCK_SYMBOL);
|
|
}
|
|
|
|
/* Wait DIV[ACK] change to 1 */
|
|
u32TempVal = CLOCK_DIV_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((SCG_HWA_GetPll1DivAck((SCG_DivEnableType)u32Pll1DivEn) != true), u32TempVal, eStatusVal)
|
|
}
|
|
else
|
|
{
|
|
/* Clear CFG configuration */
|
|
SCG_HWA_SetPllCfg(SCG_PLL1_CLOCK_SYMBOL, 0U);
|
|
|
|
/* Clear CSR configuration */
|
|
SCG_HWA_SetPllCsr(SCG_PLL1_CLOCK_SYMBOL, 0U);
|
|
|
|
/* Clear DIV configuration*/
|
|
SCG_HWA_SetPllDiv(SCG_PLL1_CLOCK_SYMBOL, 0U);
|
|
}
|
|
|
|
}
|
|
|
|
return eStatusVal;
|
|
}
|
|
|
|
static SCG_StatusType SCG_DisablePLL0(void)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
uint32_t u32TempVal;
|
|
|
|
/* unlock PLL CSR register */
|
|
SCG_HWA_UnlockPllCsr(SCG_PLL0_CLOCK_SYMBOL);
|
|
|
|
/* Clear CFG configuration */
|
|
SCG_HWA_SetPllCfg(SCG_PLL0_CLOCK_SYMBOL, 0U);
|
|
|
|
/* Clear CSR configuration */
|
|
SCG_HWA_SetPllCsr(SCG_PLL0_CLOCK_SYMBOL, 0U);
|
|
|
|
u32TempVal = CLOCK_OFF_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((true == SCG_HWA_GetClockVliad(SCG_PLL0_CLOCK_SYMBOL)), u32TempVal, eStatusVal)
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* Clear CSR register */
|
|
SCG_HWA_SetPllCsr(SCG_PLL0_CLOCK_SYMBOL, 0U);
|
|
|
|
/* In order to avoid the DIV register value not cleared, Clear PLL DIV register twice */
|
|
SCG_HWA_SetPllDiv(SCG_PLL0_CLOCK_SYMBOL, 0U);
|
|
SCG_HWA_SetPllDiv(SCG_PLL0_CLOCK_SYMBOL, 0U);
|
|
}
|
|
|
|
|
|
return eStatusVal;
|
|
}
|
|
|
|
static SCG_StatusType SCG_DisablePLL1(void)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
uint32_t u32TempVal;
|
|
|
|
/* unlock PLL CSR register */
|
|
SCG_HWA_UnlockPllCsr(SCG_PLL1_CLOCK_SYMBOL);
|
|
|
|
/* Clear CFG configuration */
|
|
SCG_HWA_SetPllCfg(SCG_PLL1_CLOCK_SYMBOL, 0U);
|
|
|
|
/* Clear CSR configuration */
|
|
SCG_HWA_SetPllCsr(SCG_PLL1_CLOCK_SYMBOL, 0U);
|
|
|
|
u32TempVal = CLOCK_OFF_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((true == SCG_HWA_GetClockVliad(SCG_PLL1_CLOCK_SYMBOL)), u32TempVal, eStatusVal)
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* Clear CSR register */
|
|
SCG_HWA_SetPllCsr(SCG_PLL1_CLOCK_SYMBOL, 0U);
|
|
|
|
/* In order to avoid the DIV register value not cleared, Clear PLL DIV register twice */
|
|
SCG_HWA_SetPllDiv(SCG_PLL1_CLOCK_SYMBOL, 0U);
|
|
SCG_HWA_SetPllDiv(SCG_PLL1_CLOCK_SYMBOL, 0U);
|
|
}
|
|
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Check the system clock frequency
|
|
* @details This function check the system clock source valid and the system clock dividers valid, and get the frequency of eClock
|
|
*
|
|
* @param eClock selected clock source
|
|
* @param pSysClkConfig system clock configuration
|
|
* @param pClockFreq pointer to the memory to save clock source frequency
|
|
* @return SCG_StatusType function status
|
|
*
|
|
*/
|
|
static SCG_StatusType SCG_CheckSystemClockSourceFreq(const SCG_ClockSrcType eClock,const SCG_ClockCtrlType *const pSysClkConfig,uint32_t *pClockFreq)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
uint32_t u32Freq;
|
|
uint32_t u32FreqCore, u32FreqBus, u32FreqSlow;
|
|
bool eClockValid;
|
|
|
|
if (SCG_CLOCK_SRC_FOSC == eClock)
|
|
{
|
|
eClockValid = SCG_HWA_GetClockVliad(SCG_FOSC_CLOCK_SYMBOL);
|
|
u32Freq = FOSC_FREQUENCY;
|
|
}
|
|
else if (SCG_CLOCK_SRC_FIRC == eClock)
|
|
{
|
|
eClockValid = SCG_HWA_GetClockVliad(SCG_FIRC_CLOCK_SYMBOL);
|
|
u32Freq = FIRC_CLOCK;
|
|
}
|
|
else if (SCG_CLOCK_SRC_PLL0 == eClock)
|
|
{
|
|
eClockValid = SCG_HWA_GetClockVliad(SCG_PLL0_CLOCK_SYMBOL);
|
|
u32Freq = SCG_CalculatePll0Freq(SCG_PLL0_CLK);
|
|
|
|
}
|
|
else if (SCG_CLOCK_SRC_SIRC == eClock)
|
|
{
|
|
eClockValid = SCG_HWA_GetClockVliad(SCG_SIRC_CLOCK_SYMBOL);
|
|
u32Freq = SIRC_CLOCK;
|
|
}
|
|
else
|
|
{
|
|
eClockValid = false;
|
|
}
|
|
|
|
if(eClockValid == false)
|
|
{
|
|
eStatusVal = SCG_STATUS_SEQUENCE_ERROR;
|
|
}
|
|
else
|
|
{
|
|
*pClockFreq = u32Freq;
|
|
|
|
if(pSysClkConfig != NULL_PTR)
|
|
{
|
|
u32FreqCore = u32Freq / ((uint8_t)pSysClkConfig->eDivCore + 1U);
|
|
u32FreqBus = u32FreqCore / ((uint8_t)pSysClkConfig->eDivBus + 1U);
|
|
u32FreqSlow = u32FreqBus / ((uint8_t)pSysClkConfig->eDivSlow + 1U);
|
|
if ((u32FreqCore > SYS_CORE_CLK_MAX) || (u32FreqBus > SYS_BUS_CLK_MAX) || (u32FreqSlow > SYS_SLOW_CLK_MAX))
|
|
{
|
|
eStatusVal = SCG_STATUS_PARAM_ERROR;
|
|
}
|
|
}
|
|
}
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Switch system clock source , and configure system clock divider if pSysClkConfig is not null.
|
|
* @details If pSysClkConfig is null , and clock switch form slow to fast(eg. FIRC to PLL0),
|
|
* the bus and slow clock may exceed the max value. So the new divider must be configured
|
|
* if the system clock is switched to a faster source.
|
|
*
|
|
* @param eClock selected clock source
|
|
* @return SCG_StatusType function status
|
|
* SCG_STATUS_SUCCESS : clock source and dividers are valid,and switch system clock successfully
|
|
* SCG_STATUS_SEQUENCE_ERROR: new clock source is not enabled
|
|
* SCG_STATUS_PARAM_ERROR: the core bus slow divider are invalid
|
|
* SCG_STATUS_TIMEOUT: switch system clock procedure time out
|
|
*/
|
|
static SCG_StatusType SCG_SwitchSystemClockWithConfig(const SCG_ClockSrcType eClock,const SCG_ClockCtrlType *const pSysClkConfig)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
uint32_t u32Timeout;
|
|
uint32_t u32CurClkFreq = 0U,u32NewClkFreq;
|
|
uint32_t u32RegValue;
|
|
uint8_t u8CurClkSrc,u8ClkSrc;
|
|
|
|
u8CurClkSrc = SCG_HWA_GetSysClkSrc();
|
|
if(u8CurClkSrc != eClock)
|
|
{
|
|
eStatusVal = SCG_CheckSystemClockSourceFreq(eClock,pSysClkConfig,&u32NewClkFreq);
|
|
|
|
if(eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* Get current system clock source frequency */
|
|
if (SCG_CLOCK_SRC_FOSC == u8CurClkSrc)
|
|
{
|
|
u32CurClkFreq = FOSC_FREQUENCY;
|
|
}
|
|
else if (SCG_CLOCK_SRC_FIRC == u8CurClkSrc)
|
|
{
|
|
u32CurClkFreq = FIRC_CLOCK;
|
|
}
|
|
else if (SCG_CLOCK_SRC_PLL0 == u8CurClkSrc)
|
|
{
|
|
u32CurClkFreq = SCG_CalculatePll0Freq(SCG_PLL0_CLK);
|
|
}
|
|
else if (SCG_CLOCK_SRC_SIRC == u8CurClkSrc)
|
|
{
|
|
u32CurClkFreq = SIRC_CLOCK;
|
|
}
|
|
else
|
|
{
|
|
/* Never come here */
|
|
}
|
|
|
|
/* To switch the system clock source from slow to fast, configure the divider first to ensure that
|
|
the core bus slow clocks do not exceed the max value */
|
|
if((pSysClkConfig != NULL_PTR) && (u32NewClkFreq > u32CurClkFreq))
|
|
{
|
|
u32RegValue = SCG_HWA_GetCCR();
|
|
u32RegValue &= ~(SCG_CCR_SYSCLK_CME_MASK | SCG_CCR_DIVCORE_MASK | SCG_CCR_DIVBUS_MASK | SCG_CCR_DIVSLOW_MASK);
|
|
u32RegValue |= (uint32_t)((uint32_t)SCG_CCR_SYSCLK_CME(pSysClkConfig->bSysClkMonitor) |
|
|
(uint32_t)SCG_CCR_DIVCORE(pSysClkConfig->eDivCore) |
|
|
(uint32_t)SCG_CCR_DIVBUS(pSysClkConfig->eDivBus) |
|
|
(uint32_t)SCG_CCR_DIVSLOW(pSysClkConfig->eDivSlow));
|
|
SCG_HWA_SetCCR(u32RegValue);
|
|
}
|
|
|
|
SCG_HWA_SetSystemClock((uint8_t)eClock);
|
|
|
|
u32Timeout = SCG_CLKSRC_STABILIZATION_TIMEOUT;
|
|
do {
|
|
u8ClkSrc = SCG_HWA_GetSysClkSrc();
|
|
--u32Timeout;
|
|
if(u32Timeout == 0U)
|
|
{
|
|
eStatusVal = SCG_STATUS_TIMEOUT;
|
|
break;
|
|
}
|
|
} while((SCG_HWA_GetSysClkUPRD() == false) && (u8ClkSrc != (uint8_t)eClock));
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* To change the system clock source from fast to slow, configure the divider after selecting the clock source,
|
|
because it is safe to divide the slow frequency with the old divider */
|
|
if((pSysClkConfig != NULL_PTR) && (u32NewClkFreq <= u32CurClkFreq))
|
|
{
|
|
u32RegValue = SCG_HWA_GetCCR();
|
|
u32RegValue &= ~(SCG_CCR_SYSCLK_CME_MASK | SCG_CCR_DIVCORE_MASK | SCG_CCR_DIVBUS_MASK | SCG_CCR_DIVSLOW_MASK);
|
|
u32RegValue |= (uint32_t)((uint32_t)SCG_CCR_SYSCLK_CME(pSysClkConfig->bSysClkMonitor) |
|
|
(uint32_t)SCG_CCR_DIVCORE(pSysClkConfig->eDivCore) |
|
|
(uint32_t)SCG_CCR_DIVBUS(pSysClkConfig->eDivBus) |
|
|
(uint32_t)SCG_CCR_DIVSLOW(pSysClkConfig->eDivSlow));
|
|
SCG_HWA_SetCCR(u32RegValue);
|
|
|
|
u32Timeout = SCG_CLKSRC_STABILIZATION_TIMEOUT;
|
|
while(SCG_HWA_GetSysClkUPRD() == false)
|
|
{
|
|
--u32Timeout;
|
|
if(u32Timeout == 0U)
|
|
{
|
|
eStatusVal = SCG_STATUS_TIMEOUT;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
return eStatusVal;
|
|
}
|
|
|
|
/***************** Global Functions *********************/
|
|
/**
|
|
* @brief Enable SOSC
|
|
*
|
|
* @param pSoscConfig SOSC configuration
|
|
* @return SCG_StatusType Function status
|
|
*/
|
|
SCG_StatusType SCG_EnableSOSC(const SCG_SoscType *const pSoscConfig)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
uint32_t u32TempVal;
|
|
|
|
DEV_ASSERT(NULL_PTR != pSoscConfig);
|
|
DEV_ASSERT(32768U == SOSC_FREQUENCY);
|
|
|
|
/* Configure SOSC */
|
|
SCG_HWA_SetSoscRecommendCfg();
|
|
|
|
/* Unlock CSR register first */
|
|
SCG_HWA_UnlockSoscCsrReg();
|
|
|
|
/* Configure SOSC CSR register */
|
|
u32TempVal = SCG_HWA_GetSoscCsr();
|
|
u32TempVal &= ~(uint32_t)(SCG_SOSCCSR_BYPASS_MASK | SCG_SOSCCSR_CM_MASK | SCG_SOSCCSR_CMRE_MASK);
|
|
u32TempVal |= SCG_SOSCCSR_BYPASS(pSoscConfig->bBypass);
|
|
SCG_HWA_SetSoscCsr(u32TempVal);
|
|
|
|
/* Enable SOSC*/
|
|
SCG_HWA_EnableSosc();
|
|
|
|
/* Wait SOSC valid */
|
|
u32TempVal = SOSC_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((false == SCG_HWA_GetClockVliad(SCG_SOSC_CLOCK_SYMBOL)), u32TempVal, eStatusVal)
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
if (pSoscConfig->bCm)
|
|
{
|
|
SCG_HWA_EnableSoscClockMonitor();
|
|
}
|
|
|
|
if (pSoscConfig->bCmre)
|
|
{
|
|
SCG_HWA_EnableSoscClockMonitorReset();
|
|
}
|
|
|
|
if (pSoscConfig->bLock)
|
|
{
|
|
/* Lock CSR */
|
|
SCG_HWA_LockSoscCsrReg();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SCG_HWA_SetSoscCsr(0U);
|
|
}
|
|
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Disable SOSC
|
|
*
|
|
* @return SCG_StatusType Function status
|
|
*/
|
|
SCG_StatusType SCG_DisableSOSC(void)
|
|
{
|
|
SCG_StatusType eStatusVal;
|
|
uint32_t u32TempVal;
|
|
|
|
/* Unlock CSR register first */
|
|
SCG_HWA_UnlockSoscCsrReg();
|
|
|
|
/* Disable SOSC */
|
|
SCG_HWA_DisableSosc();
|
|
|
|
/* Wait SOSC valid */
|
|
u32TempVal = SOSC_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((true == SCG_HWA_GetClockVliad(SCG_SOSC_CLOCK_SYMBOL)), u32TempVal, eStatusVal)
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* Clear CSR register */
|
|
SCG_HWA_SetSoscCsr(0U);
|
|
}
|
|
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Enable FOSC clock with input configuration
|
|
*
|
|
* @param pFoscConfig FOSC configuration
|
|
* @return SCG_StatusType function status
|
|
*/
|
|
SCG_StatusType SCG_EnableFOSC(const SCG_FoscType *const pFoscConfig)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
uint32_t u32TempVal,u32FoscFreq;
|
|
uint8_t u8MSBVal;
|
|
uint32_t u32DivHClockFreq = 0U;
|
|
uint32_t u32DivMClockFreq = 0U;
|
|
uint32_t u32DivLClockFreq = 0U;
|
|
uint32_t u32FoscDivEn = 0U;
|
|
|
|
DEV_ASSERT(NULL_PTR != pFoscConfig);
|
|
|
|
/* Check DIV clock frequency is valid or not */
|
|
if(pFoscConfig->eDivH != SCG_ASYNC_CLOCK_DISABLE)
|
|
{
|
|
u32DivHClockFreq = (uint32_t)FOSC_FREQUENCY >> ((uint32_t)pFoscConfig->eDivH - 1U);
|
|
u32FoscDivEn |= (uint32_t)SCG_CLOCK_DIV_H;
|
|
}
|
|
if(pFoscConfig->eDivM != SCG_ASYNC_CLOCK_DISABLE)
|
|
{
|
|
u32DivMClockFreq = (uint32_t)FOSC_FREQUENCY >> ((uint32_t)pFoscConfig->eDivM - 1U);
|
|
u32FoscDivEn |= (uint32_t)SCG_CLOCK_DIV_M;
|
|
}
|
|
if(pFoscConfig->eDivL != SCG_ASYNC_CLOCK_DISABLE)
|
|
{
|
|
u32DivLClockFreq = (uint32_t)FOSC_FREQUENCY >> ((uint32_t)pFoscConfig->eDivL - 1U);
|
|
u32FoscDivEn |= (uint32_t)SCG_CLOCK_DIV_L;
|
|
}
|
|
|
|
if ((u32DivHClockFreq > FOSC_DIVH_MAX_CLOCK) || (u32DivMClockFreq > FOSC_DIVM_MAX_CLOCK) || (u32DivLClockFreq > FOSC_DIVL_MAX_CLOCK))
|
|
{
|
|
eStatusVal = SCG_STATUS_PARAM_ERROR;
|
|
}
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* Unlock CSR register */
|
|
SCG_HWA_UnlockFoscCsrReg();
|
|
|
|
/* COMP_EN is setting to 1 COMP_EN must be 1 when using an external crystal */
|
|
/* Configure GM to the max value, GM_SEL: 15U */
|
|
u32TempVal = SCG_FOSCCFG_BYPASS(pFoscConfig->bBypass) | SCG_FOSCCFG_COMP_EN(!pFoscConfig->bBypass) |
|
|
SCG_FOSCCFG_EOCV(50U) | SCG_FOSCCFG_GM_SEL(15U) |
|
|
SCG_FOSCCFG_ALC_D(1U) | SCG_FOSCCFG_HYST_D(0U);
|
|
SCG_HWA_SetFoscCfg(u32TempVal);
|
|
|
|
/* Configure CSR register */
|
|
u32TempVal = SCG_HWA_GetFoscCsr();
|
|
u32TempVal &= ~(uint32_t)(SCG_FOSCCSR_STEN_MASK | SCG_FOSCCSR_CM_MASK | SCG_FOSCCSR_CMRE_MASK);
|
|
u32TempVal |= SCG_FOSCCSR_STEN(pFoscConfig->bSten);
|
|
SCG_HWA_SetFoscCsr(u32TempVal);
|
|
|
|
/* Configure DIV value */
|
|
SCG_HWA_DiableFoscDiv(SCG_CLOCK_DIV_ALL);
|
|
u32TempVal = SCG_HWA_GetClockDiv(SCG_FOSC_CLOCK_SYMBOL);
|
|
u32TempVal &= ~(uint32_t)(SCG_FOSCDIV_DIVL_MASK | SCG_FOSCDIV_DIVM_MASK | SCG_FOSCDIV_DIVH_MASK);
|
|
u32TempVal |= (SCG_FOSCDIV_DIVH(pFoscConfig->eDivH) | SCG_FOSCDIV_DIVM(pFoscConfig->eDivM) | SCG_FOSCDIV_DIVL(
|
|
pFoscConfig->eDivL));
|
|
SCG_HWA_SetFoscDiv(u32TempVal) ;
|
|
|
|
/* Enable FOSC */
|
|
SCG_HWA_EnableFosc();
|
|
|
|
/* Wait FOSC vaild */
|
|
u32TempVal = FOSC_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((false == SCG_HWA_GetClockVliad(SCG_FOSC_CLOCK_SYMBOL)), u32TempVal, eStatusVal)
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* Enable DIV */
|
|
SCG_HWA_EnableFoscDiv((SCG_DivEnableType)u32FoscDivEn);
|
|
|
|
if (pFoscConfig->bCm)
|
|
{
|
|
SCG_HWA_EnableFoscClockMonitor();
|
|
}
|
|
|
|
if (pFoscConfig->bCmre)
|
|
{
|
|
SCG_HWA_EnableFoscClockMonitorReset();
|
|
}
|
|
|
|
if (pFoscConfig->bLock)
|
|
{
|
|
/* Lock FOSC CSR register */
|
|
SCG_HWA_LockFoscCsrReg();
|
|
}
|
|
|
|
/* Wait DIV[ACK] change to 1 */
|
|
u32TempVal = CLOCK_DIV_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((SCG_HWA_GetFoscDivAck((SCG_DivEnableType)u32FoscDivEn) != true), u32TempVal, eStatusVal)
|
|
|
|
/* if OSC >= 40M ,set 5, if OSC = 32M,set 10, if OSC = 24M, set 15, if OSC = 16M, set 20, if OSC = 8M, set 25*/
|
|
/* This is the protection measure during low power wake up, if SCG register not valid after the setting time, the chip will reset
|
|
* and will set clock error flag in RGM register */
|
|
u32FoscFreq = FOSC_FREQUENCY;
|
|
u8MSBVal = ((u32FoscFreq / 8000000U) >= 5U) ? (uint8_t)5U : (uint8_t)((6U - (FOSC_FREQUENCY / 8000000U)) * 5U);
|
|
SCG_HWA_SetWKPWDG(u8MSBVal);
|
|
}
|
|
else
|
|
{
|
|
/* Clear CSR configuration */
|
|
SCG_HWA_SetFoscCsr(0U);
|
|
|
|
/* Clear CFG configuration*/
|
|
SCG_HWA_SetFoscCfg(0U);
|
|
|
|
/* Clear DIV configuration*/
|
|
SCG_HWA_SetFoscDiv(0U);
|
|
}
|
|
}
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Disable FOSC
|
|
*
|
|
* @return SCG_StatusType function status
|
|
*/
|
|
SCG_StatusType SCG_DisableFOSC(void)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
uint32_t u32TempVal;
|
|
uint8_t u8ClkSrc;
|
|
|
|
u8ClkSrc = SCG_HWA_GetSysClkSrc();
|
|
if ((uint8_t)SCG_CLOCK_SRC_FOSC == u8ClkSrc)
|
|
{
|
|
eStatusVal = SCG_STATUS_SEQUENCE_ERROR;
|
|
}
|
|
else if ((SCG_HWA_GetPllSrc(SCG_PLL0_CLOCK_SYMBOL) == (uint8_t)SCG_PLLSOURCE_FOSC) && ((uint8_t)SCG_CLOCK_SRC_PLL0 == u8ClkSrc))
|
|
{
|
|
eStatusVal = SCG_STATUS_SEQUENCE_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* do nothing */
|
|
}
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* Unlock CSR register */
|
|
SCG_HWA_UnlockFoscCsrReg();
|
|
|
|
/* Clear FOSC[EN] bit */
|
|
SCG_HWA_DisableFosc();
|
|
|
|
u32TempVal = CLOCK_OFF_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((true == SCG_HWA_GetClockVliad(SCG_FOSC_CLOCK_SYMBOL)), u32TempVal, eStatusVal)
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* Clear CSR register */
|
|
SCG_HWA_SetFoscCsr(0U);
|
|
|
|
/* In order to avoid the DIV register value not cleared, Clear FOSC DIV register twice */
|
|
SCG_HWA_SetFoscDiv(0U);
|
|
SCG_HWA_SetFoscDiv(0U);
|
|
}
|
|
}
|
|
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Set SIRC configuration and configure SIRC DIV
|
|
*
|
|
* @param pSircConfig SIRC configuration
|
|
* @return SCG_StatusType function status
|
|
*/
|
|
SCG_StatusType SCG_SetSIRC(const SCG_SircType *const pSircConfig)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
uint32_t u32TempVal;
|
|
uint32_t u32SircDivEn = 0U;
|
|
uint16_t u16TrimDiv = 0U;
|
|
|
|
DEV_ASSERT(NULL_PTR != pSircConfig);
|
|
DEV_ASSERT(pSircConfig->eDivH <= (uint32_t)SCG_ASYNCCLOCKDIV_BY64);
|
|
DEV_ASSERT(pSircConfig->eDivM <= (uint32_t)SCG_ASYNCCLOCKDIV_BY64);
|
|
DEV_ASSERT(pSircConfig->eDivL <= (uint32_t)SCG_ASYNCCLOCKDIV_BY64);
|
|
|
|
/* Unlock SIRC CSR register */
|
|
SCG_HWA_UnlockSircCsrReg();
|
|
|
|
/* Configure CSR register */
|
|
u32TempVal = SCG_HWA_GetSircCsr();
|
|
u32TempVal &= ~(uint32_t)(SCG_SIRCCSR_STEN_MASK | SCG_SIRCCSR_LPEN_MASK | SCG_SIRCCSR_TREN_MASK | SCG_SIRCCSR_TRUP_MASK | SCG_SIRCCSR_CM_MASK);
|
|
u32TempVal |= (uint32_t)(SCG_SIRCCSR_TRUP(pSircConfig->bTrEn) | SCG_SIRCCSR_TREN(pSircConfig->bTrEn) | SCG_SIRCCSR_LPEN(pSircConfig->bLpen) | SCG_SIRCCSR_STEN(pSircConfig->bSten));
|
|
SCG_HWA_SetSircCsr(u32TempVal);
|
|
|
|
/* Disable SIRC DIV[EN] bit */
|
|
SCG_HWA_DiableSircDiv(SCG_CLOCK_DIV_ALL);
|
|
|
|
if (pSircConfig->bCm)
|
|
{
|
|
SCG_HWA_EnableSircClockMonitor();
|
|
}
|
|
|
|
if (pSircConfig->bLock)
|
|
{
|
|
/* lock CSR */
|
|
SCG_HWA_LockSircCsrReg();
|
|
}
|
|
|
|
/* Configure SIRC DIV */
|
|
u32TempVal = SCG_HWA_GetClockDiv(SCG_SIRC_CLOCK_SYMBOL);
|
|
u32TempVal &= ~(uint32_t)(SCG_SIRCDIV_DIVL_MASK | SCG_SIRCDIV_DIVM_MASK | SCG_SIRCDIV_DIVH_MASK);
|
|
u32TempVal |= (uint32_t)(SCG_SIRCDIV_DIVL(pSircConfig->eDivL) | SCG_SIRCDIV_DIVM(pSircConfig->eDivM) | SCG_SIRCDIV_DIVH(
|
|
pSircConfig->eDivH));
|
|
SCG_HWA_SetSircDiv(u32TempVal);
|
|
|
|
/* Enable SIRC DIV */
|
|
u32SircDivEn |= (pSircConfig->eDivH != SCG_ASYNC_CLOCK_DISABLE) ? (uint32_t)SCG_CLOCK_DIV_H : 0U;
|
|
u32SircDivEn |= (pSircConfig->eDivM != SCG_ASYNC_CLOCK_DISABLE) ? (uint32_t)SCG_CLOCK_DIV_M : 0U;
|
|
u32SircDivEn |= (pSircConfig->eDivL != SCG_ASYNC_CLOCK_DISABLE) ? (uint32_t)SCG_CLOCK_DIV_L : 0U;
|
|
SCG_HWA_EnableSircDiv((SCG_DivEnableType)u32SircDivEn);
|
|
u32TempVal = CLOCK_DIV_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((SCG_HWA_GetSircDivAck((SCG_DivEnableType)u32SircDivEn) != true), u32TempVal, eStatusVal)
|
|
|
|
if (SCG_STATUS_SUCCESS != eStatusVal)
|
|
{
|
|
/* Clear SIRC DIV register */
|
|
SCG_HWA_SetSircDiv(0U);
|
|
}
|
|
|
|
/* Set SIRCTCFG register */
|
|
if (pSircConfig->bTrEn == true)
|
|
{
|
|
/* set SIRCTCFG trim configuration */
|
|
if (pSircConfig->u8TrimSrc == (uint8_t)SCG_IRC_TRIMSRC_FOSC)
|
|
{
|
|
/* Trim clock source choose FOSC */
|
|
u16TrimDiv = (uint16_t)(FOSC_FREQUENCY / 250000U - 1U);
|
|
}
|
|
else if (pSircConfig->u8TrimSrc == (uint8_t)SCG_IRC_TRIMSRC_SOSC)
|
|
{
|
|
/* Trim clock source choose SOSC */
|
|
u16TrimDiv = 0U;
|
|
}
|
|
else
|
|
{
|
|
/* Do nothing */
|
|
}
|
|
u32TempVal = (uint32_t)(SCG_SIRCTCFG_TRIMSRC(pSircConfig->u8TrimSrc) | SCG_SIRCTCFG_TRIMDIV(u16TrimDiv));
|
|
SCG_HWA_SetSircTcfg(u32TempVal);
|
|
}
|
|
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Disable SIRC DIV and clear DIV configuration
|
|
*
|
|
* @return SCG_StatusType function status
|
|
*/
|
|
SCG_StatusType SCG_ClearSIRC(void)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
|
|
/* check SIRC is invalid, if invalid, do not configure SIRC */
|
|
if (true != SCG_HWA_GetClockVliad(SCG_SIRC_CLOCK_SYMBOL))
|
|
{
|
|
eStatusVal = SCG_STATUS_SEQUENCE_ERROR;
|
|
}
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* Unlock SIRC CSR register */
|
|
SCG_HWA_UnlockSircCsrReg();
|
|
|
|
/* Disable SIRC DIV[EN] bit */
|
|
SCG_HWA_DiableSircDiv(SCG_CLOCK_DIV_ALL);
|
|
|
|
/* Clear SIRC DIV register */
|
|
SCG_HWA_SetSircDiv(0U);
|
|
}
|
|
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Enable SIRC32K
|
|
*
|
|
* @param pSirc32kConfig SIRC32K configuration
|
|
* @return SCG_StatusType function status
|
|
*/
|
|
SCG_StatusType SCG_EnableSIRC32K(const SCG_Sirc32kType *const pSirc32kConfig)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
uint32_t u32TempVal;
|
|
|
|
DEV_ASSERT(NULL_PTR != pSirc32kConfig);
|
|
|
|
/* Unlock SIRC32K CSR register */
|
|
SCG_HWA_UnlockSirc32kCsrReg();
|
|
|
|
/* Enable SIRC32K */
|
|
SCG_HWA_EnableSirc32kCsr();
|
|
|
|
/* Wait SIRC32K valid */
|
|
u32TempVal = SIRC_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((false == SCG_HWA_GetClockVliad(SCG_SIRC32K_CLOCK_SYMBOL)), u32TempVal, eStatusVal)
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
if (pSirc32kConfig->bLock)
|
|
{
|
|
/* Lock SIRC32K CSR register */
|
|
SCG_HWA_LockSirc32kCsrReg();
|
|
}
|
|
}
|
|
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Disable SIRC32K
|
|
*
|
|
* @return SCG_StatusType function status
|
|
*/
|
|
SCG_StatusType SCG_DisableSIRC32K(void)
|
|
{
|
|
SCG_StatusType eStatusVal;
|
|
uint32_t u32TempVal;
|
|
|
|
/* Unlock SIRC32K CSR register */
|
|
SCG_HWA_UnlockSirc32kCsrReg();
|
|
|
|
/* Disable SIRC32K */
|
|
SCG_HWA_DisableSirc32kCsr();
|
|
|
|
/* Wait SIRC32K not valid */
|
|
u32TempVal = SIRC_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((true == SCG_HWA_GetClockVliad(SCG_SIRC32K_CLOCK_SYMBOL)), u32TempVal, eStatusVal)
|
|
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Enable FIRC
|
|
*
|
|
* @param pFircConfig FIRC configuration
|
|
* @return SCG_StatusType function status
|
|
*/
|
|
SCG_StatusType SCG_EnableFIRC(const SCG_FircType *const pFircConfig)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
uint32_t u32TempVal, u32DivLClockFreq = 0U;
|
|
uint32_t u32FircDivEn = 0U;
|
|
uint16_t u16TrimDiv = 0U;
|
|
|
|
DEV_ASSERT(NULL_PTR != pFircConfig);
|
|
DEV_ASSERT(pFircConfig->eDivH <= (uint32_t)SCG_ASYNCCLOCKDIV_BY64);
|
|
DEV_ASSERT(pFircConfig->eDivM <= (uint32_t)SCG_ASYNCCLOCKDIV_BY64);
|
|
DEV_ASSERT(pFircConfig->eDivL <= (uint32_t)SCG_ASYNCCLOCKDIV_BY64);
|
|
|
|
/* Check DIV clock frequency is valid or not */
|
|
if(pFircConfig->eDivL != SCG_ASYNC_CLOCK_DISABLE)
|
|
{
|
|
u32DivLClockFreq = (uint32_t)(FIRC_CLOCK >> (pFircConfig->eDivL - 1));
|
|
u32FircDivEn |= (uint32_t)SCG_CLOCK_DIV_L;
|
|
}
|
|
if (u32DivLClockFreq > FIRC_DIVL_MAX_CLOCK)
|
|
{
|
|
eStatusVal = SCG_STATUS_PARAM_ERROR;
|
|
}
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* Unlock CSR register */
|
|
SCG_HWA_UnlockFircCsrReg();
|
|
|
|
/* Configure recommend value */
|
|
SCG_HWA_SetFircCfg(SCG_FIRCCFG_CLKEN(3U));
|
|
|
|
/* Configure CSR register */
|
|
u32TempVal = SCG_HWA_GetFircCsr();
|
|
u32TempVal &= ~(uint32_t)(SCG_FIRCCSR_STEN_MASK | SCG_FIRCCSR_TREN_MASK | SCG_FIRCCSR_TRUP_MASK | SCG_FIRCCSR_CM_MASK);
|
|
u32TempVal |= (uint32_t)(SCG_FIRCCSR_TRUP(pFircConfig->bTrEn) | /* configure TRUP and EN together with TREN setting */
|
|
SCG_FIRCCSR_TREN(pFircConfig->bTrEn) |
|
|
SCG_FIRCCSR_STEN(pFircConfig->bSten));
|
|
SCG_HWA_SetFircCsr(u32TempVal);
|
|
|
|
/* Configure DIV value */
|
|
SCG_HWA_DiableFircDiv(SCG_CLOCK_DIV_ALL);
|
|
u32TempVal = SCG_HWA_GetClockDiv(SCG_FIRC_CLOCK_SYMBOL);
|
|
u32TempVal &= ~(uint32_t)(SCG_FIRCDIV_DIVL_MASK | SCG_FIRCDIV_DIVM_MASK | SCG_FIRCDIV_DIVH_MASK);
|
|
u32TempVal |= (SCG_FIRCDIV_DIVH(pFircConfig->eDivH) | SCG_FIRCDIV_DIVM(pFircConfig->eDivM) | SCG_FIRCDIV_DIVL(
|
|
pFircConfig->eDivL));
|
|
SCG_HWA_SetFircDiv(u32TempVal) ;
|
|
|
|
/* Set CSR[EN] bit to 1 */
|
|
SCG_HWA_EnableFirc();
|
|
|
|
/* Wait FIRC valid */
|
|
u32TempVal = FIRC_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((false == SCG_HWA_GetClockVliad(SCG_FIRC_CLOCK_SYMBOL)), u32TempVal, eStatusVal)
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
if (pFircConfig->bCm)
|
|
{
|
|
SCG_HWA_EnableFircClockMonitor();
|
|
}
|
|
|
|
if (pFircConfig->bLock)
|
|
{
|
|
/* lock CSR register */
|
|
SCG_HWA_LockFircCsrReg();
|
|
}
|
|
|
|
/* Enable DIV */
|
|
u32FircDivEn |= (pFircConfig->eDivH != SCG_ASYNC_CLOCK_DISABLE) ? (uint32_t)SCG_CLOCK_DIV_H : 0U;
|
|
u32FircDivEn |= (pFircConfig->eDivM != SCG_ASYNC_CLOCK_DISABLE) ? (uint32_t)SCG_CLOCK_DIV_M : 0U;
|
|
SCG_HWA_EnableFircDiv((SCG_DivEnableType)u32FircDivEn);
|
|
|
|
/* Wait DIV[ACK] change to 1 */
|
|
u32TempVal = CLOCK_DIV_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((SCG_HWA_GetSircDivAck((SCG_DivEnableType)u32FircDivEn) != true), u32TempVal, eStatusVal)
|
|
|
|
/* For clock auto trim, set TREN to True together with TRUP to True */
|
|
if (pFircConfig->bTrEn == true)
|
|
{
|
|
/* set FIRCTCFG trim configuration */
|
|
if (pFircConfig->u8TrimSrc == (uint8_t)SCG_IRC_TRIMSRC_FOSC)
|
|
{
|
|
/* Trim clock source choose FOSC */
|
|
u16TrimDiv = (uint16_t)(FOSC_FREQUENCY / 250000U - 1U);
|
|
}
|
|
else if (pFircConfig->u8TrimSrc == (uint8_t)SCG_IRC_TRIMSRC_SOSC)
|
|
{
|
|
/* Trim clock source choose SOSC */
|
|
u16TrimDiv = 0U;
|
|
}
|
|
else
|
|
{
|
|
/* do nothing */
|
|
}
|
|
u32TempVal = (uint32_t)(SCG_FIRCTCFG_TRIMSRC(pFircConfig->u8TrimSrc) | SCG_FIRCTCFG_TRIMDIV(u16TrimDiv));
|
|
SCG_HWA_SetFircTcfg(u32TempVal);
|
|
}
|
|
else
|
|
{
|
|
/* Trim disabled, just using IC internal IRC trim value */
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
/* Clear CSR configuration */
|
|
SCG_HWA_SetFircCsr(0U);
|
|
|
|
/* Clear DIV configuration*/
|
|
SCG_HWA_SetFircDiv(0U);
|
|
}
|
|
}
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Disable FIRC
|
|
*
|
|
* @return SCG_StatusType function status
|
|
*/
|
|
SCG_StatusType SCG_DisableFIRC(void)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
uint32_t u32TempVal;
|
|
uint8_t u8ClkSrc;
|
|
|
|
u8ClkSrc = SCG_HWA_GetSysClkSrc();
|
|
if ((uint8_t)SCG_CLOCK_SRC_FIRC == u8ClkSrc)
|
|
{
|
|
eStatusVal = SCG_STATUS_SEQUENCE_ERROR;
|
|
}
|
|
else if ((SCG_HWA_GetPllSrc(SCG_PLL0_CLOCK_SYMBOL) == (uint8_t)SCG_PLLSOURCE_FIRC) && ((uint8_t)SCG_CLOCK_SRC_PLL0 == u8ClkSrc))
|
|
{
|
|
eStatusVal = SCG_STATUS_SEQUENCE_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* do nothing */
|
|
}
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* Unlock CSR register */
|
|
SCG_HWA_UnlockFircCsrReg();
|
|
|
|
/* Disable FIRC */
|
|
SCG_HWA_DisableFirc();
|
|
|
|
/* Wait FIRC not valid */
|
|
u32TempVal = FIRC_STABILIZATION_TIMEOUT;
|
|
SCG_CheckClockAckStatus((true == SCG_HWA_GetClockVliad(SCG_FIRC_CLOCK_SYMBOL)), u32TempVal, eStatusVal)
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
/* Clear CSR register */
|
|
SCG_HWA_SetFircCsr(0U);
|
|
|
|
/* In order to avoid the DIV register value not cleared, Clear FIRC DIV register twice */
|
|
SCG_HWA_SetFircDiv(0U);
|
|
SCG_HWA_SetFircDiv(0U);
|
|
}
|
|
}
|
|
return eStatusVal;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Enable PLL
|
|
*
|
|
* @param ePLL PLL instance
|
|
* @param pPllConfig PLL configuration
|
|
* @return SCG_StatusType function status
|
|
*/
|
|
SCG_StatusType SCG_EnablePLL(const SCG_PllClkType ePll, const SCG_PllType *const pPllConfig)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
|
|
DEV_ASSERT(NULL_PTR != pPllConfig);
|
|
DEV_ASSERT(((ePll == SCG_PLL0) || (ePll == SCG_PLL1)));
|
|
DEV_ASSERT(((pPllConfig->eSrc == SCG_PLLSOURCE_FOSC) || (pPllConfig->eSrc == SCG_PLLSOURCE_FIRC)));
|
|
DEV_ASSERT((pPllConfig->u16Mult > 95U) && (pPllConfig->u16Mult < 512U));
|
|
DEV_ASSERT(pPllConfig->u8Prediv < 32U);
|
|
DEV_ASSERT(pPllConfig->u8Prediv != 2U);
|
|
DEV_ASSERT((pPllConfig->ePstDiv == SCG_PLLPSTDIV_BY2) ||
|
|
(pPllConfig->ePstDiv == SCG_PLLPSTDIV_BY4) ||
|
|
(pPllConfig->ePstDiv == SCG_PLLPSTDIV_BY8));
|
|
DEV_ASSERT(pPllConfig->eDivH <= (uint32_t)SCG_ASYNCCLOCKDIV_BY64);
|
|
DEV_ASSERT(pPllConfig->eDivM <= (uint32_t)SCG_ASYNCCLOCKDIV_BY64);
|
|
DEV_ASSERT(pPllConfig->eDivL <= (uint32_t)SCG_ASYNCCLOCKDIV_BY64);
|
|
|
|
|
|
if ((true != SCG_HWA_GetClockVliad(SCG_FOSC_CLOCK_SYMBOL)) && (SCG_PLLSOURCE_FOSC == pPllConfig->eSrc))
|
|
{
|
|
eStatusVal = SCG_STATUS_SEQUENCE_ERROR;
|
|
}
|
|
else if ((true != SCG_HWA_GetClockVliad(SCG_FIRC_CLOCK_SYMBOL)) && (SCG_PLLSOURCE_FIRC == pPllConfig->eSrc))
|
|
{
|
|
eStatusVal = SCG_STATUS_SEQUENCE_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* do nothing */
|
|
}
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
if (SCG_PLL0 == ePll)
|
|
{
|
|
eStatusVal = SCG_EnablePLL0(pPllConfig);
|
|
}
|
|
else if (SCG_PLL1 == ePll)
|
|
{
|
|
eStatusVal = SCG_EnablePLL1(pPllConfig);
|
|
}
|
|
else
|
|
{
|
|
/* do nothing */
|
|
}
|
|
}
|
|
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Disable PLL
|
|
*
|
|
* @param ePll PLL instance
|
|
* @return SCG_StatusType function status
|
|
*/
|
|
SCG_StatusType SCG_DisablePLL(const SCG_PllClkType ePll)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
|
|
if (SCG_PLL0 == ePll)
|
|
{
|
|
if (SCG_HWA_GetSysClkSrc() == (uint8_t)SCG_CLOCK_SRC_PLL0)
|
|
{
|
|
eStatusVal = SCG_STATUS_SEQUENCE_ERROR;
|
|
}
|
|
else
|
|
{
|
|
eStatusVal = SCG_DisablePLL0();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* (SCG_PLL1 == ePll) */
|
|
eStatusVal = SCG_DisablePLL1();
|
|
}
|
|
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Set system run time clock and related CORE/BUS/SLOW clock.
|
|
*
|
|
* @param pSysClkConfig pointer to the clockCtrlType structure data instance,which defined for system clock selection.
|
|
* @return SCG_StatusType function status
|
|
* SCG_STATUS_SUCCESS : clock source and dividers are valid,and switch system clock successfully
|
|
* SCG_STATUS_SEQUENCE_ERROR: new clock source is not enabled
|
|
* SCG_STATUS_PARAM_ERROR: the core bus slow divider are invalid
|
|
* SCG_STATUS_TIMEOUT: switch system clock procedure time out
|
|
*/
|
|
SCG_StatusType SCG_SetClkCtrl(const SCG_ClockCtrlType *const pSysClkConfig)
|
|
{
|
|
DEV_ASSERT(NULL_PTR != pSysClkConfig);
|
|
|
|
return SCG_SwitchSystemClockWithConfig(pSysClkConfig->eSrc,pSysClkConfig);
|
|
}
|
|
|
|
/**
|
|
* @brief Get clock frequency
|
|
*
|
|
* @param eScgClockName Clock source type
|
|
* @return uint32_t frequency value
|
|
*/
|
|
uint32_t SCG_GetScgClockFreq(const SCG_ClkSrcType eScgClockName)
|
|
{
|
|
uint32_t u32Freq;
|
|
DEV_ASSERT(eScgClockName < SCG_END_OF_CLOCKS);
|
|
|
|
if ((SCG_CORE_CLK == eScgClockName) ||
|
|
(SCG_BUS_CLK == eScgClockName) ||
|
|
(SCG_SLOW_CLK == eScgClockName))
|
|
{
|
|
u32Freq = SCG_CalculateSystemFreq(eScgClockName);
|
|
}
|
|
else if ((SCG_SIRC_CLK == eScgClockName) ||
|
|
(SCG_SIRCDIVH_CLK == eScgClockName) ||
|
|
(SCG_SIRCDIVM_CLK == eScgClockName) ||
|
|
(SCG_SIRCDIVL_CLK == eScgClockName))
|
|
{
|
|
u32Freq = SCG_CalculateSircFreq(eScgClockName);
|
|
}
|
|
else if ((SCG_FIRC_CLK == eScgClockName) ||
|
|
(SCG_FIRCDIVH_CLK == eScgClockName) ||
|
|
(SCG_FIRCDIVM_CLK == eScgClockName) ||
|
|
(SCG_FIRCDIVL_CLK == eScgClockName))
|
|
{
|
|
u32Freq = SCG_CalculateFircFreq(eScgClockName);
|
|
}
|
|
else if ((SCG_FOSC_CLK == eScgClockName) ||
|
|
(SCG_FOSCDIVH_CLK == eScgClockName) ||
|
|
(SCG_FOSCDIVM_CLK == eScgClockName) ||
|
|
(SCG_FOSCDIVL_CLK == eScgClockName))
|
|
{
|
|
u32Freq = SCG_CalculateFoscFreq(eScgClockName);
|
|
}
|
|
else if ((SCG_PLL0_CLK == eScgClockName) ||
|
|
(SCG_PLL0DIVH_CLK == eScgClockName) ||
|
|
(SCG_PLL0DIVM_CLK == eScgClockName) ||
|
|
(SCG_PLL0DIVL_CLK == eScgClockName))
|
|
{
|
|
u32Freq = SCG_CalculatePll0Freq(eScgClockName);
|
|
}
|
|
else if ((SCG_PLL1_CLK == eScgClockName) ||
|
|
(SCG_PLL1DIVH_CLK == eScgClockName) ||
|
|
(SCG_PLL1DIVM_CLK == eScgClockName) ||
|
|
(SCG_PLL1DIVL_CLK == eScgClockName))
|
|
{
|
|
u32Freq = SCG_CalculatePll1Freq(eScgClockName);
|
|
}
|
|
else if (SCG_SIRC32K_CLK == eScgClockName)
|
|
{
|
|
u32Freq = SIRC32K_CLOCK;
|
|
}
|
|
else if (SCG_SOSC_CLK == eScgClockName)
|
|
{
|
|
u32Freq = SOSC_FREQUENCY;
|
|
}
|
|
else if (SCG_SCG_CLKOUT_CLK == eScgClockName)
|
|
{
|
|
u32Freq = SCG_CalculateClkOutFreq();
|
|
}
|
|
else if(SCG_NVMINIT_CLK == eScgClockName)
|
|
{
|
|
u32Freq = NVM_CLOCK;
|
|
}
|
|
else if(SCG_CMU4REF_CLK == eScgClockName)
|
|
{
|
|
u32Freq = SCG_CalculateCMU4RefFreq();
|
|
}
|
|
else
|
|
{
|
|
u32Freq = UNKNOWN_CLOCK;
|
|
}
|
|
|
|
if (UNKNOWN_CLOCK == u32Freq)
|
|
{
|
|
u32Freq = 0U;
|
|
}
|
|
|
|
return u32Freq;
|
|
}
|
|
|
|
/**
|
|
* @brief Select clock out source
|
|
*
|
|
* @param eClkoutSel clock out source
|
|
*/
|
|
void SCG_SetClkOut(const SCG_ClockoutSrcType eClkoutSel)
|
|
{
|
|
DEV_ASSERT(eClkoutSel <= SCG_CLOCKOUT_SRC_SIRC32K);
|
|
|
|
SCG_HWA_SetClkOutSel((uint8_t)eClkoutSel);
|
|
}
|
|
|
|
/**
|
|
* @brief Select NVM clock source
|
|
*
|
|
* @param eNvmClkSrc NVM clock source
|
|
* @return uint32_t function status
|
|
*/
|
|
SCG_StatusType SCG_SetNvmClk(const SCG_NvmClkSrcType eNvmClkSrc)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
DEV_ASSERT((eNvmClkSrc == SCG_NVMCLK_SRC_SIRC) || (eNvmClkSrc == SCG_NVMCLK_SRC_FIRC));
|
|
|
|
if ((true != SCG_HWA_GetClockVliad(SCG_FIRC_CLOCK_SYMBOL)) && (eNvmClkSrc == SCG_NVMCLK_SRC_FIRC))
|
|
{
|
|
eStatusVal = SCG_STATUS_SEQUENCE_ERROR;
|
|
}
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
SCG_HWA_SetNvmClk(((uint32_t)1U << eNvmClkSrc));
|
|
}
|
|
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Select CMU4 clock source
|
|
*
|
|
* @param eCmu4ClkSrc CMU4 clock source
|
|
* @return SCG_StatusType function status
|
|
*/
|
|
SCG_StatusType SCG_SetCmu4Clk(const SCG_Cmu4ClkSrcType eCmu4ClkSrc)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
DEV_ASSERT((eCmu4ClkSrc == SCG_CMU4CLK_SRC_SIRC) || (eCmu4ClkSrc == SCG_CMU4CLK_SRC_FOSC));
|
|
|
|
if ((true != SCG_HWA_GetClockVliad(SCG_FOSC_CLOCK_SYMBOL)) && (eCmu4ClkSrc == SCG_CMU4CLK_SRC_FOSC))
|
|
{
|
|
eStatusVal = SCG_STATUS_SEQUENCE_ERROR;
|
|
}
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
SCG_HWA_SetCmu4Clk(((uint32_t)1U << eCmu4ClkSrc));
|
|
}
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Generate the origion SCG register CRC result, and configure the SCG register CRC option.
|
|
*
|
|
* @param eMode The SCG register CRC trigger mode
|
|
* @return CRC configure status
|
|
* SCG_STATUS_SUCCESS : CRC configure successfully
|
|
* SCG_STATUS_TIMEOUT : CRC configure time out
|
|
*/
|
|
SCG_StatusType SCG_RegCrcConfig(SCG_CrcModeType eMode)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
uint32_t u32Timeout = 0xFFFFU;
|
|
|
|
DEV_ASSERT((eMode == SCG_CRC_SW_MODE) || (eMode == SCG_CRC_TRIGGER_MODE));
|
|
|
|
/* Deinit CRC register */
|
|
SCG_HWA_DisableCrcCheck();
|
|
SCG_HWA_DisableCrcTriggerMode();
|
|
SCG_HWA_DisableCrcErrorOutput();
|
|
SCG_HWA_ClearCrcErrorFlag();
|
|
|
|
/* Generate original CRC result */
|
|
SCG_HWA_GenCrcVal();
|
|
while (SCG_HWA_GetCrcBusyStatus() == true)
|
|
{
|
|
u32Timeout--;
|
|
if (u32Timeout == 0U)
|
|
{
|
|
eStatusVal = SCG_STATUS_TIMEOUT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (eStatusVal == SCG_STATUS_SUCCESS)
|
|
{
|
|
if (eMode == SCG_CRC_TRIGGER_MODE)
|
|
{
|
|
SCG_HWA_EnableCrcTriggerMode();
|
|
}
|
|
|
|
/* Enable SCG CRC error to FCSMU in CSC0_SMU_CTRL4[SCG_CRC] */
|
|
CSC0_HWA_CTRL4_EnableReqToSMU(CSC_SMU_SCG_CRC);
|
|
/* Generate CRC error output */
|
|
SCG_HWA_EnableCrcErrorOutput();
|
|
/* Generate CRC check */
|
|
SCG_HWA_EnableCrcCheck();
|
|
}
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Trigger the SCG register CRC generation by software
|
|
*
|
|
*/
|
|
void SCG_RegCrcGenerate(void)
|
|
{
|
|
SCG_HWA_GenCrcVal();
|
|
}
|
|
|
|
/**
|
|
* @brief Trigger the SCG register CRC generation by software,and wait the CRC check result
|
|
*
|
|
* @return CRC check result
|
|
*/
|
|
SCG_CrcCheckResType SCG_RegCrcGenerateWaitResult(void)
|
|
{
|
|
SCG_CrcCheckResType eStatusVal = SCG_CRC_CHECK_SUCCESS;
|
|
uint32_t u32Timeout = 0xFFFFU;
|
|
|
|
SCG_HWA_GenCrcVal();
|
|
while (SCG_HWA_GetCrcBusyStatus() == true)
|
|
{
|
|
u32Timeout--;
|
|
if (u32Timeout == 0U)
|
|
{
|
|
eStatusVal = SCG_CRC_GEN_TIMEOUT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Check CRC is success or not */
|
|
if (SCG_HWA_GetCrcErrorStatus())
|
|
{
|
|
eStatusVal = SCG_CRC_CHECK_FAILED;
|
|
}
|
|
|
|
return eStatusVal;
|
|
}
|
|
|
|
/**
|
|
* @brief Clock source De-init
|
|
*
|
|
* @return SCG_StatusType function status
|
|
*/
|
|
SCG_StatusType SCG_Deinit(void)
|
|
{
|
|
SCG_StatusType eStatusVal = SCG_STATUS_SUCCESS;
|
|
SCG_FircType tFircCfg =
|
|
{
|
|
.bLock = false,
|
|
.bCm = false,
|
|
.bTrEn = false,
|
|
.bSten = false,
|
|
.u8TrimSrc = 0U,
|
|
.eDivL = SCG_ASYNCCLOCKDIV_BY4,
|
|
.eDivM = SCG_ASYNCCLOCKDIV_BY2,
|
|
.eDivH = SCG_ASYNCCLOCKDIV_BY1
|
|
};
|
|
|
|
if (SCG_HWA_GetSysClkSrc() != (uint8_t)SCG_CLOCK_SRC_FIRC)
|
|
{
|
|
eStatusVal = SCG_SwitchSystemClockWithConfig(SCG_CLOCK_SRC_FIRC,NULL_PTR);
|
|
if (SCG_STATUS_SEQUENCE_ERROR == eStatusVal)
|
|
{
|
|
eStatusVal = SCG_EnableFIRC(&tFircCfg);
|
|
if (SCG_STATUS_TIMEOUT != eStatusVal)
|
|
{
|
|
eStatusVal = SCG_SwitchSystemClockWithConfig(SCG_CLOCK_SRC_FIRC,NULL_PTR);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SCG_STATUS_SUCCESS == eStatusVal)
|
|
{
|
|
/* Disable all clock source */
|
|
(void)SCG_DisablePLL(SCG_PLL1);
|
|
(void)SCG_DisablePLL(SCG_PLL0);
|
|
(void)SCG_DisableFOSC();
|
|
(void)SCG_DisableSOSC();
|
|
(void)SCG_DisableSIRC32K();
|
|
}
|
|
|
|
return eStatusVal;
|
|
}
|
|
|