#include <windows.h>
#include <Winbase.h>
#include <s2440.h>
#include <nkintr.h>
#include <oalintr.h>
#include <p2.h>

#include "HW_OV9650.h"

#include "camif.h"

#define U8	unsigned char
#define U16	unsigned short
#define U32	unsigned int

#define CAM_OV7620	(0) // OMNI Vision camera, 640x480 VGA
#define CAM_S5X433	(1) // Samsung S5X433 VGA camera
#define CAM_S5X532	(2) // Samsung S5X532 VGA camera
#define CAM_AU70H	(3) // 1152x864 MegaPixel Camera, max 19.3Mhz
#define CAM_S5X3A1	(4) // Mega pixel


volatile CLKPWRreg *s2440CLKPW = (CLKPWRreg *)CLKPWR_BASE;

//#define SlaveID	0x42  //OV7620 Slave ID 
#define SlaveID	0x30  //S5X532 Slave ID 

#define WRDATA      (1)
#define RDDATA      (3)
#define SETRDADDR   (4)
#define CAMIICBUFSIZE 0x20
#define IICBUFSIZE 	0x20

// Change GP8(I2CSDA) as input/output mode.
#define	SET_SDA_INPUT	(s2440IOP->rGPECON &= ~(3<<30))
#define	SET_SDA_OUTPUT	(s2440IOP->rGPECON = (s2440IOP->rGPECON & ~(2<<30)) |(1<<30) )

static U8 _iicData[IICBUFSIZE];
static volatile int _iicDataCount;
static volatile int _iicStatus;
static volatile int _iicMode;
static int _iicPt;

/*
const unsigned char Ov7620_YCbCr8bit_TV[][2] = {
// OMNI Vision	
	{0x12, 0x80},		// Camera Soft reset. Self cleared after reset.
	{0x00, 0x00},
	{0x01, 0x80},		// set blue gain
	{0x02, 0x80},		// set red gain
	{0x03, 0xb0},
	{0x06, 0x60},		// set brightness
	{0x0c, 0x24},		// set blue background
	{0x0d, 0x24},		// set red background
	{0x10, 0xff},		// set exposure time, brightness control
	{0x11, 0x80},		// set frame rate CLK_input = PCLK
	{0x12, 0x74},		// set 8 Bit YUV mode, enable AGC/AWB, mirror image enabled.
	{0x13, 0x21}, 		 // 8bit Data, CCIR601 Format
	{0x15, 0x01},		// Use PCLK falling edge to latch data, 8 Bit UYVY....
	{0x16, 0x03},		//
	{0x17, 0x2f},		//
	{0x18, 0xcf},	       // (207-47)*4 = 640
	{0x19, 0x06},		//
	{0x1a, 0xf5},	       // ((244-5)+1)*2=480
	{0x1b, 0x00},
	{0x20, 0x00},
	{0x21, 0x80},
	{0x22, 0x80},
	{0x23, 0x00},
	{0x26, 0xa2},
	{0x27, 0xea},
	{0x29, 0x00},
	{0x2a, 0x00},
	{0x2b, 0x00},
	{0x2c, 0x88},
	{0x2e, 0x80},
	{0x2f, 0x44},
	{0x60, 0x27},
	{0x61, 0x82},
	{0x62, 0x5f},
	{0x63, 0xd5},
	{0x64, 0x57},
	{0x65, 0x83},
	{0x66, 0x55},
	{0x68, 0xcf},
	{0x69, 0x76},
	{0x6a, 0x22},
	{0x6b, 0x00},
	{0x6c, 0x08},
	{0x6d, 0x48},	
	{0x6e, 0x80},
	{0x6f, 0x0c},
	{0x70, 0x89},
	{0x71, 0x00},
	{0x72, 0x14},
	{0x73, 0x54},	
	{0x75, 0x0e},
	{0x76, 0x00},
	{0x77, 0xff},
	{0x78, 0x80},
	{0x79, 0x80},
	{0x7a, 0x80},
	{0x7b, 0xe6},
	{0x7c, 0x00},	
	{0x13, 0x21},
	{0x14, 0x94},	
	{0x24, 0x10},
	{0x25, 0x8a},
	{0x28, 0x20},	// Progressive mode.
	{0x2d, 0x95},	//
	{0x67, 0x92},	// 
	{0x74, 0x00},	// -CJH

	{0x12, 0x74}		// set 8 Bit YUV mode, enable AGC/AWB, mirror image enabled.
};
*/

const unsigned char S5X532_YCbCr8bit_TV[][2] = 
{
#if 0
	// page 5
	{0xec,0x05},
	{0x08,0x55},
	{0x0a,0x75},
	{0x0c,0x90},
	{0x0e,0x18},
	{0x12,0x09},
	{0x14,0x9d},
	{0x16,0x90},
	{0x1a,0x18},
	{0x1c,0x0c},
	{0x1e,0x09},
	{0x20,0x06},
	{0x22,0x20},
	{0x2a,0x00},
	{0x2d,0x04},
	{0x12,0x24},
	// page 3
	{0xec,0x03},
	{0x0c,0x09},
	{0x6c,0x09},
	{0x2b,0x10}, // momo clock inversion
	// page 2
	{0xec,0x02},
	{0x03,0x09},
	{0x05,0x08},
	{0x06,0x01},
	{0x07,0xf8},
	{0x15,0x25},
	{0x30,0x29},
	{0x36,0x12},
	{0x38,0x04},
	{0x1b,0x77}, // 24MHz : 0x77, 12MHz : 0x22
	{0x1c,0x77}, // 24MHz : 0x77, 12MHz : 0x22
	// page 1
	{0xec,0x01},
	{0x00,0x03}, // 
	{0x0a,0x08}, // 0x0-QQVGA, 0x06-CIF, 0x02-QCIF, 0x08-VGA, 0x04-QVGA, 0x0a-SXGA
	{0x0c,0x00}, // Pattern selectio. 0-CIS, 1-Color bar, 2-Ramp, 3-Blue screen
	//{0x10,0x27}, // 0x21-ITU-R656(CbYCrY), 0x25-ITU-R601(CbYCrY), 0x26-ITU-R601(YCrYCb)
	{0x10,0x21}, // 0x21-ITU-R656(CbYCrY), 0x25-ITU-R601(CbYCrY), 0x26-ITU-R601(YCrYCb)
	{0x50,0x21},		// Hblank
	{0x51,0x00},		// Hblank
	{0x52,0xA1},		// Hblank
	{0x53,0x02},		// Hblank
	{0x54,0x01},		// Vblank
	{0x55,0x00},		// Vblank
	{0x56,0xE1},		// Vblank 		
	{0x57,0x01},		// Vblank
	{0x58,0x21},		// Hsync
	{0x59,0x00},		// Hsync
	{0x5a,0xA1},		// Hsync
	{0x5b,0x02},		// Hsync
	{0x5c,0x03},		// Vref
	{0x5d,0x00},		// Vref
	{0x5e,0x05},		// Vref
	{0x5f,0x00},		// Vref	
	{0x70,0x0E},
	{0x71,0xD6},
	{0x72,0x30},
	{0x73,0xDB},
	{0x74,0x0E},
	{0x75,0xD6},
	{0x76,0x18},
	{0x77,0xF5},
	{0x78,0x0E},
	{0x79,0xD6},
	{0x7a,0x28},
	{0x7b,0xE6},
	{0x50,0x00},
	{0x5c,0x00},

	// page 0
	{0xec,0x00},
	{0x79,0x01},
	{0x58,0x90},
	{0x59,0xA0},
	{0x5a,0x50},
	{0x5b,0x70},
	{0x5c,0xD0},
	{0x5d,0xC0},
	{0x5e,0x28},
	{0x5f,0x08},
	{0x50,0x90},
	{0x51,0xA0},
	{0x52,0x50},
	{0x53,0x70},
	{0x54,0xD0},
	{0x55,0xC0},
	{0x56,0x28},
	{0x57,0x00},
	{0x48,0x90},
	{0x49,0xA0},
	{0x4a,0x50},
	{0x4b,0x70},
	{0x4c,0xD0},
	{0x4d,0xC0},
	{0x4e,0x28},
	{0x4f,0x08},
	{0x72,0x82}, // main clock = 24MHz:0xd2, 16M:0x82, 12M:0x54
	{0x75,0x05} // absolute vertical mirror.  junon
#endif 

#if 1
	{0xec,0x00},
	{0x02,0x00},
	{0x14,0x60},
	{0x15,0x60},
	{0x16,0x60},
	{0x1b,0x20},
	{0x1c,0x20},
	{0x1d,0x20},
	{0x1e,0x20},
	{0x72,0xdc},
	{0x73,0x11},
	{0x76,0x82},
	{0x77,0x90},
	{0x78,0x6c},
	{0x0a,0x02},
	{0x34,0x0d},
	{0x35,0x0a},
	{0x36,0x05},
	{0x37,0x05},
	{0x38,0x06},
	{0x39,0x08},
	{0x3A,0x0d},
	{0x3B,0x0d},
	{0x3C,0x18},
	{0x3D,0xE0},
	{0x3E,0x20},
	{0x66,0x02},
	{0x6c,0x40},
	{0x7c,0x01},
	{0x0D,0x24},
	{0x40,0x1B},
	{0x41,0x4F},
	{0x42,0x24},
	{0x43,0x3E},
	{0x44,0x32},
	{0x45,0x30},
	{0x48,0xa0},
	{0x49,0xd0},
	{0x4A,0x28},
	{0x4B,0x7d},
	{0x4C,0xd0},
	{0x4D,0xe0},
	{0x4E,0x1a},
	{0x4F,0xa0},
	{0x50,0xc0},
	{0x51,0xc0},
	{0x52,0x42},
	{0x53,0x7e},
	{0x54,0xc0},
	{0x55,0xf0},
	{0x56,0x1e},
	{0x57,0xe0},
	{0x58,0xc0},
	{0x59,0xa0},
	{0x5A,0x4a},
	{0x5B,0x7e},
	{0x5C,0xc0},
	{0x5D,0xf0},
	{0x5E,0x2a},
	{0x5F,0x10},
	{0x79,0x00},          
	{0x7a,0x00},
	{0xe0,0x0f},
	{0xe3,0x14}, 
	{0xe5,0x48},
	{0xe7,0x58},

	//=============== page1 ===============//
	{0xec,0x01},
	{0x10,0x05},
	{0x20,0xde},
	{0x0b,0x06},
	{0x30,0x00},
	{0x31,0x00},
	{0x32,0x00},
	{0x24,0x28},
	{0x25,0x3F},
	{0x26,0x65},
	{0x27,0xA1},
	{0x28,0xFF},
	{0x29,0x96},
	{0x2A,0x85},
	{0x2B,0xFF},
	{0x2C,0x00},
	{0x2D,0x1B},
	{0xB0,0x28},
	{0xB1,0x3F},
	{0xB2,0x65},
	{0xB3,0xA1},
	{0xB4,0xFF},
	{0xB5,0x96},
	{0xB6,0x85},
	{0xB7,0xFF},
	{0xB8,0x00},
	{0xB9,0x1B},
	{0x15,0x15},
	{0x18,0x85},
	{0x1f,0x05},
	{0x87,0x40},
	{0x37,0x60},
	{0x38,0xd5},
	{0x48,0xa0},
	{0x61,0x54},
	{0x62,0x54},
	{0x63,0x14},
	{0x64,0x14},
	{0x6d,0x12},
	{0x78,0x09},
	{0x79,0xD7},
	{0x7A,0x14},
	{0x7B,0xEE},
	                 
	//=============== page2 ===============//
	{0xec,0x02},
	{0x2c,0x76},
	{0x25,0x25},
	{0x27,0x27},
	{0x30,0x29},
	{0x36,0x08},
	{0x38,0x04},

	//=============== page3 ===============//
	{0xec,0x03},
	{0x08,0x00},
	{0x09,0x33},

	//=============== page4 ===============//
	{0xec,0x04},
	{0x00,0x21},
	{0x01,0x00},            
	{0x02,0x9d},            
	{0x03,0x02},            
	{0x04,0x04},         
	{0x05,0x00},            
	{0x06,0x1f},          
	{0x07,0x02},            
	{0x08,0x21},            
	{0x09,0x00},            
	{0x0a,0x9d},           
	{0x0b,0x02},            
	{0x0c,0x04},             
	{0x0d,0x00},            
	{0x0e,0x20},            
	{0x0f,0x02},            
	{0x1b,0x3c},            
	{0x1c,0x3c},            

	//=============== page5 ===============//
	{0xec,0x05},                               
	{0x1f,0x00},                               
	{0x08,0x59},            
	{0x0a,0x71},            
	{0x1e,0x23},            
	{0x0e,0x3c},            

	//=============== page7 ===============//
	{0xec,0x07},
	{0x11,0xfe},

	// added by junon
	{0xec,0x01}, 
	{0x10,0x26}, // 0x21-ITU-R656(CbYCrY), 0x25-ITU-R601(CbYCrY), 0x26-ITU-R601(YCrYCb)
#endif
};


extern void Camera_Initialize(void);

extern volatile IOPreg *s2440IOP;
extern volatile IICreg *s2440IIC;

void Camera_Initialize(void);
void Delay(int time);
void SetCAMClockDivider(int divn);

void CAM_WriteBlock(void);
void Wr_CamIIC(U32 slvAddr, U32 addr, U8 data);
void Rd_CamIIC(U32 slvAddr, U32 addr, U8 *data);
void Run_IicPoll(void);
void IicPoll(void);


#define	udelay(x)		Delay(x/50)
#define	mdelay(x)		Delay((x)*8)

extern void msWait(unsigned msVal);


extern void ReadCameraProductID(void);

void ReadCameraProductID(void);

static HANDLE IIC_InterruptEvent = NULL;


#define rGPEDAT  (*(volatile unsigned *)0xB1600044)
#define rGPECON1  (*(volatile unsigned *)0xB1600040)
#define  rGPEUP1   (*(volatile unsigned *)0xB1600048)

#define WAIT_STAB udelay(100)   //msWait(1)
#define WAIT_CYL  udelay(100)

/************************************************/
//some macros and inline function to support porting
//from linux driver, hzh
//#define	CLKCON					rCLKCON
#define	CLKCON_CAMIF		(1<<19)
//#define	UPLLCON					rUPLLCON
//#define	CLKDIVN					rCLKDIVN
#define	DIVN_UPLL_EN			(1<<3)
//#define	CAMDIVN					rCAMDIVN
#define	CAMCLK_SET_DIV			(1<<4)
//#define	CAM_CTRL				rCIGCTRL	//??

#define	GPIO_E14				14
#define	GPIO_E15				15
#define	GPIO_PULLUP_EN			(0<<30)
#define	GPIO_PULLUP_DIS			(1<<30)
#define	GPIO_MODE_IN			(0<<31)
#define	GPIO_MODE_OUT			(1UL<<31)

#define	read_gpio_bit(x)		((rGPEDAT & (1<<(x))) ? 1 : 0)
#define	write_gpio_bit_set(x)	(rGPEDAT |= 1<<(x))
#define	write_gpio_bit_clear(x)	(rGPEDAT &= ~(1<<(x)))


#define SET_SIOD_READ()     rGPECON1=(rGPECON1&0x3FFFFFFF)
#define SET_SIOD_WRITE()    rGPECON1=(rGPECON1&0x3FFFFFFF)|0x40000000
#define SET_SIOC_READ()     rGPECON1=(rGPECON1&0xCFFFFFFF)
#define SET_SIOC_WRITE()    rGPECON1=(rGPECON1&0xCFFFFFFF)|0x10000000

static __inline void set_gpio_ctrl(unsigned int gpio)
{
	rGPECON1 &= ~(3<<((gpio&0xf)*2));
	if(gpio&GPIO_MODE_OUT)
		rGPECON1 |= 1<<((gpio&0xf)*2);
	if(gpio&GPIO_PULLUP_DIS)
		rGPEUP1 |= 1<<(gpio&0xf);
	else
		rGPEUP1 &= ~(1<<(gpio&0xf));
}


/*********** start of OV7620 ********************/
/* refer to 25p of OV7620 datasheet */
#define OV7620_SCCB_ID 0x60//0x42  /* CS[2:0] = 000 */	//hzh, use variable

#define OV7620_MAX_CLK 24000000 // 24MHz
#define OV7620_PRODUCT_ID 0x7FA2


#define OV7620_SCCB_DELAY    100 
#define OV7620_SCCB_DELAY2   100

#define SIO_C          (GPIO_E14)
#define SIO_D          (GPIO_E15)
#define MAKE_HIGH(_x)  write_gpio_bit_set(_x)
#define MAKE_LOW(_x)   write_gpio_bit_clear(_x)
#define BIT_READ(_x)   read_gpio_bit(_x)
#define CFG_READ(_x)   set_gpio_ctrl(_x | GPIO_PULLUP_DIS | GPIO_MODE_IN)
#define CFG_WRITE(_x)  set_gpio_ctrl(_x | GPIO_PULLUP_DIS | GPIO_MODE_OUT)


/* 2-wire SCCB */
void __inline ov7620_sccb_start(void)
{
	MAKE_HIGH(SIO_C);
	MAKE_HIGH(SIO_D);
	WAIT_STAB;
	MAKE_LOW(SIO_D);
	WAIT_STAB;
	MAKE_LOW(SIO_C);
	WAIT_STAB;
}

/* 2-wire SCCB */
void __inline ov7620_sccb_end(void)
{
	MAKE_LOW(SIO_D);
	WAIT_STAB;
	MAKE_HIGH(SIO_C);
	WAIT_STAB;
	MAKE_HIGH(SIO_D);
	WAIT_STAB;
}

void __inline ov7620_sccb_write_bit(unsigned char bit)
{
	if (bit)
		MAKE_HIGH(SIO_D);
	else
		MAKE_LOW(SIO_D);
	WAIT_STAB;
	MAKE_HIGH(SIO_C);
	WAIT_CYL;
	MAKE_LOW(SIO_C);
	WAIT_STAB;
}

int __inline ov7620_sccb_read_bit(void)
{
	int tmp = 0;

	MAKE_HIGH(SIO_C);
	WAIT_CYL;
	tmp = BIT_READ(SIO_D);
	MAKE_LOW(SIO_C);
	WAIT_STAB;

	return tmp;
}	

void __inline ov7620_sccb_writechar(unsigned char data)
{
	int i = 0;

	/* data */
	for (i = 0; i < 8; i++ ) {
		ov7620_sccb_write_bit(data & 0x80);
		data <<= 1;
	}

	/* 9th bit - Don't care */
	ov7620_sccb_write_bit(1);
}

void __inline ov7620_sccb_readchar(unsigned char *val)
{
	int i;
	int tmp = 0;

	CFG_READ(SIO_D);

	for (i = 7; i >= 0; i--)
		tmp |= ov7620_sccb_read_bit() << i;

	CFG_WRITE(SIO_D);

	/* 9th bit - N.A. */
	ov7620_sccb_write_bit(1);

	*val = tmp & 0xff;
}

/* 3-phase write */
static void ov7620_sccb_sendbyte(unsigned char subaddr, unsigned char data)
{
//	down(&dev.bus_lock);

	ov7620_sccb_start();
	ov7620_sccb_writechar(OV7620_SCCB_ID);
	ov7620_sccb_writechar(subaddr);
	ov7620_sccb_writechar(data);
	ov7620_sccb_end();

	mdelay(1);

//	up(&dev.bus_lock);
}

/* 2-phase read */
static unsigned char ov7620_sccb_receivebyte(unsigned char subaddr)
{
	unsigned char value;

//	down(&dev.bus_lock);

	/* 2-phase write */
	ov7620_sccb_start();
	ov7620_sccb_writechar(OV7620_SCCB_ID);
	ov7620_sccb_writechar(subaddr);
	ov7620_sccb_end();

	/* 2-phase read */
	ov7620_sccb_start();
	ov7620_sccb_writechar(OV7620_SCCB_ID | 0x01);
	ov7620_sccb_readchar(&value);
	ov7620_sccb_end();

	//msWait(7);
	mdelay(7);

//	up(&dev.bus_lock);

	return value;
}


void ReadCameraProductID(void)
{
    U8 id ;
	id = 0 ;

    //s2440CLKPW->rCLKCON |= 0x80000;
    
	s2440IOP->rGPGCON  &= 0xFCFFFFFF ;
	s2440IOP->rGPGCON |= (1<<24) ; 
	s2440IOP->rGPGUP |= (1<<12) ;
	s2440IOP->rGPGDAT &= ~(1<<12) ;
	
		
    //s2440IOP->rGPECON &= ~(0xF<<28);                //GPE15:IICSDA , GPE14:IICSCL    
    //s2440IOP->rGPECON |=  (0xa<<28);                //GPE15:IICSDA , GPE14:IICSCL    

    //Enable ACK, Prescaler IICCLK=PCLK/16, Enable interrupt, Transmit clock value Tx clock=IICCLK/16
    //s2440IIC->rIICCON  = (1<<7) | (0<<6) | (1<<5) | (0xf);
	

   // s2440IIC->rIICADD  = 0x10;                    	//2440 slave address = [7:1]. this is avialable when 240 is slave.
   // s2440IIC->rIICSTAT = 0x10;                    	//IIC bus data output enable(Rx/Tx)
   // s2440IIC->rIICLC = (1<<2)|(3);  				// Filter enable, 15 clocks SDA output delay     added into 2440

	CFG_WRITE(SIO_C);
	CFG_WRITE(SIO_D);
	mdelay(10);
	
	id = ov7620_sccb_receivebyte(10);
	
	RETAILMSG(1,(TEXT("ID=0x%x\r\n"),id));
    
    //Rd_CamIIC(SlaveID,10,&id) ;
	
  //  RETAILMSG(1,(TEXT("------------------\r\n")));
   // RETAILMSG(1,(TEXT("Product ID = 0x%x\r\n"), id));
	
}

void Camera_Initialize(void)
{
/*
	if (IIC_InterruptEvent == NULL)
	{
	    // allocate the interrupt event for IIC
	    IIC_InterruptEvent = CreateEvent(NULL, FALSE, FALSE,NULL);
	    
	    if (NULL == IIC_InterruptEvent) {
			RETAILMSG(1,(TEXT("IIC interrupt event Error1\r\n")));
	    }
	    // initialize the card insertion interrupt event
	    if (!InterruptInitialize (SYSINTR_IIC, IIC_InterruptEvent, NULL, 0)) {
			RETAILMSG(1,(TEXT("IIC interrupt event Error2\r\n")));
	    }
	}
	*/
	RETAILMSG(1,(TEXT("Use IIC for initialization\r\n")));

/*
       CFG_WRITE(SIO_C);
	CFG_WRITE(SIO_D);
	mdelay(10);

       s2440IOP->rGPGCON  &= 0xFCFFFFFF ;
	s2440IOP->rGPGCON |= (1<<24) ; 
	s2440IOP->rGPGUP |= (1<<12) ;
	s2440IOP->rGPGDAT &= ~(1<<12) ;
	*/

ReadCameraProductID();
ReadCameraProductID();
ReadCameraProductID();
ReadCameraProductID();
	ReadCameraProductID();
		
	// Use IIC for initialization
	CAM_WriteBlock();
}

void SetCAMClockDivider(int divn) // divn is even number 0~15
{
	volatile CLKPWRreg	*s2440PWR = (CLKPWRreg *)CLKPWR_BASE;
	
	s2440PWR->rCAMDIVN = (s2440PWR->rCAMDIVN & ~(0xf))|(0x10)|(divn); // CAMCLK is divided..
//	RETAILMSG(1,(TEXT("s2440PWR->rCLKCON:0x%x\r\n"),s2440PWR->rCLKCON));
}

void CAM_WriteBlock(void)
{
/*
    unsigned int i, save_E, save_PE;
    static U8 rdata[256]; 
    int err = 0;

   s2440CLKPW->rCLKCON |= 0x80000;
		
    save_E   = s2440IOP->rGPECON;
    save_PE  = s2440IOP->rGPEUP;

    //s2440IOP->rGPEUP  &= ~0xc000;                  	//Pull-up disable
    //s2440IOP->rGPEUP  |=  0xc000;                  	//Pull-up disable
    s2440IOP->rGPECON &= ~(0xF<<28);                //GPE15:IICSDA , GPE14:IICSCL    
    s2440IOP->rGPECON |=  (0xa<<28);                //GPE15:IICSDA , GPE14:IICSCL    

    //Enable ACK, Prescaler IICCLK=PCLK/16, Enable interrupt, Transmit clock value Tx clock=IICCLK/16
s2440IIC->rIICCON  = (1<<7) | (0<<6) | (1<<5) | (0xf);	

    s2440IIC->rIICADD  = 0x10;                    	//2440 slave address = [7:1]. this is avialable when 240 is slave.
    s2440IIC->rIICSTAT = 0x10;                    	//IIC bus data output enable(Rx/Tx)
    s2440IIC->rIICLC = (1<<2)|(3);  				// Filter enable, 15 clocks SDA output delay     added into 2440
  
    for(i=0; i<(sizeof(S5X532_YCbCr8bit_TV)/2); i++){
    	//RETAILMSG(1,(TEXT("num:%d\r\n"),i));	
		Wr_CamIIC(SlaveID, S5X532_YCbCr8bit_TV[i][0], S5X532_YCbCr8bit_TV[i][1]);
		Sleep(1);
	}
	
    RETAILMSG(1,(TEXT("Block TX Ended...\r\n")));	

    s2440IOP->rGPEUP  = save_PE;
    s2440IOP->rGPECON = save_E;

*/
	int i;
	for (i = 0; i < OV9650_REGS; i++) {
		if (ov9650_reg[i].subaddr == CHIP_DELAY)
			Delay(ov9650_reg[i].value);
			//mdelay(ov9650_reg[i].value);
		else
			ov7620_sccb_sendbyte(ov9650_reg[i].subaddr & 0xff
					, ov9650_reg[i].value & 0xff);
	}
	
}

void Wr_CamIIC(U32 slvAddr, U32 addr, U8 data)
{
    _iicMode      = WRDATA;
    _iicPt        = 0;
    _iicData[0]   = (U8)addr;
    _iicData[1]   = data;
    _iicDataCount = 2;
    // write slave address
    s2440IIC->rIICDS	= slvAddr;  //0x42: OV7620 Slave ID 
    // After this time, timing is critical, because IIC start.
    s2440IIC->rIICSTAT	= 0xf0; 	//Start Master TX Condition    
    s2440IIC->rIICCON	= 0xAf;   	//Clearing the pending bit isn't needed because the pending bit has been cleared.

    while(_iicDataCount!=-1)
       Run_IicPoll();
    
}

void Rd_CamIIC(U32 slvAddr,U32 addr,U8 *data)
{
	/*IIC Slave Addr Write + IIC Reg Addr Write */	
	_iicMode      = SETRDADDR;
	_iicPt        = 0;
	_iicData[0]   = (U8)addr;
	_iicDataCount = 1;
       
    // write slave address
    s2440IIC->rIICDS	= (slvAddr<<1)&0;  //0x42: OV7620 Slave ID 
    // After this time, timing is critical, because IIC start.
    s2440IIC->rIICSTAT	= 0xf0; 	//Start Master TX Condition    
    s2440IIC->rIICCON	= 0xAf;   	//Clearing the pending bit isn't needed because the pending bit has been cleared.

    while(_iicDataCount!=-1)
       Run_IicPoll();

    _iicMode      = RDDATA;
    _iicPt        = 0;
    _iicDataCount = 1;
    
    s2440IIC->rIICDS   = (slvAddr<<1)&1;
    s2440IIC->rIICSTAT = 0xb0;                    //Master Rx,Start
    s2440IIC->rIICCON  = 0xAf;                    //Resumes IIC operation. 

    while(_iicDataCount!=-1)
       Run_IicPoll();

	*data = _iicData[1];    
	RETAILMSG(1,(TEXT("Data0:0x%x\r\n"),_iicData[0]));
	RETAILMSG(1,(TEXT("Data1:0x%x\r\n"),_iicData[1]));
}

void Run_IicPoll(void)
{
	DWORD waitStatus;
	
	// When using Interrupt mode
	//waitStatus = WaitForSingleObject(IIC_InterruptEvent, INFINITE);
	// When using polling mode
    if(s2440IIC->rIICCON & 0x10)                  //Tx/Rx Interrupt Enable
       	IicPoll();
}       

void IicPoll(void)
{
    volatile U32 i;

	//RETAILMSG(1,(TEXT("IIC Interrupt occur\r\n")));

    switch(_iicMode)
    {
        case RDDATA:
            if((_iicDataCount--)==0)
            {
                _iicData[_iicPt++] = s2440IIC->rIICDS;
            
                s2440IIC->rIICSTAT = 0x90;      //Stop MasRx condition 
                s2440IIC->rIICCON  = 0xAf;      //Resumes IIC operation.
                Delay(20);                 //Wait until stop condtion is in effect., Too long time... 
                                                //The pending bit will not be set after issuing stop condition.
                break;    
            }      
            _iicData[_iicPt++] = s2440IIC->rIICDS;     //The last data has to be read with no ack.

            if((_iicDataCount)==0)
                s2440IIC->rIICCON = 0x2f;                 //Resumes IIC operation with NOACK in case of OV7620 Cameara  
            else 
                s2440IIC->rIICCON = 0xAf;                 //Resumes IIC operation with ACK
            break;

        case WRDATA:
            if((_iicDataCount--)==0)
            {
                s2440IIC->rIICSTAT = 0xd0;                //stop MasTx condition 
                s2440IIC->rIICCON  = 0xAf;                //resumes IIC operation.
                Delay(10);                       		// we should adjust this time.
                
                //The pending bit will not be set after issuing stop condition.
                break;    
            }
          
            s2440IIC->rIICDS = _iicData[_iicPt++];        	//_iicData[0] has dummy.
            //for setup time until rising edge of IICSCL. we have to adjust this time.
			Delay(10);
            //for(i=0;i<1000;i++);
			// IICDS has to be written before clearing the IIC interrupt pending bit
			//RETAILMSG(1,(TEXT("BB")));						// we should adjust this time.
            
            s2440IIC->rIICCON = 0xAf;                    	 //resumes IIC operation.
            
            break;

        case SETRDADDR:
            if((_iicDataCount--)==0)
            {
                  s2440IIC->rIICSTAT = 0xd0;                //stop MasTx condition 
    		      s2440IIC->rIICCON  = 0xAf;                //resumes IIC operation.
                  Delay(1);      //wait until stop condtion is in effect.
                  
                  
                  break;                  //IIC operation is stopped because of IICCON[4]    
            }

            s2440IIC->rIICDS = _iicData[_iicPt++];
			Delay(20); 
			//for(i=0;i<1000;i++);          //for setup time until rising edge of IICSCL
            //RETAILMSG(1,(TEXT("RD")));				// we should adjust this time.
            s2440IIC->rIICCON = 0xAf;             //resumes IIC operation.
            break;

        default:
            break;      
    }
    
    InterruptDone(SYSINTR_IIC);
}

void Delay(int time)
{
/*
    volatile int i;
    
    for(;time>0;time--)
        for(i=0;i<100;i++);
        */

volatile int i, j = 0;
	volatile static int loop = S2440FCLK/100000;
	
	for(;time > 0;time--)
		for(i=0;i < loop; i++) { j++; }
		
}
