/******************************************************************************

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:		Micron.c $
$Revision: 1.3 $
$Date: 2008/03/24 20:03:52 $


Description:
	This file creates a simple interface to the micron video sensor
	

Modification History:
====================
Revision 1.0 - BJ 2006/03/27
	Created file
Revision 1.1 - BJ 2006/05/08
	Updated example to support revision to device access functions
Revision 2.0 - BJ 2006/07/02
	Updated to support new device model
	
******************************************************************************/



/******************************************************************************

Include files

******************************************************************************/

#include <SensorCommon/device.h>
#include <SensorCommon/micron.h>
#include <drivers/sensor/micron/adi_mt9v022.h>
#include <drivers/twi/adi_twi.h>




/******************************************************************************

Definitions

******************************************************************************/

#define MT9V022_WIDTH			720
#define MT9V022_HEIGHT			480




/******************************************************************************

Function definitions

******************************************************************************/

static void micron_callback(void *, u32, void *);




/******************************************************************************

	Function: micron_detect_mt9v022
	
	Description: Detect the presence of the micron MT9V022 sensor

******************************************************************************/

u32 micron_detect_mt9v022m(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;
	
	
	// Configuration table for the input driver
	ADI_DEV_CMD_VALUE_PAIR Config[]={
		{ADI_MT9V022_CMD_SET_TWICONFIG,(void *)TWIConfig},
		{ADI_MT9V022_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,
		&ADIMT9V022EntryPoint,
		0,
		&Handle,
		&Handle,
		ADI_DEV_DIRECTION_INBOUND,
		NULL,
		NULL,
		micron_callback))!=ADI_DEV_RESULT_SUCCESS) return Code;
	
	
	// now configure the device
	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: micron_open_mt9v022m
	
	Description: Open the MT9V022 sensor for input streaming, The buffer is
		setup to copy the data into an NTSC frame.
	
	Note: This sensor outputs a 10bit greyscale image, so some processing
		has to be done to output a yuv signal.

******************************************************************************/

ADI_DEV_DEVICE_HANDLE micron_open_mt9v022m(
	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,Scale=0;
	GFX_MODE Mode=GFX_MODE_NTSCI;
	ADI_DEV_DEVICE_HANDLE Handle=NULL;
	
	
	while (Args&&Args->CommandID!=ADI_DEV_CMD_END)
	{
		switch (Args->CommandID)
		{
			case MICRON_CMD_SET_SCALE:
				Scale=(u32)Args->Value<2?(u32)Args->Value:2;
				break;
			
			case MICRON_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[]={
		    // Sensor configuration table
		    {ADI_MT9V022_READMODE,0x0330|Scale|(Scale<<2)},
		    {ADI_MT9V022_CHIPCONTROL,Mode==GFX_MODE_NTSCI||Mode==GFX_MODE_PALI?0x038A:0x0388},
		    {ADI_MT9V022_COLUMNSTART,16},
		    {ADI_MT9V022_ROWSTART,6},
		    {ADI_MT9V022_WINDOWWIDTH,MT9V022_WIDTH},
		    {ADI_MT9V022_WINDOWHEIGHT,MT9V022_HEIGHT},
		    {ADI_DEV_REGEND,0}
		};
		
		
		ADI_DEV_CMD_VALUE_PAIR Config[]={
			// Configuration table for the input driver
			{ADI_MT9V022_CMD_SET_TWICONFIG,(void *)TWIConfig},
			{ADI_MT9V022_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_MT9V022_CMD_GET_WIDTH,(void *)&Width},
			{ADI_MT9V022_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,
			&ADIMT9V022EntryPoint,
			0,
			&Handle,
			&Handle,
			ADI_DEV_DIRECTION_INBOUND,
			DevDMA,
			DevDCB,
			Callback?Callback:micron_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!=MT9V022_WIDTH/(1<<Scale)&&Height!=MT9V022_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: micron_callback
	
	Description: Default callback routine, used if NULL is passed to open.

******************************************************************************/

void micron_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;
	}
}

/*****************************************************************************/

