/*******************************************************************
Analog Devices, Inc. All Rights Reserved.

This software is proprietary and confidential.  By using this software
you agree to the terms of the associated Analog Devices License Agreement.

Hardware:		ADSP-BF526/BF537 EZ-KIT Lite

Description:	This file sets up the AD7147 so that users
				can use the CAP touch PBs and scroll wheel
*******************************************************************/

/*******************************************************************
*  include files
*******************************************************************/
#if defined(__ADSPBF537__)		/* __ADSPBF537__ */

#include <cdefBF537.h>

#define AD7147_INT						PF7
#define AD7147_INT_IMASK				SIC_IMASK
#define AD7147_INT_IMASK_BIT			0x08000000
#define AD7147_INT_IVG					ik_ivg12

#elif defined(__ADSPBF526__)	/* __ADSPBF526__ */

#include <cdefBF526.h>

#define AD7147_INT						PG11
#define AD7147_INT_IMASK				SIC_IMASK1
#define AD7147_INT_IMASK_BIT			0x00000100
#define AD7147_INT_IVG					ik_ivg12

#elif defined(__ADSPBF518__)	/* __ADSPBF518__ */

#include <cdefBF518.h>

#define AD7147_INT						PH1
#define AD7147_INT_IMASK				SIC_IMASK0
#define AD7147_INT_IMASK_BIT			0x20000000
#define AD7147_INT_IVG					ik_ivg11

#else							/* NOT DEFINED */
#error *** Processor not supported ***
#endif

#include <ccblkfn.h>
#include <sys\exception.h>
#include "AD7147.h"


#define pAD7147_INT_IMASK 			((volatile unsigned long *)AD7147_INT_IMASK)

/****************************************************************************
*   Function:    Init_AD7147_Interrupt
*   Description: Initialize AD7147 interrupts
******************************************************************************/
void Init_AD7147_Interrupt(void)
{
	/* clear pending IVG12 interrupts */
	*pILAT |= EVT_IVG12;
	ssync();

#if defined(__ADSPBF537__)		/* __ADSPBF537__ */

	/* setup INT as input */
	*pPORTFIO_POLAR = AD7147_INT;
	*pPORTFIO_INEN 	= AD7147_INT;
	*pPORTFIO_DIR 	&= (~AD7147_INT);

	*pPORTFIO_EDGE	= AD7147_INT;
    *pPORTFIO_MASKA_SET	= AD7147_INT;

#elif defined(__ADSPBF526__)	/* __ADSPBF526__ */

	/* setup INT as input */
	*pPORTGIO_POLAR = AD7147_INT;
	*pPORTGIO_INEN 	= AD7147_INT;
	*pPORTGIO_DIR 	&= (~AD7147_INT);

	*pPORTGIO_EDGE	= AD7147_INT;
    *pPORTGIO_MASKA_SET	= AD7147_INT;
    
#elif defined(__ADSPBF518__)	/* __ADSPBF518__ */

	/* setup INT as input */
	*pPORTHIO_POLAR = AD7147_INT;
	*pPORTHIO_INEN 	= AD7147_INT;
	*pPORTHIO_DIR 	&= (~AD7147_INT);

	*pPORTHIO_EDGE	= AD7147_INT;
    *pPORTHIO_MASKA_SET	= AD7147_INT;

#else							/* NOT DEFINED */
#error *** Processor not supported ***
#endif



}

/****************************************************************************
*   Function:    Assign_AD7147_IntVector
*   Description: assign ISR to interrupt vector
******************************************************************************/
void Assign_AD7147_IntVector(ex_handler_fn func)
{
	/* assign ISRs to interrupt vectors		*/
	register_handler(AD7147_INT_IVG, func);
}

/****************************************************************************
*   Function:    Config_AD7147
*   Description: Initialize AD7147 interrupts
******************************************************************************/
void Config_AD7147(void)
{
	unsigned short StageBuffer[8];

	/***********************************************************************
	********														********
	********			Configure the scroll wheel					********
	********														********
	***********************************************************************/
	/*======================
	  = Stage 0 - CIN6 (+) =
	  ====================== */
	StageBuffer[0]=0xEFFF;  /*Register 0x80*/
	StageBuffer[1]=0x1FFF;  /*Register 0x81*/
	StageBuffer[2]=0x0000;  /*Register 0x82*/
	StageBuffer[3]=0x2626;  /*Register 0x83*/
	StageBuffer[4]=2920;   	/*Register 0x84*/
	StageBuffer[5]=2920;   	/*Register 0x85*/
	StageBuffer[6]=3650;   	/*Register 0x86*/
	StageBuffer[7]=3650;   	/*Register 0x87*/
	Write_AD7147(STAGE0_CONNECTION, StageBuffer, 8);

	/*======================
	  = Stage 1 - CIN7 (+) =
	  ====================== */
	StageBuffer[0]=0xFFFF;  /*Register 0x88*/
	StageBuffer[1]=0x1FFE;  /*Register 0x89*/
	StageBuffer[2]=0x0000;  /*Register 0x8A*/
	StageBuffer[3]=0x2626;  /*Register 0x8B*/
	StageBuffer[4]=2920;    /*Register 0x8C*/
	StageBuffer[5]=2920;    /*Register 0x8D*/
	StageBuffer[6]=3650;    /*Register 0x8E*/
	StageBuffer[7]=3650;    /*Register 0x8F*/
	Write_AD7147(STAGE1_CONNECTION, StageBuffer, 8);

	/*======================
	  = Stage 2 - CIN8 (+) =
	  ====================== */
	StageBuffer[0]=0xFFFF;  /*Register 0x90*/
	StageBuffer[1]=0x1FFB;  /*Register 0x91*/
	StageBuffer[2]=0x0000;  /*Register 0x92*/
	StageBuffer[3]=0x2626;  /*Register 0x93*/
	StageBuffer[4]=2920;    /*Register 0x94*/
	StageBuffer[5]=2920;    /*Register 0x95*/
	StageBuffer[6]=3650;    /*Register 0x96*/
	StageBuffer[7]=3650;    /*Register 0x97*/
	Write_AD7147(STAGE2_CONNECTION, StageBuffer, 8);

	/*======================
	  = Stage 3 - CIN9 (+) =
	  ====================== */
	StageBuffer[0]=0xFFFF;  /*Register 0x98*/
	StageBuffer[1]=0x1FEF;  /*Register 0x99*/
	StageBuffer[2]=0x0000;  /*Register 0x9A*/
	StageBuffer[3]=0x2626;  /*Register 0x9B*/
	StageBuffer[4]=2920;    /*Register 0x9C*/
	StageBuffer[5]=2920;    /*Register 0x9D*/
	StageBuffer[6]=3650;    /*Register 0x9E*/
	StageBuffer[7]=3650;    /*Register 0x9F*/
	Write_AD7147(STAGE3_CONNECTION, StageBuffer, 8);

	/*======================
	  = Stage 4 - CIN10 (+) =
	  ====================== */
	StageBuffer[0]=0xFFFF;  /*Register 0xA0*/
	StageBuffer[1]=0x1FBF;  /*Register 0xA1*/
	StageBuffer[2]=0x0000;  /*Register 0xA2*/
	StageBuffer[3]=0x2626;  /*Register 0xA3*/
	StageBuffer[4]=2920;    /*Register 0xA4*/
	StageBuffer[5]=2920;    /*Register 0xA5*/
	StageBuffer[6]=3650;    /*Register 0xA6*/
	StageBuffer[7]=3650;    /*Register 0xA7*/
	Write_AD7147(STAGE4_CONNECTION, StageBuffer, 8);

	/*======================
	  = Stage 5 - CIN11 (+) =
	  ====================== */
	StageBuffer[0]=0xFFFF;  /*Register 0xA8*/
	StageBuffer[1]=0x1EFF;  /*Register 0xA9*/
	StageBuffer[2]=0x0000;  /*Register 0xAA*/
	StageBuffer[3]=0x2626;  /*Register 0xAB*/
	StageBuffer[4]=2920;    /*Register 0xAC*/
	StageBuffer[5]=2920;    /*Register 0xAD*/
	StageBuffer[6]=3650;    /*Register 0xAE*/
	StageBuffer[7]=3650;    /*Register 0xAF*/
	Write_AD7147(STAGE5_CONNECTION, StageBuffer, 8);

	/*======================
	  = Stage 6 - CIN4 (+) =
	  ====================== */
	StageBuffer[0]=0xFEFF;   /*Register 0xB0*/
	StageBuffer[1]=0x1FFF;   /*Register 0xB1*/
	StageBuffer[2]=0x0000;   /*Register 0xB2*/
	StageBuffer[3]=0x2626;   /*Register 0xB3*/
	StageBuffer[4]=2920;     /*Register 0xB4*/
	StageBuffer[5]=2920;     /*Register 0xB5*/
	StageBuffer[6]=3650;     /*Register 0xB6*/
	StageBuffer[7]=3650;     /*Register 0xB7*/
	Write_AD7147(STAGE6_CONNECTION, StageBuffer, 8);

	/*======================
	  = Stage 7 - CIN5 (+) =
	  ====================== */
	StageBuffer[0]=0xFBFF;  /*Register 0xB8*/
	StageBuffer[1]=0x1FFF;  /*Register 0xB9*/
	StageBuffer[2]=0x0000;  /*Register 0xBA*/
	StageBuffer[3]=0x2626;  /*Register 0xBB*/
	StageBuffer[4]=2920;    /*Register 0xBC*/
	StageBuffer[5]=2920;    /*Register 0xBD*/
	StageBuffer[6]=3650;    /*Register 0xBE*/
	StageBuffer[7]=3650;    /*Register 0xBF*/
	Write_AD7147(STAGE7_CONNECTION, StageBuffer, 8);

	/***********************************************************************
	********														********
	********				Configure the PBs						********
	********														********
	***********************************************************************/

	/*======================
	  = Stage 8 - CIN0 (+) =
	  ====================== */
	StageBuffer[0]=0xFFFE;  /*Register 0xC0*/
	StageBuffer[1]=0x1FFF;  /*Register 0xC1*/
	StageBuffer[2]=0x0000;  /*Register 0xC2*/
	StageBuffer[3]=0x2626;  /*Register 0xC3*/
	StageBuffer[4]=5664;    /*Register 0xC4*/
	StageBuffer[5]=5664;    /*Register 0xC5*/
	StageBuffer[6]=7080;    /*Register 0xC6*/
	StageBuffer[7]=7080;    /*Register 0xC7*/
	Write_AD7147(STAGE8_CONNECTION, StageBuffer, 8);

	/*======================
	  = Stage 9 - CIN1 (+) =
	  ====================== */
	StageBuffer[0]=0xFFFB;  /*Register 0xC8*/
	StageBuffer[1]=0x1FFF;  /*Register 0xC9*/
	StageBuffer[2]=0x0000;  /*Register 0xCA*/
	StageBuffer[3]=0x2626;  /*Register 0xCB*/
	StageBuffer[4]=5664;    /*Register 0xCC*/
	StageBuffer[5]=5664;    /*Register 0xCD*/
	StageBuffer[6]=7080;    /*Register 0xCE*/
	StageBuffer[7]=7080;    /*Register 0xCF*/
	Write_AD7147(STAGE9_CONNECTION, StageBuffer, 8);

	/*======================
	  = Stage 10 - CIN2 (+) =
	  ====================== */
	StageBuffer[0]=0xFFEF;  /*Register 0xD0*/
	StageBuffer[1]=0x1FFF;  /*Register 0xD1*/
	StageBuffer[2]=0x0000;  /*Register 0xD2*/
	StageBuffer[3]=0x2626;  /*Register 0xD3*/
	StageBuffer[4]=5664;    /*Register 0xD4*/
	StageBuffer[5]=5664;    /*Register 0xD5*/
	StageBuffer[6]=7080;    /*Register 0xD6*/
	StageBuffer[7]=7080;    /*Register 0xD7*/
	Write_AD7147(STAGE10_CONNECTION, StageBuffer, 8);

	/*======================
	  = Stage 11 - CIN3 (+) =
	  ====================== */
	StageBuffer[0]=0xFFBF;  /*Register 0xD8*/
	StageBuffer[1]=0x1FFF;  /*Register 0xD9*/
	StageBuffer[2]=0x0000;  /*Register 0xDA*/
	StageBuffer[3]=0x2626;  /*Register 0xDB*/
	StageBuffer[4]=5664;    /*Register 0xDC*/
	StageBuffer[5]=5664;    /*Register 0xDD*/
	StageBuffer[6]=7080;    /*Register 0xDE*/
	StageBuffer[7]=7080;    /*Register 0xDF*/
	Write_AD7147(STAGE11_CONNECTION, StageBuffer, 8);


	/* initialize the Bank 1 registers */
	AD7147Registers[PWR_CONTROL]=0x00B2;			/*Register 0x00*/
	Write_AD7147(PWR_CONTROL, &AD7147Registers[PWR_CONTROL], 1);

	/* Read High and Low Limit Status registers before enabling interrupt */
	Read_AD7147(STAGE_LOW_LIMIT_INT, &AD7147Registers[STAGE_LOW_LIMIT_INT], 3);

	/**************************************************************
	* Start off in End of Conversion interrupt mode on power up.
	**************************************************************/
	AD7147Registers[AMB_COMP_CTRL0]=0x3230;			/*Register 0x02*/
	AD7147Registers[AMB_COMP_CTRL1]=0x0819;			/*Register 0x03*/
	AD7147Registers[AMB_COMP_CTRL2]=0x0832;			/*Register 0x04*/
	AD7147Registers[STAGE_LOW_INT_EN]=0x0000;		/*Register 0x05*/
	AD7147Registers[STAGE_HIGH_INT_EN]=0x0000;		/*Register 0x06*/
	AD7147Registers[STAGE_COMPLETE_INT_EN]=0x0001;	/*Register 0x07*/
	Write_AD7147(AMB_COMP_CTRL0, &AD7147Registers[AMB_COMP_CTRL0], 6);


	AD7147Registers[STAGE_CAL_EN]=0x0FFF;  			/*Register 0x01*/
	Write_AD7147(STAGE_CAL_EN, &AD7147Registers[STAGE_CAL_EN], 1);

	/* read high and low limit status registers to clear INT */
	Read_AD7147(STAGE_LOW_LIMIT_INT, &AD7147Registers[STAGE_LOW_LIMIT_INT], 3);
}


/*******************************************************************
*   Function:    Do_Calibration
*   Description: Do the auto calibration
*******************************************************************/
void Do_Calibration(void)
{
	unsigned short usRegValue;

	Read_AD7147(AMB_COMP_CTRL0, &AD7147Registers[AMB_COMP_CTRL0], 1);
	AD7147Registers[AMB_COMP_CTRL0] |= 0x4000;
	Write_AD7147(AMB_COMP_CTRL0, &AD7147Registers[AMB_COMP_CTRL0], 1);
}

/*******************************************************************
*   Function:    ad7147_Reset_TWI
*   Description: reset the TWI interface
*******************************************************************/
void ad7147_Reset_TWI(void)
{
    /* RESET_TWI CONTROLLER */
	*pTWI_CONTROL = RESET_TWI;
	ssync();

	/* CLEAR ALL ERRONOUS CONDITIONS BEFORE ENABLING TWI */
	*pTWI_MASTER_STAT = BUFWRERR | BUFRDERR | LOSTARB | ANAK | DNAK;
	ssync();

	/* CLEAR ALL INTERRUPTS BEFORE ENABLING TWI */
	*pTWI_INT_STAT = SINIT | SCOMP | SERR | SOVF | MCOMP | MERR | XMTSERV | RCVSERV;
	ssync();

	/* FLUSH THE FIFOs - BOTH TX AND RX. */
	*pTWI_FIFO_CTL = XMTFLUSH | RCVFLUSH;
	ssync();
}

/*******************************************************************
*   Function:    Set_AD7147_Addr
*   Description: Set the address within the AD7147 that we will write/read
*******************************************************************/
void Set_AD7147_Addr(unsigned short RegAddr)
{
	/* load HI byte of the address into the FIFO */
	*pTWI_XMT_DATA8 = RegAddr >> 8;
	ssync();

	/* Start transmission */
	*pTWI_MASTER_CTL |= MEN;

	/* wait for the byte to be sent */
	while (*pTWI_FIFO_STAT == XMTSTAT)
		ssync();

	/* load LO byte of the address into the FIFO */
	*pTWI_XMT_DATA8 = RegAddr;
	ssync();

}

/*******************************************************************
*   Function:    Write_AD7147_Data_Byte
*   Description: write a byte of data to the AD7147
*******************************************************************/
void Write_AD7147_Data_Byte(unsigned char DataByte)
{
	/* wait for previous writes to finish */
	while (*pTWI_FIFO_STAT == XMTSTAT)
		ssync();

	/* load next data byte into the FIFO */
	*pTWI_XMT_DATA8 = DataByte;
	ssync();
}

/*******************************************************************
*   Function:    Write_AD7147
*   Description: do a master mode write to AD7147
*******************************************************************/
void Write_AD7147(unsigned short RegAddr, unsigned short *TWI_Data_Pointer, unsigned short DataCount)
{
	int i, j;
	unsigned short TotalCount = (DataCount * sizeof(unsigned short)) + 2;	/* Count of data and number of bytes for the Register */

    *pTWI_FIFO_CTL = 0;									/* Clear the bit manually */
	*pTWI_CONTROL = TWI_ENA | PRESCALE_VALUE;			/* PRESCALE = fsclk/10MHz */
	*pTWI_CLKDIV = ((CLKDIV_HI) << 8) | (CLKDIV_LO);	/* For 100KHz SCL speed */

	*pTWI_MASTER_ADDR = AD7147_ADDRESS;					/* Target address (7-bits plus the read/write bit the TWI controls */

	*pTWI_MASTER_CTL = (TotalCount<<6);					/* set the length of the entire transfer */

	Set_AD7147_Addr(RegAddr);								/* write the AD7147 register addr */

    /* start sending the data */
	for (j = 0; j < DataCount; j++)
	{
		Write_AD7147_Data_Byte( TWI_Data_Pointer[j] >> 8);
		Write_AD7147_Data_Byte( TWI_Data_Pointer[j] );
	}

	while ((*pTWI_INT_STAT & MCOMP) == 0)				/* Wait until transmission complete and MCOMP is set */
		ssync();

	*pTWI_INT_STAT = XMTSERV | MCOMP;					/* service TWI for next transmission */


	asm("nop;");
	asm("nop;");
	asm("nop;");

}


/*******************************************************************
*   Function:    Read_AD7147
*   Description: do a master mode read of AD7147
*******************************************************************/
void Read_AD7147(unsigned short RegAddr, unsigned short *TWI_Data_Pointer, unsigned short Count)
{
	int i, j;
	unsigned short usTempData;

	/* First select the Register we will be reading */
	Write_AD7147( RegAddr, NULL, 0 );

	/* do the read */
    *pTWI_FIFO_CTL = 0;									/* Clear the bit manually */
	*pTWI_CONTROL = TWI_ENA | PRESCALE_VALUE;			/* PRESCALE = fsclk/10MHz */
	*pTWI_CLKDIV = ((CLKDIV_HI) << 8) | (CLKDIV_LO);	/* For 100KHz SCL speed */

	*pTWI_MASTER_ADDR = AD7147_ADDRESS;					/* Target address (7-bits plus the read/write bit the TWI controls */

	*pTWI_MASTER_CTL = ((Count * sizeof(unsigned short))<<6) | MEN | MDIR;	/* Start transmission */

	/* read our data */
	for (i = 0; i < Count; i++)
	{

		while (*pTWI_FIFO_STAT == RCV_EMPTY)	/* wait for data to be in FIFO */
			ssync();

		usTempData = *pTWI_RCV_DATA8;			/* read the data */
		ssync();

		usTempData <<= 8;						/* store byte in our temp variable */

		while (*pTWI_FIFO_STAT == RCV_EMPTY)	/* wait for data to be in FIFO */
			ssync();

		usTempData |= *pTWI_RCV_DATA8;			/* read the other byte */
		ssync();

		TWI_Data_Pointer[i] = usTempData;		/* set the data in our outgoing buffer */
	}

	/* Wait until transmission complete and MCOMP is set */
	while ((*pTWI_INT_STAT & MCOMP) == 0)
			ssync();

	/* service TWI for next transmission */
	*pTWI_INT_STAT = RCVSERV | MCOMP;

	asm("nop;");
	asm("nop;");
	asm("nop;");
}

/****************************************************************************
*   Function:    Enable_INT
*   Description: unmasks INT interrupt
******************************************************************************/
void Enable_INT(void)
{
	/* enable SIC level interrupts */
    *pAD7147_INT_IMASK |= AD7147_INT_IMASK_BIT;
    ssync();
}

/****************************************************************************
*   Function:    Disable_INT
*   Description: masks INT interrupt
******************************************************************************/
void Disable_INT(void)
{
	/* disable SIC level interrupts */
    *pAD7147_INT_IMASK &= (~(AD7147_INT_IMASK_BIT));
    ssync();
}
