
#include "r_device.h"
#include "Clock.h"

#define   CLOCK_MAIN_OSC_START_WAIT         (65536UL)
#define   CLOCK_PLL1_START_WAIT             (65536UL)

Clock_Status_en_t g_enClockMainOSCStatus;


#define _WRITE_PROTECT_COMMAND              (0x000000A5UL)  /* Write protected */
#define _CGC_FOUT_CLK_SOURCE_LSOSC          (0x00000003UL) /* LS IntOSC */
#define _CGC_FOUT_DIVISION_RATIO                  (0x00000004UL) /* Clock divider N */
#define _CGC_CKSC_AFOUTS_STPM_DEFAULT_VALUE       (0x00000002UL) /* CKSC_AFOUTS_STPM default value */
#define _CGC_FOUT_CLK_REQUEST_STOP           (0x00000000UL) /* C_AWO_FOUT is stopped in standby mode */

void Clock_Run_Mode_Init(void)
{
    uint32_t u32TimeOut;
    Clock_Status_en_t enPLL1Status;
    
    /*** Start 8MHz MainOsc ***/
    if ((CLKCTLMOSCS & 0x00000004UL) == 0x00000004UL)   /* MainOsc is already running */
    {
        g_enClockMainOSCStatus = CLOCK_RUN;
    }
    else                                                /* MainOsc needs to be started */
    {
        CLKCTLMOSCC  = 0x00000007UL;                    /* Set MainOSC gain for 8MHz */
        CLKCTLMOSCST = 0x00003E80UL;                    /* Set MainOSC stabilization time to 2ms */
        
        #if CLOCK_MAIN_OSC_RUN_IN_SLEEP_MODE
            CLKCTLMOSCSTPM = 0x00000003UL;              /* MainOSC continues operation in stand-by mode */
        #else
            CLKCTLMOSCSTPM = 0x00000002UL;              /* MainOSC stops operation in stand-by mode */
        #endif
        
        /* Trigger Enable (protected write) */
        protected_write(WPROTRPROTCMD0, WPROTRPROTS0, CLKCTLMOSCE, 0x00000001UL);   
        
        u32TimeOut = CLOCK_MAIN_OSC_START_WAIT;
        g_enClockMainOSCStatus = CLOCK_START;
        
        while ((u32TimeOut > 0) && (g_enClockMainOSCStatus == CLOCK_START))
        {
            u32TimeOut--;
            if ((CLKCTLMOSCS & 0x00000004UL) == 0x00000004UL)
            {
                g_enClockMainOSCStatus = CLOCK_RUN;
            }
        }
    }
    
    /*** Start PLL1 ***/
    if ((CLKCTLPLL1S & 0x00000004UL) == 0x00000004UL)   /* PLL is already running */
    {
        enPLL1Status = CLOCK_RUN;
    }
    else                                                /* PLL needs to be started */
    {
        if (g_enClockMainOSCStatus == CLOCK_RUN)
        {
            /* Select MainOSC as PLL1 clock source */
            protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_PLL1IS_CTL, 0x00000001UL);
            while(CLKCTLCKSC_PLL1IS_ACT != 0x00000001UL)
            {
                
            }
        }
        else
        {
            /* Select HS IntOSC as PLL1 clock source */
            protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_PLL1IS_CTL, 0x00000002UL);
            while(CLKCTLCKSC_PLL1IS_ACT != 0x00000002UL)
            {
                
            }
        }
        
        CLKCTLPLL1C = 0x0001033BUL;                     /* 8 MHz / 1(Mr) * 60(Nr) = 480MHz VCO freq */
        
        /* Enable PLL */
        protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLPLL1E, 0x00000001UL);
        
        u32TimeOut = CLOCK_PLL1_START_WAIT;
        enPLL1Status = CLOCK_START;
        
        while ((u32TimeOut > 0) && (enPLL1Status == CLOCK_START))
        {
            u32TimeOut--;
            if ((CLKCTLPLL1S & 0x00000004UL) == 0x00000004UL)
            {
                enPLL1Status = CLOCK_RUN;
            }
        }
    }
    
    if (enPLL1Status != CLOCK_RUN)
    {
        /* PLL startup failed, reset MCU */
    }
    
    /* CPLL1OUT = VCOOUT � 1/4 = 120 MHz */
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_CPUCLKD_CTL, 0x00000011UL);
    while(CLKCTLCKSC_CPUCLKD_ACT != 0x00000011UL)
    {
        
    }
  
    /* CPLLOUT -> CPU Clock */ 
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_CPUCLKS_CTL, 0x00000003UL);
    while(CLKCTLCKSC_CPUCLKS_ACT != 0x00000003UL)
    {
        
    }
  
    /* PPLLOUT -> PPLLCLK = 80MHz */
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_PPLLCLKS_CTL, 0x00000003UL);
    while(CLKCTLCKSC_PPLLCLKS_ACT != 0x00000003UL)
    {
        
    }        
    
    /*** Start clock monitor ***/
    
    /*** Config clock domains ***/
    
    /* 1. C_AWO_WDTA */
    /* Use default setting: C_AWO_WDTA = LS IntOSC / 128 */ 
    
    /* 2. C_AWO_TAUJ */
    /* C_AWO_TAUJ = PPLLCLK2 = PPLLCLK / 2 */
    protected_write(WPROTRPROTCMD0, WPROTRPROTS0, CLKCTLCKSC_ATAUJS_CTL, 0x00000004UL);
    while(CLKCTLCKSC_ATAUJS_ACT != 0x00000004UL)
    {
        
    }
    
    /* 3. C_AWO_RTCA */
    #if CLOCK_MAIN_OSC_RUN_IN_SLEEP_MODE
    if (CLKCTLCKSC_ARTCAS_ACT != 0x00000002UL)
    {
        if (CLKCTLCKSC_ARTCAD_ACT != 0x00000000UL)
        {
            /* Disable C_AWO_RTCA before setting */
            protected_write(WPROTRPROTCMD0, WPROTRPROTS0, CLKCTLCKSC_ARTCAD_CTL, 0x00000000UL);
            while (CLKCTLCKSC_ARTCAD_ACT != 0x00000000UL)
            {
                
            }
        }
        
        /* C_AWO_RTCA = MainOSC / 8 */
        protected_write(WPROTRPROTCMD0, WPROTRPROTS0, CLKCTLCKSC_ARTCAS_CTL, 0x00000002UL);
        while(CLKCTLCKSC_ARTCAS_ACT != 0x00000002UL)
        {
            
        }
        
        protected_write(WPROTRPROTCMD0, WPROTRPROTS0, CLKCTLCKSC_ARTCAD_CTL, 0x00000004UL);
        while(CLKCTLCKSC_ARTCAD_ACT != 0x00000004UL)
        {
            
        }
        
        CLKCTLCKSC_ARTCAD_STPM = 0x00000003UL;          /* C_AWO_RTCA is not stopped in stand-by mode */
    }
    #else
    if (CLKCTLCKSC_ARTCAS_ACT != 0x00000003UL)
    {
        /* C_AWO_RTCA = LS IntOSC */
        protected_write(WPROTRPROTCMD0, WPROTRPROTS0, CLKCTLCKSC_ARTCAS_CTL, 0x00000003UL);
        while(CLKCTLCKSC_ARTCAS_ACT != 0x00000003UL)
        {
            
        }
        
        protected_write(WPROTRPROTCMD0, WPROTRPROTS0, CLKCTLCKSC_ARTCAD_CTL, 0x00000001UL);
        while(CLKCTLCKSC_ARTCAD_ACT != 0x00000001UL)
        {
            
        }
        
        CLKCTLCKSC_ARTCAD_STPM = 0x00000003UL;          /* C_AWO_RTCA is not stopped in stand-by mode */
    } 
    #endif
    
    /* 4. C_AWO_ADCA */
    /* C_AWO_ADCA = PPLLCLK2 = PPLLCLK / 2 */
    protected_write(WPROTRPROTCMD0, WPROTRPROTS0, CLKCTLCKSC_AADCAS_CTL, 0x00000003UL);
    while(CLKCTLCKSC_AADCAS_ACT != 0x00000003UL)
    {
        
    }
    
    /* 5. C_AWO_FOUT */
    /* Use default setting: Disabled */ 
    
    /* 6. C_ISO_PERI1 */
    /* C_ISO_PERI1 = PPLLCLK */
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_IPERI1S_CTL, 0x00000001UL);
    while (CLKCTLCKSC_IPERI1S_ACT != 0x00000001UL);
    
    /* 7. C_ISO_PERI2 */
    /* C_ISO_PERI2 = PPLLCLK2 = PPLLCLK / 2 */
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_IPERI2S_CTL, 0x00000001UL);
    while (CLKCTLCKSC_IPERI2S_ACT != 0x00000001UL);
    
    /* 8. C_ISO_LIN */
    /* C_ISO_LIN = PPLLCLK2 = PPLLCLK / 2 */
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_ILINS_CTL, 0x00000001UL);
    while (CLKCTLCKSC_ILINS_ACT != 0x00000001UL)
    {
        
    }
    
    /* 9. C_ISO_CAN */
    /* C_ISO_CAN = PPLLCLK2 = PPLLCLK / 2 */
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_ICANS_CTL, 0x00000003UL);
    while (CLKCTLCKSC_ICANS_ACT != 0x00000003UL)
    {
        
    }

    /* 10. C_ISO_CANOSC */
    /* C_ISO_CANOSC = MainOSC */
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_ICANOSCD_CTL, 0x00000001UL);
    while (CLKCTLCKSC_ICANOSCD_ACT != 0x00000001UL);
    
    /* 11. C_ISO_CSI */
    /* C_ISO_CSI = PPLLCLK */
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_ICSIS_CTL, 0x00000001UL);
    while (CLKCTLCKSC_ICSIS_ACT != 0x00000001UL);
    
    /* 12. C_ISO_IIC */
    /* C_ISO_IIC = PPLLCLK2 = PPLLCLK / 2 */
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_IIICS_CTL, 0x00000001UL);
    while (CLKCTLCKSC_IIICS_ACT != 0x00000001UL);




    

    /* Frequency output clock setting */
    WPROTR.PROTCMD0 = _WRITE_PROTECT_COMMAND;
    CLKCTL.CKSC_AFOUTS_CTL = _CGC_FOUT_CLK_SOURCE_LSOSC;
    CLKCTL.CKSC_AFOUTS_CTL = (uint32_t) ~_CGC_FOUT_CLK_SOURCE_LSOSC;
    CLKCTL.CKSC_AFOUTS_CTL = _CGC_FOUT_CLK_SOURCE_LSOSC;
    while (CLKCTL.CKSC_AFOUTS_ACT != _CGC_FOUT_CLK_SOURCE_LSOSC)
    {
        __NOP();
    }
    CLKCTL.FOUTDIV = _CGC_FOUT_DIVISION_RATIO;
    CLKCTL.CKSC_AFOUTS_STPM = _CGC_CKSC_AFOUTS_STPM_DEFAULT_VALUE | _CGC_FOUT_CLK_REQUEST_STOP;

}

void Clock_Sleep_Mode_Init(void)
{
    /*** Config clock domains ***/
    
    /* 1. C_AWO_WDTA */
    /* Use default setting: C_AWO_WDTA = LS IntOSC / 128 */ 
    
    /* 2. C_AWO_TAUJ */
    /* C_AWO_TAUJ = Disabled */
    protected_write(WPROTRPROTCMD0, WPROTRPROTS0, CLKCTLCKSC_ATAUJS_CTL, 0x00000000UL);
    while(CLKCTLCKSC_ATAUJS_ACT != 0x00000000UL)
    {
        
    }
    
    /* 3. C_AWO_RTCA */
    /* Keep startup setting */
    
    /* 4. C_AWO_ADCA */
    /* C_AWO_ADCA = Disabled */
    protected_write(WPROTRPROTCMD0, WPROTRPROTS0, CLKCTLCKSC_AADCAS_CTL, 0x00000000UL);
    while(CLKCTLCKSC_AADCAS_ACT != 0x00000000UL)
    {
        
    }
    
    /* 5. C_AWO_FOUT */
    /* Use default setting: Disabled */ 
    
    /* 6. C_ISO_PERI1 */
    /* C_ISO_PERI1 = Disabled */
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_IPERI1S_CTL, 0x00000000UL);
    while (CLKCTLCKSC_IPERI1S_ACT != 0x00000000UL);
    
    /* 7. C_ISO_PERI2 */
    /* C_ISO_PERI2 = Disabled */
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_IPERI2S_CTL, 0x00000000UL);
    while (CLKCTLCKSC_IPERI2S_ACT != 0x00000000UL);
    
    /* 8. C_ISO_LIN */
    /* C_ISO_LIN = Disabled */
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_ILINS_CTL, 0x00000000UL);
    while (CLKCTLCKSC_ILINS_ACT != 0x00000000UL)
    {
        
    }

    /* 9. C_ISO_CANOSC */
    /* C_ISO_CANOSC = Disabled */
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_ICANOSCD_CTL, 0x00000000UL);
    while (CLKCTLCKSC_ICANOSCD_ACT != 0x00000000UL);

    /* 10. C_ISO_CAN */
    /* C_ISO_CAN = Disabled */
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_ICANS_CTL, 0x00000000UL);
    while (CLKCTLCKSC_ICANS_ACT != 0x00000000UL)
    {
        
    }
    
    /* 11. C_ISO_CSI */
    /* C_ISO_CSI = Disabled */
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_ICSIS_CTL, 0x00000000UL);
    while (CLKCTLCKSC_ICSIS_ACT != 0x00000000UL);
    
    /* 12. C_ISO_IIC */
    /* C_ISO_IIC = Disabled */
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_IIICS_CTL, 0x00000000UL);
    while (CLKCTLCKSC_IIICS_ACT != 0x00000000UL);
    
    /* 13. C_ISO_CPUCLK */
    /* C_ISO_CPUCLK = EMCLK = HS IntOSC */ 
    protected_write(WPROTRPROTCMD1, WPROTRPROTS1, CLKCTLCKSC_CPUCLKS_CTL, 0x00000001UL);
    while(CLKCTLCKSC_CPUCLKS_ACT != 0x00000001UL)
    {
        
    }
}

Clock_Status_en_t Clock_Get_Main_OSC_Status(void)
{
    return g_enClockMainOSCStatus;
}
