/******************** (C) COPYRIGHT 2014 SONiX *******************************
* COMPANY:			SONiX
* DATE:					2014/02
* AUTHOR:				SA1
* IC:						SN32F100
* DESCRIPTION:	Codec related functions.
*____________________________________________________________________________
*	REVISION	Date				User		Description
*	1.0				2013/04/08	SA1			First release
*	1.1				2014/02/27	SA1			1. Update Auto Gain Control related code.
*
*____________________________________________________________________________
* 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 "..\I2S\I2S.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 __________________________________________________*/
void Codec_PowerControl(uint8_t enable, uint8_t module);
void Auto_Gain_Control(uint8_t enable);

void DAC_Init(void);
void ADC_Init(void);

void DAC_DeInit(void);
void ADC_DeInit(void);

void Delay_ms(uint16_t ms, uint32_t sys_clk);

/*****************************************************************************
* Function		: Codec_PowerControl
* Description	: Codec power control
* Input			: enable - ENABLE or DISABLE for power on or off
*				  		module - CODEC_MOD_ADC for ADC; CODEC_MOD_DAC for DAC;
                       CODEC_MOD_ALL for ADC and DAC
* Output		: None
* Return		: None
* Note			: None
*****************************************************************************/
void Codec_PowerControl(uint8_t enable, uint8_t module)
{
	if(enable)
	{
		I2S_init();	
		
		if(module & CODEC_MOD_ADC)
			ADC_Init();

		if(module & CODEC_MOD_DAC)
		{
			SN_SYS1->PRST_b.CODECDARST = 1;	
			SN_DAC->SET2_b.DAC_EN_IN = 1;  
		}

		// Note: ADC digital enable to MCLKOEN needs 21us setup time
		SN_I2S->CLK_b.MCLKOEN = 1;
		
		if(module & CODEC_MOD_ADC)
		{
			//Todo: User Enable/Disable AGC on demand
			Auto_Gain_Control(DISABLE);	
			//Auto_Gain_Control(ENABLE);
		}
		if(module & CODEC_MOD_DAC)
			DAC_Init();
			
	}	
	else
	{
		if(module & CODEC_MOD_DAC)
			DAC_DeInit();
			
		if(module & CODEC_MOD_ADC)
		{	
			Auto_Gain_Control(DISABLE);	
		}
		
		SN_I2S->CLK_b.MCLKOEN = 0;
		
		if(module & CODEC_MOD_DAC)
			SN_DAC->SET2_b.DAC_EN_IN = 0;  
		
		if(module & CODEC_MOD_ADC)
			ADC_DeInit();
	}	
}

/*****************************************************************************
* Function		: Auto_Gain_Control
* Description	: auto gain control setting, 
*               adaptively adjusting ADC input path gain
* Input			: enable - ENABLE or DISABLE for enable/disable AGC
* Output		: None
* Return		: None
* Note			: None
*****************************************************************************/
void Auto_Gain_Control(uint8_t enable)
{
	if(enable == 0)
	{	
		SN_ADC->SET14_b.AGC_OFF = 1;	
	}	
	else
	{
		// ADC output high bound and low bound
		SN_ADC->SET1_b.LB_H = 0x40;
		SN_ADC->SET2_b.LB_L = 0x00;
		SN_ADC->SET3_b.HB_H = 0x60;
		SN_ADC->SET4_b.HB_L = 0x00;
		
		// search and mute threshold 
		SN_ADC->SET7_b.SEARCH_TH_H = 0x03;
		SN_ADC->SET8_b.SEARCH_TH_L = 0x00;
		SN_ADC->SET9_b.MUTE_TH_H = 0x10;
		SN_ADC->SET10_b.MUTE_TH_L = 0x00;
		
		// PGA and boost setting for normal and mute mode
		SN_ADC->SET14_b.BOOST_SET_VAL = 0x3;
		SN_ADC->SET14_b.PGA_SET_VAL = 0x10;
		SN_ADC->SET19_b.BOOST_MUTE_VAL = 0x3;
		SN_ADC->SET19_b.PGA_MUTE_VAL = 0x10;

		// update gain and calculating period 
		SN_ADC->SET5_b.NOR_POD = 0x05;
		SN_ADC->SET6_b.MUTE_POD = 0x0B;
		SN_ADC->SET11_b.MUTE_CAL_POD = 0x9;
		
		// digital attenuation control for normal and mute mode
		SN_ADC->SET18_b.VOL_CTRL = 0x0;
		SN_ADC->SET18_b.MUTE_CTRL = 0x0;

		// updating period: 
		// bit[7:4] from mute to normal mode, bit[3:0] from normal to mute mode
		SN_ADC->SET20_b.VOL_MUTE_POD_L = 0x2;
		SN_ADC->SET20_b.VOL_MUTE_POD_H = 0x1;

		// AGC enable
		SN_ADC->SET14_b.AGC_OFF = 0;	
	}	
}
/*****************************************************************************
* Function		: ADC_Init
* Description	: Codec ADC power on sequence,
*               including analog and digital pwoer on
* Input			: None
* Output		: None
* Return		: None
* Note			: None
*****************************************************************************/

void ADC_Init(void)
{
		SN_SYS1->PRST_b.CODECADRST = 1;

		SN_ADC->SET23_b.SEL_MIC = 1;

				//Recorder gain
				SN_ADC->SET16_b.BOOST = 2;
				SN_ADC->SET16_b.PGA = 0x9;

		SN_ADC->SET15_b.IWL = ADC_DATA_BIT; 

		SN_ADC->SET23_b.SEL_MICB = 0;
		SN_ADC->SET23_b.SEL_MIX_MIC = 1;
	
		// ADC Analog Enable
		SN_ADC->SET22_b.IREF_EN = 1;
		SN_ADC->SET22_b.VREF_EN = 1;
		SN_ADC->SET21_b.MICBT_EN = 1;
		SN_ADC->SET21_b.PGA_EN = 1;
		SN_ADC->SET21_b.ADC_EN = 1;
		SN_ADC->SET22_b.CK_EN = 1;
		SN_ADC->SET22_b.MICB_EN = 1;
		
		// ADC Digital Enable
		SN_ADC->SET15_b.ACTIVE = 1;

}
/*****************************************************************************
* Function		: DAC_Init
* Description	: Codec DAC power on sequence,
*               including analog power on. 
*               (the digital power should be turn on before I2S MCLK enable) 
* Input			: None
* Output		: None
* Return		: None
* Note			: None
*****************************************************************************/
void DAC_Init(void)
{
		SN_DAC->SET2_b.MUTX = 0;
		SN_DAC->SET2_b.RMP = 0;
		SN_DAC->SET3_b.VOL = 0x0;

		// DAC Analog Enable	
		SN_DAC->SET1_b.PD_IREF = 0;
		SN_DAC->SET1_b.VMIDSEL = 1;
		SN_DAC->SET1_b.PD_VREF = 0;
		SN_DAC->SET1_b.VMIDSEL = 0;
		SN_DAC->SET1_b.PD_DAC = 0;
		SN_DAC->SET1_b.PD_CLK = 0;

		Delay_ms(20, 12000000); // avoid pop noise
		SN_DAC->SET4_b.PD_DRV = 0;

		// initial DAC RAM
		while(SN_DAC->STATUS_b.Ini_RAM_Ready == 1);
		SN_DAC->SET4_b.INI_RAM_EN = 1;
		while(SN_DAC->STATUS_b.Ini_RAM_Ready == 0);
		SN_DAC->SET4_b.INI_RAM_EN = 0;
		while(SN_DAC->STATUS_b.Ini_RAM_Ready == 1);
}

/*****************************************************************************
* Function		: ADC_DeInit
* Description	: Codec ADC power off sequence,
*               including analog and digital power off. 
* Input			: None
* Output		: None
* Return		: None
* Note			: None
*****************************************************************************/
void ADC_DeInit(void)
{
	SN_ADC->SET15_b.ACTIVE = 0;
	
	SN_ADC->SET21_b.ADC_EN = 0;  
	SN_ADC->SET21_b.PGA_EN = 0; 
	SN_ADC->SET21_b.MICBT_EN = 0;
	SN_ADC->SET22_b.MICB_EN = 0;
	SN_ADC->SET22_b.VREF_EN = 0;
	SN_ADC->SET22_b.IREF_EN = 0;
	SN_ADC->SET22_b.CK_EN = 0;
}

/*****************************************************************************
* Function		: DAC_DeInit
* Description	: Codec DAC power off sequence,
*               including analog and digital power off. 
* Input			: None
* Output		: None
* Return		: None
* Note			: None
*****************************************************************************/
void DAC_DeInit(void)
{
	SN_DAC->SET4_b.PD_DRV = 1;
	SN_DAC->SET1_b.PD_DAC = 1; 	
	SN_DAC->SET1_b.VMIDSEL = 0;
	SN_DAC->SET1_b.PD_VREF = 1;
	SN_DAC->SET1_b.PD_IREF = 1;
	SN_DAC->SET1_b.PD_CLK = 1; 
}
/*****************************************************************************
* Function		: Delay_ms
* Description	: delay ms
* Input			: ms - delay time
*				  		sys_clk - system clock for reference delay
* Output		: None
* Return		: None
* Note			: None
*****************************************************************************/
void Delay_ms(uint16_t ms, uint32_t sys_clk)
{
	uint16_t i,j;
	uint32_t clk_scale = sys_clk/12000000;
	
	for(j=0;j<ms*clk_scale; j++)
	{
		for(i=0;i<0x680;i++);
	}
}
