/**
  *********************************************************************************
  *
  * @file    hal_cmu.c
  * @brief   CMU module driver.
  *
  * @version V1.0
  * @date    22 Nov 2017
  * @author  AE Team
  * @note
  *
  * Copyright (C) Shanghai Eastsoft Microelectronics Co. Ltd. All rights reserved.
  *
  *********************************************************************************
  * @verbatim
  ==============================================================================
                        ##### How to use this driver #####
  ==============================================================================
    [..]
     *** System clock configure ***
     =================================
     [..]
       (+) If you don't change system clock, you can using cmu_clock_config_default() API.
           It will select HRC as system clock. The system clock is 24MHz.
       (+) If you want to change system clock, you can using cmu_clock_config() API.
           You can select one of the following as system clock:
             @ref CMU_CLOCK_HRC   2MHz or 24MHz
             @ref CMU_CLOCK_LRC   32768Hz
             @ref CMU_CLOCK_LOSC  32768Hz
             @ref CMU_CLOCK_PLL1  32MHz or 48MHz
             @ref CMU_CLOCK_HOSC  1MHz -- 24MHz
       (+) If you select CMU_CLOCK_PLL1 as system clock, it must config the PLL1
           using cmu_pll1_config() API. The input of clock must be 4MHz.
       (+) If you get current clock, you can using cmu_get_clock() API.

     *** BUS division control ***
     ===================================

     PLCK            sys_clk                     hclk1
     -------DIV_SYS-----------+------DIV_AHB1------------Peripheral(GPIO, CRC, ... etc.)
                              |
                              |                  pclk1
                              +------DIV_APB1------------Peripheral(TIM, UART, ... etc.)
                              |
                              |                  pclk2
                              +------DIV_APB2------------Peripheral(ADC, WWDT, ... etc.)

     [..]
       (+) Configure the division using cmu_div_config() API.
       (+) Get sys_clk using mcu_get_sys_clock() API.
       (+) Get hclk1 using mcu_get_hclk1_clock() API.
       (+) Get pclk1 using mcu_get_pclk1_clock() API.
       (+) Get pclk2 using mcu_get_pclk2_clock() API.

     *** Clock safe configure ***
     ===================================
     [..]
       (+) If you select CMU_CLOCK_HOSC as system clock, you need enable
           clock safe using cmu_hosc_safe_config() API. It will change
           CMU_CLOCK_HRC as system clock, when the outer crystal stoped.
       (+) If you select CMU_CLOCK_LOSC as system clock, you need enable
           clock safe using cmu_losc_safe_config() API. It will change
           CMU_CLOCK_LRC as system clock, when the outer crystal stoped.
       (+) If you select CMU_CLOCK_PLL1 as system clock, you need enable
           clock safe using cmu_pll_safe_config() API. It will change
           CMU_CLOCK_HRC as system clock, when the pll1 is lose.
       (+) The cmu_irq_cbk() will be invoked, when CMU interrupt has
           been occurred. You can overwrite this function in application.

     *** Clock output configure ***
     ===================================
     [..]
       (+) Output high-speed clock using cmu_output_high_clock_config() API.
       (+) Output low-speed clock using cmu_output_low_clock_config() API.

     *** Peripheral clock configure ***
     ===================================
     [..]
       (+) Configure buzz clock using cmu_buzz_config() API.
       (+) Selected lptim0 clock using cmu_lptim0_clock_select() API.
       (+) Selected lpuart clock using cmu_lpuart0_clock_select() API.
       (+) Selected lcd clock using cmu_lcd_clock_select() API.
       (+) Enable/Disable peripheral clock using cmu_perh_clock_config() API.

     *** CMU HAL driver macros list ***
     =============================================
     [..]
       Below the list of most used macros in CMU driver.

      (+) MCU_LOSC_ENABLE():     Enable outer low crystal(32768Hz).
      (+) MCU_LOSC_DISABLE():    Disable outer low crystal(32768Hz).
      (+) MCU_LRC_ENABLE():      Enable LRC(32768Hz).
      (+) MCU_LRC_DISABLE():     Disable LRC(32768Hz).
      (+) MCU_ULRC_ENABLE():     Enable ULRC(10KHz).
      (+) MCU_ULRC_DISABLE():    Disable ULRC(10KHz).
      (+) MCU_LP_LRC_ENABLE():   Enable low power LRC(32768Hz).
      (+) MCU_LP_LRC_DISABLE():  Disable low power LRC(32768Hz).
      (+) MCU_LP_LOSC_ENABLE():  Enable low power LOSC(32768Hz).
      (+) MCU_LP_LOSC_DISABLE(): Disable low power LOSC(32768Hz).
      (+) MCU_LP_HRC_ENABLE():   Enable low power HRC(2MHz or 24MHz).
      (+) MCU_LP_HRC_DISABLE():  Disable low power HRC(2MHz OR 24MHz).
      (+) MCU_LP_HOSC_ENABLE():  Enable low power HOSC(1MHz -- 24MHz).
      (+) MCU_LP_HOSC_DISABLE(): Disable low power HOSC(1MHz -- 24MHz).

     [..]
      (@) You can refer to the CMU driver header file for used the macros

  @endverbatim
  ******************************************************************************
  */

#include "hal_cmu.h"


/** @addtogroup ES32FXXX_HAL
  * @{
  */

/** @defgroup CMU CMU
  * @brief CMU module driver
  * @{
  */

/**
  * @defgroup CMU_Private_Variables CMU Private Variables
  * @{
  */
uint32_t __system_clock  = 20000000;
/**
  * @}
  */

/** @defgroup CMU_Private_Functions CMU Private Functions
  * @{
  */

/**
  * @brief  Update the current system clock. This function
  *         will be invoked, when system clock has changed.
  * @param  clock: The new clock.
  * @retval None
  */

static void cmu_clock_update(uint32_t clock)
{
	__system_clock = clock;
	__init_tick(TICK_INT_PRIORITY);

	return;
}

/**
  * @brief  CMU module interrupt handler
  * @retval None
  */
void CMU_Handler(void)
{
	/* HOSC stop */
	if (CMU->HOSMCR.STPIF == 1 && CMU->HOSMCR.STPIE == 1) {
		SYSCFG_UNLOCK();
		CMU->HOSMCR.STPIF = 1;
		SYSCFG_LOCK();

		if ((CMU->HOSMCR.CLKS == 1) && (CMU->CSR.SYS_STU == 1
				|| CMU->CSR.SYS_STU == 5))
			cmu_clock_update(CMU->CFGR.HRCFST == 1 ? 2000000 : 24000000);

	}

	/* LOSC stop */
	if (CMU->LOSMCR.STPIF == 1 && CMU->LOSMCR.STPIE == 1) {
		SYSCFG_UNLOCK();
		CMU->LOSMCR.STPIF = 1;
		SYSCFG_LOCK();
	}

	/* PLL1 lose */
	if (CMU->PULMCR.ULKIF == 1 && CMU->PULMCR.ULKIE == 1) {
		SYSCFG_UNLOCK();
		CMU->PULMCR.ULKIF = 1;
		SYSCFG_LOCK();

		if ((CMU->PULMCR.CLKS == 1) && (CMU->CSR.SYS_STU == 1
				|| CMU->CSR.SYS_STU == 4))
			cmu_clock_update(CMU->CFGR.HRCFST == 1 ? 2000000 : 24000000);

	}

	cmu_irq_cbk();
	return;
}
/**
  * @}
  */

/** @defgroup CMU_Public_Functions CMU Public Functions
  * @{
  */

/** @defgroup CMU_Public_Functions_Group1 System clock configuration
  * @brief    System clock configuration functions
  *
  * @verbatim
  ==============================================================================
              ##### System clock Configuration functions #####
  ==============================================================================
    [..]  This section provides functions allowing to:
      (+) Configure system clock using default parameters.
      (+) Configure system clock using specified parameters.
      (+) Configure PLL1 using specified parameters.
      (+) Get system clock.

    @endverbatim
  * @{
  */

/**
  * @brief  Configure system clock using default.
  *         Select CMU_CLOCK_HRC(24MHz) as system clock and
  *         enable CMU_CLOCK_LRC(32768Hz).
  * @retval The status of HAL.
  */
hal_status_t cmu_clock_config_default(void)
{
	SYSCFG_UNLOCK();

	/* Select HRC */
	CMU->CSR.SYS_CMD = CMU_CLOCK_HRC;
	while (CMU->CSR.SYS_RDYN);

	if (CMU->CSR.SYS_STU != CMU_CLOCK_HRC) {
		SYSCFG_LOCK();
		return ERROR;
	}

	CMU->CFGR.HRCFSW  = 0;	/* Select 24Mhz */
	CMU->CLKENR.HRCEN = 1;
	CMU->CLKENR.LRCEN = 1;	/* Enable LRC */

	SYSCFG_LOCK();
	return OK;
}

/**
  * @brief  Configure system clock using specified parameters
  * @param  clk: The parameter can be one of the following:
  *           @arg @ref CMU_CLOCK_HRC  2MHz or 24MHz
  *           @arg @ref CMU_CLOCK_LRC  32768Hz
  *           @arg @ref CMU_CLOCK_LOSC 32768Hz
  *           @arg @ref CMU_CLOCK_PLL1 32MHz or 48MHz
  *           @arg @ref CMU_CLOCK_HOSC 1MHz -- 24MHz
  * @param  clock: The clock which will be set. the value depends
  *         on the parameter of clk.
  * @retval The status of HAL.
  */
hal_status_t cmu_clock_config(cmu_clock_t clk, uint32_t clock)
{
	assert_param(IS_CMU_CLOCK(clk));
	SYSCFG_UNLOCK();

	switch (clk) {
	case CMU_CLOCK_HRC:
		assert_param(clock == 24000000 || clock == 2000000);

		CMU->CSR.SYS_CMD = CMU_CLOCK_HRC;
		while (CMU->CSR.SYS_RDYN);

		if (CMU->CSR.SYS_STU != CMU_CLOCK_HRC) {
			SYSCFG_LOCK();
			return ERROR;
		}

		if (clock == 24000000)
			CMU->CFGR.HRCFSW  = 0;
		else
			CMU->CFGR.HRCFSW  = 1;

		CMU->CLKENR.HRCEN = 1;
		cmu_clock_update(clock);
		break;

	case CMU_CLOCK_LRC:
		CMU->CSR.SYS_CMD = CMU_CLOCK_LRC;
		while (CMU->CSR.SYS_RDYN);

		if (CMU->CSR.SYS_STU != CMU_CLOCK_LRC) {
			SYSCFG_LOCK();
			return ERROR;
		}

		CMU->CLKENR.LRCEN = 1;
		cmu_clock_update(32768);
		break;

	case CMU_CLOCK_LOSC:
		CMU->CSR.SYS_CMD = CMU_CLOCK_LOSC;
		while (CMU->CSR.SYS_RDYN);

		if (CMU->CSR.SYS_STU != CMU_CLOCK_LOSC) {
			SYSCFG_LOCK();
			return ERROR;
		}

		CMU->CLKENR.LOSCEN = 1;
		cmu_clock_update(32768);
		break;

	case CMU_CLOCK_PLL1:
		CMU->CSR.SYS_CMD = CMU_CLOCK_PLL1;
		while (CMU->CSR.SYS_RDYN);

		if (CMU->CSR.SYS_STU != CMU_CLOCK_PLL1) {
			SYSCFG_LOCK();
			return ERROR;
		}

		CMU->CLKENR.PLL1EN = 1;
		cmu_clock_update(clock);
		break;

	case CMU_CLOCK_HOSC:
		assert_param(clock <= 24000000);

		CMU->CSR.SYS_CMD = CMU_CLOCK_HOSC;
		while (CMU->CSR.SYS_RDYN);

		if (CMU->CSR.SYS_STU != CMU_CLOCK_HOSC) {
			SYSCFG_LOCK();
			return ERROR;
		}

		CMU->CLKENR.HOSCEN = 1;
		CMU->HOSCCFG.FREQ  = clock / 1000000 - 1;
		cmu_clock_update(clock);
		break;

	default:
		break;
	}

	SYSCFG_LOCK();
	return OK;
}



/**
  * @brief  Configure PLL1 using specified parameters.
  * @param  input: The input clock type.
  * @param  output: The output clock which can be 32MHz or 48MHz.
  * @retval None
  */
void cmu_pll1_config(cmu_pll1_input_t input, cmu_pll1_output_t output)
{
	assert_param(IS_CMU_PLL1_INPUT(input));
	assert_param(IS_CMU_PLL1_OUTPUT(output));

	SYSCFG_UNLOCK();

	CMU->PLLCFG.PLL1RFS = input;
	CMU->PLLCFG.PLL1OS  = output;

	while (CMU->PLLCFG.PLL1LCKN);
	CMU->CLKENR.PLL1EN = 1;
	while (CMU->CLKSR.PLL1RDYN);

	SYSCFG_LOCK();
	return;
}

/**
  * @brief  Gets current system clock.
  * @retval The value of system clock.
  */
uint32_t cmu_get_clock(void)
{
	return __system_clock;
}
/**
  * @}
  */

/** @defgroup CMU_Public_Functions_Group2 BUS division control
  * @brief    BUS division control functions
  *
  * @verbatim
  ==============================================================================
              ##### BUS division control functions #####
  ==============================================================================
    [..]  This section provides functions allowing to:
      (+) Configure the bus division.
      (+) Get ahb1 clock.
      (+) Get sys bus clock.
      (+) Get apb1 clock.
      (+) Get apb2 clock.

    @endverbatim
  * @{
  */

/**
  * @brief  Configure the bus division.
  * @param  bus: The type of bus:
  *          @arg CMU_HCLK_1
  *          @arg CMU_SYS
  *          @arg CMU_PCLK_1
  *          @arg CMU_PCLK_2
  * @param  div: The value of divider.
  * @retval None
  */
void cmu_div_config(cmu_bus_t bus, cmu_div_t div)
{
	assert_param(IS_CMU_BUS(bus));
	assert_param(IS_CMU_DIV(div));

	SYSCFG_UNLOCK();

	switch (bus) {
	case CMU_HCLK_1:
		CMU->CFGR.HCLK1DIV = div;
		break;

	case CMU_SYS:
		CMU->CFGR.SYSDIV = div;
		break;

	case CMU_PCLK_1:
		CMU->CFGR.PCLK1DIV = div;
		break;

	case CMU_PCLK_2:
		CMU->CFGR.PCLK2DIV = div;
		break;

	default:
		break;
	}

	SYSCFG_LOCK();
	return;
}

/**
  * @brief  Get AHB1 clock.
  * @retval The value of AHB1 clock.
  */
uint32_t cmu_get_hclk1_clock(void)
{
	return (__system_clock >> CMU->CFGR.SYSDIV) >> CMU->CFGR.HCLK1DIV;
}

/**
  * @brief  Get SYS clock
  * @retval The value of SYS clock
  */
uint32_t cmu_get_sys_clock(void)
{
	return __system_clock >> CMU->CFGR.SYSDIV;
}

/**
  * @brief  Get APB1 clock.
  * @retval The value of APB1 clock.
  */
uint32_t cmu_get_pclk1_clock(void)
{
	return (__system_clock >> CMU->CFGR.SYSDIV) >> CMU->CFGR.PCLK1DIV;
}

/**
  * @brief  Get APB2 clock.
  * @retval The value of APB2 clock.
  */
uint32_t cmu_get_pclk2_clock(void)
{
	return (__system_clock >> CMU->CFGR.SYSDIV) >> CMU->CFGR.PCLK2DIV;
}
/**
  * @}
  */

/** @defgroup CMU_Public_Functions_Group3 Clock safe configure
  * @brief    Clock safe configure functions
  *
  * @verbatim
  ==============================================================================
              ##### Clock safe configure functions #####
  ==============================================================================
    [..]  This section provides functions allowing to:
      (+) Enable/Disable outer high crystal safe mode.
      (+) Enable/Disable outer low crystal safe mode.
      (+) Enable/Disable PLL1 safe mode.
      (+) Interrupt callback function.

    @endverbatim
  * @{
  */

/**
  * @brief  Enable/Disable outer high crystal safe mode.
  * @param  clock: the value of outer crystal frequency.
  * @param  status: The new status.
  * @retval None
  */
void cmu_hosc_safe_config(cmu_hosc_range_t clock, type_func_t status)
{
	assert_param(IS_CMU_HOSC_RANGE(clock));
	assert_param(IS_FUNC_STATE(status));

	SYSCFG_UNLOCK();

	if (status) {
		CMU->HOSMCR.STPIF = 1;
		CMU->HOSMCR.FRQS  = clock;
		CMU->HOSMCR.EN    = 1;
		CMU->HOSMCR.STPIE = 1;

		mcu_irq_config(CMU_IRQn, 2, 2, ENABLE);
	}
	else {
		CMU->HOSMCR.EN    = 0;
		CMU->HOSMCR.STPIE = 0;

		if (CMU->LOSMCR.EN == 0 && CMU->PULMCR.EN == 0)
			mcu_irq_config(CMU_IRQn, 2, 2, DISABLE);
	}

	SYSCFG_LOCK();
	return;
}

/**
  * @brief  Enable/Disable outer low crystal safe mode.
  * @param  status: The new status.
  * @retval None
  */
void cmu_losc_safe_config(type_func_t status)
{
	assert_param(IS_FUNC_STATE(status));
	SYSCFG_UNLOCK();

	if (status) {
		CMU->LOSMCR.STPIF = 1;
		CMU->LOSMCR.EN    = 1;
		CMU->LOSMCR.STPIE = 1;

		mcu_irq_config(CMU_IRQn, 2, 2, ENABLE);
	}
	else {
		CMU->LOSMCR.EN    = 0;
		CMU->LOSMCR.STPIE = 0;

		if (CMU->HOSMCR.EN == 0 && CMU->PULMCR.EN == 0)
			mcu_irq_config(CMU_IRQn, 2, 2, DISABLE);
	}

	SYSCFG_LOCK();
	return;
}

/**
  * @brief  Enable/Disable PLL1 safe mode.
  * @param  status: The new status.
  * @retval None
  */
void cmu_pll_safe_config(type_func_t status)
{
	assert_param(IS_FUNC_STATE(status));
	SYSCFG_UNLOCK();

	if (status) {
		CMU->PULMCR.ULKIF = 1;
		CMU->PULMCR.MODE  = 1;
		CMU->PULMCR.EN    = 1;
		CMU->PULMCR.ULKIE = 1;

		mcu_irq_config(CMU_IRQn, 2, 2, ENABLE);
	}
	else {
		CMU->PULMCR.EN    = 0;
		CMU->PULMCR.ULKIE = 0;

		if (CMU->HOSMCR.EN == 0 && CMU->LOSMCR.EN == 0)
			mcu_irq_config(CMU_IRQn, 2, 2, DISABLE);
	}

	SYSCFG_LOCK();
	return;
}

/**
  * @brief  Interrupt callback function.
  * @note   This function is declared as __weak to be overwritten in case of other
  *         implementations in user file.
  * @retval None
  */
__weak void cmu_irq_cbk(void)
{
	return;
}
/**
  * @}
  */

/** @defgroup CMU_Public_Functions_Group4 Clock output configure
  * @brief    Clock output configure functions
  *
  * @verbatim
  ==============================================================================
              ##### Clock output configure functions #####
  ==============================================================================
    [..]  This section provides functions allowing to:
      (+) Configure the high-speed clock output.
      (+) Configure the low-speed clock output.

    @endverbatim
  * @{
  */

/**
  * @brief  Configure the high-speed clock output.
  * @param  sel: Select the source:
  *           @arg CMU_OUTPUT_HIGH_SEL_HOSC
  *           @arg CMU_OUTPUT_HIGH_SEL_LOSC
  *           @arg CMU_OUTPUT_HIGH_SEL_HRC
  *           @arg CMU_OUTPUT_HIGH_SEL_LRC
  *           @arg CMU_OUTPUT_HIGH_SEL_HOSM
  *           @arg CMU_OUTPUT_HIGH_SEL_PLL1
  *           @arg CMU_OUTPUT_HIGH_SEL_PLL2
  *           @arg CMU_OUTPUT_HIGH_SEL_SYSCLK
  * @param  div: The value of divider:
  *           @arg CMU_OUTPUT_DIV_1
  *           @arg CMU_OUTPUT_DIV_2
  *           @arg CMU_OUTPUT_DIV_4
  *           @arg CMU_OUTPUT_DIV_8
  *           @arg CMU_OUTPUT_DIV_16
  *           @arg CMU_OUTPUT_DIV_32
  *           @arg CMU_OUTPUT_DIV_64
  *           @arg CMU_OUTPUT_DIV_128
  * @param  status: The new status.
  * @retval None
  */
void cmu_output_high_clock_config(cmu_output_high_sel_t sel,
		cmu_output_high_div_t div, type_func_t status)
{
	assert_param(IS_CMU_OUTPUT_HIGH_SEL(sel));
	assert_param(IS_CMU_OUTPUT_HIGH_DIV(div));
	assert_param(IS_FUNC_STATE(status));

	SYSCFG_UNLOCK();

	if (status) {
		CMU->CLKOCR.HSCOS   = sel;
		CMU->CLKOCR.HSCODIV = div;
		CMU->CLKOCR.HSCOEN  = 1;
	}
	else {
		CMU->CLKOCR.HSCOEN = 0;
	}

	SYSCFG_LOCK();
	return;
}

/**
  * @brief  Configure the low-speed clock output.
  * @param  sel: Select the source:
  *           @arg CMU_OUTPUT_LOW_SEL_LOSC
  *           @arg CMU_OUTPUT_LOW_SEL_LRC
  *           @arg CMU_OUTPUT_LOW_SEL_LOSM
  *           @arg CMU_OUTPUT_LOW_SEL_BUZZ
  *           @arg CMU_OUTPUT_LOW_SEL_ULRC
  * @param  status: The new status.
  * @retval None
  */
void cmu_output_low_clock_config(cmu_output_low_sel_t sel, type_func_t status)
{
	assert_param(IS_CMU_OUTPUT_LOW_SEL(sel));
	assert_param(IS_FUNC_STATE(status));

	SYSCFG_UNLOCK();

	if (status) {
		CMU->CLKOCR.LSCOS  = sel;
		CMU->CLKOCR.LSCOEN = 1;
	}
	else {
		CMU->CLKOCR.LSCOEN = 0;
	}

	SYSCFG_LOCK();
	return;
}
/**
  * @}
  */

/** @defgroup CMU_Public_Functions_Group5 Peripheral Clock configure
  * @brief    Peripheral clock configure functions
  *
  * @verbatim
  ==============================================================================
              ##### Peripheral clock configure functions #####
  ==============================================================================
    [..]  This section provides functions allowing to:
      (+) Configure buzz clock.
      (+) Select lptim0 clock source.
      (+) Select lpuart0 clock source.
      (+) Select lcd clock source.
      (+) Enable/Disable peripheral clock.

    @endverbatim
  * @{
  */

/**
  * @brief  Configure buzz clock.
  *         freq = sysclk / (2^(div + 1) * (dat + 1))
  * @param  div: The value of divider.
  * @param  dat: The value of coefficient.
  * @param  status: The new status.
  * @retval None
  */
void cmu_buzz_config(cmu_buzz_div_t div, uint16_t dat, type_func_t status)
{
	assert_param(IS_CMU_BUZZ_DIV(div));
	assert_param(IS_FUNC_STATE(status));

	SYSCFG_UNLOCK();

	if (status) {
		CMU->BUZZCR.DIV = div;
		CMU->BUZZCR.DAT = dat;
		CMU->BUZZCR.EN  = 1;
	}
	else {
		CMU->BUZZCR.EN = 0;
	}

	SYSCFG_LOCK();
	return;
}

/**
  * @brief  Select lptim0 clock source.
  * @param  clock: The clock source:
  *           @arg CMU_LP_PERH_CLOCK_SEL_PCLK2
  *           @arg CMU_LP_PERH_CLOCK_SEL_PLL1
  *           @arg CMU_LP_PERH_CLOCK_SEL_PLL2
  *           @arg CMU_LP_PERH_CLOCK_SEL_HRC
  *           @arg CMU_LP_PERH_CLOCK_SEL_HOSC
  *           @arg CMU_LP_PERH_CLOCK_SEL_LRC
  *           @arg CMU_LP_PERH_CLOCK_SEL_LOSC
  *           @arg CMU_LP_PERH_CLOCK_SEL_ULRC
  *           @arg CMU_LP_PERH_CLOCK_SEL_HRC_1M
  *           @arg CMU_LP_PERH_CLOCK_SEL_HOSC_1M
  *           @arg CMU_LP_PERH_CLOCK_SEL_LOSM
  *           @arg CMU_LP_PERH_CLOCK_SEL_HOSM
  * @retval None
  */
void cmu_lptim0_clock_select(cmu_lp_perh_clock_sel_t clock)
{
	assert_param(IS_CMU_LP_PERH_CLOCK_SEL(clock));

	SYSCFG_UNLOCK();
	CMU->PERICR.C_LPTIM0 = clock;
	SYSCFG_LOCK();

	return;
}

/**
  * @brief  Select lpuart0 clock source.
  * @param  clock: The clock source:
  *           @arg CMU_LP_PERH_CLOCK_SEL_PCLK2
  *           @arg CMU_LP_PERH_CLOCK_SEL_PLL1
  *           @arg CMU_LP_PERH_CLOCK_SEL_PLL2
  *           @arg CMU_LP_PERH_CLOCK_SEL_HRC
  *           @arg CMU_LP_PERH_CLOCK_SEL_HOSC
  *           @arg CMU_LP_PERH_CLOCK_SEL_LRC
  *           @arg CMU_LP_PERH_CLOCK_SEL_LOSC
  *           @arg CMU_LP_PERH_CLOCK_SEL_ULRC
  *           @arg CMU_LP_PERH_CLOCK_SEL_HRC_1M
  *           @arg CMU_LP_PERH_CLOCK_SEL_HOSC_1M
  *           @arg CMU_LP_PERH_CLOCK_SEL_LOSM
  *           @arg CMU_LP_PERH_CLOCK_SEL_HOSM
  * @retval None
  */
void cmu_lpuart0_clock_select(cmu_lp_perh_clock_sel_t clock)
{
	assert_param(IS_CMU_LP_PERH_CLOCK_SEL(clock));

	SYSCFG_UNLOCK();
	CMU->PERICR.C_LPUART0 = clock;
	SYSCFG_LOCK();

	return;
}

/**
  * @brief  Select lcd clock source.
  * @param  clock: The clock source:
  *           @arg CMU_LCD_SEL_LOSM
  *           @arg CMU_LCD_SEL_LOSC
  *           @arg CMU_LCD_SEL_LRC
  *           @arg CMU_LCD_SEL_ULRC
  *           @arg CMU_LCD_SEL_HRC_1M
  *           @arg CMU_LCD_SEL_HOSC_1M
  * @retval None
  */
void cmu_lcd_clock_select(cmu_lcd_clock_sel_t clock)
{
	assert_param(IS_CMU_LCD_CLOCK_SEL(clock));

	SYSCFG_UNLOCK();
	CMU->PERICR.C_LCD = clock;
	SYSCFG_LOCK();

	return;
}

/**
  * @brief  Enable/Disable peripheral clock.
  * @param  perh: The type of peripheral, you can see @ref cmu_perh_t
  * @param  status: The new status.
  * @retval None
    */
void cmu_perh_clock_config(cmu_perh_t perh, type_func_t status)
{
	uint32_t idx, pos;

	assert_param(IS_CMU_PERH(perh));
	assert_param(IS_FUNC_STATE(status));

	idx = (perh >> 27) & 0x3;
	pos = perh & ~(0x3 << 27);

	SYSCFG_UNLOCK();

	if (status) {
		switch (idx) {
		case 0:
			CMU->AHB1ENR.Word |= pos;
			break;

		case 1:
			CMU->APB1ENR.Word |= pos;
			break;

		case 2:
			CMU->APB2ENR.Word |= pos;
			break;

		default:
			break;
		}
	}
	else {
		switch (idx) {
		case 0:
			CMU->AHB1ENR.Word &= ~pos;
			break;

		case 1:
			CMU->APB1ENR.Word &= ~pos;
			break;

		case 2:
			CMU->APB2ENR.Word &= ~pos;
			break;

		default:
			break;
		}
	}

	SYSCFG_LOCK();
	return;
}


/**
 * @}
 */
/**
 * @}
 */

/**
 * @}
 */

/**
 * @}
 */
