/******************** (C) COPYRIGHT 2006 STMicroelectronics ********************
* File Name          : 75x_mrcc.c
* Author             : MCD Application Team
* Date First Issued  : 03/10/2006
* Description        : This file provides all the MRCC software functions.
********************************************************************************
* History:
* 07/17/2006 : V1.0
* 03/10/2006 : V0.1
********************************************************************************
* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "75x_mrcc.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define MRCC_FLAG_Mask    0x1F    /* MRCC Flag Mask */

/* MRCC_PWRCTRL mask bits */
#define MRCC_LP_Set_Mask             0x00000001
#define MRCC_LP_Reset_Mask           0xFFFFFFFE
#define MRCC_SWRESET_Mask            0x00000002
#define MRCC_WFI_Mask                0x00000004
#define MRCC_STANDBY_Mask            0x00000006
#define MRCC_LPMC_Reset_Mask         0xFFFFFFF9
#define MRCC_LPDONE_Reset_Mask       0xFFFFFF7F
#define MRCC_LPPARAM_Reset_Mask      0xFFFF1FFF
#define MRCC_WFIParam_Reset_Mask     0xFFFF1FEF
#define MRCC_CKRTCSEL_Set_Mask       0x03000000
#define MRCC_CKRTCSEL_Reset_Mask     0xFCFFFFFF
#define MRCC_CKRTCOK_Mask            0x08000000
#define MRCC_LPOSCEN_Mask            0x10000000
#define MRCC_OSC32KEN_Mask           0x20000000
            
/* MRCC_CLKCTL mask bits */
#define MRCC_PPRESC_Set_Mask        0x00000003
#define MRCC_PPRESC_Reset_Mask      0xFFFFFFFC
#define MRCC_PPRESC2_Mask           0x00000004
#define MRCC_HPRESC_Set_Mask        0x00000018
#define MRCC_HPRESC_Reset_Mask      0xFFFFFFE7
#define MRCC_MCOS_Reset_Mask        0xFFFFFF3F
#define MRCC_XTDIV2_Set_Mask        0x00008000
#define MRCC_XTDIV2_Reset_Mask      0xFFFF7FFF
#define MRCC_OSC4MBYP_Set_Mask      0x00010000
#define MRCC_OSC4MBYP_Reset_Mask    0xFFFEFFFF
#define MRCC_OSC4MOFF_Set_Mask      0x00020000  
#define MRCC_OSC4MOFF_Reset_Mask    0xFFFDFFFF
#define MRCC_NCKDF_Set_Mask         0x00040000
#define MRCC_NCKDF_Reset_Mask       0xFFFBFFFF
#define MRCC_CKOSCSEL_Set_Mask      0x00200000
#define MRCC_CKOSCSEL_Reset_Mask    0xFFDFFFFF
#define MRCC_CKUSBSEL_Mask          0x00400000
#define MRCC_CKSEL_Set_Mask         0x00800000
#define MRCC_CKSEL_Reset_Mask       0xFF7FFFFF
#define MRCC_CKSEL_CKOSCSEL_Mask    0x00A00000
#define MRCC_PLLEN_Set_Mask         0x01000000
#define MRCC_PLLEN_Reset_Mask       0xFEFFFFFF
#define MRCC_PLL2EN_Set_Mask        0x02000000
#define MRCC_PLL2EN_Reset_Mask      0xFDFFFFFF
#define MRCC_MX_Set_Mask            0x18000000
#define MRCC_MX_Reset_Mask          0xE7FFFFFF
#define MRCC_LOCK_Mask              0x80000000
#define MRCC_PLLEN_LOCK_Mask        0x81000000

/* Typical Value of the OSC4M in Hz */
#define OSC4M_Value    4000000   

/* Typical Value of the OSC4M divided by 128 (used to clock the RTC) in Hz */
#define OSC4M_Div128_Value    31250
   
/* Typical Value of the OS32K Oscillator Frequency in Hz */
#define OSC32K_Value    32768     

/* Typical Reset Value of the Internal LPOSC Oscillator Frequency in Hz */
#define LPOSC_Value    245000   

/* Typical Reset Value of the Internal FREEOSC Oscillator Frequency in Hz */
#define FREEOSC_Value    5000000 

/* Time out for OSC4M start up */
#define OSC4MStartUp_TimeOut   0xFE

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static ErrorStatus SetCKSYS_FREEOSC(void);
static ErrorStatus SetCKSYS_OSC4M(u32 PLL_State);
static ErrorStatus SetCKSYS_OSC4MPLL(u32 PLL_Mul);
static ErrorStatus SetCKSYS_RTC(u32 PLL_State);
static void WriteLPBit(void);
static void WriteCKOSCSELBit(void);

/* Private functions ---------------------------------------------------------*/

/*******************************************************************************
* Function Name  : MRCC_DeInit
* Description    : Deinitializes the MRCC peripheral registers to their default
*                  reset values. 
*                   - Depending on the system clock state, some bits in MRCC_CLKCTL
*                     register can’t be reset.
*                   - The OSC32K, LPOSC and RTC clock selection configuration 
*                     bits in MRCC_PWRCTRL register are not cleared by this  
*                     function. To reset those bits, use the dedicated functions 
*                     available within this driver.
*                   - The MRCC_RFSR, MRCC_BKP0 and MRCC_BKP1 registers are not
*                     reset by this function.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_DeInit(void)
{
  /* Try to clear NCKDF bit */
  MRCC->CLKCTL &= MRCC_NCKDF_Reset_Mask;

  if((MRCC->CLKCTL & MRCC_NCKDF_Set_Mask) != RESET)
  {/* No clock detected on OSC4M */

    /* Reset LOCKIE, LOCKIF, CKUSBSEL, NCKDIE, OSC4MOFF, OSC4MBYP, MCOS[1:0], 
       MCOP, HPRESC[1:0], PPRES[2:0] bits */
    MRCC->CLKCTL &= 0x9FB40000;
     
    if((MRCC->CLKCTL & MRCC_CKOSCSEL_Set_Mask) != RESET)
    { 
      /* Clear CKOSCSEL bit --------------------------------------------------*/         
      /* Execute CKOSCSEL bit writing sequence */
      WriteCKOSCSELBit();
    }
  }
  else
  {/* Clock present on OSC4M */

    if((MRCC->CLKCTL & MRCC_CKOSCSEL_Set_Mask) != RESET)
    { 
      /* Reset CKSEL bit */
      MRCC->CLKCTL &= MRCC_CKSEL_Reset_Mask;

      /* Clear CKOSCSEL bit --------------------------------------------------*/
      /* Execute CKOSCSEL bit writing sequence */
      WriteCKOSCSELBit();
    }

    if((MRCC->CLKCTL & MRCC_CKSEL_Set_Mask) == RESET)
    {
      /* Set CKSEL bit */
      MRCC->CLKCTL |= MRCC_CKSEL_Set_Mask;  
    }

    /* Disable PLL */
    MRCC->CLKCTL &= MRCC_PLLEN_Reset_Mask;

    /* Reset LOCKIE, LOCKIF, MX[1:0], CKUSBSEL, NCKDIE, MCOS[1:0], MCOP,
       HPRESC[1:0], PPRES[2:0] bits */
    MRCC->CLKCTL &= 0x87B70000;

    /* Reset CKSEL bit */
    MRCC->CLKCTL &= MRCC_CKSEL_Reset_Mask;

    /* Reset OSC4MOFF and OSC4MBYP bits */
    MRCC->CLKCTL &= 0xFFFCFFFF;   
  }

  /* Reset RTCM, EN33V, LP_PARAM[15:13], WFI_FLASH_EN, LPMC_DBG and LPMC[1:0] bits */
  MRCC->PWRCTRL &= 0xFBFE1FE1;
  
  /* Reset PCLKEN register bits */
  MRCC->PCLKEN = 0x00;
  
  /* Reset PSWRES register bits */
  MRCC->PSWRES = 0x00;  

  /* Clear NCKDF bit */
  MRCC->CLKCTL &= MRCC_NCKDF_Reset_Mask; 
}

/*******************************************************************************
* Function Name  : MRCC_XTDIV2Config
* Description    : Enables or disables the oscillator divider by 2. This function
*                  must not be used when the PLL is enabled.
* Input          : - MRCC_XTDIV2: specifies the new state of the oscillator 
*                    divider by 2.
*                    This parameter can be one of the following values:
*                          - MRCC_XTDIV2_Disable: oscillator divider by 2 disbaled
*                          - MRCC_XTDIV2_Enable: oscillator divider by 2 enbaled
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_XTDIV2Config(u32 MRCC_XTDIV2)
{
  if(MRCC_XTDIV2 == MRCC_XTDIV2_Enable)
  {
    MRCC->CLKCTL |= MRCC_XTDIV2_Enable;
  }
  else
  {
    MRCC->CLKCTL &= MRCC_XTDIV2_Disable;
  }  
}

/*******************************************************************************
* Function Name  : MRCC_CKSYSConfig
* Description    : Configures the system clock (CK_SYS).
* Input          : - MRCC_CKSYS: specifies the clock source used as system clock.
*                    This parameter can be one of the following values:
*                          - MRCC_CKSYS_FREEOSC
*                          - MRCC_CKSYS_OSC4M
*                          - MRCC_CKSYS_OSC4MPLL
*                          - MRCC_CKSYS_RTC (RTC clock source must be previously
*                            configured using MRCC_CKRTCConfig() function)
*                : - MRCC_PLL: specifies the PLL configuration.
*                    This parameter can be one of the following values:
*                          - MRCC_PLL_Disabled: PLL disabled
*                          - MRCC_PLL_NoChange: No change on PLL configuration
*                          - MRCC_PLL_Mul_12: Multiplication by 12
*                          - MRCC_PLL_Mul_14: Multiplication by 14
*                          - MRCC_PLL_Mul_15: Multiplication by 15
*                          - MRCC_PLL_Mul_16: Multiplication by 16
* Output         : None
* Return         : An ErrorStatus enumuration value:
*                         - SUCCESS: Clock configuration succeeded
*                         - ERROR: Clock configuration failed
*******************************************************************************/
ErrorStatus MRCC_CKSYSConfig(u32 MRCC_CKSYS, u32 MRCC_PLL)
{
  ErrorStatus Status = ERROR;

  switch(MRCC_CKSYS)
  {
    case MRCC_CKSYS_FREEOSC:
      if((MRCC_PLL == MRCC_PLL_Disabled) || (MRCC_PLL == MRCC_PLL_NoChange))
      {
        Status = SetCKSYS_FREEOSC();
      }
      break;

    case MRCC_CKSYS_OSC4M:
      if((MRCC_PLL == MRCC_PLL_Disabled) || (MRCC_PLL == MRCC_PLL_NoChange))
      {
        Status = SetCKSYS_OSC4M(MRCC_PLL);
      }
      break;

    case MRCC_CKSYS_OSC4MPLL:
      if((MRCC_PLL == MRCC_PLL_Mul_12) || (MRCC_PLL == MRCC_PLL_Mul_14) ||
         (MRCC_PLL == MRCC_PLL_Mul_15) || (MRCC_PLL == MRCC_PLL_Mul_16))
      {
        Status = SetCKSYS_OSC4MPLL(MRCC_PLL);
      }
      break;

    case MRCC_CKSYS_RTC:
      if((MRCC_PLL == MRCC_PLL_Disabled) || (MRCC_PLL == MRCC_PLL_NoChange))
      {    
        Status = SetCKSYS_RTC(MRCC_PLL);
      }
      break;

    default:
      Status = ERROR;
      break;
  }
  return Status;
}

/*******************************************************************************
* Function Name  : MRCC_HCLKConfig
* Description    : Configures the AHB clock (HCLK).
* Input          : - MRCC_HCLK: defines the AHB clock. This clock is derived
*                    from the system clock(CK_SYS).
*                    This parameter can be one of the following values:
*                          - MRCC_CKSYS_Div1: AHB clock = CK_SYS
*                          - MRCC_CKSYS_Div2: AHB clock = CK_SYS/2
*                          - MRCC_CKSYS_Div4: AHB clock = CK_SYS/4
*                          - MRCC_CKSYS_Div8: AHB clock = CK_SYS/8
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_HCLKConfig(u32 MRCC_HCLK)
{
  u32 Temp = 0;
  
  /* Clear HPRESC[1:0] bits */
  Temp = MRCC->CLKCTL & MRCC_HPRESC_Reset_Mask;
  
  /* Set HPRESC[1:0] bits according to MRCC_HCLK value */
  Temp |= MRCC_HCLK;
  
  /* Store the new value */
  MRCC->CLKCTL = Temp;  
}

/*******************************************************************************
* Function Name  : MRCC_CKTIMConfig
* Description    : Configures the TIM clock (CK_TIM).
* Input          : - MRCC_CKTIM: defines the TIM clock. This clock is derived
*                    from the AHB clock(HCLK).
*                    This parameter can be one of the following values:
*                          - MRCC_HCLK_Div1: TIM clock = HCLK
*                          - MRCC_HCLK_Div2: TIM clock = HCLK/2
*                          - MRCC_HCLK_Div4: TIM clock = HCLK/4
*                          - MRCC_HCLK_Div8: TIM clock = HCLK/8
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_CKTIMConfig(u32 MRCC_CKTIM)
{
  u32 Temp = 0;
  
  /* Clear PPRESC[1:0] bits */
  Temp = MRCC->CLKCTL & MRCC_PPRESC_Reset_Mask;
  
  /* Set PPRESC[1:0] bits according to MRCC_CKTIM value */
  Temp |= MRCC_CKTIM;
  
  /* Store the new value */
  MRCC->CLKCTL = Temp;
}

/*******************************************************************************
* Function Name  : MRCC_PCLKConfig
* Description    : Configures the APB clock (PCLK).
* Input          : - MRCC_PCLK: defines the APB clock. This clock is derived 
*                    from the TIM clock(CK_TIM).
*                    This parameter can be one of the following values:
*                          - MRCC_CKTIM_Div1: APB clock = CKTIM
*                          - MRCC_CKTIM_Div2: APB clock = CKTIM/2
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_PCLKConfig(u32 MRCC_PCLK)
{
  if(MRCC_PCLK == MRCC_CKTIM_Div2)
  {
    MRCC->CLKCTL |= MRCC_CKTIM_Div2;
  }
  else
  {
    MRCC->CLKCTL &= MRCC_CKTIM_Div1;
  }
}

/*******************************************************************************
* Function Name  : MRCC_CKRTCConfig
* Description    : Configures the RTC clock (CK_RTC).
* Input          : - MRCC_CKRTC: specifies the clock source to be used as RTC
*                    clock.
*                    This parameter can be one of the following values:
*                          - MRCC_CKRTC_OSC4M_Div128
*                          - MRCC_CKRTC_OSC32K (OSC32K must be previously enabled
*                            using MRCC_OSC32KConfig() function)
*                          - MRCC_CKRTC_LPOSC (LPOSC must be previously enabled
*                            using MRCC_LPOSCConfig() function)
* Output         : None
* Return         : An ErrorStatus enumuration value:
*                         - SUCCESS: Clock configuration succeeded
*                         - ERROR: Clock configuration failed
*******************************************************************************/
ErrorStatus MRCC_CKRTCConfig(u32 MRCC_CKRTC)
{
  u32 Tmp = 0;

  if(((MRCC->CLKCTL & MRCC_CKOSCSEL_Set_Mask) != RESET) &&
     ((MRCC->CLKCTL & MRCC_CKSEL_Set_Mask) != RESET))
  { 
    /* CK_RTC used as CK_SYS clock source */
    return ERROR;
  }
  else
  {    
    /* Clear CKRTCSEL[1:0] bits */
    Tmp = MRCC->PWRCTRL & MRCC_CKRTCSEL_Reset_Mask;

    /* Set CKRTCSEL[1:0] bits according to MRCC_CKRTC value */
    Tmp |= MRCC_CKRTC;

    /* Store the new value */
    MRCC->PWRCTRL = Tmp;       
  }

  return SUCCESS;
}

/*******************************************************************************
* Function Name  : MRCC_CKUSBConfig
* Description    : Configures the USB clock(CK_USB).
* Input          : - MRCC_CKUSB: specifies the clock source to be used as USB
*                    clock.
*                    This parameter can be one of the following values:
*                          - MRCC_CKUSB_Internal(CK_PLL2 enabled)
*                          - MRCC_CKUSB_External(CK_PLL2 disabled)
* Output         : None
* Return         : An ErrorStatus enumuration value:
*                         - SUCCESS: Clock configuration succeeded
*                         - ERROR: Clock configuration failed
*******************************************************************************/
ErrorStatus MRCC_CKUSBConfig(u32 MRCC_CKUSB)
{
  if(MRCC_CKUSB == MRCC_CKUSB_External)
  {
    /* Disable CK_PLL2 */
    MRCC->CLKCTL &= MRCC_PLL2EN_Reset_Mask;

    /* External USB clock selected */
    MRCC->CLKCTL |= MRCC_CKUSB_External;
  }
  else
  {
    if((MRCC->CLKCTL & MRCC_PLLEN_LOCK_Mask) != RESET)
    { /* PLL enabled and locked */
      
      /* Enable CK_PLL2 */
      MRCC->CLKCTL |= MRCC_PLL2EN_Set_Mask;

      /* Internal USB clock selected */
      MRCC->CLKCTL &= MRCC_CKUSB_Internal;
    }
    else
    {
      /* PLL not enabled */
      return ERROR;
    }
  }

  return SUCCESS;  
}

/*******************************************************************************
* Function Name  : MRCC_ITConfig
* Description    : Enables or disables the specified MRCC interrupts.
* Input          : - MRCC_IT: specifies the MRCC interrupts sources to be
*                    enabled or disabled. This parameter can be any combination
*                    of the following values:
*                          - MRCC_IT_LOCK: PLL lock interrupt
*                          - MRCC_IT_NCKD: No Clock detected interrupt
*                  - NewState: new state of the MRCC interrupts.
*                    This parameter can be: ENABLE or DISABLE.
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_ITConfig(u32 MRCC_IT, FunctionalState NewState)
{
  if(NewState == ENABLE)
  {
    MRCC->CLKCTL |= MRCC_IT;
  }
  else
  {
    MRCC->CLKCTL &= ~MRCC_IT;
  }
}

/*******************************************************************************
* Function Name  : MRCC_PeripheralClockConfig
* Description    : Enables or disables the specified peripheral clock.
* Input          : - MRCC_Peripheral: specifies the peripheral to gates its
*                    clock. More than one peripheral can be selected using
*                    the “|” operator.
*                  - NewState: new state of the specified peripheral clock.
*                    This parameter can be one of the following values:
*                          - ENABLE: the selected peripheral clock is enabled
*                          - DISABLE: the selected peripheral clock is disabled
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_PeripheralClockConfig(u32 MRCC_Peripheral, FunctionalState NewState)
{
  if(NewState == ENABLE)
  {
    MRCC->PCLKEN |= MRCC_Peripheral;
  }
  else
  {
    MRCC->PCLKEN &= ~MRCC_Peripheral;
  }
}

/*******************************************************************************
* Function Name  : MRCC_PeripheralSWResetConfig
* Description    : Forces or releases peripheral software reset.
* Input          : - MRCC_Peripheral: specifies the peripheral to reset. More
*                    than one peripheral can be selected using the “|” operator.
*                  - NewState: new state of the specified peripheral software
*                    reset. This parameter can be one of the following values:
*                          - ENABLE: the selected peripheral is kept under reset
*                          - DISABLE: the selected peripheral exits from reset
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_PeripheralSWResetConfig(u32 MRCC_Peripheral, FunctionalState NewState)
{
  if(NewState == ENABLE)
  {
    MRCC->PSWRES |= MRCC_Peripheral;
  }
  else
  {
    MRCC->PSWRES &= ~MRCC_Peripheral;
  }
}

/*******************************************************************************
* Function Name  : MRCC_GetClocksStatus
* Description    : Returns the status and frequencies of different on chip clocks.
*                  Don’t use this function when CK_SYS is clocked by an external
*                  clock source (OSC4M bypassed).
* Input          : - MRCC_ClocksStatus: pointer to a MRCC_ClocksTypeDef structure
*                    which will hold the clocks information.
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_GetClocksStatus(MRCC_ClocksTypeDef*  MRCC_ClocksStatus)
{
  u32 PLLMul = 0;
  u32 Temp = 0;
  u32 Presc = 0;

  /* Get the Status of PLL */
  if((MRCC->CLKCTL & MRCC_PLLEN_Set_Mask) == RESET)  
  {
    MRCC_ClocksStatus->PLL_Status = OFF;
  }
  else
  {
    MRCC_ClocksStatus->PLL_Status = ON;
  }
  
  /* Get the Status of OSC4M */
  if((MRCC->CLKCTL & MRCC_OSC4MOFF_Set_Mask) == RESET)  
  {
    MRCC_ClocksStatus->OSC4M_Status = ON;
  }
  else
  {
    MRCC_ClocksStatus->OSC4M_Status = OFF;
  }  
  
  /* Get the Status of LPOSC */
  if((MRCC->PWRCTRL & MRCC_LPOSCEN_Mask) == RESET)  
  {
    MRCC_ClocksStatus->LPOSC_Status = OFF;
  }
  else
  {
    MRCC_ClocksStatus->LPOSC_Status = ON;
  }  
  
  /* Get the Status of OSC32K */
  if((MRCC->PWRCTRL & MRCC_OSC32KEN_Mask) == RESET)  
  {
    MRCC_ClocksStatus->OSC32K_Status = OFF;
  }
  else
  {
    MRCC_ClocksStatus->OSC32K_Status = ON;
  } 
    
/* Get CKU_SB source ---------------------------------------------------------*/  
  if((MRCC->CLKCTL & MRCC_CKUSBSEL_Mask) != RESET)
  {
    MRCC_ClocksStatus->CKUSB_Source = External;    
  }
  else
  {  
    if((MRCC->CLKCTL & MRCC_PLL2EN_Set_Mask) != RESET)
    {
      MRCC_ClocksStatus->CKUSB_Source = Internal;
    
    }
    else 
    {
      MRCC_ClocksStatus->CKUSB_Source = Disabled;    
    }
  }

/* Get CK_RTC source ---------------------------------------------------------*/ 
  Temp = MRCC->PWRCTRL & MRCC_CKRTCSEL_Set_Mask;
  Temp = Temp >> 24;
    
  switch(Temp)
  {
    case 0x00:
      MRCC_ClocksStatus->CKRTC_Source = Disabled;
      break;

    case 0x01:
      MRCC_ClocksStatus->CKRTC_Source = OSC4M_Div128;
      break;

    case 0x02:
      MRCC_ClocksStatus->CKRTC_Source = OSC32K;
      break;
        
    case 0x03:
      MRCC_ClocksStatus->CKRTC_Source = LPOSC;              
      break;
        
    default:
      MRCC_ClocksStatus->CKRTC_Source = Disabled;
      break;          
  }
      
/* Get CK_SYS source ---------------------------------------------------------*/   
  if((MRCC->CLKCTL & MRCC_CKSEL_Set_Mask) != RESET)
  {/* CK_OSC used as CK_SYS clock source */
    
    if((MRCC->CLKCTL & MRCC_CKOSCSEL_Set_Mask) != RESET)
    { /* CK_RTC used as CK_OSC clock source */
      MRCC_ClocksStatus->CKSYS_Source = CKRTC;
      
      if(MRCC_ClocksStatus->CKRTC_Source == OSC32K)
      {
        /* CK_SYS clock frequency */
        MRCC_ClocksStatus->CKSYS_Frequency = OSC32K_Value;         
      }         
      else if(MRCC_ClocksStatus->CKRTC_Source == LPOSC)

      {
        /* CK_SYS clock frequency */
        MRCC_ClocksStatus->CKSYS_Frequency = LPOSC_Value;             
      }
      else if(MRCC_ClocksStatus->CKRTC_Source == OSC4M_Div128)

      {
        /* CK_SYS clock frequency */
        MRCC_ClocksStatus->CKSYS_Frequency = OSC4M_Div128_Value;             
      }
    }
    else
    { /* OSC4M used as CK_OSC clock source */
      MRCC_ClocksStatus->CKSYS_Source = OSC4M; 
    
      if((MRCC->CLKCTL & MRCC_XTDIV2_Set_Mask) != RESET)
      {
        /* CK_SYS clock frequency */
        MRCC_ClocksStatus->CKSYS_Frequency = Main_Oscillator >> 1;
      }
      else
      {
        /* CK_SYS clock frequency */
        MRCC_ClocksStatus->CKSYS_Frequency = Main_Oscillator;
      }          
    }
  }     
  else
  {/* CK_PLL1 used as CK_SYS clock */
    
    if(MRCC_ClocksStatus->PLL_Status == OFF)
    { /* FREEOSC used as CK_PLL1 clock source */
      MRCC_ClocksStatus->CKSYS_Source = FREEOSC; 
      
      /* CK_SYS clock frequency */
      MRCC_ClocksStatus->CKSYS_Frequency = FREEOSC_Value;               
    }
    else
    { /* OSC4M followed by PLL used as CK_PLL1 clock source */
      MRCC_ClocksStatus->CKSYS_Source = OSC4MPLL;
                    
      /* Get PLL factor ------------------------------------------------------*/
      Temp = MRCC->CLKCTL & MRCC_MX_Set_Mask;
      Temp = Temp >> 27;
    
      switch(Temp)
      {
        case 0x00:
          PLLMul = 16;
          break;

        case 0x01:
          PLLMul = 15;
          break;

        case 0x02:
          PLLMul = 14;
          break;
        
        case 0x03:
          PLLMul = 12;
          break;
        
        default:
          PLLMul = 16;
          break;          
      } 
      
      /* CK_SYS clock frequency */
      MRCC_ClocksStatus->CKSYS_Frequency = OSC4M_Value * PLLMul;     
    }
  }

/* Compute HCLK, CKTIM and PCLK clocks frequencies ---------------------------*/    
  /* Get HCLK prescaler */
  Presc = MRCC->CLKCTL & MRCC_HPRESC_Set_Mask;
  Presc = Presc >> 3;
  /* HCLK clock frequency */
  MRCC_ClocksStatus->HCLK_Frequency = MRCC_ClocksStatus->CKSYS_Frequency >> Presc;

  /* Get CK_TIM prescaler */
  Presc = MRCC->CLKCTL & MRCC_PPRESC_Set_Mask;
  /* CK_TIM clock frequency */
  MRCC_ClocksStatus->CKTIM_Frequency = MRCC_ClocksStatus->HCLK_Frequency >> Presc;
 
  /* Get PCLK prescaler */
  Presc = MRCC->CLKCTL & MRCC_PPRESC2_Mask;
  Presc = Presc >> 2;
  /* PCLK clock frequency */
  MRCC_ClocksStatus->PCLK_Frequency = MRCC_ClocksStatus->CKTIM_Frequency >> Presc;
}

/*******************************************************************************
* Function Name  : MRCC_LPMC_DBGonfig
* Description    : Enables or disables the Low Power Debug Mode.
* Input          : - MRCC_LPDM: specifies the LPDM new state value.
*                    This parameter can be one of the following values:
*                          - MRCC_LPDM_Disable
*                          - MRCC_LPDM_Enable
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_LPMC_DBGConfig(u32 MRCC_LPDM)
{
  if(MRCC_LPDM == MRCC_LPDM_Enable)
  {
    MRCC->PWRCTRL |= MRCC_LPDM_Enable;
  }
  else
  {
    MRCC->PWRCTRL &= MRCC_LPDM_Disable;
  }
}

/*******************************************************************************
* Function Name  : MRCC_EnterWFIMode
* Description    : Enters WFI mode.
*                  If the Flash is used in Burst mode, it must be kept enabled
*                  in WFI mode(use MRCC_WFIParam_FLASHOn as parameter)
* Input          : - MRCC_WFIParam: specifies the WFI mode control parameters.
*                    This parameter can be one of the following values:
*                          - MRCC_WFIParam_FLASHPowerDown(DMA not allowed during WFI)
*                          - MRCC_WFIParam_FLASHOn(DMA allowed during WFI)
*                          - MRCC_WFIParam_FLASHOff(DMA not allowed during WFI)
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_EnterWFIMode(u32 MRCC_WFIParam)
{
/* Low Power mode configuration ----------------------------------------------*/
  /* Clear LPMC[1:0] bits */
   MRCC->PWRCTRL &= MRCC_LPMC_Reset_Mask;

  /* Select WFI mode */
  MRCC->PWRCTRL |= MRCC_WFI_Mask;

/* Low Power mode control parameters configuration ---------------------------*/
  /* Clear LP_PARAM[15:13] and WFI_FLASH_EN bits */
  MRCC->PWRCTRL &= MRCC_WFIParam_Reset_Mask;
  
  if(MRCC_WFIParam != MRCC_WFIParam_FLASHPowerDown)
  {
    /* Set LP_PARAM[15:13] and WFI_FLASH_EN bits according to MRCC_WFIParam value */
    MRCC->PWRCTRL |= MRCC_WFIParam;
  }
    
/* Execute the Low Power bit writing sequence --------------------------------*/
  WriteLPBit();
}

/*******************************************************************************
* Function Name  : MRCC_EnterSTOPMode
* Description    : Enters STOP mode.
* Input          : - MRCC_STOPParam: specifies the STOP mode control parameters.
*                    This parameter can be one of the following values:
*                          - MRCC_STOPParam_Default (OSC4M On, FLASH On, MVREG On)
*                          - MRCC_STOPParam_OSC4MOff
*                          - MRCC_STOPParam_FLASHOff
*                          - MRCC_STOPParam_MVREGOff
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_EnterSTOPMode(u32 MRCC_STOPParam)
{
/* Low Power mode configuration ----------------------------------------------*/
  /* Clear LPMC[1:0] bits (STOP mode is selected) */
   MRCC->PWRCTRL &= MRCC_LPMC_Reset_Mask;

/* Low Power mode control parameters configuration ---------------------------*/
  /* Clear LP_PARAM[15:13] bits */
  MRCC->PWRCTRL &= MRCC_LPPARAM_Reset_Mask;
  
  if(MRCC_STOPParam != MRCC_STOPParam_Default)
  {
    /* Set LP_PARAM[15:13] bits according to MRCC_STOPParam value */
    MRCC->PWRCTRL |= MRCC_STOPParam;
  }

/* Execute the Low Power bit writing sequence --------------------------------*/
  WriteLPBit();
}

/*******************************************************************************
* Function Name  : MRCC_EnterSTANDBYMode
* Description    : Enters STANDBY mode.
*                  Make sure that WKPF flag is cleared before using this function.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_EnterSTANDBYMode(void)
{
/* Low Power mode configuration ----------------------------------------------*/
  /* Clear LPMC[1:0] bits */
   MRCC->PWRCTRL &= MRCC_LPMC_Reset_Mask;

  /* Select STANDBY mode */
  MRCC->PWRCTRL |= MRCC_STANDBY_Mask;

/* Execute the Low Power bit writing sequence --------------------------------*/
  WriteLPBit();
}

/*******************************************************************************
* Function Name  : MRCC_GenerateSWReset
* Description    : Generates a system software reset.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_GenerateSWReset(void)
{
/* Low Power mode configuration ----------------------------------------------*/
  /* Clear LPMC[1:0] bits */
  MRCC->PWRCTRL &= MRCC_LPMC_Reset_Mask;

  /* Select software reset */
  MRCC->PWRCTRL |= MRCC_SWRESET_Mask;

/* Execute the Low Power bit writing sequence --------------------------------*/
  WriteLPBit();
}

/*******************************************************************************
* Function Name  : MRCC_WriteBackupRegister
* Description    : Writes user data to the specified backup register.
* Input          : - MRCC_BKP: specifies the backup register.
*                    This parameter can be one of the following values:
*                          - MRCC_BKP0
*                          - MRCC_BKP1
*                  - Data: data to write.
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_WriteBackupRegister(MRCC_BKPReg MRCC_BKP, u32 Data)
{
  if(MRCC_BKP == MRCC_BKP0)
  {
    MRCC->BKP0 = Data;
  }
  else
  {
    MRCC->BKP1 = Data;
  }
}

/*******************************************************************************
* Function Name  : MRCC_ReadBackupRegister
* Description    : Reads data from the specified backup register.
* Input          : - MRCC_BKP: specifies the backup register.
*                    This parameter can be one of the following values:
*                          - MRCC_BKP0
*                          - MRCC_BKP1
* Output         : None
* Return         : The content of the specified backup register.
*******************************************************************************/
u32 MRCC_ReadBackupRegister(MRCC_BKPReg MRCC_BKP)
{
  if(MRCC_BKP == MRCC_BKP0)
  {
    return(MRCC->BKP0);
  }
  else
  {
    return(MRCC->BKP1);
  }
}

/*******************************************************************************
* Function Name  : MRCC_IOVoltageRangeConfig
* Description    : Configures the I/O pins voltage range.
* Input          : - MRCC_IOVoltageRange: specifies the I/O pins voltage range.
*                    This parameter can be one of the following values:
*                          - MRCC_IOVoltageRange_5V
*                          - MRCC_IOVoltageRange_3V3
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_IOVoltageRangeConfig(u32 MRCC_IOVoltageRange)
{
  if(MRCC_IOVoltageRange == MRCC_IOVoltageRange_3V3)
  {
    MRCC->PWRCTRL |= MRCC_IOVoltageRange_3V3;
  }
  else
  {
    MRCC->PWRCTRL &= MRCC_IOVoltageRange_5V;
  }
}

/*******************************************************************************
* Function Name  : MRCC_MCOConfig
* Description    : Selects the clock source to output on MCO pin (P0.1).
*                  To output the clock, the associated alternate function must
*                  be enabled in the I/O port controller.
* Input          : - MRCC_MCO: specifies the clock source to output.
*                    This parameter can be one of the following values:
*                          - MRCC_MCO_HCLK
*                          - MRCC_MCO_PCLK
*                          - MRCC_MCO_OSC4M
*                          - MRCC_MCO_CKPLL2
*                  - MRCC_MCOPrescaler: specifies if prescaler, divide by 1 or 2,
*                    is applied to this clock before outputting it to MCO pin.
*                    This parameter can be one of the following values:
*                          - MRCC_MCOPrescaler_1
*                          - MRCC_MCOPrescaler_2
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_MCOConfig(u32 MRCC_MCO, u32 MCO_MCOPrescaler)
{
  u32 Temp = 0;
/* MCO prescaler configuration -----------------------------------------------*/
  if(MCO_MCOPrescaler == MRCC_MCOPrescaler_2)
  {
    MRCC->CLKCTL |= MRCC_MCOPrescaler_2;
  }
  else
  {
    MRCC->CLKCTL &= MRCC_MCOPrescaler_1;
  }

/* MCO selection configuration -----------------------------------------------*/

  /* Clear MCOS[1:0] bits */
  Temp = MRCC->CLKCTL & MRCC_MCOS_Reset_Mask;

  /* Set MCOS[1:0] bits according to MRCC_MCO value */
  Temp |= MRCC_MCO;
  
  /* Store the new value */
  MRCC->CLKCTL = Temp;
}

/*******************************************************************************
* Function Name  : MRCC_OSC4MConfig
* Description    : Configures the 4MHz main oscillator (OSC4M).
*                  This function must be used when the CK_SYS is not clocked
*                  by the OSC4M and the PLL is not enabled.
* Input          : - MRCC_OSC4M: specifies the new state of the OSC4M oscillator.
*                    This parameter can be one of the following values:
*                          - MRCC_OSC4M_Default: OSC4M enabled, bypass disabled
*                          - MRCC_OSC4M_Disable: OSC4M disabled
*                          - MRCC_OSC4M_Bypass:  OSC4M bypassed
* Output         : None
* Return         : An ErrorStatus enumuration value:
*                         - SUCCESS: Clock configuration succeeded
*                         - ERROR: Clock configuration failed
*******************************************************************************/
ErrorStatus MRCC_OSC4MConfig(u32 MRCC_OSC4M)
{
  ErrorStatus Status = SUCCESS;

/* If CK_SYS is driven by OSC4M or the PLL is enabled, exit ------------------*/           
  if(((MRCC->CLKCTL & MRCC_CKSEL_CKOSCSEL_Mask) == MRCC_CKSEL_Set_Mask) ||    
     (((MRCC->CLKCTL & MRCC_CKSEL_CKOSCSEL_Mask) == MRCC_CKSEL_CKOSCSEL_Mask) &&
     ((MRCC->PWRCTRL & MRCC_CKRTCSEL_Reset_Mask) != RESET))||
     ((MRCC->CLKCTL & MRCC_PLLEN_Set_Mask) != RESET))
  {
    Status = ERROR;
  }
/* Else configure the OSC4MOFF and OSC4MBYP bits -----------------------------*/   
  else
  {  
    switch(MRCC_OSC4M)
    {
      case MRCC_OSC4M_Default:
        MRCC->CLKCTL &= MRCC_OSC4MOFF_Reset_Mask & MRCC_OSC4MBYP_Reset_Mask;
        break;
      
      case MRCC_OSC4M_Disable:
        MRCC->CLKCTL &= MRCC_OSC4MBYP_Reset_Mask;
        MRCC->CLKCTL |= MRCC_OSC4MOFF_Set_Mask;
        break;
        
      case MRCC_OSC4M_Bypass:
        MRCC->CLKCTL &= MRCC_OSC4MOFF_Reset_Mask;
        MRCC->CLKCTL |= MRCC_OSC4MBYP_Set_Mask;
        break;        
      
      default:
        Status =  ERROR;
        break;      
    }
  }  
  
  return Status; 
}

/*******************************************************************************
* Function Name  : MRCC_OSC32KConfig
* Description    : Configures the OSC32K oscillator.
*                  This function must be used when the CK_SYS is not clocked by
*                  the CK_RTC.
* Input          : - MRCC_OSC32K: specifies the new state of the OSC32K oscillator.
*                    This parameter can be one of the following values:
*                          - MRCC_OSC32K_Disable: OSC32K disabled
*                          - MRCC_OSC32K_Enable: OSC32K enabled
*                  - MRCC_OSC32KBypass: specifies if the OSC32K oscillator is
*                    bypassed or not.
*                    This parameter can be one of the following values:
*                          - MRCC_OSC32KBypass_Disable: OSC32K selected
*                          - MRCC_OSC32KBypass_Enable: OSC32K bypassed                          
* Output         : None
* Return         : An ErrorStatus enumuration value:
*                         - SUCCESS: Clock configuration succeeded
*                         - ERROR: Clock configuration failed
*******************************************************************************/
ErrorStatus MRCC_OSC32KConfig(u32 MRCC_OSC32K, u32 MRCC_OSC32KBypass)
{ 
/* If CK_SYS is driven by CK_RTC, exit ---------------------------------------*/     
  if(((MRCC->CLKCTL & MRCC_CKSEL_Set_Mask) != RESET) &&
      ((MRCC->CLKCTL & MRCC_CKOSCSEL_Set_Mask) != RESET))
  {
    return ERROR;
  }
/* Else configure the OSC32KEN and OSC32KBYP bits ----------------------------*/ 
  else
  { 
    /* Configure OSC32KEN bit */
    if(MRCC_OSC32K == MRCC_OSC32K_Enable)
    {
      MRCC->PWRCTRL |= MRCC_OSC32K_Enable;
    }
    else
    {
      MRCC->PWRCTRL &= MRCC_OSC32K_Disable;
    }
    
    /* Configure OSC32KBYP bit */
    if(MRCC_OSC32KBypass == MRCC_OSC32KBypass_Enable)
    {
      MRCC->PWRCTRL |= MRCC_OSC32KBypass_Enable;
    }
    else
    {
      MRCC->PWRCTRL &= MRCC_OSC32KBypass_Disable;
    }   
     
    return SUCCESS;   
  }
}

/*******************************************************************************
* Function Name  : MRCC_LPOSCConfig
* Description    : Enables or disables the LPOSC oscillator.
*                  This function must be used when the CK_SYS is not clocked by
*                  the CK_RTC.
* Input          : - MRCC_LPOSC: specifies the new state of the LPOSC oscillator.
*                    This parameter can be one of the following values:
*                          - MRCC_LPOSC_Disable: LPOSC disabled
*                          - MRCC_LPOSC_Enable: LPOSC enabled
* Output         : None
* Return         : An ErrorStatus enumuration value:
*                         - SUCCESS: Clock configuration succeeded
*                         - ERROR: Clock configuration failed
*******************************************************************************/
ErrorStatus MRCC_LPOSCConfig(u32 MRCC_LPOSC)
{
/* If CK_SYS is driven by CK_RTC or LPOSC is used as CK_RTC clock source, exit*/      
  if((((MRCC->CLKCTL & MRCC_CKSEL_Set_Mask) != RESET) &&
     ((MRCC->CLKCTL & MRCC_CKOSCSEL_Set_Mask) != RESET)) ||
     ((MRCC->PWRCTRL & MRCC_CKRTCSEL_Set_Mask) == MRCC_CKRTC_LPOSC)) 
  {
    return ERROR;
  }
/* Else configure the LPOSCEN bit --------------------------------------------*/  
  else
  {   
    if(MRCC_LPOSC == MRCC_LPOSC_Enable)
    {
      MRCC->PWRCTRL |= MRCC_LPOSC_Enable;
    }
    else
    {
      MRCC->PWRCTRL &= MRCC_LPOSC_Disable;
    }

    return SUCCESS;
  }     
}

/*******************************************************************************
* Function Name  : MRCC_RTCMConfig
* Description    : Enables or disables RTC clock measurement.
* Input          : - MRCC_RTCM: specifies whether CK_RTC is connected to TB 
*                    timer IC1 or not.
*                    This parameter can be one of the following values:
*                          - MRCC_RTCM_Disable: CK_RTC not connected to TB timer IC1
*                          - MRCC_RTCM_Enable: CK_RTC connected to TB timer IC1
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_RTCMConfig(u32 MRCC_RTCM)
{
  if(MRCC_RTCM == MRCC_RTCM_Enable)
  {
    MRCC->PWRCTRL |= MRCC_RTCM_Enable;
  }
  else
  {
    MRCC->PWRCTRL &= MRCC_RTCM_Disable;
  }  
}

/*******************************************************************************
* Function Name  : MRCC_SetBuilderCounter
* Description    : Sets the builder counter value which defines the delay for
*                  the 4MHz main oscillator (OSC4M) clock to be stabilized.
* Input          : - BuilderCounter: defines the delay for the OSC4M oscillator
*                    clock to be stabilized.
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_SetBuilderCounter(u8 BuilderCounter)
{ 
  *(u8 *) 0x60000026 = BuilderCounter;
}

/*******************************************************************************
* Function Name  : MRCC_GetCKSYSCounter
* Description    : Gets the result of the delay applied to CK_SYS before
*                  starting the CPU.
* Input          : None
* Output         : None
* Return         : SCOUNT value.
*******************************************************************************/
u16 MRCC_GetCKSYSCounter(void)
{
  return((u16)(MRCC->RFSR & 0x0FFF));
}

/*******************************************************************************
* Function Name  : MRCC_GetFlagStatus
* Description    : Checks whether the specified MRCC flag is set or not.
* Input          : - MRCC_FLAG: specifies the flag to check.
*                    This parameter can be one of the following values:
*                          - MRCC_FLAG_LOCK: PLL Locked flag
*                          - MRCC_FLAG_LOCKIF: PLL Lock Interrupt status flag
*                          - MRCC_FLAG_CKSEL: CK_SYS source staus flag
*                          - MRCC_FLAG_CKOSCSEL: CK_OSC clock source staus flag
*                          - MRCC_FLAG_NCKD: No Clock Detected flag
*                          - MRCC_FLAG_SWR: Software Reset flag
*                          - MRCC_FLAG_WDGR: Watchdog Reset flag
*                          - MRCC_FLAG_EXTR: External Reset flag
*                          - MRCC_FLAG_WKP: Wake-Up flag
*                          - MRCC_FLAG_STDB: STANDBY flag
*                          - MRCC_FLAG_BCOUNT:   Builder Counter Flag
*                          - MRCC_FLAG_OSC32KRDY: Oscillator 32K Ready
*                          - MRCC_FLAG_CKRTCOK: CK_RTC OK
*                          - MRCC_FLAG_LPDONE: Low Power Bit Sequence has been performed
*                          - MRCC_FLAG_LP: Low Power Mode Entry
* Output         : None
* Return         : The new state of MRCC_FLAG (SET or RESET).
*******************************************************************************/
FlagStatus MRCC_GetFlagStatus(u8 MRCC_FLAG)
{
  u32 MRCCReg = 0, FlagPos = 0;
  u32 StatusReg = 0;

  /* Get the MRCC register index */
  MRCCReg = MRCC_FLAG >> 5;

  /* Get the flag position */
  FlagPos = MRCC_FLAG & MRCC_FLAG_Mask;

  if(MRCCReg == 1) /* The flag to check is in CLKCTL register */
  {
    StatusReg = MRCC->CLKCTL;
  }
  else if (MRCCReg == 2) /* The flag to check is in RFSR register */
  {
    StatusReg = MRCC->RFSR;
  }
  else if(MRCCReg == 3) /* The flag to check is in PWRCTRL register */
  {
    StatusReg = MRCC->PWRCTRL;
  }
  
  if((StatusReg & (1 << FlagPos))!= RESET)
  {
    return SET;
  }
  else
  {
    return RESET;
  }
}

/*******************************************************************************
* Function Name  : MRCC_ClearFlag
* Description    : Clears the MRCC’s pending flags.
* Input          : - MRCC_FLAG: specifies the flag to clear.
*                    This parameter can be one of the following values:
*                          - MRCC_FLAG_NCKD: No Clock Detected flag
*                          - MRCC_FLAG_SWR: Software Reset flag
*                          - MRCC_FLAG_WDGR: Watchdog Reset flag
*                          - MRCC_FLAG_EXTR: External Reset flag
*                          - MRCC_FLAG_WKP: Wake-Up flag
*                          - MRCC_FLAG_STDB: STANDBY flag
*                          - MRCC_FLAG_LPDONE: Low Power Bit Sequence has been performed
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_ClearFlag(u8 MRCC_FLAG)
{
  u32 MRCCReg = 0, FlagPos = 0;

  /* Get the MRCC register index */
  MRCCReg = MRCC_FLAG >> 5;

  /* Get the flag position */
  FlagPos = MRCC_FLAG & MRCC_FLAG_Mask;

  if(MRCCReg == 1) /* The flag to clear is in CLKCTL register */
  {
    MRCC->CLKCTL &= ~(1 << FlagPos);
  }
  else if (MRCCReg == 2) /* The flag to clear is in RFSR register */
  {
    MRCC->RFSR &= ~(1 << FlagPos);
  }
  else if(MRCCReg == 3) /* The flag to clear is in PWRCTRL register */
  {
    MRCC->PWRCTRL &= ~(1 << FlagPos);
  }
}

/*******************************************************************************
* Function Name  : MRCC_GetITStatus
* Description    : Checks whether the specified MRCC interrupt has occurred or not.
* Input          : - MRCC_IT: specifies the MRCC interrupt source to check.
*                    This parameter can be one of the following values:
*                          - MRCC_IT_LOCK: PLL lock interrupt
*                          - MRCC_IT_NCKD: No Clock detected interrupt
* Output         : None
* Return         : The new state of MRCC_IT (SET or RESET).
*******************************************************************************/
ITStatus MRCC_GetITStatus(u32 MRCC_IT)
{
  /* Check the specified interrupt pending bit */
  if((MRCC->CLKCTL & (MRCC_IT >> 1)) != RESET)
  {
    return SET;
  }
  else
  {
    return RESET;
  }
}

/*******************************************************************************
* Function Name  : MRCC_ClearITPendingBit
* Description    : Clears the MRCC’s interrupt pending bits.
* Input          : - MRCC_IT: specifies the interrupt pending bit to clear.
*                    This parameter can be any combination of the following
*                    values:
*                          - MRCC_IT_LOCK: PLL lock interrupt
*                          - MRCC_IT_NCKD: No Clock detected interrupt
* Output         : None
* Return         : None
*******************************************************************************/
void MRCC_ClearITPendingBit(u32 MRCC_IT)
{
  /* Clear the specified interrupt pending bit */
  MRCC->CLKCTL &= ~(MRCC_IT >> 1);
}

/*******************************************************************************
* Function Name  : MRCC_WaitForOSC4MStartUp
* Description    : Waits for OSC4M start-up.
* Input          : None
* Output         : None
* Return         : An ErrorStatus enumuration value:
*                         - SUCCESS: OSC4M oscillator is stable and ready to use
*                         - ERROR: no clock is detected on OSC4M
*******************************************************************************/
ErrorStatus MRCC_WaitForOSC4MStartUp(void)
{
  u32 StartUpCounter = 0;

  do
  {
    /* Clear No Clock Detected flag */
    if(MRCC_GetFlagStatus(MRCC_FLAG_NCKD) != RESET)
    {
      MRCC_ClearFlag(MRCC_FLAG_NCKD);
    }

    StartUpCounter++;

  }while((MRCC_GetFlagStatus(MRCC_FLAG_BCOUNT) == RESET)&&
         (StartUpCounter != OSC4MStartUp_TimeOut));
  
  if(MRCC_GetFlagStatus(MRCC_FLAG_BCOUNT) != RESET)
  {
    return SUCCESS;
  }
  else
  {
    return ERROR;
  }  
}

/*******************************************************************************
* Function Name  : SetCKSYS_FREEOSC
* Description    : Selects FREEOSC as CK_SYS clock source.
* Input          : None
* Output         : None
* Return         : An ErrorStatus enumuration value:
*                         - SUCCESS: Clock configuration succeeded
*                         - ERROR: Clock configuration failed
*******************************************************************************/
static ErrorStatus SetCKSYS_FREEOSC(void)
{
  /* Check if the PLL is enabled */
  if((MRCC->CLKCTL & MRCC_PLLEN_Set_Mask) != RESET)
  {  
    if((MRCC->CLKCTL & MRCC_CKSEL_Set_Mask) == RESET)
    { /* CK_PLL1 used as Ck_SYS clock source*/

      if((MRCC->CLKCTL & MRCC_CKOSCSEL_Set_Mask) != RESET)
      {/* Check if CK_RTC source clock is present*/ 
        if((MRCC->PWRCTRL & MRCC_CKRTCSEL_Set_Mask) == RESET) 
        {
          /* CK_RTC disabled*/
          return ERROR;
        }
      }
      
      /* Select CK_OSC as CK_SYS clock source */
      MRCC->CLKCTL |= MRCC_CKSEL_Set_Mask;
    }  
    
    /* Disable PLL */
    MRCC->CLKCTL &= MRCC_PLLEN_Reset_Mask;
  }

  /* Select CK_PLL1 as CK_SYS clock source */
  MRCC->CLKCTL &= MRCC_CKSEL_Reset_Mask;

  if((MRCC->CLKCTL & MRCC_CKSEL_Set_Mask) == RESET)
  {
    return SUCCESS;
  }
  else
  {
    return ERROR;
  }
}

/*******************************************************************************
* Function Name  : SetCKSYS_OSC4M
* Description    : Selects 4MHz main oscillator (OSC4M) as CK_SYS clock source.
* Input          : PLL_State: specifies the PLL state.
* Output         : None
* Return         : An ErrorStatus enumuration value:
*                         - SUCCESS: Clock configuration succeeded
*                         - ERROR: Clock configuration failed
*******************************************************************************/
static ErrorStatus SetCKSYS_OSC4M(u32 PLL_State)
{
/* If OSC4M is not present, exit ---------------------------------------------*/      
  if(((MRCC->CLKCTL & MRCC_NCKDF_Set_Mask) != RESET) || 
     ((MRCC->CLKCTL & MRCC_OSC4MOFF_Set_Mask) != RESET) ) 
  {
    /* OSC4M disabled or OSC4M clock is not present*/
    return ERROR;
  }

/* Else configure CKSEL and CKOSCSEL bits ------------------------------------*/          
  if((MRCC->CLKCTL & MRCC_CKOSCSEL_Set_Mask) != RESET)
  { /* CK_RTC used as CK_OSC clock */   
  
    if((MRCC->CLKCTL & MRCC_CKSEL_Set_Mask) != RESET) 
    {
      /* Select CK_PLL1 as CK_SYS clock source */
      MRCC->CLKCTL &= MRCC_CKSEL_Reset_Mask;
    }
    
    /* Clear CKOSCSEL bit ----------------------------------------------------*/
    /* Execute CKOSCSEL bit writing sequence */
    WriteCKOSCSELBit();

    /* Check if CKOSCSEL is set to 0 */
    if((MRCC->CLKCTL & MRCC_CKOSCSEL_Set_Mask) != RESET)
    {
      return ERROR;
    }
  }  
 
  /* Select CK_OSC as CK_SYS clock source */
  MRCC->CLKCTL |= MRCC_CKSEL_Set_Mask;

  if((MRCC->CLKCTL & MRCC_CKSEL_Set_Mask) != RESET)
  {
    if(PLL_State == MRCC_PLL_Disabled)
    {
      /* Disable PLL */
      MRCC->CLKCTL &= MRCC_PLLEN_Reset_Mask;
    }
    
    return SUCCESS;
  }
  else
  {
    return ERROR;
  }  
}

/*******************************************************************************
* Function Name  : SetCKSYS_OSC4MPLL
* Description    : Selects 4MHz main oscillator (OSC4M) followed by PLL as
*                  CK_SYS clock source.
* Input          : PLL_Mul: specifies the PLL factor.
* Output         : None
* Return         : An ErrorStatus enumuration value:
*                         - SUCCESS: Clock configuration succeeded
*                         - ERROR: Clock configuration failed
*******************************************************************************/
static ErrorStatus SetCKSYS_OSC4MPLL(u32 PLL_Mul)
{
  /* Check if 4MHz main oscillator clock is present */
  if(((MRCC->CLKCTL & MRCC_NCKDF_Set_Mask) == RESET) && 
     ((MRCC->CLKCTL & MRCC_OSC4MOFF_Set_Mask) == RESET)) 
  {    
    if(((MRCC->CLKCTL & MRCC_PLLEN_Set_Mask) != RESET) &&
       ((MRCC->CLKCTL & MRCC_MX_Set_Mask) == PLL_Mul))
    {
      /* Select CK_PLL1 as CK_SYS clock source */
      MRCC->CLKCTL &= MRCC_CKSEL_Reset_Mask;

      if((MRCC->CLKCTL & MRCC_CKSEL_Set_Mask) == RESET)
      {
        return SUCCESS;
      }
      else
      {
        return ERROR;
      }
    }
    else
    {
      /* If CK_RTC is selected as CK_OSC clock source */
      if((MRCC->CLKCTL & MRCC_CKOSCSEL_Set_Mask) != RESET)
      {
        if((MRCC->CLKCTL & MRCC_CKSEL_Set_Mask) != RESET)
        {
          /* Clear CKSEL bit */
          MRCC->CLKCTL &= MRCC_CKSEL_Reset_Mask;
        }

        /* Clear CKOSCSEL bit ------------------------------------------------*/
        /* Execute CKOSCSEL bit writing sequence */
        WriteCKOSCSELBit();
      
        /* Check if CKOSCSEL is set to 0 */
        if((MRCC->CLKCTL & MRCC_CKOSCSEL_Set_Mask) != RESET)
        {
          return ERROR;
        }
      }

      /* Select CK_OSC as CK_SYS clock source */
      MRCC->CLKCTL |= MRCC_CKSEL_Set_Mask;

      /* Disable PLL */
      MRCC->CLKCTL &= MRCC_PLLEN_Reset_Mask;

      /* Configure PLL factor */
      if(PLL_Mul == MRCC_PLL_Mul_16)
      {
        MRCC->CLKCTL &= MRCC_MX_Reset_Mask;
      }
      else if((PLL_Mul == MRCC_PLL_Mul_15) || (PLL_Mul == MRCC_PLL_Mul_14) ||
            (PLL_Mul == MRCC_PLL_Mul_12))
      {
        /* Clear MX[1:0] bits */
        MRCC->CLKCTL &= MRCC_MX_Reset_Mask;
        /* Set MX[1:0] bits according to PLL_Mul value */
        MRCC->CLKCTL |= PLL_Mul;
      }
       
      if(Main_Oscillator == 4000000)
      {/* 4 MHz external Quartz oscillator used as main oscillator */
        /* Disable Oscillator Divider by 2 */
        MRCC->CLKCTL &= MRCC_XTDIV2_Reset_Mask;
      }
      else if(Main_Oscillator == 8000000)
      {/* 8 MHz external Quartz oscillator used as main oscillator */
        /* Enable Oscillator Divider by 2 */
        MRCC->CLKCTL |= MRCC_XTDIV2_Set_Mask;
      }

      /* Enable PLL */
      MRCC->CLKCTL |= MRCC_PLLEN_Set_Mask;
   
      /* Wait until the PLL is locked */
      while((MRCC->CLKCTL & MRCC_LOCK_Mask) == RESET)
      {
        /* If OSC4M clock disapear or the PLL is disabled, exit */
        if(((MRCC->CLKCTL & MRCC_NCKDF_Set_Mask) != RESET) ||
           ((MRCC->CLKCTL & MRCC_PLLEN_Set_Mask) == RESET))       
        {
          return ERROR;
        }
      }

      /* Select CK_PLL1 as CK_SYS clock source */
      MRCC->CLKCTL &= MRCC_CKSEL_Reset_Mask;

      if((MRCC->CLKCTL & MRCC_CKSEL_Set_Mask) == RESET)
      {
        return SUCCESS;
      }
      else
      {
        return ERROR;
      }
    }
  }
  else 
  {
    /* OSC4M disabled or OSC4M clock is not present*/
    return ERROR;
  }
}

/*******************************************************************************
* Function Name  : SetCKSYS_RTC
* Description    : Selects RTC clock (CK_RTC) as CK_SYS clock source.
* Input          : PLL_State: specifies the PLL state.
* Output         : None
* Return         : An ErrorStatus enumuration value:
*                         - SUCCESS: Clock configuration succeeded
*                         - ERROR: Clock configuration failed
*******************************************************************************/
static ErrorStatus SetCKSYS_RTC(u32 PLL_State)
{
  /* Check if CK_RTC clock is enabled and ready to use */
  if(((MRCC->PWRCTRL & MRCC_CKRTCSEL_Set_Mask) != RESET)||
     ((MRCC->CLKCTL & MRCC_CKRTCOK_Mask) == RESET))
  {
/* Configure CK_RTC as Ck_SYS clock source -----------------------------------*/
    if((MRCC->CLKCTL & MRCC_CKOSCSEL_Set_Mask) == RESET)
    { 
      /* Select CK_PLL1 as CK_SYS clock source */
      MRCC->CLKCTL &= MRCC_CKSEL_Reset_Mask;
    
      /* Set CKOSCSEL bit ----------------------------------------------------*/
      /* Execute CKOSCSEL bit writing sequence */
      WriteCKOSCSELBit();
      
      /* Check if CKOSCSEL is set to 1 */
      if((MRCC->CLKCTL & MRCC_CKOSCSEL_Set_Mask) == RESET)
      {
         return ERROR;
      }
    }
    
    /* Select CK_OSC as CK_SYS clock source */
    MRCC->CLKCTL |= MRCC_CKSEL_Set_Mask;          
    
    if((MRCC->CLKCTL & MRCC_CKSEL_Set_Mask) != RESET)
    {
      if(PLL_State == MRCC_PLL_Disabled)
      {
        /* Disable PLL */
        MRCC->CLKCTL &= MRCC_PLLEN_Reset_Mask;
      }
    
      return SUCCESS;
    }
    else
    {
      return ERROR;
    }    
  }
  else
  {      
    /* CK_RTC disabled */
    return ERROR;
  }  
}

/*******************************************************************************
* Function Name  : WriteLPBit
* Description    : Executes the Low Power bit writing sequence.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
static void WriteLPBit(void)
{
  u32 Tmp = 0, Tmp1 = 0, Tmp2 = 0;

  /* Clear LP_DONE flag */
  MRCC->PWRCTRL &= MRCC_LPDONE_Reset_Mask;

  Tmp = MRCC->PWRCTRL;
  Tmp1 = Tmp | MRCC_LP_Set_Mask;
  Tmp2 = Tmp & MRCC_LP_Reset_Mask;

  /* Set LP bit */
  MRCC->PWRCTRL = Tmp1;

  /* Set LP bit */
  MRCC->PWRCTRL = Tmp1;

  /* Reset LP bit */
  MRCC->PWRCTRL = Tmp2;

  /* Set LP bit */
  MRCC->PWRCTRL = Tmp1;

  /* Read LP bit*/
  Tmp = MRCC->PWRCTRL;  
}

/*******************************************************************************
* Function Name  : WriteCKOSCSELBit
* Description    : Executes the CKOSCSEL bit writing sequence.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
static void WriteCKOSCSELBit(void)
{
  u32 Tmp = 0, Tmp1 = 0, Tmp2 = 0;

  Tmp = MRCC->CLKCTL;
  Tmp1 = Tmp | MRCC_CKOSCSEL_Set_Mask;
  Tmp2 = Tmp & MRCC_CKOSCSEL_Reset_Mask;

  /* Set CKOSCSEL bit */
  MRCC->CLKCTL = Tmp1;

  /* Set CKOSCSEL bit */
  MRCC->CLKCTL = Tmp1;

  /* Reset CKOSCSEL bit */
  MRCC->CLKCTL = Tmp2;

  /* Set CKOSCSEL bit */
  MRCC->CLKCTL = Tmp1;
  
  /* Read CKOSCSEL bit */
  Tmp = MRCC->CLKCTL;
}
/******************* (C) COPYRIGHT 2006 STMicroelectronics *****END OF FILE****/
