/*******************************************************************
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 is used to initialize everything necessary
				use the touchscreen
*******************************************************************/

/*******************************************************************
*  include files and processor specific defines
*******************************************************************/

#if defined(__ADSPBF537__)		/* __ADSPBF537__ */

#include <cdefBF537.h>

#define AD7879_CS						PF10
#define AD7879_PENIRQ					PF7
#define AD7879_PENIRQ_IMASK				SIC_IMASK
#define AD7879_PENIRQ_IMASK_BIT			0x08000000
#define AD7879_PENIRQ_IVG				ik_ivg12
#define AD7879_SPI_CTRL					SPI_CTL
#define AD7879_CS_PORT					PORTFIO


#elif defined(__ADSPBF526__)	/* __ADSPBF526__ */

#include <cdefBF526.h>

#define AD7879_CS						PH8
#define AD7879_PENIRQ					PG0
#define AD7879_PENIRQ_IMASK				SIC_IMASK1
#define AD7879_PENIRQ_IMASK_BIT			0x00000100
#define AD7879_PENIRQ_IVG				ik_ivg12
#define AD7879_SPI_CTRL					SPI_CTL
#define AD7879_CS_PORT					PORTHIO

#elif defined(__ADSPBF548__)	/* __ADSPBF548__ */

#include <cdefBF548.h>

#define AD7879_CS						PG6
#define AD7879_PENIRQ					PG13
#define AD7879_PENIRQ_IMASK				SIC_IMASK2
#define AD7879_PENIRQ_IMASK_BIT			0x40000000
#define AD7879_PENIRQ_IVG				ik_ivg12
#define AD7879_SPI_CTRL					SPI1_CTL
#define AD7879_CS_PORT					PORTGIO

#elif defined(__ADSPBF518__)	/* __ADSPBF518__ */

#include <cdefBF518.h>

#define AD7879_CS						PG0
#define AD7879_PENIRQ					PH0
#define AD7879_PENIRQ_IMASK				SIC_IMASK0
#define AD7879_PENIRQ_IMASK_BIT			0x20000000
#define AD7879_PENIRQ_IVG				ik_ivg11
#define AD7879_SPI_CTRL					SPI1_CTL
#define AD7879_CS_PORT					PORTGIO

#else							/* NOT DEFINED */
#error *** Processor not supported ***
#endif

#include <ccblkfn.h>
#include <sys\exception.h>
#include "AD7879.h"


#define pAD7879_PENIRQ_IMASK 			((volatile unsigned long *)AD7879_PENIRQ_IMASK)

#define pAD7879_SPI_CTRL 				((volatile unsigned short *)AD7879_SPI_CTRL)
#define pAD7879_SPI_FLG 				((volatile unsigned short *)(AD7879_SPI_CTRL + 0x4))
#define pAD7879_SPI_STAT 				((volatile unsigned short *)(AD7879_SPI_CTRL + 0x8))
#define pAD7879_SPI_TDBR 				((volatile unsigned short *)(AD7879_SPI_CTRL + 0xC))
#define pAD7879_SPI_RDBR 				((volatile unsigned short *)(AD7879_SPI_CTRL + 0x10))
#define pAD7879_SPI_BAUD 				((volatile unsigned short *)(AD7879_SPI_CTRL + 0x14))

#define pAD7879_CS_PORT 				((volatile unsigned short *)AD7879_CS_PORT)
#define pAD7879_CS_PORT_CLEAR 			((volatile unsigned short *)(AD7879_CS_PORT + 0x4))
#define pAD7879_CS_PORT_SET 			((volatile unsigned short *)(AD7879_CS_PORT + 0x8))
#define pAD7879_CS_PORT_TOGGLE 			((volatile unsigned short *)(AD7879_CS_PORT + 0xC))
#define pAD7879_CS_PORT_MASKA 			((volatile unsigned short *)(AD7879_CS_PORT + 0x10))
#define pAD7879_CS_PORT_MASKA_CLEAR 	((volatile unsigned short *)(AD7879_CS_PORT + 0x14))
#define pAD7879_CS_PORT_MASKA_SET 		((volatile unsigned short *)(AD7879_CS_PORT + 0x18))
#define pAD7879_CS_PORT_MASKA_TOGGLE 	((volatile unsigned short *)(AD7879_CS_PORT + 0x1C))
#define pAD7879_CS_PORT_MASKB 			((volatile unsigned short *)(AD7879_CS_PORT + 0x20))
#define pAD7879_CS_PORT_MASKB_CLEAR 	((volatile unsigned short *)(AD7879_CS_PORT + 0x24))
#define pAD7879_CS_PORT_MASKB_SET 		((volatile unsigned short *)(AD7879_CS_PORT + 0x28))
#define pAD7879_CS_PORT_MASKB_TOGGLE 	((volatile unsigned short *)(AD7879_CS_PORT + 0x2C))
#define pAD7879_CS_PORT_DIR 			((volatile unsigned short *)(AD7879_CS_PORT + 0x30))
#define pAD7879_CS_PORT_POLAR 			((volatile unsigned short *)(AD7879_CS_PORT + 0x34))
#define pAD7879_CS_PORT_EDGE 			((volatile unsigned short *)(AD7879_CS_PORT + 0x38))
#define pAD7879_CS_PORT_BOTH 			((volatile unsigned short *)(AD7879_CS_PORT + 0x3C))
#define pAD7879_CS_PORT_INEN 			((volatile unsigned short *)(AD7879_CS_PORT + 0x40))

/*******************************************************************
*  global variables and defines
*******************************************************************/
#define COMMON_SPI_SETTINGS (SPE|MSTR|SIZE)	/* SPI enable, Master, 8 bit */

#define TIMOD01 (0x01)		/* sets the SPI to work with core instructions */

#define SPI_DELAY 2000
#define BAUD_DIV	10

/*******************************************************************
*  function prototypes
*******************************************************************/
static void SetupSPI(int spi_setting);
static void SPI_OFF(void);
static void Wait_For_SPIF(void);
static void Clear_CS(void);
static void Set_CS(void);

/****************************************************************************
*   Function:    Init_AD7879_Interrupt
*   Description: Initialize AD7879 interrupts
******************************************************************************/
void Init_AD7879_Interrupt(void)
{
	/* clear pending IVG interrupts */
	*pILAT |= EVT_IVG12;
	ssync();

#if defined(__ADSPBF537__)		/* __ADSPBF537__ */

	/* setup PENIRQ as input */
	*pPORTFIO_INEN 	= AD7879_PENIRQ;
    *pPORTFIO_DIR 	&= (~AD7879_PENIRQ);

    *pPORTFIO_EDGE	= AD7879_PENIRQ;
    *pPORTFIO_MASKA_SET	= AD7879_PENIRQ;

#elif defined(__ADSPBF526__)	/* __ADSPBF526__ */

	/* setup PENIRQ as input */
	*pPORTGIO_POLAR = AD7879_PENIRQ;
	*pPORTGIO_INEN 	= AD7879_PENIRQ;
    *pPORTGIO_DIR 	&= (~AD7879_PENIRQ);

    *pPORTGIO_EDGE	= AD7879_PENIRQ;
    *pPORTGIO_MASKA_SET	= AD7879_PENIRQ;

#elif defined(__ADSPBF518__)	/* __ADSPBF518__ */

	/* setup PENIRQ as input */
	*pPORTHIO_POLAR = AD7879_PENIRQ;
	*pPORTHIO_INEN 	= AD7879_PENIRQ;
    *pPORTHIO_DIR 	&= (~AD7879_PENIRQ);

    *pPORTHIO_EDGE	= AD7879_PENIRQ;
    *pPORTHIO_MASKA_SET	= AD7879_PENIRQ;

#elif defined(__ADSPBF548__)	/* __ADSPBF548__ */

	/* setup PENIRQ as input */
	*pPORTG_INEN = AD7879_PENIRQ;
	*pPORTG_DIR_CLEAR = AD7879_PENIRQ;

	*pPINT2_ASSIGN = 0x400;

	*pPINT2_INVERT_SET = AD7879_PENIRQ;
	*pPINT2_EDGE_SET = AD7879_PENIRQ;
	*pPINT2_LATCH = AD7879_PENIRQ;

	// unmask interrupts
    *pPINT2_MASK_SET = AD7879_PENIRQ;

#else							/* NOT DEFINED */
#error *** Processor not supported ***
#endif

}

/****************************************************************************
*   Function:    Assign_AD7879_IntVector
*   Description: assign ISR to interrupt vector
******************************************************************************/
void Assign_AD7879_IntVector(ex_handler_fn func)
{
	/* assign ISRs to interrupt vectors		*/
	register_handler(AD7879_PENIRQ_IVG, func);
}

/****************************************************************************
*   Function:    Setup_SPI
*   Description: setup spi for communication with the maxim 1233
******************************************************************************/
void Setup_SPI(int spi_setting)
{
  	int i;

#if defined(__ADSPBF537__)		/* __ADSPBF537__ */
	/* configure SPI SCK, MISO, and MOSI */
	*pPORTF_FER   |= 0x3800;
#elif defined(__ADSPBF526__)	/* __ADSPBF526__ */
	/* configure SPI SCK, MISO, and MOSI */
  	*pPORTG_FER   |= 0x1C;
	*pPORTG_MUX   &= 0xFFFC;
#elif defined(__ADSPBF548__)	/* __ADSPBF548__ */
	/* configure SPI SCK, MISO, and MOSI */
  	*pPORTG_FER   = PG8 | PG9 | PG10;
	*pPORTG_MUX   &= (~0x3F0000);
#elif defined(__ADSPBF518__)	/* __ADSPBF518__ */
	/* configure SPI SCK, MISO, and MOSI */
  	*pPORTH_FER   |= 0xE;
	*pPORTH_MUX   = 0x0001;
#else							/* NOT DEFINED */
#error *** Processor not supported ***
#endif


   	for(i=0; i<100; i++)
	{
		asm("nop;");
	}

    *pAD7879_SPI_BAUD = BAUD_DIV;		/* set SPI BAUD */
   	*pAD7879_SPI_CTRL = spi_setting;	/* configure SPI CTL */
}

/****************************************************************************
*   Function:    SPI_OFF
*   Description: disable the SPI
******************************************************************************/
void SPI_OFF(void)
{
	int i;

	*pAD7879_SPI_CTRL = 0x0000;	/* disable SPI */
	*pAD7879_SPI_FLG = 0;

	for( i=0 ; i < SPI_DELAY; i++ )
	{
		asm("nop;");
	}
}

/****************************************************************************
*   Function:    Wait_For_SPIF
*   Description: Polls the SPIF (SPI single word transfer complete) bit
* 				 of SPISTAT until the transfer is complete.
******************************************************************************/
void Wait_For_SPIF()
{
	int n;
	unsigned char dummyread;

	for( n=0; n < SPI_DELAY; n++ )
	{
		asm("nop;");
	}

	while(1)
	{
		unsigned short iTest = *pAD7879_SPI_STAT;
		if( (iTest & SPIF) )
		{
			break;
		}
	}

	dummyread = *pAD7879_SPI_RDBR;	/*read dummy to empty the receive register */
	asm("nop;");
}

/****************************************************************************
*   Function:    Read_AD7879
*   Description: Read from the AD7879
******************************************************************************/
void Read_AD7879(u8 RegAddress, u16 *pu16Data)
{
	u16 dummywrite = 0, dummyread = 0;
	u16 CommandWord = 0xE400 | RegAddress;

	/* configure SPI registers */
	Setup_SPI( (COMMON_SPI_SETTINGS|TIMOD01) );

	/* pull CS low */
	Clear_CS();

	/* write the command word indicating we are reading */
	*pAD7879_SPI_TDBR = CommandWord;
	Wait_For_SPIF();

	/* dummyread to clear RX FIFO */
	dummyread  = *pAD7879_SPI_RDBR;

	/* dummywrite to shift our data out */
	*pAD7879_SPI_TDBR = dummywrite;
	Wait_For_SPIF();

	/* read our data */
	*pu16Data  = *pAD7879_SPI_RDBR;	// read data

	/* CS back high */
	Set_CS();

	/* Turns the SPI off */
	SPI_OFF();
}

/****************************************************************************
*   Function:    Write_AD7879
*   Description: Write to the AD7879
******************************************************************************/
void Write_AD7879(u8 RegAddress, u16 u16Data)
{
	u16 dummywrite = 0, dummyread = 0;
	u16 CommandWord = 0xE000 | RegAddress;

	Setup_SPI( (COMMON_SPI_SETTINGS|TIMOD01) );

	/* pull CS low */
	Clear_CS();

	/* write the command word indicating we are writing */
	*pAD7879_SPI_TDBR = CommandWord;
	Wait_For_SPIF();

	/* dummyread to clear RX FIFO */
	dummyread  = *pAD7879_SPI_RDBR;

	/* put the data in the FIFO */
	*pAD7879_SPI_TDBR = u16Data;		// write data
	Wait_For_SPIF();

	/* dummyread to clear RX FIFO */
	dummyread = *pAD7879_SPI_RDBR;

	/* CS back high */
	Set_CS();

	/* Turns the SPI off */
	SPI_OFF();
}

/****************************************************************************
*   Function:    Enable_PENIRQ
*   Description: unmasks PENIRQ interrupt
******************************************************************************/
void Enable_PENIRQ(void)
{
	/* enable SIC level interrupts */
    *pAD7879_PENIRQ_IMASK |= AD7879_PENIRQ_IMASK_BIT;
    ssync();
}

/****************************************************************************
*   Function:    Disable_PENIRQ
*   Description: masks PENIRQ interrupt
******************************************************************************/
void Disable_PENIRQ(void)
{
	/* disable SIC level interrupts */
    *pAD7879_PENIRQ_IMASK &= (~(AD7879_PENIRQ_IMASK_BIT));
    ssync();
}

/****************************************************************************
*   Function:    Clear_PENIRQ
*   Description: clears the PENIRQ interrupt bit
******************************************************************************/
void Clear_PENIRQ(void)
{
#if defined(__ADSPBF537__)		/* __ADSPBF537__ */
	 *pPORTFIO_CLEAR = AD7879_PENIRQ;
#elif defined(__ADSPBF526__)	/* __ADSPBF526__ */
	 *pPORTGIO_CLEAR = AD7879_PENIRQ;
#elif defined(__ADSPBF548__)	/* __ADSPBF548__ */
	 *pPORTG_CLEAR = AD7879_PENIRQ;
#elif defined(__ADSPBF518__)	/* __ADSPBF518__ */
	 *pPORTHIO_CLEAR = AD7879_PENIRQ;
#else							/* NOT DEFINED */
	#error *** Processor not supported ***
#endif
}

/****************************************************************************
*   Function:    Clear_CS
*   Description: clears the chip select
******************************************************************************/
void Clear_CS()
{

#if defined(__ADSPBF548__)	/* __ADSPBF518__ */
	/* pull CS low */
	*pPORTGIO_DIR |= AD7879_CS;
 	*pPORTGIO_CLEAR = AD7879_CS;
#else
	/* pull CS low */
	*pAD7879_CS_PORT_DIR |= AD7879_CS;
 	*pAD7879_CS_PORT_CLEAR = AD7879_CS;
#endif

}

/****************************************************************************
*   Function:    Set_CS
*   Description: sets the chip select
******************************************************************************/
void Set_CS()
{

#if defined(__ADSPBF548__)	/* __ADSPBF548__ */
	/* CS high */
 	*pPORTG_SET = AD7879_CS;
#else
	/* CS high */
 	*pAD7879_CS_PORT_SET = AD7879_CS;
#endif

}
