/*
 * Copyright (c) 2022, Shenzhen CVA Innovation CO.,LTD
 * All rights reserved.
 *
 * Shenzhen CVA Innovation CO.,LTD (CVA chip) is supplying this file for use
 * exclusively with CVA's microcontroller products. This file can be freely
 * distributed within development tools that are supporting such microcontroller
 * products.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
 * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
 * CVA SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
 * OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 */

/*******************************************************************************
 * the includes
 ******************************************************************************/

#include <stddef.h>
#include "clock_drv.h"
#include "rcm_reg.h"
#include "scg0_reg.h"
#include "scg1_reg.h"
#include "scg2_reg.h"
#include "pcc0_reg.h"
#include "pcc1_reg.h"

/*******************************************************************************
 * the defines
 ******************************************************************************/

/* Definitions for LPO frequencies */
#define LPO_128K_FREQUENCY            (128000UL)
#define LPO_32K_FREQUENCY             (32000UL)
#define LPO_1K_FREQUENCY              (1000UL)

/* Definitions for all the get and set clock interface */
#define GET_FREQ_FUNC_DEF(module)     static inline bool ClockDrv_Get##module##Freq(const ClockDrvType *obj, uint32_t *frequency)
#define GET_FREQ_FUNC(module)         ClockDrv_Get##module##Freq
#define CONFIG_CLOCK_FUNC_DEF(module) static inline bool ClockDrv_Set##module##Clock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
#define CONFIG_CLOCK_FUNC(module)     ClockDrv_Set##module##Clock

/*******************************************************************************
 * the typedefs
 ******************************************************************************/

/*! \brief Module clock function table element definition
 */
typedef struct _ClockDrv_ModuleClkFuncType_
{
    bool (*getFreqFunc)(const ClockDrvType *, uint32_t *);
    bool (*setClockFunc)(ClockDrvType *, const ClockDrv_ModuleClkConfigType *);
} ClockDrv_ModuleClkFuncType;

/*******************************************************************************
 * the globals
 ******************************************************************************/

/*******************************************************************************
 * the constants
 ******************************************************************************/

/* Forward decleratios for all get and set clock interface */
GET_FREQ_FUNC_DEF(Sosc);
CONFIG_CLOCK_FUNC_DEF(Sosc);
GET_FREQ_FUNC_DEF(Sirc);
GET_FREQ_FUNC_DEF(Pll);
CONFIG_CLOCK_FUNC_DEF(Pll);
GET_FREQ_FUNC_DEF(SoscDiv);
CONFIG_CLOCK_FUNC_DEF(SoscDiv);
GET_FREQ_FUNC_DEF(SoscDivMft);
CONFIG_CLOCK_FUNC_DEF(SoscDivMft);
GET_FREQ_FUNC_DEF(SircDiv);
CONFIG_CLOCK_FUNC_DEF(SircDiv);
GET_FREQ_FUNC_DEF(SircDivMft);
CONFIG_CLOCK_FUNC_DEF(SircDivMft);
GET_FREQ_FUNC_DEF(PllDiv);
CONFIG_CLOCK_FUNC_DEF(PllDiv);
GET_FREQ_FUNC_DEF(PllDivMft);
CONFIG_CLOCK_FUNC_DEF(PllDivMft);
GET_FREQ_FUNC_DEF(Sys);
CONFIG_CLOCK_FUNC_DEF(Sys);
GET_FREQ_FUNC_DEF(Core);
CONFIG_CLOCK_FUNC_DEF(Core);
GET_FREQ_FUNC_DEF(Apb);
CONFIG_CLOCK_FUNC_DEF(Apb);
GET_FREQ_FUNC_DEF(Fls);
CONFIG_CLOCK_FUNC_DEF(Fls);
GET_FREQ_FUNC_DEF(ClkOut);
CONFIG_CLOCK_FUNC_DEF(ClkOut);
GET_FREQ_FUNC_DEF(RtcPadIn);
GET_FREQ_FUNC_DEF(Lpo1k);
CONFIG_CLOCK_FUNC_DEF(Lpo1k);
GET_FREQ_FUNC_DEF(Lpo32k);
CONFIG_CLOCK_FUNC_DEF(Lpo32k);
GET_FREQ_FUNC_DEF(Lpo128k);
CONFIG_CLOCK_FUNC_DEF(Lpo32k);
GET_FREQ_FUNC_DEF(Touch);
CONFIG_CLOCK_FUNC_DEF(Touch);
GET_FREQ_FUNC_DEF(PortA);
CONFIG_CLOCK_FUNC_DEF(PortA);
GET_FREQ_FUNC_DEF(PortB);
CONFIG_CLOCK_FUNC_DEF(PortB);
GET_FREQ_FUNC_DEF(PortC);
CONFIG_CLOCK_FUNC_DEF(PortC);
GET_FREQ_FUNC_DEF(Lptmr);
CONFIG_CLOCK_FUNC_DEF(Lptmr);
GET_FREQ_FUNC_DEF(Lpit);
CONFIG_CLOCK_FUNC_DEF(Lpit);
GET_FREQ_FUNC_DEF(RtcCnt);
CONFIG_CLOCK_FUNC_DEF(RtcCnt);
GET_FREQ_FUNC_DEF(PortAFlt);
CONFIG_CLOCK_FUNC_DEF(PortAFlt);
GET_FREQ_FUNC_DEF(PortBFlt);
CONFIG_CLOCK_FUNC_DEF(PortBFlt);
GET_FREQ_FUNC_DEF(PortCFlt);
CONFIG_CLOCK_FUNC_DEF(PortCFlt);
GET_FREQ_FUNC_DEF(ExtFlt);
CONFIG_CLOCK_FUNC_DEF(ExtFlt);
GET_FREQ_FUNC_DEF(Dma);
CONFIG_CLOCK_FUNC_DEF(Dma);
GET_FREQ_FUNC_DEF(Mscm);
CONFIG_CLOCK_FUNC_DEF(Mscm);
GET_FREQ_FUNC_DEF(Crc);
CONFIG_CLOCK_FUNC_DEF(Crc);
GET_FREQ_FUNC_DEF(Eim);
CONFIG_CLOCK_FUNC_DEF(Eim);
GET_FREQ_FUNC_DEF(Erm);
CONFIG_CLOCK_FUNC_DEF(Erm);
GET_FREQ_FUNC_DEF(Fhu);
CONFIG_CLOCK_FUNC_DEF(Fhu);
GET_FREQ_FUNC_DEF(Adc);
CONFIG_CLOCK_FUNC_DEF(Adc);
GET_FREQ_FUNC_DEF(Pdb);
CONFIG_CLOCK_FUNC_DEF(Pdb);
GET_FREQ_FUNC_DEF(Spi0);
CONFIG_CLOCK_FUNC_DEF(Spi0);
GET_FREQ_FUNC_DEF(Spi1);
CONFIG_CLOCK_FUNC_DEF(Spi1);
GET_FREQ_FUNC_DEF(Uart0);
CONFIG_CLOCK_FUNC_DEF(Uart0);
GET_FREQ_FUNC_DEF(Uart1);
CONFIG_CLOCK_FUNC_DEF(Uart1);
GET_FREQ_FUNC_DEF(I2C);
CONFIG_CLOCK_FUNC_DEF(I2C);
GET_FREQ_FUNC_DEF(PwmLite0);
CONFIG_CLOCK_FUNC_DEF(PwmLite0);
GET_FREQ_FUNC_DEF(PwmLite1);
CONFIG_CLOCK_FUNC_DEF(PwmLite1);
GET_FREQ_FUNC_DEF(Mft0);
CONFIG_CLOCK_FUNC_DEF(Mft0);
GET_FREQ_FUNC_DEF(Mft1);
CONFIG_CLOCK_FUNC_DEF(Mft1);
GET_FREQ_FUNC_DEF(Cmus);
CONFIG_CLOCK_FUNC_DEF(Cmus);
GET_FREQ_FUNC_DEF(Cmup);
CONFIG_CLOCK_FUNC_DEF(Cmup);
GET_FREQ_FUNC_DEF(Tclk0);
GET_FREQ_FUNC_DEF(Tclk1);
GET_FREQ_FUNC_DEF(Tclk2);
GET_FREQ_FUNC_DEF(ExtMft0);
CONFIG_CLOCK_FUNC_DEF(ExtMft0);
GET_FREQ_FUNC_DEF(ExtMft1);
CONFIG_CLOCK_FUNC_DEF(ExtMft1);
GET_FREQ_FUNC_DEF(FixMft0);
CONFIG_CLOCK_FUNC_DEF(FixMft0);
GET_FREQ_FUNC_DEF(FixMft1);
CONFIG_CLOCK_FUNC_DEF(FixMft1);
GET_FREQ_FUNC_DEF(Mpu);
CONFIG_CLOCK_FUNC_DEF(Mpu);

/* Function table for all get and set clock interface */
const ClockDrv_ModuleClkFuncType c_clockFuncTable[CLOCKDRV_CLOCK_NUM] = {
    {GET_FREQ_FUNC(Sosc),       CONFIG_CLOCK_FUNC(Sosc)      }, /* CLOCKDRV_SOSC */
    {GET_FREQ_FUNC(Sirc),       NULL                         }, /* CLOCKDRV_SIRC */
    {GET_FREQ_FUNC(Pll),        CONFIG_CLOCK_FUNC(Pll)       }, /* CLOCKDRV_PLL */
    {GET_FREQ_FUNC(SoscDiv),    CONFIG_CLOCK_FUNC(SoscDiv)   }, /* CLOCKDRV_SOSC_DIV */
    {GET_FREQ_FUNC(SoscDivMft), CONFIG_CLOCK_FUNC(SoscDivMft)}, /* CLOCKDRV_SOSC_DIV_MFT */
    {GET_FREQ_FUNC(SircDiv),    CONFIG_CLOCK_FUNC(SircDiv)   }, /* CLOCKDRV_SIRC_DIV */
    {GET_FREQ_FUNC(SircDivMft), CONFIG_CLOCK_FUNC(SircDivMft)}, /* CLOCKDRV_SIRC_DIV_MFT */
    {GET_FREQ_FUNC(PllDiv),     CONFIG_CLOCK_FUNC(PllDiv)    }, /* CLOCKDRV_PLL_DIV */
    {GET_FREQ_FUNC(PllDivMft),  CONFIG_CLOCK_FUNC(PllDivMft) }, /* CLOCKDRV_PLL_DIV_MFT */
    {GET_FREQ_FUNC(Sys),        CONFIG_CLOCK_FUNC(Sys)       }, /* CLOCKDRV_SYS */
    {GET_FREQ_FUNC(Core),       CONFIG_CLOCK_FUNC(Core)      }, /* CLOCKDRV_CORE */
    {GET_FREQ_FUNC(Apb),        CONFIG_CLOCK_FUNC(Apb)       }, /* CLOCKDRV_APB */
    {GET_FREQ_FUNC(Fls),        CONFIG_CLOCK_FUNC(Fls)       }, /* CLOCKDRV_FLS */
    {GET_FREQ_FUNC(ClkOut),     CONFIG_CLOCK_FUNC(ClkOut)    }, /* CLOCKDRV_CLKOUT */
    {GET_FREQ_FUNC(RtcPadIn),   NULL                         }, /* CLOCKDRV_RTC_PADIN */
    {GET_FREQ_FUNC(Lpo1k),      CONFIG_CLOCK_FUNC(Lpo1k)     }, /* CLOCKDRV_LPO_1K */
    {GET_FREQ_FUNC(Lpo32k),     CONFIG_CLOCK_FUNC(Lpo32k)    }, /* CLOCKDRV_LPO_32K */
    {GET_FREQ_FUNC(Lpo128k),    NULL                         }, /* CLOCKDRV_LPO_128K */
    {GET_FREQ_FUNC(Touch),      CONFIG_CLOCK_FUNC(Touch)     }, /* CLOCKDRV_TOUCH */
    {GET_FREQ_FUNC(PortA),      CONFIG_CLOCK_FUNC(PortA)     }, /* CLOCKDRV_PORTA */
    {GET_FREQ_FUNC(PortB),      CONFIG_CLOCK_FUNC(PortB)     }, /* CLOCKDRV_PORTB */
    {GET_FREQ_FUNC(PortC),      CONFIG_CLOCK_FUNC(PortC)     }, /* CLOCKDRV_PORTC */
    {GET_FREQ_FUNC(Lptmr),      CONFIG_CLOCK_FUNC(Lptmr)     }, /* CLOCKDRV_LPTMR */
    {GET_FREQ_FUNC(Lpit),       CONFIG_CLOCK_FUNC(Lpit)      }, /* CLOCKDRV_LPIT */
    {GET_FREQ_FUNC(RtcCnt),     CONFIG_CLOCK_FUNC(RtcCnt)    }, /* CLOCKDRV_RTC_CNT */
    {GET_FREQ_FUNC(PortAFlt),   CONFIG_CLOCK_FUNC(PortAFlt)  }, /* CLOCKDRV_PORTA_FLT */
    {GET_FREQ_FUNC(PortBFlt),   CONFIG_CLOCK_FUNC(PortBFlt)  }, /* CLOCKDRV_PORTB_FLT */
    {GET_FREQ_FUNC(PortCFlt),   CONFIG_CLOCK_FUNC(PortCFlt)  }, /* CLOCKDRV_PORTC_FLT */
    {GET_FREQ_FUNC(ExtFlt),     CONFIG_CLOCK_FUNC(ExtFlt)    }, /* CLOCKDRV_EXT_FLT */
    {GET_FREQ_FUNC(Dma),        CONFIG_CLOCK_FUNC(Dma)       }, /* CLOCKDRV_DMA */
    {GET_FREQ_FUNC(Mscm),       CONFIG_CLOCK_FUNC(Mscm)      }, /* CLOCKDRV_MSCM */
    {GET_FREQ_FUNC(Crc),        CONFIG_CLOCK_FUNC(Crc)       }, /* CLOCKDRV_CRC */
    {GET_FREQ_FUNC(Eim),        CONFIG_CLOCK_FUNC(Eim)       }, /* CLOCKDRV_EIM */
    {GET_FREQ_FUNC(Erm),        CONFIG_CLOCK_FUNC(Erm)       }, /* CLOCKDRV_ERM */
    {GET_FREQ_FUNC(Fhu),        CONFIG_CLOCK_FUNC(Fhu)       }, /* CLOCKDRV_FHU */
    {GET_FREQ_FUNC(Adc),        CONFIG_CLOCK_FUNC(Adc)       }, /* CLOCKDRV_ADC */
    {GET_FREQ_FUNC(Pdb),        CONFIG_CLOCK_FUNC(Pdb)       }, /* CLOCKDRV_PDB */
    {GET_FREQ_FUNC(Spi0),       CONFIG_CLOCK_FUNC(Spi0)      }, /* CLOCKDRV_SPI0 */
    {GET_FREQ_FUNC(Spi1),       CONFIG_CLOCK_FUNC(Spi1)      }, /* CLOCKDRV_SPI1 */
    {GET_FREQ_FUNC(Uart0),      CONFIG_CLOCK_FUNC(Uart0)     }, /* CLOCKDRV_UART0 */
    {GET_FREQ_FUNC(Uart1),      CONFIG_CLOCK_FUNC(Uart1)     }, /* CLOCKDRV_UART1 */
    {GET_FREQ_FUNC(I2C),        CONFIG_CLOCK_FUNC(I2C)       }, /* CLOCKDRV_I2C */
    {GET_FREQ_FUNC(PwmLite0),   CONFIG_CLOCK_FUNC(PwmLite0)  }, /* CLOCKDRV_PWMLITE0 */
    {GET_FREQ_FUNC(PwmLite1),   CONFIG_CLOCK_FUNC(PwmLite1)  }, /* CLOCKDRV_PWMLITE1 */
    {GET_FREQ_FUNC(Mft0),       CONFIG_CLOCK_FUNC(Mft0)      }, /* CLOCKDRV_MFT0 */
    {GET_FREQ_FUNC(Mft1),       CONFIG_CLOCK_FUNC(Mft1)      }, /* CLOCKDRV_MFT1 */
    {GET_FREQ_FUNC(Cmus),       CONFIG_CLOCK_FUNC(Cmus)      }, /* CLOCKDRV_CMUS */
    {GET_FREQ_FUNC(Cmup),       CONFIG_CLOCK_FUNC(Cmup)      }, /* CLOCKDRV_CMUP */
    {GET_FREQ_FUNC(Tclk0),      NULL                         }, /* CLOCKDRV_TCLK0 */
    {GET_FREQ_FUNC(Tclk1),      NULL                         }, /* CLOCKDRV_TCLK1 */
    {GET_FREQ_FUNC(Tclk2),      NULL                         }, /* CLOCKDRV_TCLK2 */
    {GET_FREQ_FUNC(ExtMft0),    CONFIG_CLOCK_FUNC(ExtMft0)   }, /* CLOCKDRV_EXT_MFT0 */
    {GET_FREQ_FUNC(ExtMft1),    CONFIG_CLOCK_FUNC(ExtMft1)   }, /* CLOCKDRV_EXT_MFT1 */
    {GET_FREQ_FUNC(FixMft0),    CONFIG_CLOCK_FUNC(FixMft0)   }, /* CLOCKDRV_FIX_MFT0 */
    {GET_FREQ_FUNC(FixMft1),    CONFIG_CLOCK_FUNC(FixMft1)   }, /* CLOCKDRV_FIX_MFT1 */
    {GET_FREQ_FUNC(Mpu),        CONFIG_CLOCK_FUNC(Mpu)       }, /* CLOCKDRV_MPU */
};

/*******************************************************************************
 * the functions
 ******************************************************************************/

static inline bool ClockDrv_GetSoscFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Scg0Reg_GetOscCtrlEnSosc(obj->scg0Reg) && Scg0Reg_GetStatusSoscRdy(obj->scg0Reg))
    {
        *frequency = obj->xtalClkFreq;
        return true;
    }
    return false;
}

static inline bool ClockDrv_SetSoscClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    /* Disable SOSC first, before configure */
    Scg0Reg_SetOscCtrlEnSosc(obj->scg0Reg, 0);

    /* Enable SOSC if required */
    if(moduleClkConfig->gating)
    {
        uint8_t soscRange = obj->xtalClkFreq < 4000000 ? 0 : (obj->xtalClkFreq < 8000000 ? 1 : (obj->xtalClkFreq < 24000000 ? 2 : (obj->xtalClkFreq <= 40000000 ? 3 : 4)));
        if(4 == soscRange)
        {
            return false;
        }
        /* Set SOSC frequency range */
        Scg0Reg_SetOscCtrlRange(obj->scg0Reg, soscRange);
        /* Disable external EXTAL clock in, cannot enable at the same time */
        Scg0Reg_SetOscCtrlEnExtClk(obj->scg0Reg, 0);
        /* Enable SOSC */
        Scg0Reg_SetOscCtrlEnSosc(obj->scg0Reg, 1);
        while(Scg0Reg_GetStatusSoscRdy(obj->scg0Reg) == 0)
        {
            ; /* Wait until SOSC is locked */
        }
    }

    return true;
}

static inline bool ClockDrv_GetSircFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    /* SIRC always enabled */
    if(Scg0Reg_GetStatusSircRdy(obj->scg0Reg))
    {
        *frequency = obj->sircFreq;
        return true;
    }
    return false;
}

static inline bool ClockDrv_GetPllFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = false;
    if(Scg0Reg_GetPllCtrl0PllEn(obj->scg0Reg) && Scg0Reg_GetStatusPllLock(obj->scg0Reg))
    {
        uint32_t freq;
        switch(Scg0Reg_GetPllCtrl1PllClkinSel(obj->scg0Reg))
        {
        case 0: /* SIRC clock as source */
            retval = ClockDrv_GetSircFreq(obj, &freq);
            break;
        case 1: /* SOSC clock as source */
            retval = ClockDrv_GetSoscFreq(obj, &freq);
            break;
        default:
            break;
        }
        /* If the source clock is valid */
        if(false == retval)
        {
            return false;
        }

        /* Get the PLL pre-divider */
        uint32_t preDiv = 1;
        switch(Scg0Reg_GetPllCtrl0PllPreDiv(obj->scg0Reg))
        {
        case 0:
            preDiv = 1;
            break;
        case 1:
            preDiv = 2;
            break;
        case 2:
            preDiv = 4;
            break;
        case 3:
            preDiv = 8;
            break;
        default:
            /* should not get here */
            break;
        }
        /* Get the PLL feedback divider setting */
        uint32_t mult = Scg0Reg_GetPllCtrl0PllM(obj->scg0Reg);
        mult          = (mult == 0 ? 128 : mult);
        /* Get the PLL feedback divider setting */
        uint32_t postDiv = Scg0Reg_GetPllCtrl0PllPosDiv(obj->scg0Reg);
        postDiv          = (postDiv == 0 ? 8 : postDiv);
        /* Get the PLL Feedback clock divider pre-scaler */
        uint32_t outDiv = Scg0Reg_GetPllCtrl0PllOutDiv(obj->scg0Reg) + 1;

        /* Calculate the final PLL frequency */
        *frequency = (freq * mult) / (outDiv * preDiv * postDiv);

        retval = true;
    }

    return retval;
}

bool ClockDrv_SetPllClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    /* Disable PLL first, before configure */
    Scg0Reg_SetPllCtrl0PllEn(obj->scg0Reg, 0);

    bool retval = true;
    switch(moduleClkConfig->source)
    {
    case CLOCKDRV_SOSC: /* SOSC clock as source */
        Scg0Reg_SetPllCtrl1PllClkinSel(obj->scg0Reg, 1);
        break;
    case CLOCKDRV_SIRC: /* SIRC clock as source */
        Scg0Reg_SetPllCtrl1PllClkinSel(obj->scg0Reg, 0);
        break;
    default:
        retval = false;
        break;
    }
    /* If the source clock is valid */
    if(false == retval)
    {
        return false;
    }

    /* Set the PLL pre-divider */
    uint8_t preDiv = moduleClkConfig->pllConfig.preDiv == 1 ? 0 : (moduleClkConfig->pllConfig.preDiv == 2 ? 1 : (moduleClkConfig->pllConfig.preDiv == 4 ? 2 : (moduleClkConfig->pllConfig.preDiv == 8 ? 3 : 0xff)));
    /* If PLL pre-divider is valid */
    if(0xff == preDiv)
    {
        return false;
    }
    Scg0Reg_SetPllCtrl0PllPreDiv(obj->scg0Reg, preDiv);

    /* Set the PLL feedback divider */
    if(moduleClkConfig->mult >= 1 && moduleClkConfig->mult <= 128)
    {
        Scg0Reg_SetPllCtrl0PllM(obj->scg0Reg, moduleClkConfig->mult == 128 ? 0 : moduleClkConfig->mult);
    }
    else
    {
        return false;
    }

    /* Set the post-divider */
    if(moduleClkConfig->pllConfig.postDiv >= 1 && moduleClkConfig->pllConfig.postDiv <= 8)
    {
        Scg0Reg_SetPllCtrl0PllPosDiv(obj->scg0Reg, moduleClkConfig->pllConfig.postDiv == 8 ? 0 : moduleClkConfig->pllConfig.postDiv);
    }
    else
    {
        return false;
    }

    /* Set the feedback clock divider pre-scaler */
    if(moduleClkConfig->pllConfig.outDiv == 1 || moduleClkConfig->pllConfig.outDiv == 2)
    {
        Scg0Reg_SetPllCtrl0PllOutDiv(obj->scg0Reg, moduleClkConfig->pllConfig.outDiv - 1);
    }
    else
    {
        return false;
    }

    /* Enable PLL if required */
    if(moduleClkConfig->gating)
    {
        Scg0Reg_SetPllCtrl0PllEn(obj->scg0Reg, 1);
        while(Scg0Reg_GetStatusPllLock(obj->scg0Reg) == 0)
        {
            ; /* Wait until PLL is locked */
        }
    }

    return retval;
}

static inline bool ClockDrv_GetSoscDivFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool     retval = false;
    uint32_t freq   = 0;
    if(Scg2Reg_GetSoscCfgEn(obj->scg2Reg))
    {
        retval = ClockDrv_GetSoscFreq(obj, &freq);
        if(retval)
        {
            uint32_t div = ((uint32_t)1UL) << Scg2Reg_GetSoscCfgDiv(obj->scg2Reg);
            if(div <= 64)
            {
                *frequency = freq / div;
            }
            else
            {
                retval = false;
            }
        }
    }

    return retval;
}

static inline bool ClockDrv_SetSoscDivClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = false;
    /* Disable first before configure */
    Scg2Reg_SetSoscCfgEn(obj->scg2Reg, 0);

    uint8_t div = moduleClkConfig->div == 1 ? 0 : (moduleClkConfig->div == 2 ? 1 : (moduleClkConfig->div == 4 ? 2 : (moduleClkConfig->div == 8 ? 3 : (moduleClkConfig->div == 16 ? 4 : (moduleClkConfig->div == 32 ? 5 : (moduleClkConfig->div == 64 ? 6 : 7))))));
    if(div != 7)
    {
        Scg2Reg_SetSoscCfgDiv(obj->scg2Reg, div);
        retval = true;
    }
    /* Enable if required */
    Scg2Reg_SetSoscCfgEn(obj->scg2Reg, moduleClkConfig->gating ? 1 : 0);

    return retval;
}

static inline bool ClockDrv_GetSoscDivMftFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool     retval = false;
    uint32_t freq   = 0;
    if(Scg2Reg_GetSoscMftEn(obj->scg2Reg))
    {
        retval = ClockDrv_GetSoscFreq(obj, &freq);
        if(retval)
        {
            uint32_t div = ((uint32_t)1UL) << Scg2Reg_GetSoscMftDiv(obj->scg2Reg);
            if(div <= 64)
            {
                *frequency = freq / div;
            }
            else
            {
                retval = false;
            }
        }
    }

    return retval;
}

static inline bool ClockDrv_SetSoscDivMftClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = false;
    /* Disable first before configure */
    Scg2Reg_SetSoscMftEn(obj->scg2Reg, 0);

    uint8_t div = moduleClkConfig->div == 1 ? 0 : (moduleClkConfig->div == 2 ? 1 : (moduleClkConfig->div == 4 ? 2 : (moduleClkConfig->div == 8 ? 3 : (moduleClkConfig->div == 16 ? 4 : (moduleClkConfig->div == 32 ? 5 : (moduleClkConfig->div == 64 ? 6 : 7))))));
    if(div != 7)
    {
        Scg2Reg_SetSoscMftDiv(obj->scg2Reg, div);
        retval = true;
    }
    /* Enable if required */
    Scg2Reg_SetSoscMftEn(obj->scg2Reg, moduleClkConfig->gating ? 1 : 0);

    return retval;
}

static inline bool ClockDrv_GetSircDivFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool     retval = false;
    uint32_t freq   = 0;
    if(Scg2Reg_GetSircCfgEn(obj->scg2Reg))
    {
        retval = ClockDrv_GetSircFreq(obj, &freq);
        if(retval)
        {
            uint32_t div = ((uint32_t)1UL) << Scg2Reg_GetSircCfgDiv(obj->scg2Reg);
            if(div <= 64)
            {
                *frequency = freq / div;
            }
            else
            {
                retval = false;
            }
        }
    }

    return retval;
}

static inline bool ClockDrv_SetSircDivClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = false;
    /* Disable first before configure */
    Scg2Reg_SetSircCfgEn(obj->scg2Reg, 0);

    uint8_t div = moduleClkConfig->div == 1 ? 0 : (moduleClkConfig->div == 2 ? 1 : (moduleClkConfig->div == 4 ? 2 : (moduleClkConfig->div == 8 ? 3 : (moduleClkConfig->div == 16 ? 4 : (moduleClkConfig->div == 32 ? 5 : (moduleClkConfig->div == 64 ? 6 : 7))))));
    if(div != 7)
    {
        Scg2Reg_SetSircCfgDiv(obj->scg2Reg, div);
        retval = true;
    }
    /* Enable if required */
    Scg2Reg_SetSircCfgEn(obj->scg2Reg, moduleClkConfig->gating ? 1 : 0);

    return retval;
}

static inline bool ClockDrv_GetSircDivMftFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool     retval = false;
    uint32_t freq   = 0;
    if(Scg2Reg_GetSircMftEn(obj->scg2Reg))
    {
        retval = ClockDrv_GetSircFreq(obj, &freq);
        if(retval)
        {
            uint32_t div = ((uint32_t)1UL) << Scg2Reg_GetSircMftDiv(obj->scg2Reg);
            if(div <= 64)
            {
                *frequency = freq / div;
            }
            else
            {
                retval = false;
            }
        }
    }

    return retval;
}

static inline bool ClockDrv_SetSircDivMftClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = false;
    /* Disable first before configure */
    Scg2Reg_SetSircMftEn(obj->scg2Reg, 0);

    uint8_t div = moduleClkConfig->div == 1 ? 0 : (moduleClkConfig->div == 2 ? 1 : (moduleClkConfig->div == 4 ? 2 : (moduleClkConfig->div == 8 ? 3 : (moduleClkConfig->div == 16 ? 4 : (moduleClkConfig->div == 32 ? 5 : (moduleClkConfig->div == 64 ? 6 : 7))))));
    if(div != 7)
    {
        Scg2Reg_SetSircMftDiv(obj->scg2Reg, div);
        retval = true;
    }
    /* Enable if required */
    Scg2Reg_SetSircMftEn(obj->scg2Reg, moduleClkConfig->gating ? 1 : 0);

    return retval;
}

static inline bool ClockDrv_GetPllDivFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool     retval = false;
    uint32_t freq   = 0;
    if(Scg2Reg_GetPllCfgEn(obj->scg2Reg))
    {
        retval = ClockDrv_GetPllFreq(obj, &freq);
        if(retval)
        {
            uint32_t div = ((uint32_t)1UL) << Scg2Reg_GetPllCfgDiv(obj->scg2Reg);
            if(div <= 64)
            {
                *frequency = freq / div;
            }
            else
            {
                retval = false;
            }
        }
    }

    return retval;
}

static inline bool ClockDrv_SetPllDivClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = false;
    /* Disable first before configure */
    Scg2Reg_SetPllCfgEn(obj->scg2Reg, 0);

    uint8_t div = moduleClkConfig->div == 1 ? 0 : (moduleClkConfig->div == 2 ? 1 : (moduleClkConfig->div == 4 ? 2 : (moduleClkConfig->div == 8 ? 3 : (moduleClkConfig->div == 16 ? 4 : (moduleClkConfig->div == 32 ? 5 : (moduleClkConfig->div == 64 ? 6 : 7))))));
    if(div != 7)
    {
        Scg2Reg_SetPllCfgDiv(obj->scg2Reg, div);
        retval = true;
    }
    /* Enable if required */
    Scg2Reg_SetPllCfgEn(obj->scg2Reg, moduleClkConfig->gating ? 1 : 0);

    return retval;
}

static inline bool ClockDrv_GetPllDivMftFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool     retval = false;
    uint32_t freq   = 0;
    if(Scg2Reg_GetPllMftEn(obj->scg2Reg))
    {
        retval = ClockDrv_GetPllFreq(obj, &freq);
        if(retval)
        {
            uint32_t div = ((uint32_t)1UL) << Scg2Reg_GetPllMftDiv(obj->scg2Reg);
            if(div <= 64)
            {
                *frequency = freq / div;
            }
            else
            {
                retval = false;
            }
        }
    }

    return retval;
}

static inline bool ClockDrv_SetPllDivMftClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = false;
    /* Disable first before configure */
    Scg2Reg_SetPllMftEn(obj->scg2Reg, 0);

    uint8_t div = moduleClkConfig->div == 1 ? 0 : (moduleClkConfig->div == 2 ? 1 : (moduleClkConfig->div == 4 ? 2 : (moduleClkConfig->div == 8 ? 3 : (moduleClkConfig->div == 16 ? 4 : (moduleClkConfig->div == 32 ? 5 : (moduleClkConfig->div == 64 ? 6 : 7))))));
    if(div != 7)
    {
        Scg2Reg_SetPllMftDiv(obj->scg2Reg, div);
        retval = true;
    }
    /* Enable if required */
    Scg2Reg_SetPllMftEn(obj->scg2Reg, moduleClkConfig->gating ? 1 : 0);

    return retval;
}

static inline bool ClockDrv_GetSysFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = false;

    /* Get system clock freq */
    switch(Scg2Reg_GetCsrSysSt(obj->scg2Reg))
    {
    case 0: /* clk_sirc */
        retval = ClockDrv_GetSircFreq(obj, frequency);
        break;
    case 1: /* clk_sosc */
        retval = ClockDrv_GetSoscFreq(obj, frequency);
        break;
    case 2: /* clk_pll */
        retval = ClockDrv_GetPllFreq(obj, frequency);
        break;
    case 3: /* clk_sirc */
        retval = ClockDrv_GetSircFreq(obj, frequency);
        break;
    default:
        break;
    }

    return retval;
}

static inline bool ClockDrv_SetSysClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    uint8_t select = moduleClkConfig->source == CLOCKDRV_SIRC ? 0 : (moduleClkConfig->source == CLOCKDRV_SOSC ? 1 : (moduleClkConfig->source == CLOCKDRV_PLL ? 2 : 0xff));
    if(select == 0xff)
    {
        return false;
    }

    Scg2Reg_SetCsrSrcSys(obj->scg2Reg, select);
    while(Scg2Reg_GetCsrSysSt(obj->scg2Reg) != select)
    {
        ;
    }

    return true;
}

static inline bool ClockDrv_GetCoreFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = false;
    /* Get system clock freq */
    uint32_t sysFreq;
    retval = ClockDrv_GetSysFreq(obj, &sysFreq);
    if(false == retval)
    {
        return false;
    }
    /* Get core clock freq */
    *frequency = sysFreq / (Scg1Reg_GetCkSrcSysDiv(obj->scg1Reg) + 1U);

    return retval;
}

static inline bool ClockDrv_SetCoreClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    /* The clock source is clk_sys */
    if(moduleClkConfig->div >= 1 && moduleClkConfig->div <= 16)
    {
        Scg1Reg_SetCkSrcSysDiv(obj->scg1Reg, moduleClkConfig->div - 1);
        return true;
    }
    return false;
}

static inline bool ClockDrv_GetApbFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = false;
    /* Get core clock freq */
    uint32_t coreFreq;
    retval = ClockDrv_GetCoreFreq(obj, &coreFreq);
    if(false == retval)
    {
        return false;
    }
    /* Get APB clock freq */
    *frequency = coreFreq / (Scg2Reg_GetCsrDivAips(obj->scg2Reg) + 1U);

    return retval;
}

static inline bool ClockDrv_SetApbClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    /* The clock source is core clock */
    if(moduleClkConfig->div >= 1 && moduleClkConfig->div <= 16)
    {
        Scg2Reg_SetCsrDivAips(obj->scg2Reg, moduleClkConfig->div - 1);
        return true;
    }
    return false;
}

static inline bool ClockDrv_GetFlsFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = false;
    /* Get core clock freq */
    uint32_t srcFreq = 0;
    retval = ClockDrv_GetCoreFreq(obj, &srcFreq);

    if(false == retval)
    {
        return false;
    }
    /* Get flash clock freq */
    if(Pcc1Reg_GetFlsCtlCkEn(obj->pcc1Reg))
    {
        uint32_t tmpFreq = srcFreq / (Pcc1Reg_GetFlsCtlCntDiv(obj->pcc1Reg) + 1U);
        /* FLS clock must be 8M */
        if(tmpFreq != 8000000)
        {
            retval = false;
        }
        else
        {
            *frequency = tmpFreq;
        }
    }
    else
    {
        retval = false;
    }

    return retval;
}

static inline bool ClockDrv_SetFlsClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    /* Get core clock freq */
    uint32_t srcFreq = 0;
    if(ClockDrv_GetCoreFreq(obj, &srcFreq) == false)
    {
        return false;
    }

    if(moduleClkConfig->div >= 1 && moduleClkConfig->div <= 16
            && (srcFreq / moduleClkConfig->div) == 8000000)
    {
        /* FLS clock must be 8M */
        Pcc1Reg_SetFlsCtlCntDiv(obj->pcc1Reg, moduleClkConfig->div - 1);
        Pcc1Reg_SetFlsCtlCkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);
        return true;
    }
    return false;
}

static inline bool ClockDrv_GetClkOutFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Scg2Reg_GetClkOutEn(obj->scg2Reg) == 0)
    {
        return false;
    }

    bool     retval = false;
    uint32_t freq   = 0;
    if(Scg2Reg_GetClkOutSrc1(obj->scg2Reg) == 0)
    {
        /* SCG out selected */
        switch(Scg2Reg_GetClkOutSrc0(obj->scg2Reg))
        {
        case 0:
            /* clk_cnt_fls */
            retval = ClockDrv_GetFlsFreq(obj, &freq);
            break;
        case 1:
            /* clk_sosc */
            retval = ClockDrv_GetSoscFreq(obj, &freq);
            break;
        case 2:
            /* clk_sirc */
            retval = ClockDrv_GetSircFreq(obj, &freq);
            break;
        case 3:
            /* clk_pll */
            retval = ClockDrv_GetPllFreq(obj, &freq);
            break;
        case 4:
            /* clk_core */
            retval = ClockDrv_GetCoreFreq(obj, &freq);
            break;
        case 5:
            /* clk_apb */
            retval = ClockDrv_GetApbFreq(obj, &freq);
            break;
        case 6:
            /* clk_sosc_div */
            retval = ClockDrv_GetSoscDivFreq(obj, &freq);
            break;
        case 7:
            /* clk_sirc_div */
            retval = ClockDrv_GetSircDivFreq(obj, &freq);
            break;
        default:
            break;
        }
    }
    else
    {
        switch(Scg2Reg_GetClkOutSrc1(obj->scg2Reg))
        {
        case 1:
            /* clk_pll_div */
            retval = ClockDrv_GetPllDivFreq(obj, &freq);
            break;
        case 2:
            /* clk_lpo128, this is alway available */
            retval = ClockDrv_GetLpo128kFreq(obj, &freq);
            break;
        case 3:
            /* clk_lpo32 */
            retval = ClockDrv_GetLpo32kFreq(obj, &freq);
            break;
        case 4:
            /* clk_lpo1 */
            retval = ClockDrv_GetLpo1kFreq(obj, &freq);
            break;
        case 5:
            /* clk_rtc_cnt */
            retval = ClockDrv_GetRtcCntFreq(obj, &freq);
            break;
        case 6:
            /* clk_sirc */
            retval = ClockDrv_GetSircFreq(obj, &freq);
            break;
        case 7:
            /* clk_sirc */
            retval = ClockDrv_GetSircFreq(obj, &freq);
            break;
        default:
            break;
        }
    }

    if(true == retval)
    {
        *frequency = freq / (Scg2Reg_GetClkOutDiv(obj->scg2Reg) + 1);
    }

    return retval;
}

static inline bool ClockDrv_SetClkOutClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = true;

    /* Disable first before configure */
    Scg2Reg_SetClkOutEn(obj->scg2Reg, 0);

    switch(moduleClkConfig->source)
    {
    case CLOCKDRV_FLS:
        Scg2Reg_SetClkOutSrc1(obj->scg2Reg, 0); /* scg_out must be selected to enable scg clock out */
        Scg2Reg_SetClkOutSrc0(obj->scg2Reg, 0);
        break;
    case CLOCKDRV_SOSC:
        Scg2Reg_SetClkOutSrc1(obj->scg2Reg, 0); /* scg_out must be selected to enable scg clock out */
        Scg2Reg_SetClkOutSrc0(obj->scg2Reg, 1);
        break;
    case CLOCKDRV_SIRC:
        Scg2Reg_SetClkOutSrc1(obj->scg2Reg, 0); /* scg_out must be selected to enable scg clock out */
        Scg2Reg_SetClkOutSrc0(obj->scg2Reg, 2);
        break;
    case CLOCKDRV_PLL:
        Scg2Reg_SetClkOutSrc1(obj->scg2Reg, 0); /* scg_out must be selected to enable scg clock out */
        Scg2Reg_SetClkOutSrc0(obj->scg2Reg, 3);
        break;
    case CLOCKDRV_CORE:
        Scg2Reg_SetClkOutSrc1(obj->scg2Reg, 0); /* scg_out must be selected to enable scg clock out */
        Scg2Reg_SetClkOutSrc0(obj->scg2Reg, 4);
        break;
    case CLOCKDRV_APB:
        Scg2Reg_SetClkOutSrc1(obj->scg2Reg, 0); /* scg_out must be selected to enable scg clock out */
        Scg2Reg_SetClkOutSrc0(obj->scg2Reg, 5);
        break;
    case CLOCKDRV_SOSC_DIV:
        Scg2Reg_SetClkOutSrc1(obj->scg2Reg, 0); /* scg_out must be selected to enable scg clock out */
        Scg2Reg_SetClkOutSrc0(obj->scg2Reg, 6);
        break;
    case CLOCKDRV_SIRC_DIV:
        Scg2Reg_SetClkOutSrc1(obj->scg2Reg, 0); /* scg_out must be selected to enable scg clock out */
        Scg2Reg_SetClkOutSrc0(obj->scg2Reg, 7);
        break;
    case CLOCKDRV_PLL_DIV:
        Scg2Reg_SetClkOutSrc1(obj->scg2Reg, 1);
        break;
    case CLOCKDRV_LPO_128K:
        Scg2Reg_SetClkOutSrc1(obj->scg2Reg, 2);
        break;
    case CLOCKDRV_LPO_32K:
        Scg2Reg_SetClkOutSrc1(obj->scg2Reg, 3);
        break;
    case CLOCKDRV_LPO_1K:
        Scg2Reg_SetClkOutSrc1(obj->scg2Reg, 4);
        break;
    case CLOCKDRV_RTC_CNT:
        Scg2Reg_SetClkOutSrc1(obj->scg2Reg, 5);
        break;
    default:
        retval = false;
        break;
    }

    if(retval)
    {
        if(moduleClkConfig->div >= 1 && moduleClkConfig->div <= 8)
        {
            Scg2Reg_SetClkOutDiv(obj->scg2Reg, moduleClkConfig->div - 1);
        }
        else
        {
            retval = false;
        }
    }

    /* Enable if required */
    Scg2Reg_SetClkOutEn(obj->scg2Reg, moduleClkConfig->gating ? 1 : 0);

    return retval;
}

static inline bool ClockDrv_GetRtcPadInFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    (void)obj; /* Unused, avoid warning */
    *frequency = obj->rtcClkInFreq;
    return true;
}

static inline bool ClockDrv_GetLpo1kFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc0Reg_GetLpo1Cken(obj->pcc0Reg))
    {
        *frequency = LPO_1K_FREQUENCY;
        return true;
    }
    return false;
}

static inline bool ClockDrv_SetLpo1kClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc0Reg_SetLpo1Cken(obj->pcc0Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetLpo32kFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc0Reg_GetLpo32Cken(obj->pcc0Reg))
    {
        *frequency = LPO_32K_FREQUENCY;
        return true;
    }
    return false;
}

static inline bool ClockDrv_SetLpo32kClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc0Reg_SetLpo32Cken(obj->pcc0Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetLpo128kFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    (void)obj; /* Unused, avoid warning */
    *frequency = LPO_128K_FREQUENCY;
    return true;
}

static inline bool ClockDrv_GetTouchFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = false;
    if(Pcc0Reg_GetTouchCkEn(obj->pcc0Reg))
    {
        uint32_t freq = 0;
        switch(Pcc0Reg_GetAdcSrc(obj->pcc0Reg))
        {
        case 0: /* clk_sirc */
            retval = ClockDrv_GetSircFreq(obj, &freq);
            break;
        case 1: /* clk_sosc */
            retval = ClockDrv_GetSoscFreq(obj, &freq);
            break;
        case 2: /* clk_pll */
            retval = ClockDrv_GetPllFreq(obj, &freq);
            break;
        case 3: /* clk_pll_div */
            retval = ClockDrv_GetPllDivFreq(obj, &freq);
            break;
        default:
            break;
        }
        if(retval == true)
        {
            *frequency = freq / (Pcc0Reg_GetAdcDiv(obj->pcc0Reg) + 1);
        }
    }
    return retval;
}

static inline bool ClockDrv_SetTouchClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc0Reg_SetTouchCkEn(obj->pcc0Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetPortAFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = false;
    if(Pcc0Reg_GetPortACkEn(obj->pcc0Reg))
    {
        retval = ClockDrv_GetApbFreq(obj, frequency);
    }
    return retval;
}

static inline bool ClockDrv_SetPortAClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc0Reg_SetPortACkEn(obj->pcc0Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetPortBFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = false;
    if(Pcc0Reg_GetPortBCkEn(obj->pcc0Reg))
    {
        retval = ClockDrv_GetApbFreq(obj, frequency);
    }
    return retval;
}

static inline bool ClockDrv_SetPortBClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc0Reg_SetPortBCkEn(obj->pcc0Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetPortCFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = false;
    if(Pcc0Reg_GetPortCCkEn(obj->pcc0Reg))
    {
        retval = ClockDrv_GetApbFreq(obj, frequency);
    }
    return retval;
}

static inline bool ClockDrv_SetPortCClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc0Reg_SetPortCCkEn(obj->pcc0Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetLptmrFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool     retval = false;
    uint32_t freq   = 0;
    /* Check if the lptmr clock is enable */
    if(Pcc0Reg_GetLptmrCken(obj->pcc0Reg) == 0)
    {
        return false;
    }

    switch(Pcc0Reg_GetLptmrSrc(obj->pcc0Reg))
    {
    case 0: /* clk_sirc_div */
        retval = ClockDrv_GetSircDivFreq(obj, &freq);
        break;
    case 1: /* clk_sosc_div */
        retval = ClockDrv_GetSoscDivFreq(obj, &freq);
        break;
    case 2: /* clk_pll_div */
        retval = ClockDrv_GetPllDivFreq(obj, &freq);
        break;
    case 3: /* clk_lpo128 */
        retval = ClockDrv_GetLpo128kFreq(obj, &freq);
        break;
    case 4: /* clk_lpo1 */
        retval = ClockDrv_GetLpo1kFreq(obj, &freq);
        break;
    case 5: /* clk_lpo32 */
        retval = ClockDrv_GetLpo32kFreq(obj, &freq);
        break;
    case 6: /* RTC_CLKIN from PAD_PTA7 */
        retval = ClockDrv_GetRtcPadInFreq(obj, &freq);
        break;
    case 7: /* clk_sirc_div */
        retval = ClockDrv_GetSircDivFreq(obj, &freq);
        break;
    default:
        break;
    }

    if(retval)
    {
        uint32_t div = Pcc0Reg_GetLptmrDiv(obj->pcc0Reg) + 1;
        *frequency   = freq / div;
    }

    return retval;
}

static inline bool ClockDrv_SetLptmrClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = true;

    /* Disable first before configure */
    Pcc0Reg_SetLptmrCken(obj->pcc0Reg, 0);

    switch(moduleClkConfig->source)
    {
    case CLOCKDRV_SIRC_DIV:
        Pcc0Reg_SetLptmrSrc(obj->pcc0Reg, 0);
        /* Actually 7 also works */
        break;
    case CLOCKDRV_SOSC_DIV:
        Pcc0Reg_SetLptmrSrc(obj->pcc0Reg, 1);
        break;
    case CLOCKDRV_PLL_DIV:
        Pcc0Reg_SetLptmrSrc(obj->pcc0Reg, 2);
        break;
    case CLOCKDRV_LPO_128K:
        Pcc0Reg_SetLptmrSrc(obj->pcc0Reg, 3);
        break;
    case CLOCKDRV_LPO_1K:
        Pcc0Reg_SetLptmrSrc(obj->pcc0Reg, 4);
        break;
    case CLOCKDRV_LPO_32K:
        Pcc0Reg_SetLptmrSrc(obj->pcc0Reg, 5);
        break;
    case CLOCKDRV_RTC_PADIN:
        Pcc0Reg_SetLptmrSrc(obj->pcc0Reg, 6);
        break;
    default:
        retval = false;
        break;
    }

    if(moduleClkConfig->div >= 1 && moduleClkConfig->div <= 8)
    {
        Pcc0Reg_SetLptmrDiv(obj->pcc0Reg, moduleClkConfig->div - 1);
    }
    else
    {
        retval = false;
    }

    Pcc0Reg_SetLptmrCken(obj->pcc0Reg, moduleClkConfig->gating ? 1 : 0);

    return retval;
}

static inline bool ClockDrv_GetLpitFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = false;

    /* Check if the lpit clock is enable */
    if(Pcc0Reg_GetLpitCken(obj->pcc0Reg) == 0)
    {
        return false;
    }

    switch(Pcc0Reg_GetLpitSrc(obj->pcc0Reg))
    {
    case 0: /* clk_sirc_div */
        retval = ClockDrv_GetSircDivFreq(obj, frequency);
        break;
    case 1: /* clk_pll_div */
        retval = ClockDrv_GetPllDivFreq(obj, frequency);
        break;
    case 2: /* clk_sosc_div */
        retval = ClockDrv_GetSoscDivFreq(obj, frequency);
        break;
    case 3: /* clk_lpo128 */
        *frequency = LPO_128K_FREQUENCY;
        retval     = true;
        break;
    default:
        break;
    }

    return retval;
}

static inline bool ClockDrv_SetLpitClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = true;

    /* Disable first before configure */
    Pcc0Reg_SetLpitCken(obj->pcc0Reg, 0);

    switch(moduleClkConfig->source)
    {
    case CLOCKDRV_SIRC_DIV:
        Pcc0Reg_SetLpitSrc(obj->pcc0Reg, 0);
        break;
    case CLOCKDRV_PLL_DIV:
        Pcc0Reg_SetLpitSrc(obj->pcc0Reg, 1);
        break;
    case CLOCKDRV_SOSC_DIV:
        Pcc0Reg_SetLpitSrc(obj->pcc0Reg, 2);
        break;
    case CLOCKDRV_LPO_128K:
        Pcc0Reg_SetLpitSrc(obj->pcc0Reg, 3);
        break;
    default:
        retval = false;
        break;
    }

    Pcc0Reg_SetLpitCken(obj->pcc0Reg, moduleClkConfig->gating ? 1 : 0);

    return retval;
}

static inline bool ClockDrv_GetRtcCntFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = false;

    /* Check if the rtc function clock is enable */
    if(Pcc0Reg_GetRtcCntCken(obj->pcc0Reg) == 0)
    {
        return false;
    }

    switch(Pcc0Reg_GetRtcCntSrc(obj->pcc0Reg))
    {
    case 0: /* clk_lpo32 */
        retval = ClockDrv_GetLpo32kFreq(obj, frequency);
        break;
    case 1: /* PAD RTC_CLKIN */
        retval = ClockDrv_GetRtcPadInFreq(obj, frequency);
        break;
    case 2: /* lpo1 */
        retval = ClockDrv_GetLpo1kFreq(obj, frequency);
        break;
    case 3: /* lpo1 */
        retval = ClockDrv_GetLpo1kFreq(obj, frequency);
        break;
    default:
        break;
    }

    return retval;
}

static inline bool ClockDrv_SetRtcCntClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = false;

    /* Disable first before configure */
    Pcc0Reg_SetRtcCntCken(obj->pcc0Reg, 0);

    if(moduleClkConfig->source == CLOCKDRV_LPO_32K)
    {
        Pcc0Reg_SetRtcCntSrc(obj->pcc0Reg, 0);
        retval = true;
    }
    else if(moduleClkConfig->source == CLOCKDRV_RTC_PADIN)
    {
        Pcc0Reg_SetRtcCntSrc(obj->pcc0Reg, 1);
        retval = true;
    }
    else if(moduleClkConfig->source == CLOCKDRV_LPO_1K)
    {
        Pcc0Reg_SetRtcCntSrc(obj->pcc0Reg, 2);
        /* Actually 3 is also workable */
        retval = true;
    }

    Pcc0Reg_SetRtcCntCken(obj->pcc0Reg, moduleClkConfig->gating ? 1 : 0);

    return retval;
}

static inline bool ClockDrv_GetPortAFltFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = false;
    if(Pcc0Reg_GetPortAFltSrc(obj->pcc0Reg) == 0)
    { /* clk_apb */
        retval = ClockDrv_GetApbFreq(obj, frequency);
    }
    else if(Pcc0Reg_GetPortAFltSrc(obj->pcc0Reg) == 1)
    { /* clk_lpo128 */
        retval = ClockDrv_GetLpo128kFreq(obj, frequency);
    }
    return retval;
}

static inline bool ClockDrv_SetPortAFltClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = false;
    if(moduleClkConfig->source == CLOCKDRV_APB)
    { /* clk_apb */
        Pcc0Reg_SetPortAFltSrc(obj->pcc0Reg, 0);
    }
    else if(moduleClkConfig->source == CLOCKDRV_LPO_128K)
    { /* clk_lpo128 */
        Pcc0Reg_SetPortAFltSrc(obj->pcc0Reg, 1);
    }
    return retval;
}

static inline bool ClockDrv_GetPortBFltFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = false;
    if(Pcc0Reg_GetPortBFltSrc(obj->pcc0Reg) == 0)
    { /* clk_apb */
        retval = ClockDrv_GetApbFreq(obj, frequency);
    }
    else if(Pcc0Reg_GetPortBFltSrc(obj->pcc0Reg) == 1)
    { /* clk_lpo128 */
        retval = ClockDrv_GetLpo128kFreq(obj, frequency);
    }
    return retval;
}

static inline bool ClockDrv_SetPortBFltClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = false;
    if(moduleClkConfig->source == CLOCKDRV_APB)
    { /* clk_apb */
        Pcc0Reg_SetPortBFltSrc(obj->pcc0Reg, 0);
    }
    else if(moduleClkConfig->source == CLOCKDRV_LPO_128K)
    { /* clk_lpo128 */
        Pcc0Reg_SetPortBFltSrc(obj->pcc0Reg, 1);
    }
    return retval;
}

static inline bool ClockDrv_GetPortCFltFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = false;
    if(Pcc0Reg_GetPortCFltSrc(obj->pcc0Reg) == 0)
    { /* clk_apb */
        retval = ClockDrv_GetApbFreq(obj, frequency);
    }
    else if(Pcc0Reg_GetPortCFltSrc(obj->pcc0Reg) == 1)
    { /* clk_lpo128 */
        retval = ClockDrv_GetLpo128kFreq(obj, frequency);
    }
    return retval;
}

static inline bool ClockDrv_SetPortCFltClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = false;
    if(moduleClkConfig->source == CLOCKDRV_APB)
    { /* clk_apb */
        Pcc0Reg_SetPortCFltSrc(obj->pcc0Reg, 0);
    }
    else if(moduleClkConfig->source == CLOCKDRV_LPO_128K)
    { /* clk_lpo128 */
        Pcc0Reg_SetPortCFltSrc(obj->pcc0Reg, 1);
    }
    return retval;
}

static inline bool ClockDrv_GetExtFltFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = false;

    if(RcmReg_GetExtRstFltCk(obj->rcmReg) == 0)
    {
        /* clk_apb */
        retval = ClockDrv_GetApbFreq(obj, frequency);
    }
    else if(RcmReg_GetExtRstFltCk(obj->rcmReg) == 1)
    {
        /* clk_lpo128 */
        *frequency = LPO_128K_FREQUENCY;
        retval     = true;
    }

    return retval;
}

static inline bool ClockDrv_SetExtFltClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = false;

    if(moduleClkConfig->source == CLOCKDRV_APB)
    {
        RcmReg_SetExtRstFltCk(obj->rcmReg, 0);
        retval = true;
    }
    else if(moduleClkConfig->source == CLOCKDRV_LPO_128K)
    {
        RcmReg_SetExtRstFltCk(obj->rcmReg, 1);
        retval = true;
    }

    return retval;
}

static inline bool ClockDrv_GetDmaFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetDmaCkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }
    return ClockDrv_GetCoreFreq(obj, frequency);
}

static inline bool ClockDrv_SetDmaClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc1Reg_SetDmaCkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetMscmFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetMscmCkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }
    return ClockDrv_GetApbFreq(obj, frequency);
}

static inline bool ClockDrv_SetMscmClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc1Reg_SetMscmCkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetCrcFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetCrcCkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }
    return ClockDrv_GetApbFreq(obj, frequency);
}

static inline bool ClockDrv_SetCrcClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc1Reg_SetCrcCkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetEimFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetEimCkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }
    return ClockDrv_GetApbFreq(obj, frequency);
}

static inline bool ClockDrv_SetEimClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc1Reg_SetEimCkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetErmFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetErmCkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }
    return ClockDrv_GetCoreFreq(obj, frequency);
}

static inline bool ClockDrv_SetErmClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc1Reg_SetErmCkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetFhuFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetFhuCkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }
    return ClockDrv_GetApbFreq(obj, frequency);
}

static inline bool ClockDrv_SetFhuClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc1Reg_SetFhuCkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetAdcFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = false;
    if(Pcc0Reg_GetAdcCkEn(obj->pcc0Reg))
    {
        uint32_t freq = 0;
        switch(Pcc0Reg_GetAdcSrc(obj->pcc0Reg))
        {
        case 0: /* clk_sirc */
            retval = ClockDrv_GetSircFreq(obj, &freq);
            break;
        case 1: /* clk_sosc */
            retval = ClockDrv_GetSoscFreq(obj, &freq);
            break;
        case 2: /* clk_pll */
            retval = ClockDrv_GetPllFreq(obj, &freq);
            break;
        case 3: /* clk_pll_div */
            retval = ClockDrv_GetPllDivFreq(obj, &freq);
            break;
        default:
            break;
        }
        if(retval == true)
        {
            *frequency = freq / (Pcc0Reg_GetAdcDiv(obj->pcc0Reg) + 1);
        }
    }
    return retval;
}

static inline bool ClockDrv_SetAdcClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = true;

    /* Disable first before configure */
    Pcc0Reg_SetAdcCkEn(obj->pcc0Reg, 0);

    switch(moduleClkConfig->source)
    {
    case CLOCKDRV_SIRC:
        Pcc0Reg_SetAdcSrc(obj->pcc0Reg, 0);
        break;
    case CLOCKDRV_SOSC:
        Pcc0Reg_SetAdcSrc(obj->pcc0Reg, 1);
        break;
    case CLOCKDRV_PLL:
        Pcc0Reg_SetAdcSrc(obj->pcc0Reg, 2);
        break;
    case CLOCKDRV_PLL_DIV:
        Pcc0Reg_SetAdcSrc(obj->pcc0Reg, 3);
        break;
    default:
        retval = false;
        break;
    }

    if(moduleClkConfig->div >= 1 && moduleClkConfig->div <= 16)
    {
        Pcc0Reg_SetAdcDiv(obj->pcc0Reg, moduleClkConfig->div - 1);
    }
    else
    {
        retval = false;
    }

    Pcc0Reg_SetAdcCkEn(obj->pcc0Reg, moduleClkConfig->gating ? 1 : 0);

    return retval;
}

static inline bool ClockDrv_GetPdbFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc0Reg_GetPdbCkEn(obj->pcc0Reg) == 0)
    {
        return false;
    }
    return ClockDrv_GetApbFreq(obj, frequency);
}

static inline bool ClockDrv_SetPdbClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc0Reg_SetPdbCkEn(obj->pcc0Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetSpi0Freq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetSpi0CkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }

    bool retval = true;
    switch(Pcc1Reg_GetSpi0Src(obj->pcc1Reg))
    {
    case 0: /* clk_sirc_div */
        retval = ClockDrv_GetSircDivFreq(obj, frequency);
        break;
    case 1: /* clk_sosc_div */
        retval = ClockDrv_GetSoscDivFreq(obj, frequency);
        break;
    case 2: /* clk_pll_div */
        retval = ClockDrv_GetPllDivFreq(obj, frequency);
        break;
    case 3: /* clk_sirc_div */
        retval = ClockDrv_GetSircDivFreq(obj, frequency);
        break;
    default:
        retval = false;
        break;
    }

    return retval;
}

static inline bool ClockDrv_SetSpi0Clock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = false;
    /* Disable first before configure */
    Pcc1Reg_SetSpi0CkEn(obj->pcc1Reg, 0);
    /* Select source */
    uint8_t select = moduleClkConfig->source == CLOCKDRV_SIRC_DIV ? 0 : (moduleClkConfig->source == CLOCKDRV_SOSC_DIV ? 1 : (moduleClkConfig->source == CLOCKDRV_PLL_DIV ? 2 : 0xff));
    if(select != 0xff)
    {
        Pcc1Reg_SetSpi0Src(obj->pcc1Reg, select);
        retval = true;
    }

    Pcc1Reg_SetSpi0CkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);

    return retval;
}

static inline bool ClockDrv_GetSpi1Freq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetSpi1CkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }

    bool retval = true;
    switch(Pcc1Reg_GetSpi1Src(obj->pcc1Reg))
    {
    case 0: /* clk_sirc_div */
        retval = ClockDrv_GetSircDivFreq(obj, frequency);
        break;
    case 1: /* clk_sosc_div */
        retval = ClockDrv_GetSoscDivFreq(obj, frequency);
        break;
    case 2: /* clk_pll_div */
        retval = ClockDrv_GetPllDivFreq(obj, frequency);
        break;
    case 3: /* clk_sirc_div */
        retval = ClockDrv_GetSircDivFreq(obj, frequency);
        break;
    default:
        retval = false;
        break;
    }

    return retval;
}

static inline bool ClockDrv_SetSpi1Clock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = false;
    /* Disable first before configure */
    Pcc1Reg_SetSpi1CkEn(obj->pcc1Reg, 0);
    /* Select source */
    uint8_t select = moduleClkConfig->source == CLOCKDRV_SIRC_DIV ? 0 : (moduleClkConfig->source == CLOCKDRV_SOSC_DIV ? 1 : (moduleClkConfig->source == CLOCKDRV_PLL_DIV ? 2 : 0xff));
    if(select != 0xff)
    {
        Pcc1Reg_SetSpi1Src(obj->pcc1Reg, select);
        retval = true;
    }

    Pcc1Reg_SetSpi1CkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);

    return retval;
}

static inline bool ClockDrv_GetUart0Freq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetUart0CkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }

    bool retval = true;
    switch(Pcc1Reg_GetUart0Src(obj->pcc1Reg))
    {
    case 0: /* clk_sirc_div */
        retval = ClockDrv_GetSircDivFreq(obj, frequency);
        break;
    case 1: /* clk_sosc_div */
        retval = ClockDrv_GetSoscDivFreq(obj, frequency);
        break;
    case 2: /* clk_pll_div */
        retval = ClockDrv_GetPllDivFreq(obj, frequency);
        break;
    case 3: /* clk_sirc_div */
        retval = ClockDrv_GetSircDivFreq(obj, frequency);
        break;
    default:
        retval = false;
        break;
    }

    return retval;
}

static inline bool ClockDrv_SetUart0Clock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = false;
    /* Disable first before configure */
    Pcc1Reg_SetUart0CkEn(obj->pcc1Reg, 0);
    /* Select source */
    uint8_t select = moduleClkConfig->source == CLOCKDRV_SIRC_DIV ? 0 : (moduleClkConfig->source == CLOCKDRV_SOSC_DIV ? 1 : (moduleClkConfig->source == CLOCKDRV_PLL_DIV ? 2 : 0xff));
    if(select != 0xff)
    {
        Pcc1Reg_SetUart0Src(obj->pcc1Reg, select);
        retval = true;
    }

    Pcc1Reg_SetUart0CkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);

    return retval;
}

static inline bool ClockDrv_GetUart1Freq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetUart1CkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }

    bool retval = true;
    switch(Pcc1Reg_GetUart1Src(obj->pcc1Reg))
    {
    case 0: /* clk_sirc_div */
        retval = ClockDrv_GetSircDivFreq(obj, frequency);
        break;
    case 1: /* clk_sosc_div */
        retval = ClockDrv_GetSoscDivFreq(obj, frequency);
        break;
    case 2: /* clk_pll_div */
        retval = ClockDrv_GetPllDivFreq(obj, frequency);
        break;
    case 3: /* clk_sirc_div */
        retval = ClockDrv_GetSircDivFreq(obj, frequency);
        break;
    default:
        retval = false;
        break;
    }

    return retval;
}

static inline bool ClockDrv_SetUart1Clock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = false;
    /* Disable first before configure */
    Pcc1Reg_SetUart1CkEn(obj->pcc1Reg, 0);
    /* Select source */
    uint8_t select = moduleClkConfig->source == CLOCKDRV_SIRC_DIV ? 0 : (moduleClkConfig->source == CLOCKDRV_SOSC_DIV ? 1 : (moduleClkConfig->source == CLOCKDRV_PLL_DIV ? 2 : 0xff));
    if(select != 0xff)
    {
        Pcc1Reg_SetUart1Src(obj->pcc1Reg, select);
        retval = true;
    }

    Pcc1Reg_SetUart1CkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);

    return retval;
}

static inline bool ClockDrv_GetI2CFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetI2CCkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }

    bool retval = true;
    switch(Pcc1Reg_GetI2CSrc(obj->pcc1Reg))
    {
    case 0: /* clk_sirc_div */
        retval = ClockDrv_GetSircDivFreq(obj, frequency);
        break;
    case 1: /* clk_sosc_div */
        retval = ClockDrv_GetSoscDivFreq(obj, frequency);
        break;
    case 2: /* clk_pll_div */
        retval = ClockDrv_GetPllDivFreq(obj, frequency);
        break;
    case 3: /* clk_sirc_div */
        retval = ClockDrv_GetSircDivFreq(obj, frequency);
        break;
    default:
        retval = false;
        break;
    }

    return retval;
}

static inline bool ClockDrv_SetI2CClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = false;
    /* Disable first before configure */
    Pcc1Reg_SetI2CCkEn(obj->pcc1Reg, 0);
    /* Select source */
    uint8_t select = moduleClkConfig->source == CLOCKDRV_SIRC_DIV ? 0 : (moduleClkConfig->source == CLOCKDRV_SOSC_DIV ? 1 : (moduleClkConfig->source == CLOCKDRV_PLL_DIV ? 2 : 0xff));
    if(select != 0xff)
    {
        Pcc1Reg_SetI2CSrc(obj->pcc1Reg, select);
        retval = true;
    }

    Pcc1Reg_SetI2CCkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);

    return retval;
}

static inline bool ClockDrv_GetPwmLite0Freq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetPwm0CkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }
    return ClockDrv_GetApbFreq(obj, frequency);
}

static inline bool ClockDrv_SetPwmLite0Clock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc1Reg_SetPwm0CkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetPwmLite1Freq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetPwm1CkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }
    return ClockDrv_GetApbFreq(obj, frequency);
}

static inline bool ClockDrv_SetPwmLite1Clock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc1Reg_SetPwm1CkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetMft0Freq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetMft0CkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }
    return ClockDrv_GetCoreFreq(obj, frequency);
}

static inline bool ClockDrv_SetMft0Clock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc1Reg_SetMft0CkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetMft1Freq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetMft1CkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }
    return ClockDrv_GetCoreFreq(obj, frequency);
}

static inline bool ClockDrv_SetMft1Clock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc1Reg_SetMft1CkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetCmusFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetCmusCkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }
    return ClockDrv_GetSoscFreq(obj, frequency);
}

static inline bool ClockDrv_SetCmusClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc1Reg_SetCmusCkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetCmupFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetCmupCkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }
    return ClockDrv_GetPllFreq(obj, frequency);
}

static inline bool ClockDrv_SetCmupClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc1Reg_SetCmupCkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

static inline bool ClockDrv_GetTclk0Freq(const ClockDrvType *obj, uint32_t *frequency)
{
    (void)obj; /* Unused, avoid warning */
    *frequency = obj->tclkFreq[0];
    return true;
}

static inline bool ClockDrv_GetTclk1Freq(const ClockDrvType *obj, uint32_t *frequency)
{
    (void)obj; /* Unused, avoid warning */
    *frequency = obj->tclkFreq[1];
    return true;
}

static inline bool ClockDrv_GetTclk2Freq(const ClockDrvType *obj, uint32_t *frequency)
{
    (void)obj; /* Unused, avoid warning */
    *frequency = obj->tclkFreq[2];
    return true;
}

static inline bool ClockDrv_GetExtMft0Freq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = true;
    switch(Pcc1Reg_GetExtMft0Src(obj->pcc1Reg))
    {
    case 0: /* TCLK0 */
        retval = ClockDrv_GetTclk0Freq(obj, frequency);
        break;
    case 1: /* TCLK1 */
        retval = ClockDrv_GetTclk1Freq(obj, frequency);
        break;
    case 2: /* TCLK2 */
        retval = ClockDrv_GetTclk2Freq(obj, frequency);
        break;
    case 3: /* clk_sirc_div_mft */
        retval = ClockDrv_GetSircDivMftFreq(obj, frequency);
        break;
    case 4: /* clk_sosc_div_mft */
        retval = ClockDrv_GetSoscDivMftFreq(obj, frequency);
        break;
    case 5: /* clk_pll_div_mft */
        retval = ClockDrv_GetPllDivMftFreq(obj, frequency);
        break;
    case 6: /* clk_sirc_div_mft */
    case 7: /* clk_sirc_div_mft */
        retval = ClockDrv_GetSircDivMftFreq(obj, frequency);
        break;
    default:
        retval = false;
        break;
    }

    return retval;
}

static inline bool ClockDrv_SetExtMft0Clock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = true;

    /* Select source */
    switch(moduleClkConfig->source)
    {
    case CLOCKDRV_TCLK0: /* TCLK0 */
        Pcc1Reg_SetExtMft0Src(obj->pcc1Reg, 0);
        break;
    case CLOCKDRV_TCLK1: /* TCLK1 */
        Pcc1Reg_SetExtMft0Src(obj->pcc1Reg, 1);
        break;
    case CLOCKDRV_TCLK2: /* TCLK2 */
        Pcc1Reg_SetExtMft0Src(obj->pcc1Reg, 2);
        break;
    case CLOCKDRV_SIRC_DIV_MFT: /* clk_sirc_div_mft */
        Pcc1Reg_SetExtMft0Src(obj->pcc1Reg, 3);
        /* Actually it can also be 6 or 7 */
        break;
    case CLOCKDRV_SOSC_DIV_MFT: /* clk_sosc_div_mft */
        Pcc1Reg_SetExtMft0Src(obj->pcc1Reg, 4);
        break;
    case CLOCKDRV_PLL_DIV_MFT: /* clk_pll_div_mft */
        Pcc1Reg_SetExtMft0Src(obj->pcc1Reg, 5);
        break;
    default:
        retval = false;
        break;
    }

    return retval;
}

static inline bool ClockDrv_GetExtMft1Freq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = true;
    switch(Pcc1Reg_GetExtMft1Src(obj->pcc1Reg))
    {
    case 0: /* TCLK0 */
        retval = ClockDrv_GetTclk0Freq(obj, frequency);
        break;
    case 1: /* TCLK1 */
        retval = ClockDrv_GetTclk1Freq(obj, frequency);
        break;
    case 2: /* TCLK2 */
        retval = ClockDrv_GetTclk2Freq(obj, frequency);
        break;
    case 3: /* clk_sirc_div_mft */
        retval = ClockDrv_GetSircDivMftFreq(obj, frequency);
        break;
    case 4: /* clk_sosc_div_mft */
        retval = ClockDrv_GetSoscDivMftFreq(obj, frequency);
        break;
    case 5: /* clk_pll_div_mft */
        retval = ClockDrv_GetPllDivMftFreq(obj, frequency);
        break;
    case 6: /* clk_sirc_div_mft */
    case 7: /* clk_sirc_div_mft */
        retval = ClockDrv_GetSircDivMftFreq(obj, frequency);
        break;
    default:
        retval = false;
        break;
    }

    return retval;
}

static inline bool ClockDrv_SetExtMft1Clock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = true;
    /* Select source */
    switch(moduleClkConfig->source)
    {
    case CLOCKDRV_TCLK0: /* TCLK0 */
        Pcc1Reg_SetExtMft1Src(obj->pcc1Reg, 0);
        break;
    case CLOCKDRV_TCLK1: /* TCLK1 */
        Pcc1Reg_SetExtMft1Src(obj->pcc1Reg, 1);
        break;
    case CLOCKDRV_TCLK2: /* TCLK2 */
        Pcc1Reg_SetExtMft1Src(obj->pcc1Reg, 2);
        break;
    case CLOCKDRV_SIRC_DIV_MFT: /* clk_sirc_div_mft */
        Pcc1Reg_SetExtMft1Src(obj->pcc1Reg, 3);
        /* Actually it can also be 6 or 7 */
        break;
    case CLOCKDRV_SOSC_DIV_MFT: /* clk_sosc_div_mft */
        Pcc1Reg_SetExtMft1Src(obj->pcc1Reg, 4);
        break;
    case CLOCKDRV_PLL_DIV_MFT: /* clk_pll_div_mft */
        Pcc1Reg_SetExtMft1Src(obj->pcc1Reg, 5);
        break;
    default:
        retval = false;
        break;
    }

    return retval;
}

static inline bool ClockDrv_GetFixMft0Freq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = true;
    switch(Pcc1Reg_GetFixMft0Src(obj->pcc1Reg))
    {
    case 0: /* clk_lpo32 */
        retval = ClockDrv_GetLpo32kFreq(obj, frequency);
        break;
    case 1: /* RTC_CLKIN */
        retval = ClockDrv_GetRtcPadInFreq(obj, frequency);
        break;
    default:
        retval = false;
        break;
    }

    return retval;
}

static inline bool ClockDrv_SetFixMft0Clock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = true;

    /* Select source */
    switch(moduleClkConfig->source)
    {
    case CLOCKDRV_LPO_32K: /* clk_lpo32 */
        Pcc1Reg_SetFixMft0Src(obj->pcc1Reg, 0);
        break;
    case CLOCKDRV_RTC_PADIN: /* RTC_CLKIN */
        Pcc1Reg_SetFixMft0Src(obj->pcc1Reg, 1);
        break;
    default:
        retval = false;
        break;
    }

    return retval;
}

static inline bool ClockDrv_GetFixMft1Freq(const ClockDrvType *obj, uint32_t *frequency)
{
    bool retval = true;
    switch(Pcc1Reg_GetFixMft1Src(obj->pcc1Reg))
    {
    case 0: /* clk_lpo32 */
        retval = ClockDrv_GetLpo32kFreq(obj, frequency);
        break;
    case 1: /* RTC_CLKIN */
        retval = ClockDrv_GetRtcPadInFreq(obj, frequency);
        break;
    default:
        retval = false;
        break;
    }

    return retval;
}

static inline bool ClockDrv_SetFixMft1Clock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    bool retval = true;

    /* Select source */
    switch(moduleClkConfig->source)
    {
    case CLOCKDRV_LPO_32K: /* clk_lpo32 */
        Pcc1Reg_SetFixMft1Src(obj->pcc1Reg, 0);
        break;
    case CLOCKDRV_RTC_PADIN: /* RTC_CLKIN */
        Pcc1Reg_SetFixMft1Src(obj->pcc1Reg, 1);
        break;
    default:
        retval = false;
        break;
    }

    return retval;
}

static inline bool ClockDrv_GetMpuFreq(const ClockDrvType *obj, uint32_t *frequency)
{
    if(Pcc1Reg_GetMpuCkEn(obj->pcc1Reg) == 0)
    {
        return false;
    }
    return ClockDrv_GetCoreFreq(obj, frequency);
}

static inline bool ClockDrv_SetMpuClock(ClockDrvType *obj, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    Pcc1Reg_SetMpuCkEn(obj->pcc1Reg, moduleClkConfig->gating ? 1 : 0);
    return true;
}

void ClockDrv_Init(ClockDrvType                  *obj,
                   struct _RcmRegType_           *rcmReg,
                   struct _Pcc0RegType_          *pcc0Reg,
                   struct _Scg0RegType_          *scg0Reg,
                   struct _Scg1RegType_          *scg1Reg,
                   struct _Pcc1RegType_          *pcc1Reg,
                   struct _Scg2RegType_          *scg2Reg,
                   const ClockDrv_InitParamsType *initParams)
{
    obj->rcmReg       = rcmReg;
    obj->pcc0Reg      = pcc0Reg;
    obj->scg0Reg      = scg0Reg;
    obj->scg1Reg      = scg1Reg;
    obj->pcc1Reg      = pcc1Reg;
    obj->scg2Reg      = scg2Reg;
    obj->sircFreq     = initParams->sircFreq;
    obj->xtalClkFreq  = initParams->xtalClkFreq;
    obj->rtcClkInFreq = initParams->rtcClkInFreq;
    uint8_t i         = 0;
    for(i = 0; i < TCLK_INPUTS_NUM; ++i)
    {
        obj->tclkFreq[i] = initParams->tclkFreq[i];
    }
}

bool ClockDrv_GetFreq(const ClockDrvType *obj, ClockDrv_NamesType clockName, uint32_t *frequency)
{
    if(clockName >= CLOCKDRV_CLOCK_NUM)
    {
        return false;
    }

    bool retval = false;
    if(c_clockFuncTable[clockName].getFreqFunc != NULL)
    {
        retval = c_clockFuncTable[clockName].getFreqFunc(obj, frequency);
    }
    return retval;
}

bool ClockDrv_ConfigureClock(ClockDrvType *obj, ClockDrv_NamesType clockName, const ClockDrv_ModuleClkConfigType *moduleClkConfig)
{
    if(clockName >= CLOCKDRV_CLOCK_NUM)
    {
        return false;
    }

    bool retval = false;
    if(c_clockFuncTable[clockName].setClockFunc != NULL)
    {
        Pcc0Reg_SetKey(obj->pcc0Reg, 0x55534552); /* Unlock PCC0, PCC1 */
        Scg0Reg_SetKey(obj->scg0Reg, 0x19962020); /* Unlock SCG0, SCG1, SCG2 */
        RcmReg_SetKey(obj->rcmReg, 0x52434D4B); /* Unlock RCM */
        retval = c_clockFuncTable[clockName].setClockFunc(obj, moduleClkConfig);
        Pcc0Reg_SetKey(obj->pcc0Reg, 0); /* Lock PCC0, PCC1 again */
        Scg0Reg_SetKey(obj->scg0Reg, 0); /* Lock SCG0, SCG1, SCG2 again */
        RcmReg_SetKey(obj->rcmReg, 0); /* Lock RCM again */
    }

    return retval;
}
