/******************** (C) COPYRIGHT 2017 SONiX *******************************
* COMPANY:			SONiX
* DATE:					2017/07
* AUTHOR:				SA1
* IC:						SN32F770
* DESCRIPTION:	System Control related functions.
*____________________________________________________________________________
* REVISION	Date				User		Description
*	1.0				2017/07/14	SA1			1. First release
* 1.1				2020/12/14	SA1			1. remove prescale15 parameter of SYS0_SystemClockSwitch function
*
*____________________________________________________________________________
* THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS TIME TO MARKET.
* SONiX 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.
*****************************************************************************/

/*_____ I N C L U D E S ____________________________________________________*/
#include "SYS_con_drive.h"
#include "..\Interface\Flash\Flash.h"

/*_____ D E C L A R A T I O N S ____________________________________________*/


/*_____ D E F I N I T I O N S ______________________________________________*/


/*_____ M A C R O S ________________________________________________________*/


/*_____ F U N C T I O N S __________________________________________________*/

/*****************************************************************************
* Function		: SYS0_GetResetStatus
* Description	: Get specified reset status
* Input				: mskRst - mskSYS0_SW_RESET, mskSYS0_WDT_RESET, mskSYS0_LVD_RESET,
*												 mskSYS0_EXT_RESET, mskSYS0_POR_RESET
* Output			: None
* Return			: TRUE - Reset occurred
*								FALSE - No reset occurred
* Note				: None
*****************************************************************************/
uint32_t SYS0_GetResetStatus(uint32_t mskRst)
{
	if ((SN_SYS0->RSTST & mskRst) != 0)
		return FALSE;
	else
		return TRUE;
}

/*****************************************************************************
* Function		: SYS0_EnableIHRC
* Description	: Enable IHRC and wait for ready
* Input				: ihrcclk - SYS0_IHRC_DISABLE, SYS0_IHRC_12MHZ, 
*													SYS0_IHRC24_ENABLE, SYS0_IHRC48_ENABLE
* Output			: None
* Return			: None
* Note				: None
*****************************************************************************/
void SYS0_EnableIHRC(uint32_t ihrcclk)
{
	switch(ihrcclk){
		case SYS0_IHRC_DISABLE:	
			__SYS0_IHRC_DISABLE;
			//while (__SYS0_CHECK_IHRC_READY_STATUS == mskSYS0_IHRC_READY);
			break;
		case SYS0_IHRC_12MHZ:
			__FLASH_LPM_DISABLE;			
			__SYS0_IHRC12_ENABLE;
			while (__SYS0_CHECK_IHRC_READY_STATUS != mskSYS0_IHRC_READY);
			break;
		case SYS0_IHRC_24MHZ:
			__FLASH_LPM_FAST_MODE;
			__SYS0_IHRC24_ENABLE;
			while (__SYS0_CHECK_IHRC_READY_STATUS != mskSYS0_IHRC_READY);
			break;
		case SYS0_IHRC_48MHZ:
			__FLASH_LPM_FAST_MODE;
			__SYS0_IHRC48_ENABLE;
			while (__SYS0_CHECK_IHRC_READY_STATUS != mskSYS0_IHRC_READY);
			break;
	}
}


/***************************************************************************************
* Function		: SYS0_SystemClockSwitch
* Description	: Switch system clock to desired clock source, and set proper AHB clock 
*								prescale value.
* Input				: sysclk - SYS0_SYSCLK_IHRC
*								prescale - SYS0_AHBPRE_DIV1, SYS0_AHBPRE_DIV2, ..., SYS0_AHBPRE_DIV128
* Output			: None
* Return			: None
* Note				: User shall Enable the desired system clock source and disable
*								the unused clock by application after switching for power 
*								saving issue.
***************************************************************************************/
void SYS0_SystemClockSwitch(uint32_t sysclk, uint32_t prescale)
{
	//<-------------------- Set for ROM Power Control BEGIN -------------------->
	__FLASH_LPM_FAST_MODE
	//<-------------------- Set for ROM Power Control END   -------------------->
	
	SN_SYS0->CLKCFG = sysclk;

	switch (sysclk){
		case SYS0_SYSCLK_IHRC:
			while (__SYS0_CHECK_SYSCLK_SW_STATUS != mskSYS0_SYSCLK_SW_IHRC);
			break;
		case SYS0_CLK_ILRC:
			while (__SYS0_CHECK_SYSCLK_SW_STATUS != mskSYS0_SYSCLK_SW_ILRC);
			break;
		default:
			break;
	}
	
	SN_SYS0->AHBCP = prescale;
}

/***************************************************************************************
* Function		: SYS0_SystemCoreClockUpdate
* Description	: Switch system clock to desired clock source, and set proper AHB clock 
*								prescale value.
* Input				: hclk - HCLK (Hz)
* Output			: None
* Return			: None
* Note				: None
***************************************************************************************/
void SYS0_SystemCoreClockUpdate(uint32_t hclk)
{
	if (hclk > 24000000)
	{
		__FLASH_LPM_FAST_MODE;
	}
	else	if (hclk > 12000000)//hclk > 12000000
	{
		__FLASH_LPM_MEDIUM_MODE;
	}
	else
	{
		__FLASH_LPM_DISABLE;
	}

	return;
}

/***********************************************************************************************
* Function		: SYS1_EnableClockout
* Description	: Enable clockout and set proper Clockout	prescale value.
* Input				: src - SYS1_CLOCKOUT_DISABLE, SYS1_CLOCKOUT_ILRC, SYS1_CLOCKOUT_HCLK,
*											SYS1_CLOCKOUT_IHRC
*					  		prescale - SYS1_CLOCKOUT_DIV1, SYS1_CLOCKOUT_DIV2, ... , SYS1_CLOCKOUT_DIV128
* Output			: None
* Return			: None
* Note				: None
***********************************************************************************************/
void SYS1_EnableClockout(uint32_t src, uint32_t prescale)
{
	SN_SYS1->AHBCLKEN_b.CLKOUTSEL = src;	
	SN_SYS1->APBCP1_b.CLKOUTPRE = prescale;
}


/*******************************************************************************************************
* Function		: SYS0_LvdControl
* Description	: Set LVD interrupt, reset and voltage level
* Input				:	LvdEn - SYS0_LVD_ENABLE, SYS0_LVD_DISABLE
*								IntLvl - SYS0_LVD_RESET_2P7V, SYS0_LVD_RESET_3P0V, mskSYS0_LVD_INT_3P6V
*								RstEn - SYS0_LVD_RESET_ENABLE, SYS0_LVD_RESET_DISABLE
*								RstLvl - mskSYS0_LVD_RESET_2P7V, mskSYS0_LVD_RESET_3P0V, mskSYS0_LVD_RESET_3P6V
* Output			: None
* Return			: None
* Note				: User can modify whether LVD interrupt is enabled or not (ie., just polling) on demand.
*******************************************************************************************************/
void SYS0_LvdControl(uint32_t LvdEn, uint32_t IntLvl, uint32_t RstEn, uint32_t RstLvl)
{
	SN_SYS0->LVDCTRL_b.LVDEN = 0;									//Disable LVD
	
	if (LvdEn == SYS0_LVD_ENABLE)
	{
		if (RstEn == SYS0_LVD_RESET_ENABLE)
		{
			SN_SYS0->LVDCTRL |= (IntLvl | RstLvl);		//Set LVD Interrupt & Reset voltage level
			SN_SYS0->LVDCTRL_b.LVDRSTEN = 1;
		}
		else{
			SN_SYS0->LVDCTRL_b.LVDRSTEN = 0;
			SN_SYS0->LVDCTRL |= IntLvl;								//Set LVD Interrupt voltage level
		}

		//<-------------------- TODO: User can Enable/Disable on demand BEGIN -------------------->
		//NVIC_ClearPendingIRQ(LVD_IRQn);
		//NVIC_EnableIRQ(LVD_IRQn);
		//<-------------------- TODO: User can Enable/Disable on demand END 	-------------------->

		SN_SYS0->LVDCTRL |= mskSYS0_LVD_ENABLE;			//Enable LVD
	}
	else
		NVIC_DisableIRQ(LVD_IRQn);
}


/*****************************************************************************
* Function		: LVD_IRQHandler
* Description	: ISR of LVD interrupt
* Input			: None
* Output		: None
* Return		: None
* Note			: None
*****************************************************************************/
__irq	void LVD_IRQHandler(void)
{
	__SYS0_CLEAR_LVD_RESET;
}

