/* Driver for UDA1380 */ 

#include "lpc17xx.h"
#include "UDA1380.h"
#include "lpc17xx_i2c.h"
#include "lpc17xx_pinsel.h"

/* Register definition for UDA1380 */
typedef enum
{
	UDA1380_EVALMODE_CLK =		0x00,
	UDA1380_I2S_BUS_IO =		0x01,
	UDA1380_PW_CONTROL =		0x02,
	UDA1380_ANALOG_MIX =		0x03,
	UDA1380_HEADHONE_AMP =		0x04,
	UDA1380_MASTER_VOLUME =		0x10,
	UDA1380_MIXER_VOLUME =		0x11,
	UDA1380_MODE_SELECT =		0x12,
	UDA1380_MASTER_CHAN_MUTE =	0x13,
	UDA1380_MIXER_DETECT_OVER =	0x14,
	UDA1380_DECIM_VOLUM =		0x20,
	UDA1380_PGA =				0x21,
	UDA1380_ADC =				0x22,
	UDA1380_AGC =				0x23,
	UDA1380_SOFT_RESET =		0x7F,
	UDA1380_FILTER_STATUS =		0x18,
	UDA1380_DECIM_STATUS =		0x28,
	UDA1380_END =				0xFF
} UDA1380_Registers;

#define UDA1380_ADDR			(0x30 >> 1)

/** Used I2C device as slave definition */
#define USEDI2CDEV_M		0

#if (USEDI2CDEV_M == 0)
#define I2CDEV_M LPC_I2C0
#elif (USEDI2CDEV_M == 2)
#define I2CDEV_M LPC_I2C2
#else
#error "Master I2C device not defined!"
#endif

struct uda1380_setup
{
	UDA1380_Registers reg;
	uint16_t val;
};

I2C_M_SETUP_Type transferMCfg;
uint8_t I2C_data_transfer[3];

/* Init parameters */
const struct uda1380_setup UDA1380_InitPara[]= {
	// Restore L3 default values (software reset) 
	{UDA1380_SOFT_RESET,          	0x00FF},
	// Enable all power for now
	{UDA1380_PW_CONTROL,     		0xA5DF},
	// CODEC ADC and DAC clock from WSPLL, all clocks enabled
	{UDA1380_EVALMODE_CLK,     		0x0332},
	// I2S bus data I/O formats, use digital mixer for output BCKO is slave
	{UDA1380_I2S_BUS_IO,         	0x0000},
 	// Full mixer analog input gain
	{UDA1380_ANALOG_MIX,      		0x2222},
	// Enable headphone short circuit protection
	{UDA1380_HEADHONE_AMP,     		0x0202},
	// Full master volume
	{UDA1380_MASTER_VOLUME,     	0x4040},
	// Enable full mixer volume on both channels
	{UDA1380_MIXER_VOLUME,      	0xFF00},
	// Bass and treble boost set to flat
	{UDA1380_MODE_SELECT,     		0x0000},
	// Disable mute and de-emphasis
	{UDA1380_MASTER_CHAN_MUTE,    	0x0000},
	// Mixer off, other settings off
	{UDA1380_MIXER_DETECT_OVER,     0x0000},
	// ADC decimator volume to max
	{UDA1380_DECIM_VOLUM,      		0x0000},
 	// No PGA mute, full gain
	{UDA1380_PGA,         			0x0000},
	// Select line in and MIC, max MIC gain
	{UDA1380_ADC,         			0x0F02},
	// AGC
	{UDA1380_AGC,         			0x0000},
	 
	// End of list
	{UDA1380_END,               0xFFFF}
};

/**
  * @brief  Write specified 16-bit data to specified register.
  *
  * @param  reg_addr: Specifies the register address
  * @param  data: Specifies the 16-bit data.
  * @retval None 
  */
void static UDA1380_WriteData(uint8_t reg_addr, uint16_t data)
{   
	I2C_data_transfer[0] = reg_addr;
	I2C_data_transfer[1] = (uint8_t)((data >> 8) & 0xFF);
	I2C_data_transfer[2] = (uint8_t)(data & 0xFF);
	I2C_MasterTransferData(I2CDEV_M, &transferMCfg, I2C_TRANSFER_POLLING);
}

/**
  * @brief  Initializes UDA1380.
  *
  * @param  None
  * @retval None 
  */
void  UDA1380_Init (void)
{
	PINSEL_CFG_Type PinCfg;
	const struct uda1380_setup *preset;

	/* I2C block ------------------------------------------------------------------- */
	/*
	 * Init I2C pin connect
	 */
	PinCfg.OpenDrain = 0;
	PinCfg.Pinmode = 0;
	PinCfg.Funcnum = 1;
	PinCfg.Pinnum = 27;
	PinCfg.Portnum = 0;
	PINSEL_ConfigPin(&PinCfg);
	PinCfg.Pinnum = 28;
	PINSEL_ConfigPin(&PinCfg);

	/* Initialize Master I2C peripheral */
	I2C_Init(I2CDEV_M, 400000);

	/* Enable Master I2C operation */
	I2C_Cmd(I2CDEV_M, ENABLE);

	/* Start I2C slave device first */
	transferMCfg.sl_addr7bit = UDA1380_ADDR;
	transferMCfg.tx_data = I2C_data_transfer ;
	transferMCfg.tx_length = sizeof(I2C_data_transfer);
	transferMCfg.rx_data = NULL;
	transferMCfg.rx_length = 0;
	transferMCfg.retransmissions_max = 3;

    /* Init*/
	preset = UDA1380_InitPara;

    while (preset->reg != UDA1380_END)
    {
    	UDA1380_WriteData(preset->reg, preset->val);
    	preset++;
    }
}

/**
  * @brief  Control the master volume.
  *
  * @param  left: volume in left channel
  * @param  right: volume in right channel
  * @retval None 
  */
void UDA1380_MasterVolCtrl (uint8_t left, uint8_t right)
{
	UDA1380_WriteData(UDA1380_MASTER_VOLUME, left | (right<<8));
}
