PeripheralDriver_Flagchip_F.../Src/fc7xxx_driver_cmu.c

387 lines
11 KiB
C

/**
* @file fc7xxx_driver_cmu.c
* @author Flagchip085
* @brief FC7xxx CMU 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_cmu.h"
#include "fc7xxx_driver_scg.h"
#include "fc7xxx_driver_csc.h"
#include "HwA_cmu.h"
#define CMU_MULTIPLY_FACTOR 100U
#define CMU_PERCENT_FACTOR 100U
#define CMU_DIVID_FACTOR_1K 1000U
/** @brief CMU Reference clock div type. */
/**
* @brief Defines the CMU_ClkFrequenceType
*
* This structure is used to configure the CMU frequence include Reference clock and monitor clock
*
*/
typedef struct
{
uint32_t u32RefClk; /*!< The Reference clock frequence */
uint32_t u32MonitorClk; /*!< The target monitored clock frequence. */
} CMU_ClkFrequenceType;
typedef struct
{
uint32_t u32RefWindow; /*!< CMU_REF_WINDOW (Reference Window). */
uint32_t u32IdealMonitorCnts; /*!< Ideal monitor counter value, used to calculate the MIN,Max threshold. */
uint32_t u32MinThreshold; /*!< CMU_MIN (Minimum threshold). */
uint32_t u32MaxThreshold; /*!< CMU_MAX (Maximum threshold). */
uint32_t u32PerWindow; /*!< CMU_PERIOD (Period monitor mode configuration). */
} CMU_RegMapType;
static CMU_Type *const s_apCmuBase[CMU_INSTANCE_COUNT] = CMU_BASE_PTRS;
static CMU_ISRCallbackType s_apCmuISRCallback[CMU_INSTANCE_COUNT] = {NULL};
void CMU0_IRQHandler(void);
void CMU1_IRQHandler(void);
void CMU2_IRQHandler(void);
void CMU3_IRQHandler(void);
void CMU4_IRQHandler(void);
/* Check Reference clock and monitor clock status.*/
static CMU_StatusType CMU_ClkStatusCheck(CMU_InstanceType eInstance, CMU_ClkFrequenceType *ptCmuFreq)
{
CSC_RetStatusType bCscClkStatus;
CMU_StatusType bCmuClkStatus = CMU_VALID;
if (eInstance == CMU_INSTANCE_0)
{
/* Instance ---- Reference CLK ---- Monitored CLK.*/
/* CMU0 ---- SIRC ---- RTC_CLK.*/
ptCmuFreq->u32RefClk = SCG_GetScgClockFreq(SCG_SIRC_CLK);
bCscClkStatus = CSC0_GetCSC0ClockFreq(CSC0_RTC_CLK, &(ptCmuFreq->u32MonitorClk));
if (bCscClkStatus != CSC_E_OK)
{
bCmuClkStatus = CMU_CLK_ERROR;
}
}
else if (eInstance == CMU_INSTANCE_1)
{
/* Instance ---- Reference CLK ---- Monitored CLK.*/
/* CMU1 ---- SIRC ---- FOSC.*/
ptCmuFreq->u32RefClk = SCG_GetScgClockFreq(SCG_SIRC_CLK);
ptCmuFreq->u32MonitorClk = SCG_GetScgClockFreq(SCG_FOSC_CLK);
}
else if (eInstance == CMU_INSTANCE_2)
{
/* Instance ---- Reference CLK ---- Monitored CLK.*/
/* CMU2 ---- SIRC ---- FIRC.*/
ptCmuFreq->u32RefClk = SCG_GetScgClockFreq(SCG_SIRC_CLK);
ptCmuFreq->u32MonitorClk = SCG_GetScgClockFreq(SCG_FIRC_CLK);
}
else if (eInstance == CMU_INSTANCE_3)
{
/* Instance ---- Reference CLK ---- Monitored CLK.*/
/* CMU3 ---- FIRC ---- SIRC.*/
ptCmuFreq->u32RefClk = SCG_GetScgClockFreq(SCG_FIRC_CLK);
ptCmuFreq->u32MonitorClk = SCG_GetScgClockFreq(SCG_SIRC_CLK);
}
else if (eInstance == CMU_INSTANCE_4)
{
/* Instance ---- Reference CLK ---- Monitored CLK.*/
/* CMU4 ---- SIRC ---- SLOW CLOCK.*/
ptCmuFreq->u32MonitorClk = SCG_GetScgClockFreq(SCG_SLOW_CLK);
ptCmuFreq->u32RefClk = SCG_GetScgClockFreq(SCG_CMU4REF_CLK);
}
else
{
/* Never come here */
bCmuClkStatus = CMU_CLK_ERROR;
}
if(bCmuClkStatus == CMU_VALID)
{
if ((ptCmuFreq->u32MonitorClk == 0U) || (ptCmuFreq->u32RefClk == 0U))
{
bCmuClkStatus = CMU_CLK_ERROR;
}
}
return bCmuClkStatus;
}
CMU_StatusType CMU_Init(CMU_InstanceType eInstance, const CMU_CfgType *pInitCfg)
{
CMU_StatusType eStatus;
CMU_Type *pCmu;
CMU_RefClockDivType eDiv;
CMU_ClkFrequenceType tCmuFreq;
uint32_t u32RefWindow, u32MaxRefWindow, u32MinRefWindow;
uint32_t u32MonitorCnts, u32MinMonitorCnts, u32MaxMonitorCnts;
uint32_t u32RefClk, u32MonitorClk;
uint32_t u32Temp;
DEV_ASSERT((uint8_t)eInstance < CMU_INSTANCE_COUNT);
DEV_ASSERT(pInitCfg != NULL);
pCmu = s_apCmuBase[(uint8_t)eInstance];
eDiv = pInitCfg->eDiv;
/* Check Reference clock and monitor clock status.*/
eStatus = CMU_ClkStatusCheck(eInstance, &tCmuFreq);
if (eStatus == CMU_VALID)
{
/* divide the clock value by 1K_factor */
u32RefClk = (tCmuFreq.u32RefClk >> eDiv) / CMU_DIVID_FACTOR_1K;
u32MonitorClk = tCmuFreq.u32MonitorClk / CMU_DIVID_FACTOR_1K;
if (u32RefClk / u32MonitorClk <= 0x100U)
{
u32MaxRefWindow = (0xffffffU - 3U) / u32MonitorClk * u32RefClk / 105U * CMU_PERCENT_FACTOR - 2U;
if (u32MaxRefWindow > 0xffffffU)
{
u32MaxRefWindow = 0xffffffU;
}
}
else
{
u32MaxRefWindow = 0xffffffU;
}
u32MinRefWindow = 6U + 5U * u32RefClk / u32MonitorClk;
u32RefWindow = 100U * u32MinRefWindow;
if (u32RefWindow > u32MaxRefWindow)
{
u32RefWindow = u32MaxRefWindow;
}
u32MonitorCnts = u32MonitorClk * (u32RefWindow + 2U) / u32RefClk;
u32MinMonitorCnts = u32MonitorCnts * 95U / CMU_PERCENT_FACTOR - 3U;
u32MaxMonitorCnts = u32MonitorCnts * 105U / CMU_PERCENT_FACTOR + 3U;
CMU_HWA_SetRefWindow(pCmu, u32RefWindow);
CMU_HWA_SetMinCnts(pCmu, u32MinMonitorCnts);
CMU_HWA_SetMaxCnts(pCmu, u32MaxMonitorCnts);
/* Program program PERIOD[EN] and PERIOD[WINDOW]. */
CMU_HWA_SetPeriodEnable(pCmu, false);
if (pInitCfg->bPerMonitorEnable == true)
{
uint8_t u8MaxPeriod = (uint8_t)(u32RefClk / u32RefWindow);
if ((u8MaxPeriod >> (uint8_t)CMU_PERIOD_WINDOW_WIDTH) != 0U)
{
u8MaxPeriod = (1U << (uint8_t)CMU_PERIOD_WINDOW_WIDTH) - 1U;
}
if (u8MaxPeriod != 0U)
{
if (pInitCfg->u8PerMonitorWindow <= u8MaxPeriod)
{
CMU_HWA_SetPeriodWindow(pCmu, (uint32_t)(pInitCfg->u8PerMonitorWindow));
}
else
{
CMU_HWA_SetPeriodWindow(pCmu, (uint32_t)(u8MaxPeriod));
}
CMU_HWA_SetPeriodEnable(pCmu, pInitCfg->bPerMonitorEnable);
}
}
/* Program DIV,IRQ_EN,LP_EN,STOP_EN,ENABLE */
u32Temp = CMU_HWA_GetCTRL(pCmu);
u32Temp &= ~(uint32_t)(CMU_CTRL_REF_DIV_MASK | CMU_CTRL_IRQ_EN_MASK | \
CMU_CTRL_LP_EN_MASK | CMU_CTRL_STOP_EN_MASK | CMU_CTRL_ENABLE_MASK);
u32Temp |= (uint32_t)(CMU_CTRL_REF_DIV(eDiv) | CMU_CTRL_IRQ_EN(pInitCfg->bIntEnable) | \
CMU_CTRL_LP_EN(pInitCfg->bLpen) | CMU_CTRL_STOP_EN(pInitCfg->bSten) | \
CMU_CTRL_ENABLE(pInitCfg->bEnable));
CMU_HWA_SETCTRL(pCmu, u32Temp);
s_apCmuISRCallback[(uint8_t)eInstance] = pInitCfg->pIsrCallback;
}
else
{
/* clock status invalid, change, do nothing */
}
return eStatus;
}
void CMU_Enable(CMU_InstanceType eInstance)
{
DEV_ASSERT((uint8_t)eInstance < CMU_INSTANCE_COUNT);
CMU_HWA_Enable(s_apCmuBase[(uint8_t)eInstance]);
}
void CMU_Disable(CMU_InstanceType eInstance)
{
CMU_Type *pCmu;
DEV_ASSERT((uint8_t)eInstance < CMU_INSTANCE_COUNT);
pCmu = s_apCmuBase[(uint8_t)eInstance];
CMU_HWA_Disable(pCmu);
CMU_HWA_ClearST(pCmu);
}
void CMU_EnableInterrupt(CMU_InstanceType eInstance)
{
DEV_ASSERT((uint8_t)eInstance < CMU_INSTANCE_COUNT);
CMU_HWA_IrqEnable(s_apCmuBase[(uint8_t)eInstance],true);
}
void CMU_DisableInterrupt(CMU_InstanceType eInstance)
{
DEV_ASSERT((uint8_t)eInstance < CMU_INSTANCE_COUNT);
CMU_HWA_IrqEnable(s_apCmuBase[(uint8_t)eInstance],false);
}
CMU_InterruptType CMU_GetInterruptType(CMU_InstanceType eInstance)
{
uint32_t u32Temp;
CMU_InterruptType eStatus;
DEV_ASSERT((uint8_t)eInstance < CMU_INSTANCE_COUNT);
u32Temp = CMU_HWA_GetST(s_apCmuBase[(uint8_t)eInstance]);
if ((u32Temp & CMU_ST_LOC_MASK) != 0U)
{
eStatus = CMU_INTERRUPT_LOC;
}
else if ((u32Temp & CMU_ST_MIS_MASK) != 0U)
{
eStatus = CMU_INTERRUPT_MIS;
}
else
{
eStatus = CMU_INTERRUPT_NONE;
}
return eStatus;
}
CMU_StatusType CMU_SetCmu4RefSrc(CMU_Cmu4ClkSrcType eSrc)
{
SCG_StatusType eStatus;
SCG_HWA_SetCmu4Clk(0U);
if (CMU_CMU4_REF_CLK_FOSC == eSrc)
{
eStatus = SCG_SetCmu4Clk(SCG_CMU4CLK_SRC_FOSC);
}
else if (CMU_CMU4_REF_CLK_SIRC == eSrc)
{
eStatus = SCG_SetCmu4Clk(SCG_CMU4CLK_SRC_SIRC);
}
else
{
eStatus = SCG_STATUS_PARAM_ERROR;
}
return (eStatus == SCG_STATUS_SUCCESS) ? CMU_VALID : CMU_CLK_ERROR;
}
uint32_t CMU_GetCount(CMU_InstanceType eInstance)
{
DEV_ASSERT((uint8_t)eInstance < CMU_INSTANCE_COUNT);
return CMU_HWA_GetCount(s_apCmuBase[(uint8_t)eInstance]);
}
uint32_t CMU_GetMinCount(CMU_InstanceType eInstance)
{
DEV_ASSERT((uint8_t)eInstance < CMU_INSTANCE_COUNT);
return CMU_HWA_GetMinCnts(s_apCmuBase[(uint8_t)eInstance]);
}
uint32_t CMU_GetMaxCount(CMU_InstanceType eInstance)
{
DEV_ASSERT((uint8_t)eInstance < CMU_INSTANCE_COUNT);
return CMU_HWA_GetMaxCnts(s_apCmuBase[(uint8_t)eInstance]);
}
void CMU_LowPowerModeEnable(CMU_InstanceType eInstance, CMU_LowpowerModeType eMode, bool bModeEnable, bool bRestartEnable)
{
CMU_Type *pCmu;
DEV_ASSERT((uint8_t)eInstance < CMU_INSTANCE_COUNT);
pCmu = s_apCmuBase[(uint8_t)eInstance];
if (eMode == CMU_STANDBY_MODE)
{
CMU_HWA_StopModeEnable(pCmu, bModeEnable);
CMU_HWA_StanbyModeEnable(pCmu, bModeEnable);
}
else if (eMode == CMU_STOP_MODE)
{
CMU_HWA_StopModeEnable(pCmu, bModeEnable);
}
else
{
}
CMU_HWA_LPRestartEnable(pCmu, bRestartEnable);
}
/***************CMU IRQ Functions*****************/
static void CMU_IRQHandler(CMU_InstanceType eInstance)
{
CMU_Type *pCmu;
CMU_InterruptType eStatus;
DEV_ASSERT((uint8_t)eInstance < CMU_INSTANCE_COUNT);
pCmu = s_apCmuBase[(uint8_t)eInstance];
eStatus = CMU_GetInterruptType(eInstance);
if (s_apCmuISRCallback[(uint8_t)eInstance] != NULL)
{
s_apCmuISRCallback[(uint8_t)eInstance](eInstance, eStatus);
}
CMU_HWA_ClearST(pCmu);
}
void CMU0_IRQHandler(void)
{
CMU_IRQHandler(CMU_INSTANCE_0);
}
void CMU1_IRQHandler(void)
{
CMU_IRQHandler(CMU_INSTANCE_1);
}
void CMU2_IRQHandler(void)
{
CMU_IRQHandler(CMU_INSTANCE_2);
}
void CMU3_IRQHandler(void)
{
CMU_IRQHandler(CMU_INSTANCE_3);
}
void CMU4_IRQHandler(void)
{
CMU_IRQHandler(CMU_INSTANCE_4);
}