/*
 * Copyright (c) 2016, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/**
 * \file:   camera.c
 *
 * \brief:  configuring AR0331 sensor via I2C
 *
 * \b \Descr: This file contains the generic routines for configuring the AR0331
 * \n         sensor on the DM388 on a specific bus instance(i2c2).
 *
 */

/*
 *====================
 * Includes
 *====================
 */

#include "stdlib.h"
#include "string.h"
#include "dm8127_Platform.h"
#include "dm8127_i2c.h"

/*
 *====================
 * Global Variables
 *====================
 */
UINT16 regValue[100];
UINT16 regAddr [100];

/*
 *====================
 * Defines
 *====================
 */
#define PLL_MULTIPLIER    (0x4A)
#define INPUT_CLK         (24u)     /* EXTCLK */
#define PLL_P2            (6u)
#define PLL_M             (74u)     /* pll_multiplier */
#define PLL_pre_div       (4u)      /* pre_pll_clk_div */
#define OP_SYS_CLK_DIV	  (1u)
#define PLL_P1            (1u)     /* vt_sys_clk_div */

#define I2C_BUS_NUM            (2u)
#define I2C_WRITE_delay        (0x1FFF)
#define SENSOR_I2C_WRITE_delay (0x2FFF)

#define OUT_CLK ((INPUT_CLK * PLL_M) / (PLL_pre_div * PLL_P1 * PLL_P2) ) /* 74MHz (30fps) */

/***
 * \brief: Routine to reset aptina AR0031 Sensor by gpio pin toggling
 *
 * \b Descr: This routine reset the AR0031 Sensor
 *
 * \param: VOID
 * \return VOID
 */

void camera_reset_toggle
(
	void
)
{
	GPIO2_SYSCONFIG = 0x0000002; /* Software Reset */
	delay(0x90000);
	GPIO2_SYSCONFIG = 0x100; /* no-idle */

	GPIO2_OE &= ~(1 <<  18);
	GPIO2_SETDATAOUT = (1 <<  18);
	delay( 0x3FFFF );
	//GPIO2_CLEARDATAOUT = (1 <<  18);
	//delay( 0x3FFFF );
}

/***
 * \brief: Routine to read aptina AR0031 Sensor registers via i2c-2
 *
 * \b Descr: This routine read the AR0031 Sensor Register data
 *
 * \param: reg_addr [IN] I2c camera write address
 * \       reg_val  [IN] reference variable
 *
 * \return:  SUCCESS on success
 * \n        FAILED if any error
 */

STATUS ar0331_readRegister
(
	UINT16 reg_addr,
	UINT16 reg_val
)
{
	SINT16 u32RetVal=SUCCESS;
	UINT8 buffer[5];
	UINT8 rx_buf[2];
	UINT8 u8DataWritten=0;
	UINT8 u8DataRead=0;
	SINT32 devAddr = 0x10;


	buffer[0] = (reg_addr >> 0x8);
	buffer[1] = (reg_addr & 0xFF);

	u32RetVal=DM8127I2cWitecamera(I2C_BUS_NUM,devAddr,buffer,2,&u8DataWritten);
	if(u32RetVal!=SUCCESS)
	{
		u32RetVal=FAILED;
		return u32RetVal;
	}
	delay(SENSOR_I2C_WRITE_delay);

	u32RetVal=DM8127I2cRead(I2C_BUS_NUM,devAddr,rx_buf,2,&u8DataRead);
	if(u32RetVal!=SUCCESS)
	{
		u32RetVal=FAILED;
		return u32RetVal;
	}

	reg_val = (UINT16)((rx_buf[0] << 8) | rx_buf[1]);

	platform_write("value of register 0x%04X is 0x%04X \n",reg_addr,reg_val);

	return u32RetVal;

}

/***
 * \brief: Routine to configure aptina AR0031 Sensor registers via i2c-2
 *
 * \b \Descr: This routine configure the AR0031 Sensor Register
 *
 * \param: VOID
 *
 * \return: SUCCESS on success
 * \n       FAILED if any error
 */

STATUS ar0331_configuration
(
	void
)
{

		SINT16 u32RetVal=SUCCESS;
		int i = 0;
	    UINT8 buffer[5];
	    UINT8  u8DataWritten = 0;
	    int j;
	    SINT32 devAddr = 0x10;


    regAddr[i] = 0x302A; regValue[i] = PLL_P2 ;	i++;// VT_PIX_CLK_DIV
	regAddr[i] = 0x301A; regValue[i] = 0x0001; i++;  	// RESET_REGISTER

	regAddr[i] = 0x301A; regValue[i] = 0x0058; i++;  	// RESET_REGISTER
	regAddr[i] = 0x31AC; regValue[i] = 0x0C0C; i++; 		//DATA_FORMAT_BITS = 3084
		//PLL_settings - 4 Lane 12-bit HiSPi

	regAddr[i] = 0x302A; regValue[i] = PLL_P2 ;	i++;// VT_PIX_CLK_DIV
	regAddr[i] = 0x302C; regValue[i] = PLL_P1 ;	i++;// VT_SYS_CLK_DIV
	regAddr[i] = 0x302E; regValue[i] = PLL_pre_div ;	i++;// PRE_PLL_CLK_DIV
	regAddr[i] = 0x3030; regValue[i] = PLL_M ; 	i++;// PLL_MULTIPLIER
	regAddr[i] =0x3036; regValue[i] = 0x000C;  i++;  // OP_PIX_CLK_DIV
	regAddr[i] = 0x3038; regValue[i] = OP_SYS_CLK_DIV; 	i++;// OP_SYS_CLK_DIV
	regAddr[i] =0x3002; regValue[i] = 0x00E4;  i++;  // Y_ADDR_START
	regAddr[i] =0x3004; regValue[i] = 0x0042;  i++;  // X_ADDR_START
	regAddr[i] =0x3006; regValue[i] = 0x0523;  i++;  // Y_ADDR_END
	regAddr[i] = 0x3008; regValue[i] = 0x07c9; i++;  //regAddr[i] = 0x3008; regValue[i] = 0x07C0; i++; 	// X_ADDR_END
	regAddr[i] =0x300A; regValue[i] = 0x0465;  i++;  // FRAME_LENGTH_LINES
	regAddr[i] =0x300C; regValue[i] = 0x044C;  i++;  // LINE_LENGTH_PCK
	regAddr[i] =0x3012; regValue[i] = 0x0438;  i++;  // COARSE_INTEGRATION_TIME
	regAddr[i] =0x30A2; regValue[i] = 0x0001;  i++;  // X_ODD_INC
	regAddr[i] =0x30A6; regValue[i] = 0x0001;  i++;  // Y_ODD_INC


	regAddr[i] =0x3040; regValue[i] = 0x0000;  i++;  // READ_MODE

	regAddr[i] =0x31AE; regValue[i] = 0x0304;  i++;  // SERIAL_FORMAT
	regAddr[i] = 0x31C6; regValue[i] = 0x8400; 	i++; // HISPI_CONTROL_STATUS
	regAddr[i] =0x306E; regValue[i] = 0x9010;  i++;  // DATAPATH_SELECT
	//Analog Settings
	regAddr[i] =0x3180; regValue[i] = 0x8089;  i++;  // DELTA_DK_CONTROL

	regAddr[i] =0x301A; regValue[i] = 0x005C;  i++;  // RESET_REGISTER


	    for (j = 0; j < i; j++)
	    {
	    	buffer[0] = (regAddr[j] >> 0x8);
	    	buffer[1] = (regAddr[j] & 0xFF);

	    	buffer[2]= (regValue[j] >> 0x8);
	    	buffer[3] =(regValue[j]  & 0xFF);


	    	u32RetVal = DM8127I2cWitecamera(I2C_BUS_NUM,devAddr,buffer,4,&u8DataWritten);


	    	if(u32RetVal!=SUCCESS)
	    	{
	    		platform_write("i2c write failed for register: 0x%04X \n",regAddr[j]);
	    		return u32RetVal;
	    	}

	    	if(regAddr[j]==0x301a)
	    		delay(I2C_WRITE_delay);

	    	else
	    		delay(I2C_WRITE_delay);

	    }

	   platform_write(" ar0331_configuration completed\n");

/*read all AR0331 Sensor Register*/
#ifdef I2C_READ

	   for (k = 0; k < j; k++)
	   {
		   ar0331_readRegister(regAddr[k],reg_val);
	   }
#endif
	   return u32RetVal;
}

/***
 * \brief: Routine to configure lvds control registers via i2c-2
 *
 * \b \Descr: This routine configure the bridge chip(i.e lvds) interfacing
 * \n         between sensor and controller.
 *
 * \param: VOID
 *
 * \return: SUCCESS on success
 * \n       FAILED  if any error
 */

STATUS lvds_configuration
(
	void
)
{
	UINT8 buffer[4];
	UINT8 u8DataWritten=0;
	SINT16 u32RetVal=FAILED;


	UINT16	u8SlaveAddr=0x2d;


	 //read all register from 0x0 to 0xa
#ifdef I2C_READ
	 u32RetVal = DM8127I2cRead(I2C_BUS_NUM,u8SlaveAddr,rx_buf,0xb,&u8DataRead);
	 for(i=0;i<11;i++)
	 {
	 platform_write("device ID value is %x at register address %x\n",rx_buf[i],i);

	 }
#endif
	 //i2c write: Register->0x28 and data->0x03
	buffer[0]=0x28;
	buffer[1]=0X03;
	u32RetVal = DM8127I2cWitecamera(I2C_BUS_NUM,u8SlaveAddr,buffer,2,&u8DataWritten);
	if(u32RetVal!=SUCCESS)
	{
		platform_write("lvds i2c write failed for register:0x28\n");
		return FAILED;
	}

	delay(I2C_WRITE_delay);

	//i2c write:Register->0x09 and data->0x24
	buffer[0]=0x09;
	buffer[1]=0x24;

   u32RetVal = DM8127I2cWitecamera(I2C_BUS_NUM,u8SlaveAddr,buffer,2,&u8DataWritten);

	if(u32RetVal!=SUCCESS)
	{
		platform_write("lvds i2c write failed for register:0x09\n");
		return FAILED;
	}
	delay(I2C_WRITE_delay);

	//read register 0x09
#ifdef I2C_READ

	u32RetVal = DM8127I2cWitecamera(I2C_BUS_NUM,u8SlaveAddr,buffer,1,&u8DataWritten);
	delay(100);
	u32RetVal = DM8127I2cRead(I2C_BUS_NUM,u8SlaveAddr,rx_buf,1,&u8DataRead);
	platform_write("value of register 0x9 is %x \n",rx_buf[0]);
#endif

	//i2c write: Register->0x0a and data->0x22
	buffer[0]=0x0A;
	buffer[1]=0x22;

	u32RetVal = DM8127I2cWitecamera(I2C_BUS_NUM,u8SlaveAddr,buffer,2,&u8DataWritten);

	if(u32RetVal!=SUCCESS)
	{
		platform_write("lvds i2c write failed for register:0x0a \n");
		return FAILED;
	}
	delay(I2C_WRITE_delay);

	//read register 0x0a
#ifdef I2C_READ

	buffer[0]=0x0A;
	u32RetVal = DM8127I2cWitecamera(I2C_BUS_NUM,u8SlaveAddr,buffer,1,&u8DataWritten);
	delay(100);
	u32RetVal = DM8127I2cRead(I2C_BUS_NUM,u8SlaveAddr,rx_buf,1,&u8DataRead);

	platform_write("value of register 0xA is %x \n",rx_buf[0]);
#endif

	platform_write(" lvds configuration completed\n");
return (u32RetVal);
}

/***
 * \brief: routine to configuartion camera i2c.
 *
 *\b \descr: This routine configure the LVDS and the ar0331.
 *
 * \param: void pointer for future use
 *
 * \return:   SUCCESS on successful initialization.
 * \n         FAILED  failed to initialize.
 */

STATUS camera_i2c_configuration
(
	void *testArgs
)
{
	SINT16 u32RetVal = FAILED;
	DM8127I2cInit( 2 );

	camera_reset_toggle();

	u32RetVal=lvds_configuration();
	if(u32RetVal != SUCCESS)
	{
		return FAILED;

	}
	u32RetVal=ar0331_configuration();
	if(u32RetVal != SUCCESS)
	{
		return FAILED;
	}

return u32RetVal;
}

/***
 * \brief: Camera module handler function.
 *
 * \b \Descr: This routine configure the camera module.
 *
 * \param: testArgs Arguments pointer
 *
 * \return: STATUS   SUCCESS on success
 * \n                FAILED  on failure
 */
STATUS camera_test
(
	void *testArgs
)
{

	SINT16 testStatus;
	 Uart_stringSend("\r\n==================================="
					 "\r\n         CAMERA Test               "
					 "\r\n===================================\r\n\n");
	testStatus=camera_i2c_configuration(testArgs);
	Uart_stringSend("\r\n-------------------------X-----------------------------");
    return (testStatus);
}
