
/********************************
 *Testing A/D on a GESBC-9302
 *
 *******************************/

#include<unistd.h>
#include<sys/types.h>
#include<sys/mman.h>
#include<stdio.h>
#include<fcntl.h>
#include<assert.h>
#include<time.h>

/*Register addresses */ 
#define CHIP_SELECT_PAGE 0x80840000UL
#define SSP_PAGE         0x808A0000UL
#define SYSTEM_CTRL_PAGE 0x80930000UL

/*Offsets*/
#define SSPCR1           0x04
#define SSPCPSR          0x10
#define SSPSR            0x0C
#define SSP_DATA         0x08
#define CHIP_SELECT_DATA 0x40	/* Port H Data Register */
#define CHIP_SELECT_DDR  0x44	/* Port H Data Direction Register */
#define DEVICE_CONFIG    0x80	/* Device Config Register */

#define TRUE  0
#define FALSE !TRUE

static inline unsigned short READP16(unsigned long addr) {
        unsigned short ret;

        asm volatile (
                "ldrh %0, [ %1 ]\n"
                : "=r" (ret)
                : "r" (addr)
                : "memory"
        );
        return ret;
}

static inline void WRITEP16(unsigned long addr, unsigned short dat) {
        asm volatile (
                "strh %1, [ %0 ]\n"
                :
                : "r" (addr), "r" (dat)
                : "memory"
        );
}

static inline unsigned long READP32(unsigned long addr) {
        unsigned long ret;

        asm volatile (
                "ldr %0, [ %1 ]\n"
                : "=r" (ret)
                : "r" (addr)
                : "memory"
        );
        return ret;
}

static inline void WRITEP32(unsigned long addr, unsigned long dat) {
        asm volatile (
                "str %1, [ %0 ]\n"
                :
                : "r" (addr), "r" (dat)
                : "memory"
        );
}


static inline unsigned char READP8(unsigned long addr) {
        unsigned char ret;

        asm volatile (
                "ldrb %0, [ %1 ]\n"
                : "=r" (ret)
                : "r" (addr)
                : "memory"
        );
        return ret;
}

static inline void WRITEP8(unsigned long addr, unsigned char dat) {
        asm volatile (
                "strb %1, [ %0 ]\n"
                :
                : "r" (addr), "r" (dat)
                : "memory"
        );
}


int main(int argc, char **argv) 
{
	unsigned long deviceCFG, val[8], id, status;
	volatile unsigned char *chip_select_page, *ssp_page, *sysctrl_page;
	unsigned char portHDDR, portHDR;
	unsigned int i;
	
	int fd = open("/dev/mem", O_RDWR);
	assert(fd != -1);
	
	/* Intialize our pointers */
	chip_select_page = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, CHIP_SELECT_PAGE);
	assert(chip_select_page != MAP_FAILED);
	sysctrl_page = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, SYSTEM_CTRL_PAGE);
	assert(sysctrl_page != MAP_FAILED);

	for(i=0; i<10; i++)
	{
		//make sure Port H is configured as GPIO (Not well documented by EP9302 user gudie
		// see EP9315 user gudie page 157,804 for port H function)
		deviceCFG=READP32( (unsigned long)(sysctrl_page + DEVICE_CONFIG) ); 
		if( (deviceCFG & 0x00000800ul) > 0)
			break;
		deviceCFG|=0x00000800ul;
		outl(0xAA, sysctrl_page+0xC0ul);
		outl(deviceCFG, sysctrl_page+DEVICE_CONFIG);
		usleep(100);
	}
	assert(i<10);

	ssp_page = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, SSP_PAGE);
	assert(ssp_page != MAP_FAILED);

	/* 
	 The EP93XX Users Manual says the following algorithm must 
	 be used to configure and enable the SPI bus
	 http://www-s.ti.com/sc/ds/tmp124.pdf
	*/

	/* 1.)	Set enable bit(SSE) in register SSPCR1*/
	WRITEP32( (unsigned long)(ssp_page + SSPCR1), 0x10 );
	
	/* 2.)	Write other SSP config registers(SSPCR0 & SSPCPSR)*/
	WRITEP32( (unsigned long)ssp_page, 0x4F ); 
	WRITEP32( (unsigned long)(ssp_page + SSPCPSR), 0xFE ); 

	/* 3.)	Clear the enable bit(SSE) in register SSPCR1*/
	WRITEP32( (unsigned long)(ssp_page + SSPCR1), 0x00 ); 
	//usleep(10000); //let the lines settle
	
	/* 4.)	Set the enable bit(SSE) in register SSPCR1*/
	WRITEP32( (unsigned long)(ssp_page + SSPCR1), 0x10 ); 

	//transmit FIFO TFE
	status = READP32((unsigned long)(ssp_page + SSPSR)) & 0x01;
//	printf("TFE=0x%x\n",status);
	//receive FIFO RNE
	// Empty out the receive FIFO
	while( READP32((unsigned long)(ssp_page + SSPSR))&0x04 )
		READP8((unsigned long)(ssp_page + SSP_DATA));

	//enable the chip select, GPIO3 (Port H D1)
	portHDDR=READP8( (unsigned long)(chip_select_page + CHIP_SELECT_DDR) ); 
	WRITEP32( (unsigned long)(chip_select_page + CHIP_SELECT_DDR), 0x08 | portHDDR); 

	//Reset the A/D chip
	portHDR=READP8( (unsigned long)(chip_select_page + CHIP_SELECT_DATA) ); 
	WRITEP32( (unsigned long)(chip_select_page + CHIP_SELECT_DATA), 0xf7 & portHDR ); 
	WRITEP16( (unsigned long)(ssp_page + SSP_DATA), 0x4000 );
	usleep(100);
	//bring A/D chip select up
	portHDR=READP8( (unsigned long)(chip_select_page + CHIP_SELECT_DATA) ); 
	WRITEP32( (unsigned long)(chip_select_page + CHIP_SELECT_DATA), 0x08 | portHDR ); 
	usleep(100);
	READP8((unsigned long)(ssp_page + SSP_DATA));

	//Read A/D ID register 
	portHDR=READP8( (unsigned long)(chip_select_page + CHIP_SELECT_DATA) ); 
	WRITEP32( (unsigned long)(chip_select_page + CHIP_SELECT_DATA), 0xf7 & portHDR ); 
	WRITEP16( (unsigned long)(ssp_page + SSP_DATA), 0x5f<<8 ); /* read ID register at address 1F */
	usleep(1000);
	id=READP8((unsigned long)(ssp_page + SSP_DATA));
	//bring A/D chip select up
	portHDR=READP8( (unsigned long)(chip_select_page + CHIP_SELECT_DATA) ); 
	WRITEP32( (unsigned long)(chip_select_page + CHIP_SELECT_DATA), 0x08 | portHDR ); 
	usleep(100);
	READP8((unsigned long)(ssp_page + SSP_DATA));

	//Set 4 IO ports to output and send 0101 to 4 ports
	portHDR=READP8( (unsigned long)(chip_select_page + CHIP_SELECT_DATA) ); 
	WRITEP32( (unsigned long)(chip_select_page + CHIP_SELECT_DATA), 0xf7 & portHDR ); 
	WRITEP16( (unsigned long)(ssp_page + SSP_DATA), 0x050f );
	WRITEP16( (unsigned long)(ssp_page + SSP_DATA), 0x0605 );
	usleep(100);
	//bring A/D chip select up
	portHDR=READP8( (unsigned long)(chip_select_page + CHIP_SELECT_DATA) ); 
	WRITEP32( (unsigned long)(chip_select_page + CHIP_SELECT_DATA), 0x08 | portHDR ); 
	usleep(100);
	// Empty out the receive FIFO
	READP8((unsigned long)(ssp_page + SSP_DATA));
	READP8((unsigned long)(ssp_page + SSP_DATA));

	//Setup oscillator and reference of A/D
	portHDR=READP8( (unsigned long)(chip_select_page + CHIP_SELECT_DATA) ); 
	WRITEP32( (unsigned long)(chip_select_page + CHIP_SELECT_DATA), 0xf7 & portHDR ); 
	WRITEP16( (unsigned long)(ssp_page + SSP_DATA), 0x073f );
	usleep(100);
	//bring A/D chip select up
	portHDR=READP8( (unsigned long)(chip_select_page + CHIP_SELECT_DATA) ); 
	WRITEP32( (unsigned long)(chip_select_page + CHIP_SELECT_DATA), 0x08 | portHDR ); 
	usleep(100);
	// Empty out the receive FIFO
	READP8((unsigned long)(ssp_page + SSP_DATA));

	//Now read all A/D channels in a loop
	while(1)
	{
		for(i=0;i<8;i++)
		{
			val[i]=0;
			//lower the A/D chip select
			portHDR=READP8( (unsigned long)(chip_select_page + CHIP_SELECT_DATA) ); 
			WRITEP32( (unsigned long)(chip_select_page + CHIP_SELECT_DATA), 0xF7 & portHDR ); 
			WRITEP32( (unsigned long)(ssp_page + SSP_DATA), 0x0488+i); /* ch i */
			usleep(50);
			READP16( (unsigned long)(ssp_page + SSP_DATA) );

			WRITEP32( (unsigned long)(ssp_page + SSP_DATA), 0x40<<8); /* read A/D register 0 */
			usleep(50);
			val[i]=READP8( (unsigned long)(ssp_page + SSP_DATA) );
			if((val[i]&0x01ul)>0)
			{
				printf("invalid conversion\n");
				val[i]=0;
				continue;
			}
			val[i]=val[i]>> 4;
			WRITEP32( (unsigned long)(ssp_page + SSP_DATA), 0x41<<8); /* read A/D register 1 */
			usleep(50);
			val[i]|=READP32( (unsigned long)(ssp_page + SSP_DATA) ) << 4;
			usleep(100);

			//bring A/D chip select up
			portHDR=READP8( (unsigned long)(chip_select_page + CHIP_SELECT_DATA) ); 
			WRITEP32( (unsigned long)(chip_select_page + CHIP_SELECT_DATA), 0x08 | portHDR ); 
			usleep(1000);
		}
	        printf("ADS7870_ID=%d\n",id);
		printf("Data read from A/D. ch1 = %d, ch2 = %d, ch3 = %d, ch4 = %d\n",val[0],val[1],val[2],val[3]);
		printf("                    ch5 = %d, ch6 = %d, ch7 = %d, ch8 = %d\n",val[4],val[5],val[6],val[7]);

	}


	return 0;
	
}
