/******************************************************************************

Copyright (c) 2005 Analog Devices.  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.  

******************************************************************************/



/******************************************************************************

$File:		omnivision.c $
$Revision: 1.3 $
$Date: 2008/03/24 20:03:52 $


Description:
	This file creates a simple interface to the omnivision video sensor
	

Modification History:
====================
Revision 1.0 - BJ 2006/03/27
	Created file
Revision 1.1 - BJ 2006/05/08
	Updaed example to support revision to device access functions
Revision 2.0 - BJ 2006/07/03
	Updated to support new device model
	
******************************************************************************/



/******************************************************************************

Include files

******************************************************************************/

#include <SensorCommon/device.h>
#include <SensorCommon/omnivision.h>
#include <drivers/sensor/omnivision/adi_ov7x48.h>
#include <drivers/twi/adi_twi.h>




/******************************************************************************

Definitions

******************************************************************************/

#define OV7X48_WIDTH			640
#define OV7X48_HEIGHT			480


#define OMNIVISION_DATA_SIZE	(OV7X48_WIDTH*OV7X48_HEIGHT)




/******************************************************************************

Function definitions

******************************************************************************/

static void omnivision_callback(void *, u32, void *);




/******************************************************************************

	Function: omnivision_detect_ov7648
	
	Description: Detect the presence of the omnivision OV7648 sensor

******************************************************************************/

u32 omnivision_detect_ov7648(ADI_DEV_MANAGER_HANDLE	DevManager)
{
    // this value is setup in the pre-processor definitions in project options
#ifdef ADI_TWIPSEUDO
	static adi_twi_pseudo_port TWIPseudo=ADI_TWIPSEUDO;
	static ADI_DEV_CMD_VALUE_PAIR TWIConfig[]={
		{ADI_TWI_CMD_SET_PSEUDO,(void *)(&TWIPseudo)},
		{ADI_DEV_CMD_END,NULL}
	};
#else
	static ADI_DEV_CMD_VALUE_PAIR TWIConfig[]={
		{ADI_DEV_CMD_END,NULL}
	};
#endif
	
	
	ADI_DEV_DEVICE_HANDLE Handle;
	u32 Code,ID,Retry=2;
	
	
	// Configuration table for the input driver
	ADI_DEV_CMD_VALUE_PAIR Config[]={
		{ADI_OV7X48_CMD_SET_TWICONFIG,(void *)TWIConfig},
		{ADI_OV7X48_CMD_GET_HWID,(void *)&ID},
		{ADI_DEV_CMD_END,NULL}
	};
	

    // try and open the device, if it fails then return error code
	if ((Code=adi_dev_Open(
		DevManager,
		&ADIOV7X48EntryPoint,
		0,
		&Handle,
		&Handle,
		ADI_DEV_DIRECTION_INBOUND,
		NULL,
		NULL,
		omnivision_callback))!=ADI_DEV_RESULT_SUCCESS)
		return Code;
	
	
	// now configure the device
	Code=ADI_DEV_RESULT_FAILED;
	while (Retry--&&Code!=ADI_DEV_RESULT_SUCCESS)
		Code=adi_dev_Control(Handle,ADI_DEV_CMD_TABLE,Config);
	adi_dev_Close(Handle);
	
	
	// Return any error codes that occured while trying to open device or success
	return Code;
}



/******************************************************************************

	Function: omnivision_open_ov7648
	
	Description: Open the OV7648 sensor for input streaming.
	
******************************************************************************/

ADI_DEV_DEVICE_HANDLE omnivision_open_ov7648(
	ADI_DEV_MANAGER_HANDLE	DevManager,
	ADI_DMA_MANAGER_HANDLE	DevDMA,
	ADI_DCB_HANDLE			DevDCB,
	u32 PPI,
	u16 *Data, u8 DataSize, 
	ADI_DCB_CALLBACK_FN Callback,
	ADI_DEV_CMD_VALUE_PAIR *Args)
{
	u32 Code,Width,Height,Mode=GFX_MODE_NTSCI,Scale=0;
	ADI_DEV_DEVICE_HANDLE Handle=NULL;
	
	while (Args&&Args->CommandID!=ADI_DEV_CMD_END)
	{
		switch (Args->CommandID)
		{
			case OMNIVISION_CMD_SET_SCALE:
				Scale=(u32)Args->Value<2?(u32)Args->Value:2;
				break;
			
			case OMNIVISION_CMD_SET_MODE:
				switch ((GFX_MODE)Args->Value)
				{
					case GFX_MODE_VGA:
					case GFX_MODE_NTSCI:
					case GFX_MODE_PALI:
						Mode=(GFX_MODE)Args->Value;
						break;
					default: return NULL;
				}
				break;
		}
		Args++;
	}
	
	
	{
    	// this value is setup in the pre-processor definitions in project options
#ifdef ADI_TWIPSEUDO
		adi_twi_pseudo_port TWIPseudo=ADI_TWIPSEUDO;
		ADI_DEV_CMD_VALUE_PAIR TWIConfig[]={
			{ADI_TWI_CMD_SET_PSEUDO,(void *)(&TWIPseudo)},
			{ADI_DEV_CMD_END,NULL}
		};
#else
		ADI_DEV_CMD_VALUE_PAIR TWIConfig[]={
			{ADI_DEV_CMD_END,NULL}
		};
#endif
		
		
		ADI_DEV_ACCESS_REGISTER Write[]={
			{ADI_OV7X48_CLKRC,0x00},
			{ADI_OV7X48_COMA,Mode==GFX_MODE_VGA?0x1C:0x14},
			{ADI_OV7X48_COMB,0xA3},
			{ADI_OV7X48_COMC,0x04},
			{ADI_OV7X48_COMD,0x00},
			{ADI_OV7X48_COMH,Mode==GFX_MODE_VGA?0x20:0x00},
			{ADI_OV7X48_FACT,Mode==GFX_MODE_VGA?0x11:0x01},
			{ADI_OV7X48_PSHIFT,Mode==GFX_MODE_VGA?0x03:0x02},
			{ADI_DEV_REGEND,0}
		};
		
		
		ADI_DEV_CMD_VALUE_PAIR Config[]={
			// Configuration table for the input driver
			{ADI_OV7X48_CMD_SET_TWICONFIG,(void *)TWIConfig},
			{ADI_OV7X48_CMD_SET_PPI,(void *)PPI},
			{ADI_DEV_CMD_SET_DATAFLOW_METHOD,(void *)ADI_DEV_MODE_CHAINED_LOOPBACK},
			{ADI_DEV_CMD_REGISTER_TABLE_WRITE,(void *)&Write},
			{ADI_DEV_CMD_SET_DATAFLOW,(void *)TRUE},
			{ADI_DEV_CMD_END,NULL}
		}, Check[]={
			// Configuration table for the input driver
			{ADI_OV7X48_CMD_GET_WIDTH,(void *)&Width},
			{ADI_OV7X48_CMD_GET_HEIGHT,(void *)&Height},
			{ADI_DEV_CMD_END,NULL}
		};
		
		
	    // try and open the device, if it fails then return error code
		if ((Code=adi_dev_Open(
			DevManager,
			&ADIOV7X48EntryPoint,
			0,
			&Handle,
			&Handle,
			ADI_DEV_DIRECTION_INBOUND,
			DevDMA,
			DevDCB,
			Callback?Callback:omnivision_callback))!=ADI_DEV_RESULT_SUCCESS)
			return NULL;
		
		
		// now configure the device
		Code=adi_dev_Control(Handle,ADI_DEV_CMD_TABLE,Config);
		
		
		// wait for the height and width to be right before continuing
		while (Code==ADI_DEV_RESULT_SUCCESS&&Width!=OV7X48_WIDTH/(1<<Scale)&&Height!=OV7X48_HEIGHT/(1<<Scale))
			Code=adi_dev_Control(Handle,ADI_DEV_CMD_TABLE,Check);
	}
	
	
	if (Code==ADI_DEV_RESULT_SUCCESS)
	{
		static ADI_DEV_BUFFER Buffer[1];
		u32 i;
		
		
		for (i=0;i<sizeof(Buffer)/sizeof(Buffer[0]);i++)
		{
		    Buffer[i].TwoD.Data=Data;
		    Buffer[i].TwoD.ElementWidth=DataSize;
		    Buffer[i].TwoD.XCount=(Width*sizeof(u16))/Buffer[i].TwoD.ElementWidth;
			Buffer[i].TwoD.XModify=Buffer[i].TwoD.ElementWidth;
			Buffer[i].TwoD.YCount=Height;
			Buffer[i].TwoD.YModify=Buffer[i].TwoD.ElementWidth;
			Buffer[i].TwoD.CallbackParameter=&Buffer[i];
			Buffer[i].TwoD.pNext=NULL;
			Buffer[i].TwoD.pAdditionalInfo=(void *)ADI_DEV_BUFFER_UNDEFINED;
			Code=adi_dev_Read(Handle,ADI_DEV_2D,&Buffer[i]);
		}
	}
	
	
	// If configuration failed close the device
	if (Code!=ADI_DEV_RESULT_SUCCESS)
	{
		adi_dev_Close(Handle);
		Handle=NULL;
	}	
	
	
	return Handle;
}




/******************************************************************************

	Function: omnivision_callback
	
	Description: Default callback routine, used if NULL is passed to open.

******************************************************************************/

void omnivision_callback(void *Handle, u32 Event, void *pArg)
{	
	switch (Event)
	{
		case ADI_DEV_EVENT_BUFFER_PROCESSED:
			if (Handle&&pArg&&((ADI_DEV_BUFFER *)pArg)->TwoD.pAdditionalInfo!=ADI_DEV_BUFFER_UNDEFINED)
				adi_dev_Read(
					*((ADI_DEV_DEVICE_HANDLE *)Handle),
					(ADI_DEV_BUFFER_TYPE)((ADI_DEV_BUFFER *)pArg)->TwoD.pAdditionalInfo,
					(ADI_DEV_BUFFER *)pArg);
			break;
	}
}

/*****************************************************************************/
