/*---------------------------------------------------------------------------------------------------------*/
/*                                                                                                         */
/* SPDX-License-Identifier: Apache-2.0                                                                     */
/* Copyright(c) 2025 Nuvoton Technology Corp. All rights reserved.                                         */
/*                                                                                                         */
/*---------------------------------------------------------------------------------------------------------*/
#include "numicro_8051.h"

  /**
  * @brief This API configures modify system HIRC value
  * @param[in] u8FsysMode . Valid values are:
  *                       - \ref HIRC_24                 :Internal HIRC 24MHz .
  *                       - \ref HIRC_16                 :Internal HIRC 16MHz.
  *                       - \ref HIRC_166                :Internal HIRC 16.6MHz.
  * @note      None.
  * @exmaple : MODIFY_HIRC(HIRC_24);
  */
void MODIFY_HIRC(uint8_t u8HIRCSEL)
{
#if defined __C51__
    uint8_t data hircmap0,hircmap1, offset,judge;
#elif defined __ICC8051__
    uint8_t hircmap0, hircmap1, offset,judge;
#elif defined __SDCC__
    uint8_t __data hircmap0,hircmap1, offset,judge;
#endif
    uint8_t trimvalue16bit;
    /* Check if power on reset, modify HIRC */
    SFRS = 0 ;
    switch (u8HIRCSEL)
    {
      case HIRC_24:
        IAPAL = 0x38;
      break;
      case HIRC_16:
        IAPAL = 0x30;
      break;
      case HIRC_166:
        IAPAL = 0x30;
      break;
    }
    set_CHPCON_IAPEN;
    IAPAH = 0x00;
    IAPCN = READ_UID;
    set_IAPTRG_IAPGO;
    hircmap0 = IAPFD;
    IAPAL++;
    set_IAPTRG_IAPGO;
    hircmap1 = IAPFD;

    switch (u8HIRCSEL)
    {
      case HIRC_166:
        trimvalue16bit = ((hircmap0 << 1) + (hircmap1 & 0x01));
        judge = trimvalue16bit&0xC0;
        offset = trimvalue16bit&0x3F;
        trimvalue16bit -= 14;

        IAPCN = READ_DID;
        IAPAL = 1;
        IAPAH = 0;
        set_IAPTRG_IAPGO;
        if ((IAPFD==0x4B)||(IAPFD==0x52)||(IAPFD==0x53))    /* MS51 process */
        {
          if (offset<15)
          {
              if ((judge==0x40)||(judge==0x80)||(judge==0xC0))
              trimvalue16bit -= 14;
          }
          else 
            trimvalue16bit -= 4;
        }
        hircmap0 = trimvalue16bit >> 1;

      break;
      default: break;
    }

    TA = 0xAA;
    TA = 0x55;
    RCTRIM0 = hircmap0;
    TA = 0xAA;
    TA = 0x55;
    RCTRIM1 = hircmap1;
    clr_CHPCON_IAPEN;
    PCON &= CLR_BIT4;
}


  /**
  * @brief This API configures system clock source
  * @param[in] u8FsysMode . Valid values are:
  *                       - \ref FSYS_HXT                 :External crsytal input.
  *                       - \ref FSYS_HIRC                :Internal HIRC (16MHz as default).
  *                       - \ref FSYS_LIRC                :Internal LIRC.
  *                       - \ref FSYS_OSCIN_P30            :External clock input from P3.0.
  *                       - \ref FSYS_HXTIN_P00            :External clock input from P0.0.
  * @note      None.
  * @exmaple : FsysSelect(FSYS_HXT);
  */
void FsysSelect(uint8_t u8FsysMode)
{
  switch (u8FsysMode)
  {
    //***** HXT enable part*****
    case FSYS_HXT:
        ClockEnable(FSYS_HIRC);                      /*step1: switching system clock to HIRC */
        ClockSwitch(FSYS_HIRC);
        ClockEnable(FSYS_HXT);                       /*step2: switching system clock to HXT  */
        ClockSwitch(FSYS_HXT);
        clr_CKEN_HIRCEN;                             /*step4: disable HIRC if needed  */
    break;    
        
        //***** HIRC enable part *****  
    case FSYS_HIRC:
        ClockEnable(FSYS_HIRC);                      /*step1: switching system clock HIRC */
        ClockSwitch(FSYS_HIRC);
    break;
    
    //***** LIRC enable part*****
    case FSYS_LIRC:
        ClockEnable(FSYS_LIRC);                      /*step2: switching system clock LIRC  */
        ClockSwitch(FSYS_LIRC);
        clr_CKEN_HIRCEN;                             /*step4: disable HIRC if needed  */
    break;
        
    /***** ECLK enable part clock in with P3.0 *****/      
    case FSYS_OSCIN_P30:
        ClockEnable(FSYS_HIRC);                      /*step1: switching system clock to HIRC  */
        ClockSwitch(FSYS_HIRC);
        ClockEnable(FSYS_OSCIN_P30);                 /*step1: switching system clock to External clock  */
        ClockSwitch(FSYS_OSCIN_P30);
        clr_CKEN_HIRCEN;                             /*step5: disable HIRC if needed */
    break;
    
    /***** ECLK enable part clock in with P0.0 *****/ 
    case FSYS_OSCIN_P00:
        ClockEnable(FSYS_HIRC);                      /*step1: switching system clock to HIRC */
        ClockSwitch(FSYS_HIRC);
        ClockEnable(FSYS_OSCIN_P00);                 /*step1: switching system clock to External clock */
        ClockSwitch(FSYS_OSCIN_P00);
        clr_CKEN_HIRCEN;                             /*step5: disable HIRC if needed */
    break;
  }
}

void ClockEnable(uint8_t u8FsysMode)
{
  switch (u8FsysMode)
  {
    /***** HIRC enable part ******/
    case FSYS_HXT:
        clr_CKEN_EXTEN1;                          /*step1: Enable extnal 4~ 24MHz crystal clock source.*/
        set_CKEN_EXTEN0;
        while(!(CKSWT&SET_BIT7));                 /*step2: check clock source status and wait for ready*/
    break;
   
    /***** HIRC enable part ******/
    case FSYS_HIRC:
        set_CKEN_HIRCEN;                          /*step1: Enable extnal clock source.                  */
        while(!(CKSWT&SET_BIT5));                 /*step2: check clock source status and wait for ready */
    break;
   
    /***** LIRC enable part******/
    case FSYS_LIRC:
        set_CKEN_LIRCEN;                         /*step1: Enable extnal clock source.                   */
        while(!(CKSWT&SET_BIT4));                /*step2: check clock source status and wait for ready */
    break;
    
    /***** ECLK P30 enable part ******/
    case FSYS_OSCIN_P30:
        set_CKEN_EXTEN1;                        /*step1: Enable extnal clock source. */
        set_CKEN_EXTEN0;
        while(!(CKSWT&SET_BIT3));               /*step2: check clock source status and wait for ready  */
    break;
    
    /***** HXT P00 enable part ******/
    case FSYS_OSCIN_P00:
        set_CKEN_EXTEN1;                        /*step1: Enable extnal clock source. */
        clr_CKEN_EXTEN0;
        while(!(CKSWT&SET_BIT6));               /*step2: check clock source status and wait for ready */
    break;
  }
}

void ClockDisable(uint8_t u8FsysMode)
{
#if defined __C51__
    uint8_t data closeflag;
#elif defined __ICC8051__
    uint8_t closeflag;
#elif defined __SDCC__
    uint8_t __data closeflag;
#endif

  closeflag = 0;
  SFRS = 0;
  switch (u8FsysMode)
  {
    /***** HXT  part ******/
    case FSYS_HXT:
      closeflag = 1;
    break;
     /***** HIRC  part ******/
    case FSYS_HIRC:
        clr_CKEN_HIRCEN;
    break;
    /***** LIRC  part******/
    case FSYS_LIRC:
        clr_CKEN_LIRCEN;
    break;
    //***** External clock OSCIN from P3.0 ******/
    case FSYS_OSCIN_P30:
        closeflag = 1; 
    break;
    //***** External clock OSCIN from P0.0 ******/
    case FSYS_OSCIN_P00:
        closeflag = 1;
    break;
  }
  if (closeflag)
  {
    SFRS=0;BIT_TMP=EA;EA=0;TA=0xAA;TA=0x55;CKEN&=0x3F;EA=BIT_TMP;
    closeflag = 0;
  }
  
}

void ClockSwitch(uint8_t u8FsysMode)
{
  SFRS = 0 ;
  BIT_TMP=EA;EA=0;
  switch (u8FsysMode)
  {
    /***** HIRC  part ******/
    case FSYS_HIRC:
        clr_CKSWT_OSC1;
        clr_CKSWT_OSC0;
    break;
    /***** LIRC  part******/
    case FSYS_LIRC:
        set_CKSWT_OSC1;
        clr_CKSWT_OSC0;
    break;
    /***** External clock OSCIN from P3.0 ******/
    case FSYS_OSCIN_P30:
        set_CKSWT_ECKP30ST;
		/***** External clock OSCIN from P0.0 ******/
    break;
		    case FSYS_OSCIN_P00:
        set_CKSWT_ECKP00ST;
    break;
		
  }
  EA = BIT_TMP;
}


void HXTGain(uint8_t u8HXTGainLevel)
{
  SFRS = 2;
  switch (u8HXTGainLevel)
  {
    /***** HXT L0 For CM1003 HXT Crystal 4 to 12 MHz ******/
    case HXTGainL0:
      XTLCON = 0;
    break;
     /***** HXT L1 CM1003 HXT Crystal 12 to 24 MHz and Ceramic Resonator 4 to 24MHz  ******/
    case HXTGainL1:
      XTLCON = 0x0C;
    break;
  }
	SFRS = 0;
}

