/**
* @file         spv40xx_cmu.c
* @brief        提供系统时钟配置api，实现所有模块时钟配置
* @details      Null
*
* @author       系统软件部 - t
* @date         2023-05-23 14:10
* @version      V0.1
* @copyright    Copyright (c) 2017-2023  SpaceTouch Inc.
* +v0.1
*   添加断言
*   添加获取模块时钟函数（暂时添加部分）
 ===============================================================================
                      ##### CMU specific features #####
 ===============================================================================
    [..]
        *所有模块应该先调用时钟设置函数，再配置模块寄存器。
        *时钟接口分为上游时钟和下游时钟接口，下游时钟源只能为cmu_clock_source_t中元素:
    [..]
        *上游时钟接口风格为 int32_t cmu_set_xxx();     xxx为时钟名
        *下游之中接口统一为  int32_t cmu_xxx_set_clk();    xxx为模块名
        所有函数返回值统一如下：
             0：成功；
            -1：不支持的时钟源；
            -2：支持的时钟源未开启；
            -3：不支持的时钟输出频率；
        *另外上游时钟可获取使能状态 uint32_t cmu_get_xxx_state();
    [..]
        *时钟一但设置，就会同时使能，暂不提供关闭时钟API
        *部分时钟工作前，需要使能电源：
            CMU_Clock_PLL_CORE需要通过cmu_set_dvdd()函数打开DVDD电压；
            CMU_Clock_PLL_AUDIO需要通过cmu_set_avcc()函数打开AVCC电压
    [..]
        *dvdd电压每次更改差值不要超过2
        *高频系统时钟切换流程，例如使用corepll高频时钟作系统输入时钟：
            1).先设置corepll的时钟源，并等待其工作
            2).将系统时钟源切为corepll的时钟源
            3).将dvdd电压升至合适值
            4).设置corepll时钟参数，并等待其工作
            5).再切系统时钟源为corepll
    [..]
        请注意cmu_set_oscphy()和 cmu_set_pllusb()存在严重副作用，
    [..]
        CMU_Clock_EXT_AON与CMU_Clock_EXT_DEV目前没有配置函数

*/

#include "hal_log.h"
#include "hal_common.h"
#include "hal_cmu.h"
#include "debug.h"

#define __OSC_ADC_FREQ_HZ       (512000UL)
#define __OSC_DEV_FREQ_HZ       (24000000UL)
#define __OSC_XTAL_FREQ_HZ      (24000000UL)
#define __OSC_PHY_FREQ_HZ       (32000000UL)
#define __OSC_PLLUSB_FREQ_HZ    (480000000UL)


/**
===================================================================================
##### 上游时钟，配置接口 #####
===================================================================================
*/

/**
* @brief        打开dev振荡器
* @details      Null
* @param        Null
* @return       0：成功
* @note         会使能与aon的通信。
*/
int32_t cmu_set_oscdev()
{
    DEV_RMU->RSTEN0_f.AON = 1;
    DEV_CMU->CLKEN0_f.AON = 1;
    AON_OSC->DEV_CTL |= AON_OSC_DEV_CTL_DEV_EN;
    return 0;
}

/**
* @brief        获取dev振荡器使能状态
* @details      Null
* @param        Null
* @return       Null
* @note         会使能与aon的通信。
*/
uint32_t cmu_get_oscdev_state()
{
    uint32_t state = DISABLE;
    DEV_RMU->RSTEN0_f.AON = 1;
    DEV_CMU->CLKEN0_f.AON = 1;

    if (AON_OSC->DEV_CTL_f.DEV_EN != RESET)
    {
        state = ENABLE;
    }

    return state;
}
uint32_t cmu_enable_usb_clock(void)
{
    DEV_RMU->RSTEN0 |= DEV_CMU_CLKEN0_USB;
    DEV_CMU->CLKEN0 |= DEV_RMU_RSTEN0_USB;
    DEV_CMU->USBCLK |= (1 << 2) | (1 << 0); // USB_CLK SEL OSC_XTAL & EN
    DEV_UREG->USB_PHY_CTRL0 = (120 << 16) | //
                              (3 << 12) |   //
                              (3 << 8) |    //
                              (1 << 7) |    // PLL divider's input value select software mode
                              (1 << 3) |    // PLL reference clock select CLK12M
                              (1 << 2) |    // Force to enable PLL
                              (1 << 1) |    // EN-PHY Power on
                              (0 << 0)      // USB PHY working
                              ;
    DEV_UREG->USB_PLL_CTRL |= (0 << 29)     // OSC_USB_DIV 1
                              | (0 << 28)     // OSC_USB_SEL XCLK
                              | (1 << 26)     // PLL_USB Clock enable
                              | (1 << 25)     // OSC_USB Clock enable
                              | (1 << 24)     // USB_SOF Clock enable
                              ;
    return 0;
}

/**
* @brief        设置晶振振荡器的可配置电容参数
* @details      Null
* @param        icapf   范围0-0x1f
*               icapc   范围0-0xf
*               ocapf   范围0-0x1f
*               ocapc   范围0-0xf
* @return       0
* @note         会使能与aon的通信。
*/
int32_t cmu_set_oscxtal_capacitance(uint32_t icapf, uint32_t icapc, uint32_t ocapf, uint32_t ocapc)
{
    uint32_t osc_xtal_ctl;
    hal_assert(IS_CMU_OSCXTAL_CAPF(icapf));
    hal_assert(IS_CMU_OSCXTAL_CAPC(icapc));
    hal_assert(IS_CMU_OSCXTAL_CAPF(ocapf));
    hal_assert(IS_CMU_OSCXTAL_CAPC(ocapc));
    DEV_RMU->RSTEN0_f.AON = 1;
    DEV_CMU->CLKEN0_f.AON = 1;
    osc_xtal_ctl = AON_OSC->XTAL_CTL;
    osc_xtal_ctl &= ~(AON_OSC_XTAL_CTL_ICAPF_MASK
                      | AON_OSC_XTAL_CTL_ICAPC_MASK
                      | AON_OSC_XTAL_CTL_OCAPF_MASK
                      | AON_OSC_XTAL_CTL_OCAPC_MASK);
    osc_xtal_ctl |= (icapf << 21)
                    | (icapc << 17)
                    | (ocapf << 12)
                    | (ocapc << 8)
                    | AON_OSC_XTAL_CTL_CAPON;
    AON_OSC->XTAL_CTL = osc_xtal_ctl;
    return 0;
}

/**
* @brief        设置晶振振荡器的GM参数
* @details      Null
* @param        value   范围0-0xf
* @return       0
* @note         会使能与aon的通信。
*/
int32_t cmu_set_oscxtal_gmctl(uint32_t value)
{
    uint32_t osc_xtal_ctl;
    hal_assert(IS_CMU_OSCXTAL_GMCTL(value));
    DEV_RMU->RSTEN0_f.AON = 1;
    DEV_CMU->CLKEN0_f.AON = 1;
    osc_xtal_ctl = AON_OSC->XTAL_CTL;
    osc_xtal_ctl &= ~AON_OSC_XTAL_CTL_GMCTL_MASK;
    osc_xtal_ctl |= value << 4;
    AON_OSC->XTAL_CTL = osc_xtal_ctl;
    return 0;
}

/**
* @brief        打开外部晶振
* @details      Null
* @param        Null
* @return       0：成功
* @note         会使能与aon的通信。
*/
int32_t cmu_set_oscxtal()
{
    DEV_RMU->RSTEN0_f.AON = 1;
    DEV_CMU->CLKEN0_f.AON = 1;
    AON_OSC->XTAL_CTL |= AON_OSC_XTAL_CTL_EN;
    return 0;
}

/**
* @brief        获取晶振使能状态
* @details      Null
* @param        Null
* @return       - ENABLE 振荡器使能
*               - DISABLE 振荡器失能
* @note         会使能与aon的通信。
*/
uint32_t cmu_get_oscxtal_state()
{
    uint32_t state = DISABLE;
    DEV_RMU->RSTEN0_f.AON = 1;
    DEV_CMU->CLKEN0_f.AON = 1;

    if (AON_OSC->XTAL_CTL_f.EN != RESET)
    {
        state = ENABLE;
    }

    return state;
}


/**
* @brief        使能phy振荡器
* @details      Null
* @param        Null
* @return       0：成功
* @note         注意，此函数会打开cmu中usb时钟使能，
*               !!!特别注意，会使usb_rc时钟源工作，等效将usb pll时钟源换成usb_rc
*/
int32_t cmu_set_oscphy()
{
    DEV_RMU->RSTEN0_f.USB = 1;
    DEV_CMU->CLKEN0_f.USB = 1;
    //usb phy ctrl0 寄存器，置位bit[1] en_phy
    *(volatile uint32_t *)(0x20006000UL) |= 1UL << 1;
    //usb phy ctrl0 寄存器，复位bit[0] bit[3] ，对应phy时钟工作和 使usb rc工作且将pll时钟源切至rc
    // bit[3]不复位，usb 内部时钟不工作
    *(volatile uint32_t *)(0x20006000UL) &= ~(1UL | 1UL << 3);
    //usb_pll_ctrl寄存器，置位bit[25] bit[28] 对应 phy时钟外放，和选择usb_rc时钟
    *(volatile uint32_t *)(0x20006000UL + 0xc) |= (1UL << 25) | (1UL << 28);
    return 0;
}
/**
* @brief        获取phy振荡器使能状态
* @details      Null
* @param        Null
* @return       - ENABLE 振荡器使能
*               - DISABLE 振荡器失能
* @note
*/
uint32_t cmu_get_oscphy_state()
{
    return (((*(volatile uint32_t *)(0x20006000UL + 0xc)) & (1 << 25)) != RESET) ? ENABLE : DISABLE;
}


/**
* @brief        使能usb锁相环时钟
* @details      Null
* @param        Null
* @return       0：成功
* @note         !!!特别注意，会使usb_rc时钟源工作，等效将usb pll时钟源换成usb_rc
*/
int32_t cmu_set_pllusb()
{
    DEV_RMU->RSTEN0_f.USB = 1;
    DEV_CMU->CLKEN0_f.USB = 1;
    //usb phy ctrl0 寄存器，置位bit[1]  en_phy
    *(volatile uint32_t *)(0x20006000UL) |= (1UL << 1);
    //usb phy ctrl0 寄存器，复位bit[0] bit[3] ，对应phy时钟工作和 使usb rc工作且将pll时钟源切至rc
    // bit[3]不复位，usb 内部时钟不工作
    *(volatile uint32_t *)(0x20006000UL) &= ~(1UL | 1UL << 3);
    //usb_pll_ctrl寄存器，置位bit[26]  pll时钟外放
    *(volatile uint32_t *)(0x20006000UL + 0xc) |= (1UL << 26);
    return 0;
}
/**
* @brief        获取usb锁相环时钟状态
* @details      Null
* @param        Null
* @return       - ENABLE 锁相环时钟使能
*               - DISABLE 锁相环时钟失能
* @note         获取值为DISABLE只是为时钟未对usb pll以外输出而已。它的工作状态不会改变
*/
uint32_t cmu_get_pllusb_state()
{
    return (((*(volatile uint32_t *)(0x20006000UL + 0xc)) & (1 << 26)) != RESET) ? ENABLE : DISABLE;
}




/**
* @brief        使能core锁相环
* @details      Null
* @param        source_clk 锁相环输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*               freq_out_mhz 锁相环输出时钟，只能为6Mhz的倍数，向下取值
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         升频率时需要调节vdd电压，vdd电压跨步不能太大；
*               输出只设置6M倍数时钟，向下取值
*/
int32_t cmu_set_pllcore(cmu_clock_source_t source_clk, uint32_t freq_out_mhz)
{
    int32_t ret = 0;
    hal_assert(IS_CMU_PLLCORE_SRCCLK(source_clk));
    hal_assert(IS_CMU_PLLCORE_OUT_MHZ(freq_out_mhz));
    uint32_t real_out_freq = freq_out_mhz / 6;
    DEV_RMU->RSTEN0_f.AON = 1;
    DEV_CMU->CLKEN0_f.AON = 1;

    switch (source_clk)
    {
    case CMU_Clock_OSC_DEV:
        if (AON_OSC->DEV_CTL_f.DEV_EN != RESET)
        {
            AON_PLL->CORE_CTL = (0 << 1)
                                | AON_PLL_CORE_CTL_CUST_HARDWAREMODE
                                | real_out_freq << 4
                                | AON_PLL_CORE_CTL_EN
                                ;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (AON_OSC->XTAL_CTL_f.EN != RESET)
        {
            AON_PLL->CORE_CTL = (1 << 1)
                                | AON_PLL_CORE_CTL_CUST_HARDWAREMODE
                                | real_out_freq << 4
                                | AON_PLL_CORE_CTL_EN
                                ;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:

        //检测 外放phy时钟 是否使能
        if (((*(volatile uint32_t *)(0x20006000UL + 0xc)) & (1 << 25)) != RESET)
        {
            AON_PLL->CORE_CTL = (2 << 1)
                                | AON_PLL_CORE_CTL_CUST_HARDWAREMODE
                                | real_out_freq << 4
                                | AON_PLL_CORE_CTL_EN
                                ;
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    return ret;
}


/**
* @brief        获取core锁相环时钟状态
* @details      Null
* @param        Null
* @return       - ENABLE 锁相环时钟使能
*               - DISABLE 锁相环时钟失能
* @note         会使能与aon的通信。
*/
uint32_t cmu_get_pllcore_state()
{
    uint32_t state = DISABLE;
    DEV_RMU->RSTEN0_f.AON = 1;
    DEV_CMU->CLKEN0_f.AON = 1;

    if (AON_PLL->CORE_CTL_f.EN != RESET)
    {
        state = ENABLE;
    }

    return state;
}


/**
* @brief        使能audio锁相环
* @details      Fout*POSTDIV/CLK_SRC=LOOP_INT+LOOP_FRAC
* @param        source_clk 锁相环输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*               freq_out_mhz 锁相环输出时钟，参数为cmu_pllaudio_output_t元素
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
*               -3：不支持输出时钟频率
* @note         会使能与aon的通信。
*               该函数成立建立在dev和xtal时钟一定为24Mhz，phy时钟一定为32Mhz，否则输出不对。
*/
int32_t cmu_set_pllaudio(cmu_clock_source_t source_clk, cmu_pllaudio_output_t pllaudio_out)
{
    int32_t ret = 0;
    hal_assert(IS_CMU_PLLAUDIO_SRCCLK(source_clk));
    DEV_RMU->RSTEN0_f.AON = 1;
    DEV_CMU->CLKEN0_f.AON = 1;

    switch (source_clk)
    {
    case CMU_Clock_OSC_DEV:
        if (AON_OSC->DEV_CTL_f.DEV_EN != RESET)
        {
            switch (pllaudio_out)
            {
            case CMU_PLLADUIO_Output_11289600hz:
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_DEV
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_10
                                      | 4 << 16;
                AON_PLL->AUDIO_CTL1 = 0xb4396;
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 9;
                break;

            case CMU_PLLADUIO_Output_12288000hz:
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_DEV
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_08
                                      | 4 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0x18937;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 10;
                break;

            case CMU_PLLADUIO_Output_22579200hz:
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_DEV
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_05
                                      | 4 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0xb4396;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 9;
                break;

            case CMU_PLLADUIO_Output_24576000hz:
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_DEV
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_04
                                      | 4 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0x18937;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 10;
                break;

            case CMU_PLLADUIO_Output_33868800hz:
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_DEV
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_04
                                      | 5 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0xa511a;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 5;
                break;

            case CMU_PLLADUIO_Output_36864000hz:
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_DEV
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_03
                                      | 4 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0x9ba5e;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 9;
                break;

            case CMU_PLLADUIO_Output_45158400hz:
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_DEV
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_03
                                      | 5 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0xa511a;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 5;
                break;

            default:
                ret = -3;
                break;
            }
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (AON_OSC->XTAL_CTL_f.EN != RESET)
        {
            switch (pllaudio_out)
            {
            case CMU_PLLADUIO_Output_11289600hz:
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_XTAL
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_10
                                      | 4 << 16;
                AON_PLL->AUDIO_CTL1 = 0xb4396;
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 9;
                break;

            case CMU_PLLADUIO_Output_12288000hz:
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_XTAL
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_08
                                      | 4 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0x18937;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 10;
                break;

            case CMU_PLLADUIO_Output_22579200hz:
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_XTAL
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_05
                                      | 4 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0xb4396;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 9;
                break;

            case CMU_PLLADUIO_Output_24576000hz:
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_XTAL
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_04
                                      | 4 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0x18937;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 10;
                break;

            case CMU_PLLADUIO_Output_33868800hz:
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_XTAL
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_04
                                      | 5 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0xa511a;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 5;
                break;

            case CMU_PLLADUIO_Output_36864000hz:
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_XTAL
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_03
                                      | 4 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0x9ba5e;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 9;
                break;

            case CMU_PLLADUIO_Output_45158400hz:
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_XTAL
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_03
                                      | 5 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0xa511a;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 5;
                break;

            default:
                ret = -3;
                break;
            }
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:

        //检测 外放phy时钟 是否使能
        if (((*(volatile uint32_t *)(0x20006000UL + 0xc)) & (1 << 25)) != RESET)
        {
            switch (pllaudio_out)
            {
            case CMU_PLLADUIO_Output_11289600hz:
                //11.289600*10/32 = 3.528
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_USB
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_10
                                      | 3 << 16;
                AON_PLL->AUDIO_CTL1 = 0x872b0;
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 9;
                break;

            case CMU_PLLADUIO_Output_12288000hz:
                //12.288000*8/30 = 3.072
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_USB
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_08
                                      | 3 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0x126e9;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 10;
                break;

            case CMU_PLLADUIO_Output_22579200hz:
                //22.579200*5/32 = 3.528
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_USB
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_05
                                      | 3 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0x872b0;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 9;
                break;

            case CMU_PLLADUIO_Output_24576000hz:
                //24.576000*4/32 =3.072
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_USB
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_04
                                      | 3 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0x126e9;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 10;
                break;

            case CMU_PLLADUIO_Output_33868800hz:
                //33.868800*4/32 = 4.2336
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_XTAL
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_04
                                      | 4 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0x3bcd3;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 5;
                break;

            case CMU_PLLADUIO_Output_36864000hz:
                //36.864000*3/30 = 3.4559999999999995
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_XTAL
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_03
                                      | 3 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0x74bc6;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 9;
                break;

            case CMU_PLLADUIO_Output_45158400hz:
                //45.158400*3/32 = 4.2336
                AON_PLL->AUDIO_CTL0 = AON_PLL_AUDIO_CTL0_FRAC_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_SEL_OSC_XTAL
                                      | AON_PLL_AUDIO_CTL0_EN_ENABLE
                                      | AON_PLL_AUDIO_CTL0_ICP_4UA
                                      | AON_PLL_AUDIO_CTL0_POSTDIV_03
                                      | 4 << 16; //整数部分
                AON_PLL->AUDIO_CTL1 = 0x3bcd3;//小数部分
                AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 5;
                break;

            default:
                ret = -3;
                break;
            }
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    return ret;
}

/**
* @brief        获取audio锁相环时钟状态
* @details      Null
* @param        Null
* @return       - ENABLE 锁相环时钟使能
*               - DISABLE 锁相环时钟失能
* @note         会使能与aon的通信。
*/
uint32_t cmu_get_pllaudio_state()
{
    uint32_t state = DISABLE;
    DEV_RMU->RSTEN0_f.AON = 1;
    DEV_CMU->CLKEN0_f.AON = 1;

    if (AON_PLL->AUDIO_CTL0_f.EN != RESET)
    {
        state = ENABLE;
    }

    return state;
}


uint32_t cmu_set_clk_en(ClockEnableBits clockoption, uint8_t en)
{
    if (en)
    {
        if (clockoption < MPU_CLOCK_ENABLE)
        {
            DEV_CMU->CLKEN0 |= (uint32_t)clockoption;
        }
        else
        {
            DEV_CMU->CLKEN1 |= (uint32_t)(clockoption >> 32);
        }
    }
    else
    {
        if (clockoption < MPU_CLOCK_ENABLE)
        {
            DEV_CMU->CLKEN0 &= ~(uint32_t)clockoption;
        }
        else
        {
            DEV_CMU->CLKEN1 &= ~(uint32_t)(clockoption >> 32);
        }
    }

    return 0;
}



uint32_t rmu_set_rst_en(RstEnableBits rmu_option, uint8_t en)
{
    if (en)
    {
        if (rmu_option < MPU_RST_ENABLE)
        {
            DEV_RMU->RSTEN0 |= (uint32_t)rmu_option;
        }
        else
        {
            DEV_RMU->RSTEN1 |= (uint32_t)(rmu_option >> 32);
        }
    }
    else
    {
        if (rmu_option < MPU_RST_ENABLE)
        {
            DEV_RMU->RSTEN0 &= ~(uint32_t)rmu_option;
        }
        else
        {
            DEV_RMU->RSTEN1 &= ~(uint32_t)(rmu_option >> 32);
        }
    }

    return 0;
}

/**
* @brief        检测时钟是否工作输出时钟
* @details      Null
* @param        source_clk  被检测时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*                   - CMU_Clock_PLL_CORE
*                   - CMU_Clock_PLL_AUDIO
*                   - CMU_Clock_PLL_USB
*                   - CMU_Clock_EXT_DEV
*                   - CMU_Clock_EXT_AON
* @return       0 ：时钟开始检测
*               -1：时钟不支持硬件检测
* @note         nULL。
*/
int32_t cmu_clk_ready_detect(cmu_clock_source_t source_clk)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_DETECT_CLK(source_clk));

    switch (source_clk)
    {
    case CMU_Clock_OSC_DEV:
        clk_sel = DEV_CMU_CLKDET_OSC_DEV_DET_ENABLE;
        break;

    case CMU_Clock_OSC_XTAL:
        clk_sel = DEV_CMU_CLKDET_OSC_XTAL_DET_ENABLE;
        break;

    case CMU_Clock_OSC_PHY:
        clk_sel = DEV_CMU_CLKDET_OSC_USB_DET_ENABLE;
        break;

    case CMU_Clock_PLL_CORE:
        clk_sel = DEV_CMU_CLKDET_PLL_CORE_DET_ENABLE;
        break;

    case CMU_Clock_PLL_AUDIO:
        clk_sel = DEV_CMU_CLKDET_PLL_AUDIO_DET_ENABLE;
        break;

    case CMU_Clock_PLL_USB:
        clk_sel = DEV_CMU_CLKDET_PLL_USB_DET_ENABLE;
        break;

    case CMU_Clock_EXT_DEV:
        clk_sel = DEV_CMU_CLKDET_EXT_CLK_DET_ENABLE;
        break;

    case CMU_Clock_EXT_AON:
        clk_sel = DEV_CMU_CLKDET_EXT_CLK2_DET_ENABLE;
        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        DEV_CMU->CLKDET |= clk_sel;
    }

    return ret;
}
/**
* @brief        获取检测时钟是否工作的结构
* @details      Null
* @param        source_clk  被检测时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*                   - CMU_Clock_PLL_CORE
*                   - CMU_Clock_PLL_AUDIO
*                   - CMU_Clock_PLL_USB
*                   - CMU_Clock_EXT_DEV
*                   - CMU_Clock_EXT_AON
* @return       RESET ：时钟准备完成，或时钟不能硬件检测
*               SET：时钟仍在准备中
*               -1：时钟不支持硬件检测
* @note         nULL。
*/
int32_t cmu_get_clk_detect(cmu_clock_source_t source_clk)
{
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_DETECT_CLK(source_clk));

    switch (source_clk)
    {
    case CMU_Clock_OSC_DEV:
        clk_sel = DEV_CMU_CLKRDY_OSC_DEV_RDY;
        break;

    case CMU_Clock_OSC_XTAL:
        clk_sel = DEV_CMU_CLKRDY_OSC_XTAL_RDY;
        break;

    case CMU_Clock_OSC_PHY:
        clk_sel = DEV_CMU_CLKRDY_OSC_USB_RDY;
        break;

    case CMU_Clock_PLL_CORE:
        clk_sel = DEV_CMU_CLKRDY_PLL_CORE_RDY;
        break;

    case CMU_Clock_PLL_AUDIO:
        clk_sel = DEV_CMU_CLKRDY_PLL_AUDIO_RDY;
        break;

    case CMU_Clock_PLL_USB:
        clk_sel = DEV_CMU_CLKRDY_PLL_USB_RDY;
        break;

    case CMU_Clock_EXT_DEV:
        clk_sel = DEV_CMU_CLKRDY_EXT_CLK_RDY;
        break;

    case CMU_Clock_EXT_AON:
        clk_sel = DEV_CMU_CLKRDY_EXT_CLK2_RDY;
        break;

    default:
        clk_sel = 0;
        break;
    }

    if (clk_sel != 0)
    {
        return DEV_CMU->CLKDET & clk_sel ? RESET : SET;
    }
    else
    {
        return RESET;
    }
}


/**
===================================================================================
##### 下游时钟，配置接口 #####
===================================================================================
*/
/**
* @brief        设置cpu时钟和系统时钟参数,并使能
* @details      Null
* @param        source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_ADC
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*                   - CMU_Clock_PLL_CORE
*                   - CMU_Clock_PLL_USB
*               core_div_x  cpu时钟分频 参数为cmu_clk_div_t元素
*               sys_div_x   系统时钟在cpu时钟下继续分频  参数为cmu_clk_div_t元素
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         core_div_x分频得到cpu时钟，在cpu时钟上，sys_div_x分频得到系统时钟CMU_Clock_SYS
*               特别注意，切换高频时钟CMU_Clock_PLL_CORE和CMU_Clock_PLL_USB时，
*                   先将时钟源切为高频时钟的时钟源为系统时钟源，再切时钟源为高频时钟为系统时钟源。
*/
int32_t cmu_sys_set_clk(cmu_clock_source_t source_clk, cmu_clk_div_t core_div_x, cmu_clk_div_t  sys_div_x)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_SYS_SRCCLK(source_clk));

    switch (source_clk)
    {
    case CMU_Clock_OSC_ADC:
        clk_sel = DEV_CMU_SYSCLK_CORE_SEL_OSC_ADC;
        break;

    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_SYSCLK_CORE_SEL_OSC_DEV;
        }
        else
        {
            ret = -2 ;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_SYSCLK_CORE_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2 ;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_SYSCLK_CORE_SEL_OSC_USB;
        }
        else
        {
            ret = -2 ;
        }

        break;

    case CMU_Clock_PLL_CORE:
        if (cmu_get_pllcore_state() != DISABLE)
        {
            clk_sel = DEV_CMU_SYSCLK_CORE_SEL_PLL_CORE;
        }
        else
        {
            ret = -2 ;
        }

        break;

    case CMU_Clock_PLL_USB:
        if (cmu_get_pllusb_state() != DISABLE)
        {
            clk_sel = DEV_CMU_SYSCLK_CORE_SEL_PLL_USB;
        }
        else
        {
            ret = -2 ;
        }

        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        uint32_t clk;
        clk = (core_div_x << 4) | (sys_div_x << 8) | clk_sel;
        DEV_CMU->CLKEN1_f.SYS = 1;
        DEV_RMU->RSTEN1_f.SYS = 1;
        DEV_CMU->SYSCLK = clk;
    }

    return ret;
}


/**
* @brief        设置spi时钟参数，并使能
* @details      Null
* @param        chx     spi通道 范围0、1
*               source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*                   - CMU_Clock_PLL_CORE
*               div_x   时钟分频 参数为cmu_clk_div_t元素
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         Null
*/
int32_t cmu_spi_set_clk(uint32_t chx, cmu_clock_source_t source_clk, cmu_clk_div_t div_x)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_SPI_SRCCLK(source_clk));
    hal_assert(IS_CMU_SPI_CHANNEL(chx));

    switch (source_clk)
    {
    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_SPInCLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_SPInCLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_SPInCLK_SEL_OSC_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_PLL_CORE:
        if (cmu_get_pllcore_state() != DISABLE)
        {
            clk_sel = DEV_CMU_SPInCLK_SEL_PLL_CORE;
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        uint32_t clk;
        clk = (div_x << 4) | clk_sel;

        if (chx == 0)
        {
            DEV_CMU->CLKEN0_f.SPI0 = 1;
            DEV_RMU->RSTEN0_f.SPI0 = 1;
        }
        else if (chx == 1)
        {
            DEV_CMU->CLKEN0_f.SPI1 = 1;
            DEV_RMU->RSTEN0_f.SPI1 = 1;
        }

        DEV_CMU->SPInCLK[chx] = clk;
    }

    return ret;
}


/**
* @brief        设置spi时钟参数，并使能
* @details      Null
* @param        chx     i2c通道 范围0、1
*               source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         Null
*/
int32_t cmu_i2c_set_clk(uint32_t chx, cmu_clock_source_t source_clk)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_I2C_SRCCLK(source_clk));
    hal_assert(IS_CMU_I2C_CHANNEL(chx));

    switch (source_clk)
    {
    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_I2CnCLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_I2CnCLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_I2CnCLK_SEL_OSC_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        if (chx == 0)
        {
            DEV_CMU->CLKEN0_f.I2C0 = 1;
            DEV_RMU->RSTEN0_f.I2C0 = 1;
        }
        else if (chx == 1)
        {
            DEV_CMU->CLKEN0_f.I2C1 = 1;
            DEV_RMU->RSTEN0_f.I2C1 = 1;
        }

        DEV_CMU->I2CnCLK[chx] = clk_sel;
    }

    return ret;
}


/**
* @brief        设置UART时钟参数，并使能
* @details      Null
* @param        chx     uart通道 范围0、1、2、3
*               source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         Null
*/
int32_t cmu_uart_set_clk(uint32_t chx, cmu_clock_source_t source_clk)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_UART_SRCCLK(source_clk));
    hal_assert(IS_CMU_UART_CHANNEL(chx));

    switch (source_clk)
    {
    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_UARTnCLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_UARTnCLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_UARTnCLK_SEL_OSC_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        if (chx == 0)
        {
            DEV_CMU->CLKEN0_f.UART0 = 1;
            DEV_RMU->RSTEN0_f.UART0 = 1;
        }
        else if (chx == 1)
        {
            DEV_CMU->CLKEN0_f.UART1 = 1;
            DEV_RMU->RSTEN0_f.UART1 = 1;
        }
        else if (chx == 2)
        {
            DEV_CMU->CLKEN0_f.UART2 = 1;
            DEV_RMU->RSTEN0_f.UART2 = 1;
        }
        else if (chx == 3)
        {
            DEV_CMU->CLKEN0_f.UART3 = 1;
            DEV_RMU->RSTEN0_f.UART3 = 1;
        }

        if (chx <= 2)
        {
            DEV_CMU->UARTnCLK[chx] = clk_sel;
        }
        else
        {
            DEV_CMU->UART3CLK = clk_sel;
        }
    }

    return ret;
}


/**
* @brief        设置NOR控制器时钟参数，并使能
* @details      Null
* @param        source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_SYS
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*                   - CMU_Clock_PLL_CORE
*                   - CMU_Clock_PLL_USB
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         Null
*/
int32_t cmu_nor_set_clk(cmu_clock_source_t source_clk, cmu_clk_div_t div_x)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_NOR_SRCCLK(source_clk));

    switch (source_clk)
    {
    //没有系统时钟就，cpu不能运行，故不用检测
    case CMU_Clock_SYS:
        clk_sel = DEV_CMU_NOR0CLK_SEL_SYS_CLK;
        break;

    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_NOR0CLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_NOR0CLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_NOR0CLK_SEL_OSC_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_PLL_CORE:
        if (cmu_get_pllcore_state() != DISABLE)
        {
            clk_sel = DEV_CMU_NOR0CLK_SEL_PLL_CORE;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_PLL_USB:
        if (cmu_get_pllusb_state() != DISABLE)
        {
            clk_sel = DEV_CMU_NOR0CLK_SEL_PLL_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    default :
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        DEV_CMU->CLKEN1_f.NORC = 1;
        DEV_RMU->RSTEN1_f.NORC = 1;
        DEV_CMU->NOR0CLK = clk_sel | (div_x << 4);
    }

    return ret;
}


/**
* @brief        设置PWM时钟参数，并使能
* @details      Null
* @param        chx     pwm通道 范围0、1、2、3、4、5、6、7
*               source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_ADC
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*                   - CMU_Clock_PLL_CORE
*                   - CMU_Clock_PLL_AUDIO
*               divx 分频数，范围 1-8192
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         Null
*/
int32_t cmu_pwm_set_clk(uint32_t chx, cmu_clock_source_t source_clk, uint32_t divx)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_PWM_CHANNEL(chx));
    hal_assert(IS_CMU_PWM_SRCCLK(source_clk));
    hal_assert(IS_CMU_PWM_DIV(divx));

    switch (source_clk)
    {
    case CMU_Clock_OSC_ADC:
        clk_sel = DEV_CMU_PWMnCLK_SEL_OSC_ADC;
        break;

    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_PWMnCLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_PWMnCLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_PWMnCLK_SEL_OSC_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_PLL_CORE:
        if (cmu_get_pllcore_state() != DISABLE)
        {
            clk_sel = DEV_CMU_PWMnCLK_SEL_PLL_CORE;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_PLL_AUDIO:
        if (cmu_get_pllaudio_state() != DISABLE)
        {
            clk_sel = DEV_CMU_PWMnCLK_SEL_PLL_AUDIO;
        }
        else
        {
            ret = -2;
        }

        break;

    default :
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        DEV_CMU->CLKEN0_f.PWM = 1;
        DEV_RMU->RSTEN0_f.PWM = 1;
        DEV_CMU->PWMnCLK[chx] = DEV_CMU_PWMnCLK_EN_ENABLE
                                | clk_sel
                                | (divx - 1) << 4;
    }

    return ret;
}



/**
* @brief        设置timer时钟参数，并使能
* @details      Null
* @param        chx     timer通道 范围0、1、2、3
*               source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_ADC
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*                   - CMU_Clock_PLL_CORE
*                   - CMU_Clock_PLL_AUDIO
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         Null
*/
int32_t cmu_timer_set_clk(uint32_t chx, cmu_clock_source_t source_clk)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_TIMER_CHANNEL(chx));
    hal_assert(IS_CMU_TIMER_SRCCLK(source_clk));

    switch (source_clk)
    {
    case CMU_Clock_OSC_ADC:
        clk_sel = DEV_CMU_TIMERnCLK_SEL_OSC_ADC;
        break;

    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_TIMERnCLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_TIMERnCLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_TIMERnCLK_SEL_OSC_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_PLL_CORE:
        if (cmu_get_pllcore_state() != DISABLE)
        {
            clk_sel = DEV_CMU_TIMERnCLK_SEL_PLL_CORE;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_PLL_AUDIO:
        if (cmu_get_pllaudio_state() != DISABLE)
        {
            clk_sel = DEV_CMU_TIMERnCLK_SEL_PLL_AUDIO;
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        DEV_CMU->CLKEN0_f.TIMER = 1;
        DEV_RMU->RSTEN0_f.TIMER = 1;
        DEV_CMU->TIMERnCLK[chx] = clk_sel | DEV_CMU_TIMERnCLK_EN_ENABLE;
    }

    return ret;
}


/**
* @brief        设置adc时钟参数，并使能
* @details      Null
* @param        source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*                   - CMU_Clock_PLL_AUDIO
*               divx 时钟分频系数， 范围1-256
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         Null
*/
int32_t cmu_adc_set_clk(cmu_clock_source_t source_clk, uint32_t divx)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_ADC_SRCCLK(source_clk));
    hal_assert(IS_CMU_ADC_DIV(divx));

    switch (source_clk)
    {
    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_ADCCLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_ADCCLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_ADCCLK_SEL_OSC_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_PLL_AUDIO:
        if (cmu_get_pllaudio_state() != DISABLE)
        {
            clk_sel = DEV_CMU_ADCCLK_SEL_PLL_AUDIO;
        }
        else
        {
            ret = -2;
        }

        break;

    default :
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        DEV_CMU->CLKEN0_f.ADC = 1;
        DEV_RMU->RSTEN0_f.ADC = 1;
        DEV_CMU->ADCCLK = clk_sel
                          | DEV_CMU_ADCCLK_EN_ENABLE
                          | ((divx - 1) << 4);
    }

    return ret;
}

/**
* @brief        设置dac时钟参数，并使能
* @details      Null
* @param        source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*                   - CMU_Clock_PLL_AUDIO
*                   - CMU_Clock_ADC_CLK
*               divx dac时钟分频系数， 范围1-256
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         Null
*/
int32_t cmu_dac_set_clk(cmu_clock_source_t source_clk, uint32_t divx)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_DAC_SRCCLK(source_clk));
    hal_assert(IS_CMU_DAC_DIV(divx));

    switch (source_clk)
    {
    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_DACCLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_DACCLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_DACCLK_SEL_OSC_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_PLL_AUDIO:
        if (cmu_get_pllaudio_state() != DISABLE)
        {
            clk_sel = DEV_CMU_DACCLK_SEL_PLL_AUDIO;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_ADC_CLK:
        clk_sel = DEV_CMU_DACCLK_SEL_ADC_CLK;
        break;

    case CMU_Clock_EXT_DEV:
        clk_sel = DEV_CMU_DACCLK_SEL_EXT_CLK;
        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        DEV_CMU->CLKEN0_f.DAC = 1;
        DEV_RMU->RSTEN0_f.DAC = 1;
        DEV_CMU->DACCLK = clk_sel
                          | DEV_CMU_DACCLK_EN_ENABLE
                          | ((divx - 1) << 4);
    }

    return ret;
}

//先开dac时钟，否则配置无效
/**
* @brief        设置dac的cp2时钟参数，并使能
* @details      Null
* @param        source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*               divx dac时钟分频系数， 范围1-16
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         需要dac有时钟，cp2时钟才可配置
*/
int32_t cmu_dac_cp2_set_clk(cmu_clock_source_t source_clk, uint32_t divx)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_DAC_CP2_SRCCLK(source_clk));
    hal_assert(IS_CMU_DAC_CP2_DIV(divx));

    switch (source_clk)
    {
    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_CP2CLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_CP2CLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_CP2CLK_SEL_OSC_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        DEV_CMU->CP2CLK = clk_sel
                          | ((divx - 1) << 4)
                          | DEV_CMU_CP2CLK_EN_ENABLE;
    }

    return ret;
}

/**
* @brief        设置dac的hscal时钟参数，并使能
* @details      Null
* @param        clk_khz 输出时钟，cmu_dac_hscal_clk_t中选择
* @return       0 ：配置成功
*               -3：不支持输出时钟频率
* @note         需要dac有时钟，hscal时钟才可配置
*/
int32_t cmu_dac_hscal_set_clk(cmu_dac_hscal_clk_t clk_khz)
{
    int32_t ret = 0;

    if ((clk_khz >= CMU_DAC_HscalCLK_128Khz) && (clk_khz <= CMU_DAC_HscalCLK_2Khz))
    {
        DEV_CMU->HSCALCLK = clk_khz | DEV_CMU_HSCALCLK_EN_ENABLE;
    }
    else
    {
        ret = -3;
    }

    return ret;
}


/**
* @brief        设置dmic得delay时钟参数，并使能
* @details      Null
* @param        source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         需要adc或dac有时钟，dmic delay时钟才可配置
*/
int32_t cmu_dly_set_clk(cmu_clock_source_t source_clk)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_DLY_SRCCLK(source_clk));

    switch (source_clk)
    {
    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_DLYCLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_DLYCLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_DLYCLK_SEL_OSC_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        DEV_CMU->TICKCLK = clk_sel | DEV_CMU_DLYCLK_EN_ENABLE;
    }

    return ret;
}

/**
* @brief        设置asi时钟参数，并使能
* @details      Null
* @param        chx asi通道 参数范围0、1
*               source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*                   - CMU_Clock_PLL_AUDIO
*               divx 时钟分频系数， 范围1-256
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         Null
*/
int32_t cmu_asi_set_clk(uint32_t chx, cmu_clock_source_t source_clk, uint32_t divx)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_ASI_CHANNEL(chx));
    hal_assert(IS_CMU_ASI_SRCCLK(source_clk));
    hal_assert(IS_CMU_ASI_DIV(divx));

    switch (source_clk)
    {
    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_ASInCLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_ASInCLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_ASInCLK_SEL_OSC_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_PLL_AUDIO:
        if (cmu_get_pllaudio_state() != DISABLE)
        {
            clk_sel = DEV_CMU_ASInCLK_SEL_PLL_AUDIO;
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        if (chx == 0)
        {
            DEV_CMU->CLKEN0_f.ASI0 = 1;
            DEV_RMU->RSTEN0_f.ASI0 = 1;
        }
        else if (chx == 1)
        {
            DEV_CMU->CLKEN0_f.ASI1 = 1;
            DEV_RMU->RSTEN0_f.ASI1 = 1;
        }

        DEV_CMU->ASInCLK[chx] = clk_sel | (divx - 1) << 4;
    }

    return ret;
}


/**
* @brief        设置irrx时钟参数，并使能
* @details      Null
* @param        source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*               divx 时钟分频系数， 范围1-256
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         Null
*/
int32_t cmu_irrx_set_clk(cmu_clock_source_t source_clk, uint32_t divx)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_IRRX_SRCCLK(source_clk));
    hal_assert(IS_CMU_IRRX_DIV(divx));

    switch (source_clk)
    {
    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_IRRXCLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_IRRXCLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_IRRXCLK_SEL_OSC_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        DEV_CMU->CLKEN0_f.IRRX = 1;
        DEV_RMU->RSTEN0_f.IRRX = 1;
        DEV_CMU->IRRXCLK = clk_sel | ((divx - 1) << 4);
    }

    return ret;
}



/**
* @brief        设置irtx时钟参数，并使能
* @details      Null
* @param        source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*               divx 时钟分频系数， 范围1-16
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         Null
*/
int32_t cmu_irtx_set_clk(cmu_clock_source_t source_clk, uint32_t divx)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_IRTX_SRCCLK(source_clk));
    hal_assert(IS_CMU_IRTX_DIV(divx));

    switch (source_clk)
    {
    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_IRRXCLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_IRRXCLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_IRRXCLK_SEL_OSC_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        DEV_CMU->CLKEN0_f.IRTX = 1;
        DEV_RMU->RSTEN0_f.IRTX = 1;
        DEV_CMU->IRTXCLK = clk_sel | ((divx - 1) << 4);
    }

    return ret;
}


/**
* @brief        设置tick时钟参数，并使能
* @details      Null
* @param        source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_SYS
*                   - CMU_Clock_OSC_ADC
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*               div_x 时钟分频系数， 参数为cmu_tick_clk_div_t元素
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         Null
*/
int32_t cmu_tick_set_clk(cmu_clock_source_t source_clk, cmu_tick_clk_div_t div_x)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_TICK_SRCCLK(source_clk));

    switch (source_clk)
    {
    case CMU_Clock_SYS:
        clk_sel = DEV_CMU_TICKCLK_SEL_SYS_CLK;
        break;

    case CMU_Clock_OSC_ADC:
        clk_sel = DEV_CMU_TICKCLK_SEL_OSC_ADC;
        break;

    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_TICKCLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_TICKCLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_TICKCLK_SEL_OSC_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        DEV_CMU->CLKEN0_f.TICK = 1;
        DEV_RMU->RSTEN0_f.TICK = 1;
        DEV_CMU->TICKCLK = clk_sel | div_x << 4;
    }

    return ret;
}


/**
* @brief        设置camera时钟参数，并使能
* @details      Null
* @param        source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*                   - CMU_Clock_PLL_CORE
*               div_x 时钟分频系数， 参数为cmu_clk_div_t元素
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         Null
*/
int32_t cmu_camera_set_clk(cmu_clock_source_t source_clk, cmu_clk_div_t div_x)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_CAMERA_SRCCLK(source_clk));

    switch (source_clk)
    {
    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_CAMERACLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_CAMERACLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_CAMERACLK_SEL_OSC_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_PLL_CORE:
        if (cmu_get_pllcore_state() != DISABLE)
        {
            clk_sel = DEV_CMU_CAMERACLK_SEL_PLL_CORE;
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        DEV_CMU->CLKEN0_f.CAMERA = 1;
        DEV_RMU->RSTEN0_f.CAMERA = 1;
        DEV_CMU->CAMERACLK = clk_sel | div_x << 4;
    }

    return ret;
}

/**
* @brief        设置param时钟参数
* @details      Null
* @param        source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_SYS
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*                   - CMU_Clock_OSC_PHY
*                   - CMU_Clock_PLL_CORE
*                   - CMU_Clock_PLL_USB
*               div_x 时钟分频系数， 参数为cmu_clk_div_t元素
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         Null
*/
int32_t cmu_psram_set_clk(cmu_clock_source_t source_clk, cmu_clk_div_t div_x)
{
    int32_t ret = 0;
    uint32_t clk_sel = 0;
    hal_assert(IS_CMU_PSRAM_SRCCLK(source_clk));

    switch (source_clk)
    {
    case CMU_Clock_SYS:
        clk_sel = DEV_CMU_PSRAMCLK_SEL_SYS_CLK;
        break;

    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = DEV_CMU_PSRAMCLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = DEV_CMU_PSRAMCLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_PHY:
        if (cmu_get_oscphy_state() != DISABLE)
        {
            clk_sel = DEV_CMU_PSRAMCLK_SEL_OSC_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_PLL_CORE:
        if (cmu_get_pllcore_state() != DISABLE)
        {
            clk_sel = DEV_CMU_PSRAMCLK_SEL_PLL_CORE;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_PLL_USB:
        if (cmu_get_pllusb_state() != DISABLE)
        {
            clk_sel = DEV_CMU_PSRAMCLK_SEL_PLL_USB;
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        DEV_CMU->CLKEN1_f.PSRAM = 1;
        DEV_RMU->RSTEN1_f.PSRAM = 1;
        DEV_CMU->PSRAMCLK = clk_sel | div_x << 4;
    }

    return ret;
}

/**
* @brief        使能mpu时钟
* @details      Null
* @param        Null
* @return       0 ：配置成功
* @note         Null
*/
int32_t cmu_mpu_set_clk()
{
    DEV_CMU->CLKEN0_f.MPU = 1;
    DEV_RMU->RSTEN0_f.MPU = 1;
    return 0;
}

/**
* @brief        使能udsp时钟
* @details      Null
* @param        Null
* @return       0 ：配置成功
* @note         Null
*/
int32_t cmu_udsp_set_clk()
{
    DEV_CMU->CLKEN0_f.UDSP = 1;
    DEV_RMU->RSTEN0_f.UDSP = 1;
    return 0;
}
/**
* @brief        使能npu时钟
* @details      Null
* @param        Null
* @return       0 ：配置成功
* @note         Null
*/
int32_t cmu_npu_set_clk()
{
    DEV_CMU->CLKEN0_f.NPU = 1;
    DEV_RMU->RSTEN0_f.NPU = 1;
    return 0;
}
/**
* @brief        使能eint时钟
* @details      Null
* @param        Null
* @return       0 ：配置成功
* @note         Null
*/
int32_t cmu_eint_set_clk()
{
    DEV_CMU->CLKEN0_f.EINT = 1;
    DEV_RMU->RSTEN0_f.EINT = 1;
    return 0;
}
/**
* @brief        使能asu时钟
* @details      Null
* @param        Null
* @return       0 ：配置成功
* @note         Null
*/
int32_t cmu_asu_set_clk()
{
    DEV_CMU->CLKEN0_f.ASU = 1;
    DEV_RMU->RSTEN0_f.ASU = 1;
    return 0;
}
/**
* @brief        使能efuse时钟
* @details      Null
* @param        Null
* @return       0 ：配置成功
* @note         Null
*/
int32_t cmu_efuse_set_clk()
{
    DEV_CMU->CLKEN0_f.EFUSE = 1;
    DEV_RMU->RSTEN0_f.EFUSE = 1;
    return 0;
}
/**
* @brief        使能gpio时钟
* @details      Null
* @param        Null
* @return       0 ：配置成功
* @note         Null
*/
int32_t cmu_gpio_set_clk()
{
    DEV_CMU->CLKEN0_f.GPIO = 1;
    DEV_RMU->RSTEN0_f.GPIO = 1;
    return 0;
}
/**
* @brief        使能dma时钟
* @details      Null
* @param        Null
* @return       0 ：配置成功
* @note         Null
*/
int32_t cmu_dma_set_clk()
{
    DEV_CMU->CLKEN0_f.DMA = 1;
    DEV_RMU->RSTEN0_f.DMA = 1;
    return 0;
}

/**
* @brief        失能dma时钟
* @details      Null
* @param        Null
* @return       0 ：配置成功
* @note         Null
*/
int32_t cmu_dma_reset_clk()
{
    DEV_RMU->RSTEN0_f.DMA = 0;
    DEV_CMU->CLKEN0_f.DMA = 0;
    return 0;
}

/**
* @brief        使能与AON通信时钟
* @details      Null
* @param        Null
* @return       0 ：配置成功
* @note         Null
*/
int32_t cmu_aon_set_clk()
{
    DEV_CMU->CLKEN0_f.AON = 1;
    DEV_RMU->RSTEN0_f.AON = 1;
    return 0;
}

/**
* @brief        设置lradc时钟参数，并使能
* @details      Null
* @param        source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_ADC
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*               div_x 时钟分频系数， 参数为cmu_clk_div_t元素
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         会使能与aon的通信。
*/
int32_t cmu_aon_lradc_set_clk(cmu_clock_source_t source_clk, uint32_t divx)
{
    uint32_t clk_sel = 0;
    int32_t ret = 0;
    hal_assert(IS_CMU_LRADC_SRCCLK(source_clk));
    hal_assert(IS_CMU_LRADC_DIV(divx));
    DEV_RMU->RSTEN0_f.AON = 1;
    DEV_CMU->CLKEN0_f.AON = 1;

    switch (source_clk)
    {
    case CMU_Clock_OSC_ADC:
        clk_sel = AON_CMU_LRADCCLK_SEL_OSC_ADC;
        break;

    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = AON_CMU_LRADCCLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = AON_CMU_LRADCCLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        AON_CMU->CLKEN0_f.LRADC = 1;
        AON_RMU->RSTEN0_f.LRADC = 1;
        AON_CMU->LRADCCLK = clk_sel | (divx - 1) << 4;
    }

    return ret;
}

/**
* @brief        设置audio dmic时钟参数，并使能
* @details      Null
* @param        source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_ADC
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*               div_x 时钟分频系数， 参数为1-256
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         会使能与aon的通信。
*/
int32_t cmu_aon_aduio_dmic_set_clk(cmu_clock_source_t source_clk, uint32_t divx)
{
    uint32_t clk_sel = 0;
    int32_t ret = 0;
    hal_assert(IS_CMU_DMIC_SRCCLK(source_clk));
    hal_assert(IS_CMU_DMIC_DIV(divx));
    DEV_RMU->RSTEN0_f.AON = 1;
    DEV_CMU->CLKEN0_f.AON = 1;
    AON_CMU->CLKEN0_f.DEB = 1;

    switch (source_clk)
    {
    case CMU_Clock_OSC_ADC:
        clk_sel = AON_CMU_DMICCLK_SEL_OSC_ADC;
        break;

    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = AON_CMU_DMICCLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = AON_CMU_DMICCLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        AON_CMU->DMICCLK = clk_sel | (divx - 1) << 4;
    }

    return ret;
}
/**
* @brief        设置audio i2srx时钟参数，并使能
* @details      Null
* @param        source_clk 输入时钟，cmu_clock_source_t中选择，可选：
*                   - CMU_Clock_OSC_ADC
*                   - CMU_Clock_OSC_DEV
*                   - CMU_Clock_OSC_XTAL
*               div_x 时钟分频系数， 参数范围1-256
* @return       0 ：配置成功
*               -1：不支持输入时钟源
*               -2：正确输入时钟源，但此时钟源未使能
* @note         会使能与aon的通信。
*/
int32_t cmu_aon_aduio_i2srx_set_clk(cmu_clock_source_t source_clk, uint32_t divx)
{
    uint32_t clk_sel = 0;
    int32_t ret = 0;
    hal_assert(IS_CMU_I2S_SRCCLK(source_clk));
    hal_assert(IS_CMU_I2S_DIV(divx));
    DEV_RMU->RSTEN0_f.AON = 1;
    DEV_CMU->CLKEN0_f.AON = 1;

    switch (source_clk)
    {
    case CMU_Clock_OSC_ADC:
        clk_sel = AON_CMU_I2SRXCLK_SEL_OSC_ADC;
        break;

    case CMU_Clock_OSC_DEV:
        if (cmu_get_oscdev_state() != DISABLE)
        {
            clk_sel = AON_CMU_I2SRXCLK_SEL_OSC_DEV;
        }
        else
        {
            ret = -2;
        }

        break;

    case CMU_Clock_OSC_XTAL:
        if (cmu_get_oscxtal_state() != DISABLE)
        {
            clk_sel = AON_CMU_I2SRXCLK_SEL_OSC_XTAL;
        }
        else
        {
            ret = -2;
        }

        break;

    default:
        ret = -1;
        break;
    }

    if (ret == 0)
    {
        AON_CMU->I2SRXCLK = clk_sel | (divx - 1) << 4;
    }

    return ret;
}

/**
* @brief        使能audio时钟
* @details      Null
* @param        Null
* @return       0 ：配置成功
* @note         会使能与aon的通信。
*/
int32_t cmu_aon_aduio_set_clk()
{
    AON_CMU->CLKEN0_f.AUDI = 1;
    AON_RMU->RSTEN0_f.AUDI = 1;
    return 0;
}

/**
* @brief        使能aon buf时钟
* @details      Null
* @param        Null
* @return       0 ：配置成功
* @note         会使能与aon的通信。
*/
int32_t cmu_aon_buff_set_clk()
{
    AON_CMU->CLKEN0_f.BUFF = 1;
    AON_RMU->RSTEN0_f.BUFF = 1;
    return 0;
}

/**
* @brief        使能aon buf时钟
* @details      Null
* @param        source_clk  : DEV_CMU_DBGCTL_SEL_xxx 如DEV_CMU_DBGCTL_SEL_CPU_CLK
*               div_x       :DEV_CMU_DBGCTL_DIV_x 如DEV_CMU_DBGCTL_DIV_1
*               gpio_x      :0-31
* @return       0 ：配置成功
* @note         会使能与aon的通信。
*/
void cmu_clk_debugout(uint32_t source_clk, uint32_t div_x, uint32_t gpio_x)
{
    DEV_CMU->DBGCTL = source_clk | div_x;
    DEV_GPIO->DBIO_OE0 = 1 << gpio_x;
    DEV_GPIO->DBIO_CTL = 1;
}

/*
 * 需要
 * __OSC_ADC_FREQ_HZ
 * __OSC_DEV_FREQ_HZ
 * __OSC_XTAL_FREQ_HZ
 * __OSC_PHY_FREQ_HZ
 * __OSC_PLLUSB_FREQ_HZ
 * 这些宏的值与实际芯片相同，否则函数返回频率值与实际不符
*/

/**
* @brief        获取pollcore输出时钟
* @details      Null
* @param        Null
* @return       >0  输出时钟，单位hz
*               =0  未工作，或使用了gpio输入时钟，无法获取
* @note         Null
*/
uint32_t cmu_get_pllcore_clk(void)
{
    DEV_RMU->RSTEN0_f.AON = 1;
    DEV_CMU->CLKEN0_f.AON = 1;
    register uint32_t pllcore_cfg = AON_PLL->CORE_CTL;

    if ((pllcore_cfg & AON_PLL_CORE_CTL_EN) == 0)
    {
        return 0;
    }

    uint32_t freq = 0;
    uint32_t prediv, loopdiv, pstpdiv;

    /*hardware mode*/
    if ((pllcore_cfg & AON_PLL_CORE_CTL_CUST_MASK) == 0)
    {
        freq = pllcore_cfg & AON_PLL_CORE_CTL_FREQ_MASK;
        freq = freq >> 4;
        freq = freq * 6000000;
    }
    else
    {
        //sostware mode, freq = PLL_SRC/PREDIV* LOOPDIV/POSTDIV
        switch (pllcore_cfg & AON_PLL_CORE_CTL_SEL_MASK)
        {
        case 0:
            freq = __OSC_DEV_FREQ_HZ;
            break;

        case 2:
            freq = __OSC_XTAL_FREQ_HZ;
            break;

        case 4:
            freq = __OSC_PHY_FREQ_HZ;
            break;

        default:
            freq = 0;
            break;
        }

        prediv = (pllcore_cfg & AON_PLL_CORE_CTL_PREDIV_MASK) >> 25;
        loopdiv = (pllcore_cfg & AON_PLL_CORE_CTL_LOOPDIV_MASK) >> 16;
        pstpdiv = (pllcore_cfg & AON_PLL_CORE_CTL_POSTDIV_MASK) >> 12;

        if (!prediv || !pstpdiv)
            return 0;

        freq = freq * loopdiv / prediv / pstpdiv;
    }

    return freq;
}

/**
* @brief        获取cpu工作时钟
* @details      Null
* @param        Null
* @return       >0  工作时钟，单位hz
*               =0  未工作，或使用了gpio输入时钟无法获取
* @note         Null
*/
uint32_t cmu_get_cpuclk()
{
    uint32_t freq = 0;
    register uint32_t sysclk_cfg = DEV_CMU->SYSCLK;

    switch (sysclk_cfg & DEV_CMU_SYSCLK_CORE_SEL_MASK)
    {
    case DEV_CMU_SYSCLK_CORE_SEL_OSC_ADC:
        freq = __OSC_ADC_FREQ_HZ;
        break;

    case DEV_CMU_SYSCLK_CORE_SEL_OSC_DEV:
        freq = __OSC_DEV_FREQ_HZ;
        break;

    case DEV_CMU_SYSCLK_CORE_SEL_OSC_XTAL:
        freq = __OSC_XTAL_FREQ_HZ;
        break;

    case DEV_CMU_SYSCLK_CORE_SEL_OSC_USB:
        freq = __OSC_PHY_FREQ_HZ;
        break;

    case DEV_CMU_SYSCLK_CORE_SEL_PLL_CORE:
        freq = cmu_get_pllcore_clk();
        break;

    case DEV_CMU_SYSCLK_CORE_SEL_PLL_USB:
        freq = __OSC_PLLUSB_FREQ_HZ;
        break;

    default:
        freq = 0;
        break;
    }

    uint32_t div = 1;

    switch (sysclk_cfg & DEV_CMU_SYSCLK_CORE_DIV_MASK)
    {
    case DEV_CMU_SYSCLK_CORE_DIV_1:
        div = 1;
        break;

    case DEV_CMU_SYSCLK_CORE_DIV_2:
        div = 2;
        break;

    case DEV_CMU_SYSCLK_CORE_DIV_4:
        div = 4;
        break;

    case DEV_CMU_SYSCLK_CORE_DIV_8:
        div = 8;
        break;

    case DEV_CMU_SYSCLK_CORE_DIV_12:
        div = 12;
        break;

    case DEV_CMU_SYSCLK_CORE_DIV_16:
        div = 16;
        break;

    case DEV_CMU_SYSCLK_CORE_DIV_24:
        div = 24;
        break;

    case DEV_CMU_SYSCLK_CORE_DIV_32:
        div = 32;
        break;
    }

    freq = freq / div;
    return freq;
}

/**
* @brief        获取系统时钟
* @details      Null
* @param        Null
* @return       >0  工作时钟，单位hz
*               =0  未工作，或使用了gpio输入时钟无法获取
* @note         Null
*/
uint32_t cmu_get_sysclk()
{
    uint32_t freq = cmu_get_cpuclk();
    uint32_t sysclk_cfg = DEV_CMU->SYSCLK & DEV_CMU_SYSCLK_SYS_DIV_MASK;
    uint32_t div = 1;

    switch (sysclk_cfg)
    {
    case DEV_CMU_SYSCLK_SYS_DIV_1:
        div = 1;
        break;

    case DEV_CMU_SYSCLK_SYS_DIV_2:
        div = 2;
        break;

    case DEV_CMU_SYSCLK_SYS_DIV_4:
        div = 4;
        break;

    case DEV_CMU_SYSCLK_SYS_DIV_8:
        div = 8;
        break;

    case DEV_CMU_SYSCLK_SYS_DIV_12:
        div = 12;
        break;

    case DEV_CMU_SYSCLK_SYS_DIV_16:
        div = 16;
        break;

    case DEV_CMU_SYSCLK_SYS_DIV_24:
        div = 24;
        break;

    case DEV_CMU_SYSCLK_SYS_DIV_32:
        div = 32;
        break;
    }

    freq = freq / div;
    return freq;
}

/**
* @brief        获取tick定时器工作时钟
* @details      Null
* @param        Null
* @return       >0  工作时钟，单位hz
*               =0  未工作，或使用了gpio输入时钟无法获取
* @note         Null
*/
uint32_t cmu_get_tickclk()
{
    uint32_t freq = 0;
    register uint32_t tickclk_cfg = DEV_CMU->TICKCLK;

    switch (tickclk_cfg & DEV_CMU_TICKCLK_SEL_MASK)
    {
    case DEV_CMU_TICKCLK_SEL_SYS_CLK:
        freq = cmu_get_sysclk();
        break;

    case DEV_CMU_TICKCLK_SEL_OSC_ADC:
        freq = __OSC_ADC_FREQ_HZ;
        break;

    case DEV_CMU_TICKCLK_SEL_OSC_DEV:
        freq = __OSC_DEV_FREQ_HZ;
        break;

    case DEV_CMU_TICKCLK_SEL_OSC_XTAL:
        freq = __OSC_XTAL_FREQ_HZ;
        break;

    case DEV_CMU_TICKCLK_SEL_OSC_USB:
        freq = __OSC_PHY_FREQ_HZ;
        break;

    default:
        freq = 0;
        break;
    }

    uint32_t div = 1;

    switch (tickclk_cfg & DEV_CMU_TICKCLK_DIV_MASK)
    {
    case DEV_CMU_TICKCLK_DIV_4:
        div = 4;
        break;

    case DEV_CMU_TICKCLK_DIV_16:
        div = 16;
        break;

    case DEV_CMU_TICKCLK_DIV_24:
        div = 24;
        break;

    case DEV_CMU_TICKCLK_DIV_30:
        div = 30;
        break;
    }

    freq = freq / div;
    return freq;
}
void cmu_set_audio_pll(cmu_audio_pll_set_t audio_pll_set)
{
    uint8_t First_Flag = 0;
    uint8_t Second_Flag = 0;
    uint8_t Pass_Flag = 0;
    uint32_t timer0_val_24M = 0;
    uint32_t timer1_val_AudioPLL = 0;
    double audiopll_compare_value = 0;
    uint8_t Fout_AudioPll_Frequency;
    Fout_AudioPll_Frequency = audio_pll_set;
    DEV_CMU->TIMERnCLK[0] = DEV_CMU_TIMERnCLK_SEL_OSC_XTAL | (1 << 0);
    DEV_CMU->TIMERnCLK[1] = DEV_CMU_TIMERnCLK_SEL_PLL_AUDIO | (1 << 0);
    DEV_CMU->CLKEN0 |= DEV_CMU_CLKEN0_TIMER;
    DEV_RMU->RSTEN0 |= DEV_RMU_RSTEN0_TIMER;
    // AudioPLL ratio
    audiopll_compare_value = (Fout_AudioPll_Frequency == AUDIO_PLL_36P864M) ? 3.072 :
                             (Fout_AudioPll_Frequency == AUDIO_PLL_49P152M) ? 2.048 :
                             (Fout_AudioPll_Frequency == AUDIO_PLL_33P8688M) ? 2.8224 :
                             (Fout_AudioPll_Frequency == AUDIO_PLL_45P1584M) ? 1.8816 : 2.048;
    // VCO range
    // 147.456M:(36.864M*2*2)       1~5
    // 98.304M:(49.152M*2)          9~12
    // 135.4752M:(33.8688M*2*2)     3~6
    // 90.3168M:(45.1584M*2)        10~13
    First_Flag = (Fout_AudioPll_Frequency == AUDIO_PLL_36P864M) ? 1 :
                 (Fout_AudioPll_Frequency == AUDIO_PLL_49P152M) ? 9 :
                 (Fout_AudioPll_Frequency == AUDIO_PLL_33P8688M) ? 3 :
                 (Fout_AudioPll_Frequency == AUDIO_PLL_45P1584M) ? 10 : 9;
    Second_Flag = (Fout_AudioPll_Frequency == AUDIO_PLL_36P864M) ? 5 :
                  (Fout_AudioPll_Frequency == AUDIO_PLL_49P152M) ? 12 :
                  (Fout_AudioPll_Frequency == AUDIO_PLL_33P8688M) ? 6 :
                  (Fout_AudioPll_Frequency == AUDIO_PLL_45P1584M) ? 13 : 12;
    // fix POSTDIV = 2
    AON_PLL->AUDIO_CTL0_f.POSTDIV = 2;
    AON_PLL->AUDIO_CTL0_f.INTEG = (Fout_AudioPll_Frequency == AUDIO_PLL_36P864M) ? 6 :
                                  (Fout_AudioPll_Frequency == AUDIO_PLL_49P152M) ? 4 :
                                  (Fout_AudioPll_Frequency == AUDIO_PLL_33P8688M) ? 5 :
                                  (Fout_AudioPll_Frequency == AUDIO_PLL_45P1584M) ? 3 : 4;
    AON_PLL->AUDIO_CTL1 = (Fout_AudioPll_Frequency == AUDIO_PLL_36P864M) ? 0x24dd3 :
                          (Fout_AudioPll_Frequency == AUDIO_PLL_49P152M) ? 0x18937 :
                          (Fout_AudioPll_Frequency == AUDIO_PLL_33P8688M) ? 0xa511a :
                          (Fout_AudioPll_Frequency == AUDIO_PLL_45P1584M) ? 0xc3611 : 0x18937;
    AON_PLL->AUDIO_CTL0_f.SEL = 1;
    // ICP select // LoopDIV Fraction Enable
    AON_PLL->AUDIO_CTL0_f.ICP = 4;
    AON_PLL->AUDIO_CTL0_f.FRAC_EN = 1;

    // VCO TRIM start----------
    for (int i = First_Flag; i < Second_Flag + 1; i++)
    {
        AON_OSC->TRIM_f.AUDIO_PLL_TRIM = i; // 0x21000010
        AON_PLL->AUDIO_CTL0_f.EN = 1; // Enable Audio PLL
        DEV_TIMER->TIMER[0].CTL = 0x3;  // timer0 start
        DEV_TIMER->TIMER[1].CTL = 0x3;  // timer1 start
        delay_us(360 * MHz, 260); // 130us for wait Aduio PLL Lock
        timer0_val_24M = DEV_TIMER->TIMER[0].VAL;
        timer1_val_AudioPLL = DEV_TIMER->TIMER[1].VAL;
        DEV_TIMER->TIMER[0].CTL = 0x0;  // timer0 clear
        DEV_TIMER->TIMER[1].CTL = 0x0;  // timer1 clear

        if ((timer1_val_AudioPLL >= (uint32_t)(timer0_val_24M * audiopll_compare_value * 0.995834)) && (timer1_val_AudioPLL <= (uint32_t)(timer0_val_24M * audiopll_compare_value * 1.004166))) // 0.4166% analog threshold
        {
            if (Pass_Flag == 0)
            {
                DEV_GLOBAL->DVDD_GLOBAL1 = i;
                Pass_Flag = 1;
            }
            else if (Pass_Flag == 1)
            {
                DEV_GLOBAL->DVDD_GLOBAL2 = i;
            }
        }
    }

    // VCO TRIM end----------
    DEV_CMU->CLKEN0 &= ~DEV_CMU_CLKEN0_TIMER;
    DEV_RMU->RSTEN0 &= ~DEV_RMU_RSTEN0_TIMER;

    if (Pass_Flag == 1)
    {
        AON_OSC->TRIM_f.AUDIO_PLL_TRIM = ((uint8_t)(DEV_GLOBAL->DVDD_GLOBAL2) + (uint8_t)(DEV_GLOBAL->DVDD_GLOBAL1)) / 2;
    }
    else
    {
        AON_OSC->TRIM_f.AUDIO_PLL_TRIM = 10;
    }

    DEV_GLOBAL->DVDD_GLOBAL1 = 0;
    DEV_GLOBAL->DVDD_GLOBAL2 = 0;
    AON_PLL->AUDIO_CTL0_f.EN = 1; // Enable Audio PLL // VCO trim complete
}

/**
* @brief        死等ms级别延时
* @details      Null
* @param        Null
* @return       None
*
* @note         Null
*/
void delay_ms(uint32_t cpu_clock, uint32_t ms)
{
    uint32_t delay_count = cpu_clock / 1000 * ms;
    uint32_t current_cycle = read_csr(NDS_MCYCLE);

    while ((uint32_t)(read_csr(NDS_MCYCLE) - current_cycle) < delay_count);
}
/**
* @brief        死等us级别延时
* @details      Null
* @param        Null
* @return       None
*
* @note         Null
*/
void delay_us(uint32_t cpu_clock, uint32_t us)
{
    uint32_t delay_count = cpu_clock / 1000000 * us;
    uint32_t current_cycle = read_csr(NDS_MCYCLE);

    while ((uint32_t)(read_csr(NDS_MCYCLE) - current_cycle) < delay_count);
}


uint64_t get_mcycle(void)
{
	return read_csr(NDS_MCYCLE);
}
