#include <stdint.h>
#include "OB90A64U1.h"
#include "system_OB90A64U1.h"
#include "math.h"

// System Clock Type
#define SYS_CLK_TYPE_HIRC_24M     0x00
#define SYS_CLK_TYPE_XTAL         0x01
#define SYS_CLK_TYPE_HIRC24M_DPLL 0x02
#define SYS_CLK_TYPE_XTAL_DPLL    0x03

// DPLL Clock Option
#define DPLL_CLK_12M        12000000
#define DPLL_CLK_16M        16000000
#define DPLL_CLK_18M        18000000
#define DPLL_CLK_36M        36000000
#define DPLL_CLK_48M        48000000
#define DPLL_CLK_72M        72000000
// System Clock (Setting by User)
#define DEFAULT_SYS_CLOCK_TYPE  SYS_CLK_TYPE_HIRC24M_DPLL       // Select system clock type

#define HIRC_FREQ_24M       24000000                    // The HIRC frequence
#define DPLL_FREQ           DPLL_CLK_48M                // The DPLL frequence
#define XTAL_FREQ           24000000                    // The XTAL frequence


#if (DEFAULT_SYS_CLOCK_TYPE == SYS_CLK_TYPE_HIRC_24M )
    #define DEFAULT_SYS_CLOCK HIRC_FREQ_24M
#elif (DEFAULT_SYS_CLOCK_TYPE == SYS_CLK_TYPE_XTAL)
    #define DEFAULT_SYS_CLOCK XTAL_FREQ
#else
    #define DEFAULT_SYS_CLOCK DPLL_FREQ
#endif

volatile uint32_t SystemCoreClock = DEFAULT_SYS_CLOCK; // Current system core clock.

void SystemInit (void)
{
    // Setting system clock

#if (DEFAULT_SYS_CLOCK_TYPE == SYS_CLK_TYPE_HIRC_24M)
    OB_SYSCON->CCLKCFG_b.MCUSRCSEL = 0;
    OB_SYSCON->CCLKCFG_b.CPUWAITCNT = 0;
    while(OB_SYSCON->CPUCHIPCTR0_b.HIRC_RDY_24M != 1);    // Wait Ready

#elif (DEFAULT_SYS_CLOCK_TYPE == SYS_CLK_TYPE_XTAL)
    //-------------filter
    if(XTAL_FREQ <= 30000000)
        OB_SYSCON->CPUCHIPCTR1_b.CKFMXSEL = 1;
    else
        OB_SYSCON->CPUCHIPCTR1_b.CKFMXSEL = 2;
    //--------------------force HIRC
    OB_SYSCON->CCLKCFG_b.MCUSRCSEL = 0;
    OB_SYSCON->CCLKCFG_b.CPUWAITCNT = 0;
    while(OB_SYSCON->CPUCHIPCTR0_b.HIRC_RDY_24M != 1);     // Wait Ready

    OB_SYSCON->CCLKCFG_b.MCUSRCSEL = 2;
    while(OB_SYSCON->CPUCHIPCTR0_b.MXTAL_RDY != 1);     // Wait Ready

#else
    // DPLL Init

    uint32_t nInputSounre = 0;
    uint32_t nDiv_2M = 0;
    volatile uint32_t *pDPLLCT;
    volatile uint32_t *pDPLLDM;

     //-----------------------------DPLL Init Freq------------
    pDPLLDM = (uint32_t *) 0x50010090;
    pDPLLCT = (uint32_t *) 0x50010098;
    *pDPLLDM = 0x02;
    *pDPLLCT = (135) | (140 <<16);
    //--------------------force HIRC
    OB_SYSCON->CCLKCFG_b.MCUSRCSEL = 0;
    while(OB_SYSCON->CPUCHIPCTR0_b.HIRC_RDY_24M != 1);     // Wait Ready

    #if (DEFAULT_SYS_CLOCK_TYPE == SYS_CLK_TYPE_HIRC24M_DPLL)
    {
        nInputSounre = 0x01;
        nDiv_2M = (HIRC_FREQ_24M / 2000000) - 1;
    }
    #else
    {
        nInputSounre = 0x00;
        nDiv_2M = (XTAL_FREQ / 2000000) - 1;
    }
    #endif

    nDiv_2M = (nDiv_2M << 0x04);

    switch (DPLL_FREQ)
    {
    case DPLL_CLK_12M:
        OB_SYSCON->DPLLCON = (0xF0020C00) | ( nDiv_2M) | nInputSounre; // 144/12 = 12M
        break;
    case DPLL_CLK_16M:
        OB_SYSCON->DPLLCON = (0xF0020900) | ( nDiv_2M) | nInputSounre; // 144/9 = 16M
        break;
    case DPLL_CLK_18M:
        OB_SYSCON->DPLLCON = (0xF0020800) | ( nDiv_2M) | nInputSounre; // 144/8 = 18M
        break;
    case DPLL_CLK_36M:
        OB_SYSCON->DPLLCON = (0xF0020400) | ( nDiv_2M) | nInputSounre; // 144/4 = 36M
        break;
    case DPLL_CLK_48M:
        OB_SYSCON->DPLLCON = (0xF0020300) | ( nDiv_2M) | nInputSounre; // 144/3 = 48M
        break;
    case DPLL_CLK_72M:
        OB_SYSCON->DPLLCON = (0xF0020200) | ( nDiv_2M) | nInputSounre; // 144/2 = 72M
        break;
    default:
        OB_SYSCON->DPLLCON = (0xF0020300) | ( nDiv_2M) | nInputSounre; // 144/3 = 48M
        break;
    }

    if (DEFAULT_SYS_CLOCK > 48000000)
        OB_SYSCON->CCLKCFG_b.CPUWAITCNT = 2; // CPU Wait 2 Cycle
    else if (DEFAULT_SYS_CLOCK > 24000000)
        OB_SYSCON->CCLKCFG_b.CPUWAITCNT = 1; // CPU Wait 1 Cycle
    else
        OB_SYSCON->CCLKCFG_b.CPUWAITCNT = 0; // CPU Wait 0 Cycle
    OB_SYSCON->CCLKCFG_b.MCUSRCSEL = 1;
    while(OB_SYSCON->CPUCHIPCTR0_b.DPLL_RDY != 1);     // Wait Ready
#endif
}

void SystemCoreClockUpdate (void)
{
    uint32_t nDiv = OB_SYSCON->CCLKCFG & 0x00FF;

    SystemCoreClock = DEFAULT_SYS_CLOCK / (nDiv + 1);
}


