/****************************************************************************//**
 * @file     spi.c
 * @version  V2.00
 * $Revision: 1 $
 * $Date: 14/08/05 10:00a $
 * @brief    N572 SPI driver source file
 *
 * @note
 * Copyright (C) 2014 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "N572.h"

/** @addtogroup N572_Device_Driver N572 Device Driver
  @{
*/

/** @addtogroup N572_SPI_Driver SPI Driver
  @{
*/

/** @addtogroup N572_SPI_EXPORTED_FUNCTIONS SPI Exported Functions
  @{
*/

/**
  * @brief  Reset SPI module and disable SPI peripheral clock.
  * @param  spi is the base address of SPI module.
  * @return none
  */
void SPI_Close(SPI_T *spi)
{
	/* F065 and F072 function */
	
    /* Reset SPI */
    if((uint32_t)spi == SPI0_BASE) 
	{
        SYS->IPRST1 |= SYS_IPRST1_SPI0RST_Msk;
        SYS->IPRST1 &= ~SYS_IPRST1_SPI0RST_Msk;
    }
	else if((uint32_t)spi == SPI1_BASE)
	{
        SYS->IPRST1 |= SYS_IPRST1_SPI1RST_Msk;
        SYS->IPRST1 &= ~SYS_IPRST1_SPI1RST_Msk;		
	}
}

#if (__CHIP_SERIES__==__N572F065_SERIES__)
/**
  * @brief  This function make SPI module be ready to transfer.
  *         By default, the SPI transfer sequence is MSB first and
  *         the automatic slave select function is disabled. In
  *         Slave mode, the u32BusClock must be NULL and the SPI clock
  *         divider setting will be 0.
  * @param  spi is the base address of SPI module.
  * @param  u32SPIMode decides the transfer timing. Valid values are:
  *                    - \ref SPI_MODE_0
  *                    - \ref SPI_MODE_1
  *                    - \ref SPI_MODE_2
  *                    - \ref SPI_MODE_3
  * @param  u32BusClock is the expected frequency of SPI bus clock in Hz.
  * @return Actual frequency of SPI peripheral clock.
  */
uint32_t SPI_Open(SPI_T *spi, uint32_t u32SPIMode, uint32_t u32BusClock)
{
	/* F065 function */
	
	/* Set configuration trigger mode */
	spi->CTL = u32SPIMode;
	
	/* Set SPI bus clock */
	SPI_SetBusClock(spi,u32BusClock);
	
	return SPI_GetBusClock(spi);
}

/**
  * @brief  Set the SPI bus clock. Only available in Master mode.
  * @param  spi is the base address of SPI module.
  * @param  u32BusClock is the expected frequency of SPI bus clock.
  * @return Actual frequency of SPI peripheral clock.
  */
uint32_t SPI_SetBusClock(SPI_T *spi, uint32_t u32BusClock)
{
	/* F065 function */
	uint32_t u32Pclk;
	
	if( (uint32_t)spi == SPI0_BASE || (uint32_t)spi == SPI1_BASE )
	{
		u32Pclk = CLK_GetHCLKFreq();
	    spi->CLKDIV  = (spi->CLKDIV & ~SPI_CLKDIV_DIVIDER_Msk) | ((u32Pclk/u32BusClock)?(((u32Pclk/u32BusClock)-1)>>1):0);
		return (u32Pclk/(((spi->CLKDIV&0xFFFF)+1)*2));	    
	}
	return 0;
}

/**
  * @brief  Get the actual frequency of SPI bus clock. Only available in Master mode.
  * @param  spi is the base address of SPI module.
  * @return Actual SPI bus clock frequency.
  */
uint32_t SPI_GetBusClock(SPI_T *spi)
{
	/* F065 function */
    if( (uint32_t)spi == SPI0_BASE || (uint32_t)spi == SPI1_BASE )
	    return (CLK_GetHCLKFreq()/(((spi->CLKDIV&0xFFFF)+1)*2));	    
	else
	    return 0;
}
#endif

#if (__CHIP_SERIES__==__N572F072_SERIES__)
/**
  * @brief  This function make SPI module be ready to transfer.
  *         By default, the SPI transfer sequence is MSB first and
  *         the automatic slave select function is disabled. In
  *         Slave mode, the u32BusClock must be NULL and the SPI clock
  *         divider setting will be 0.
  * @param  spi is the base address of SPI module.
  * @param  u32MasterSlave decides the SPI module is operating in master mode or in slave mode. Valid values are:
  *                    - \ref SPI_SLAVE
  *                    - \ref SPI_MASTER
  * @param  u32SPIMode decides the transfer timing. Valid values are:
  *                    - \ref SPI_MODE_0
  *                    - \ref SPI_MODE_1
  *                    - \ref SPI_MODE_2
  *                    - \ref SPI_MODE_3
  * @param  u32BusClock is the expected frequency of SPI bus clock in Hz.
  * @return Actual frequency of SPI peripheral clock.
  */
uint32_t SPI_Open(SPI_T *spi, uint32_t u32MasterSlave, uint32_t u32SPIMode, uint32_t u32BusClock)
{
	/* F072 function */
	
	/* Set configuration of master/slave mode, trigger mode */
	spi->CTL = u32MasterSlave | u32SPIMode;
	
	/* Set SPI bus clock */
	SPI_SetBusClock(spi,u32BusClock);
	
	return SPI_GetBusClock(spi);
}

/**
  * @brief  Set the SPI bus clock. Only available in Master mode.
  * @param  spi is the base address of SPI module.
  * @param  u32BusClock is the expected frequency of SPI bus clock.
  * @return Actual frequency of SPI peripheral clock.
  */
uint32_t SPI_SetBusClock(SPI_T *spi, uint32_t u32BusClock)
{
	/* F072 function */
	uint32_t u32Pclk;	
	
	if( (uint32_t)spi == SPI0_BASE )
	{
		/* Get SPI source type */
		switch(CLK->CLKSEL1&CLK_CLKSEL1_SPI0SEL_Msk)
		{
			case CLK_CLKSEL1_SPI0SEL_PLL2_FOUT:
			u32Pclk = CLK_GetPLL2ClockFreq();
			break;
			
			case CLK_CLKSEL1_SPI0SEL_RC_48M:
			u32Pclk = __RC_48M;
			break;
			
			default:
			u32Pclk = CLK_GetHCLKFreq();	
			break;
		}
		spi->CLKDIV  = (spi->CLKDIV & ~SPI_CLKDIV_DIVIDER_Msk) | ((u32Pclk/u32BusClock)?((u32Pclk/u32BusClock)-1):0);
		return (u32Pclk/((spi->CLKDIV&0xFFFF)+1));
	}
	else if( (uint32_t)spi == SPI1_BASE )
	{
		u32Pclk = CLK_GetHCLKFreq();
	    spi->CLKDIV  = (spi->CLKDIV & ~SPI_CLKDIV_DIVIDER_Msk) | ((u32Pclk/u32BusClock)?(((u32Pclk/u32BusClock)-1)>>1):0);
		return (u32Pclk/(((spi->CLKDIV&0xFFFF)+1)*2));
	}
	return 0;
}

/**
  * @brief  Get the actual frequency of SPI bus clock. Only available in Master mode.
  * @param  spi is the base address of SPI module.
  * @return Actual SPI bus clock frequency.
  */
uint32_t SPI_GetBusClock(SPI_T *spi)
{
	/* F072 function */
    if( (uint32_t)spi == SPI0_BASE )
	{
		switch(CLK->CLKSEL1&CLK_CLKSEL1_SPI0SEL_Msk)
		{
			case CLK_CLKSEL1_SPI0SEL_PLL2_FOUT:
			return (CLK_GetPLL2ClockFreq()/((spi->CLKDIV&0xFFFF)+1));
			
			case CLK_CLKSEL1_SPI0SEL_RC_48M:
			return (__RC_48M/((spi->CLKDIV&0xFFFF)+1));
			
			default:
			return (CLK_GetHCLKFreq()/((spi->CLKDIV&0xFFFF)+1));
		} 
	}
	else if( (uint32_t)spi == SPI1_BASE )
		return (CLK_GetHCLKFreq()/(((spi->CLKDIV&0xFFFF)+1)*2));
	else
	    return 0;
}

/**
  * @brief  SPI receive timing tune.Only for SPI0.
  * @param  spi is the base address of SPI module.
  * @param  u8CoarseTune is the coars tune value.
  * @param  u8FineTune is the fine tune value. 
  * @return none
  * \hideinitializer
  */
void SPI_RxTimingTune(SPI_T *spi, uint8_t u8CoarseTune, uint8_t u8FineTune)
{
	uint8_t u8Lock;
	
	u8Lock = SYS_Unlock();
	spi->RCLK = (((u8CoarseTune<<SPI_RCLK_SPI0_CTIM_Pos)&SPI_RCLK_SPI0_CTIM_Msk)+((u8FineTune<<SPI_RCLK_SPI0_FTIM_Pos)&SPI_RCLK_SPI0_FTIM_Msk));
	SYS_Lock(u8Lock);
}

#endif

/*@}*/ /* end of group N572_SPI_EXPORTED_FUNCTIONS */

/*@}*/ /* end of group N572_SPI_Driver */

/*@}*/ /* end of group N572_Device_Driver */

/*** (C) COPYRIGHT 2014 Nuvoton Technology Corp. ***/
