#include "omw_sys.h"
#include "t1001_rtc.h"

// Description: set system clock, cpu clk and pclk is the same as system clock
void omw_set_sys_clk(uint32_t sel){
    uint32_t t;
    // analog switch
    t = *(volatile int *)(0x42002000);
    t = t | (1<<1);
    *(volatile int *)(0x42002000) = t;
    // read
    t = SYS_CTRL->SYS_CLKSEL;
    // modify
    t = t & (~SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SYSSEL_Msk);
    t = t & (~SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SEL_Msk);
    switch(sel){
        case(SYS_CLK_XTAL24M):
            t = t | (1 << SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SYSSEL_Pos);
            break;
        case(SYS_CLK_PLL48M):
            t = t | (2 << SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SYSSEL_Pos);
            t = t | (3 << SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SEL_Pos);
            break;
        case(SYS_CLK_PLL24M):
            t = t | (2 << SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SYSSEL_Pos);
            t = t | (2 << SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SEL_Pos);
            break;
        case(SYS_CLK_PLL12M):
            t = t | (2 << SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SYSSEL_Pos);
            t = t | (1 << SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SEL_Pos);
            break;
        case(SYS_CLK_PLL6M):
            t = t | (2 << SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SYSSEL_Pos);
            break;
        default:
            t = t;
            break;
    }
    // write
    SYS_CTRL->SYS_CLKSEL = t;
}

// Description: get system clock mode
uint32_t omw_get_sys_clk(void){
    uint32_t t, t0, t1;
    // read
    t = SYS_CTRL->SYS_CLKSEL;
    t0 = (t & SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SYSSEL_Msk) >> SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SYSSEL_Pos;
    t1 = (t & SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SEL_Msk) >> SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SEL_Pos;
    // decode
    if(t0 == 0)
        return SYS_CLK_RC24M;
    if(t0 == 1)
        return SYS_CLK_XTAL24M;
    if(t0 == 2){
        if(t1 == 0)
            return SYS_CLK_PLL6M;
        if(t1 == 1)
            return SYS_CLK_PLL12M;
        if(t1 == 2)
            return SYS_CLK_PLL24M;
        if(t1 == 3)
            return SYS_CLK_PLL48M;
    }
    return 0xee; // error
}

// Description: get system clock frequency
uint32_t omw_get_sys_clk_freq(void){
    uint32_t t, t0, t1;
    // read
    t = SYS_CTRL->SYS_CLKSEL;
    t0 = (t & SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SYSSEL_Msk) >> SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SYSSEL_Pos;
    t1 = (t & SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SEL_Msk) >> SYS_CTRL_SYS_CLKSEL_REG_CPU_CLK_SEL_Pos;
    // decode
    if((t0 == 0) || (t0 == 1))
        return 24e6;
    if(t0 == 2){
        if(t1 == 0)
            return 6e6;
        if(t1 == 1)
            return 12e6;
        if(t1 == 2)
            return 24e6;
        if(t1 == 3)
            return 48e6;
    }
    return 0xee; // error
}


// Description: get reset status
uint32_t omw_get_reset_flag(void){
    return AON_CTRL->CPU_RST_RCD;
}

// Description: clear reset status
void omw_clear_reset_flag(uint32_t d){
    AON_CTRL->CPU_RST_CLR = d;
}

// Description: soft reset of system
void omw_soft_reset(void){
    SYS_CTRL->SYS_RESET = 1;
}

// Description: delay ms use rtc
void omw_rtc_delay_ms(uint32_t d){
    int t, te;
    if(d == 0) d = 1;
    t = SYS_CTRL->AON_RTC;
    te = t + 32*d;
    while(1){
        t = SYS_CTRL->AON_RTC;
        //if(t == te) break; // may dead loop when debug
        if(t >= te) break; // may cause shorten delay when te wrapback
    }
}
