/*aml_i2c.h*/

#ifndef __AML_I2C_H__
#define __AML_I2C_H__

#include <common.h>
#include <linux/compiler.h>
#include <asm/arch/i2c.h>

#define AML_I2C_MAX_TOKENS		8

/*I2C_CONTROL_REG	0x2140/0x2148*/
struct aml_i2c_reg_ctrl {
	unsigned int start:1;		/*[0] Set to 1 to start list processing*/
	/*Setting this bit to 0 while the list processor is operating causes the list 
		processor to abort the current I2C operation and generate an I2C STOP
		command on the I2C bus.   Normally this bit is set to 1 and left high 
		until processing is complete.  To re-start the list processor with a 
		new list (after a previous list has been exhausted), simply set this 
		bit to zero then to one.*/
	unsigned int ack_ignore:1;	/*[1] Set to 1 to disable I2C ACK detection.*/
	/*The I2C bus uses an ACK signal after every byte transfer to detect 
		problems during the transfer.  Current Software implementations of the
		I2C bus ignore this ACK.  This bit is for compatibility with the current 
		Amlogic software.   This bit should be set to 0 to allow NACK 
		operations to abort I2C bus transactions.  If a NACK occurs, the ERROR
		bit above will be set. */
	unsigned int status:1;		/*[2] the status of the List processor*/
	#define 	I2C_IDLE		0
	#define 	I2C_RUNNING	1
	/*	0:	IDLE
		1: 	Running.  The list processor will enter this state on the clock cycle
		after the START bit is set.  The software can poll the status register to 
		determine when processing is complete.
	*/
	unsigned int error:1;		/*[3] */
	/*This read only bit is set if the I2C device generates a NACK during writing. 
		This bit is cleared at on the clock cycle after the START bit is set to 1 
		indicating the start of list processing.  Errors can be ignored by setting 
		the ACK_IGNORE bit below.  Errors will be generated on Writes to 
		devices that return NACK instead of ACK.  A NACK is returned by a 
		device if it is unable to accept any more data (for example because it 
		is processing some other real-time function).  In the event of an 
		ERROR, the I2C module will automatically generate a STOP condition 
		on the bus.*/
	unsigned int cur_token:4;	/*[7:4] the current token being processed*/
	unsigned int rd_data_cnt:4;/*[11:8] number of bytes READ over the I2C bus*/
	/*If this value is zero, then no data has been read.  If this value is 1, then 
		bits [7:0] in TOKEN_RDATA_REG0 contains valid data.  The software can 
		read this register after an I2C transaction to get the number of bytes to
		read from the I2C device*/
	unsigned int clk_delay:10;	/*[21:12] Quarter clock delay*/
	/*This value corresponds to period of the SCL clock divided by 4
		Quarter Clock Delay = * System Clock Frequency
		For example, if the system clock is 133Mhz, and the I2C clock period 
		is 10uS (100khz), then
		Quarter Clock Delay = * 133 Mhz = 332
	*/
	unsigned int manual_en:1;	/*[22] enable manual mode. */
	/*Manual I2C mode is controlled by bits 12,13,14 and 15 above.*/
	unsigned int wrscl:1;		/*[23] Sets the level of the SCL line */
	/*if manual mode is enabled.  If this bit is '0', then the SCL line is
		pulled low.  If this bit is '1' then the SCL line is tri-stated.*/
	unsigned int wrsda:1; 		/*[24] Sets the level of the SDA line */
	/*if manual mode is enabled.  If this bit is '0', 	then the SDA line is 
		pulled low.  If this bit is '1' then the SDA line is tri-stated.*/
	unsigned int rdscl:1; 		/*[25] Read back level of the SCL line*/
	unsigned int rdsda:1; 		/*[26] Read back level of the SDA line*/
#if MESON_CPU_TYPE > MESON_CPU_TYPE_MESON8
	unsigned int unused:1; 	/*[27]*/
	unsigned int clk_delay_ext:2; 	/*[29:28]*/
	unsigned int unused2:2; 	/*[31:30]*/
#else
	unsigned int unused:5; 	/*[31:27]*/
#endif
};

struct aml_i2c_reg_slave_addr {
	unsigned int slave_addr:8;	/*[7:0] SLAVE ADDRESS.*/
	/*This is a 7-bit value for a 7-bit I2C device, or (0xF0 | {A9,A8}) for a 
		10 bit I2C device.  By convention, the slave address is typically 
		stored in by first left shifting it so that it's MSB is D7 (The I2C bus
		assumes the 7-bit address is left shifted one).  Additionally, since 
		the SLAVE address is always an 7-bit value, D0 is always 0. 

		NOTE:  The I2C always transfers 8-bits even for address.  The I2C
		hardware will use D0 to dictate the direction of the bus.  Therefore, 
		D0 should always be '0' when this register is set.
	*/
	unsigned int sda_filter:3;	/*[10:8] SDA FILTER*/
	/*A filter was added in the SCL input path to allow for filtering of slow 
		rise times.  0 = no filtering, 7 = max filtering*/
	unsigned int scl_filter:3;	/*[13:11] SCL FILTER*/
	/*A filter was added in the SCL input path to allow for filtering of slow 
		rise times.  0 = no filtering, 7 = max filtering*/
#if MESON_CPU_TYPE > MESON_CPU_TYPE_MESON8
	unsigned int unused:2;	/*[15:14]*/
	unsigned int clk_low_delay:12;	/*[27:16]*/
	unsigned int clk_low_delay_en:1;	/*[28]*/
	unsigned int unused2:3;	/*[31:29]*/
#else
	unsigned int unused:18;	/*[31:14]*/
#endif
};

/*Write data associated with the DATA token should be placed into the 
	I2C_TOKEN_WDATA_REG0 or I2C_TOKEN_WDATA_REG1 registers.   
	Read data associated with the DATA or DATA-LAST token can be read from
	the I2C_TOKEN_RDATA_REG0 or I2C_TOKEN_RDATA_REG1 registers*/
	
enum aml_i2c_token {
	TOKEN_END,
	TOKEN_START,
	TOKEN_SLAVE_ADDR_WRITE,
	TOKEN_SLAVE_ADDR_READ,
	TOKEN_DATA,
	TOKEN_DATA_LAST,
	TOKEN_STOP
};

struct aml_i2c_reg_master {
	volatile unsigned int i2c_ctrl;
	volatile unsigned int i2c_slave_addr;
	volatile unsigned int i2c_token_list_0;
	volatile unsigned int i2c_token_list_1;
	volatile unsigned int i2c_token_wdata_0;
	volatile unsigned int i2c_token_wdata_1;
	volatile unsigned int i2c_token_rdata_0;
	volatile unsigned int i2c_token_rdata_1;	
};


struct aml_i2c_reg_slave_ctrl {
	unsigned int samp_rate:7;	/*[6:0] sampling rate*/
	/*Defined as MPEG system clock / (value + 1).  The SDA and SCL inputs into 
		the slave module are sampled as a way of filtering the inputs.   A 
		rising or falling edge is determined by when 3 successive samples are 
		either high or low respectively*/	
	unsigned int enable:1;		/*[7] A '1' enables the I2C slave state machine*/
	unsigned int hold_time:8;	/*[15:8]*/
	/*Data hold time after the falling edge of SCL.  
		Hold time = (MPEG system clock period) * (value + 1).
	*/
	unsigned int slave_addr:8;	/*[23-16]*/
	/*Bits [7:1] are used to identify the device.  
		Bit [0] is ignored since this corresponds to the R/W bit.*/
	unsigned int ack_always:1;	/*[24]*/
	/*Typically the ACK of a slave I2C device is dependent upon the 
		availability of data (if reading) and room to store data (when we are 
		being written).  Our I2C module has a status register that can be read
		continuously.  This bit can be set if the I2C master wants to 
		continually read the status register. */
	unsigned int irq_en:1;		/*[25]*/
	/*If this bit is set, then an interrupt will be sent to the ARC whenever 4 
		bytes have been read or 4 bytes have been written to the I2C slave 
		module.*/
	unsigned int busy:1;		/*[26] */
	/*Read only status bit.  '1' indicates that the I2C slave module is sending
		or receiving data.*/
	unsigned int rx_rdy:1;		/*[27] */
	/*This bit is set to '1' by the ARC to indicate to the slave machine that 
		the I2C slave module is ready to receive data.  This bit is cleared by 
		the I2C module when it has received 4 bytes from the I2C master.  
		This bit is also available in the status register that can be read by 
		the I2C master.   The I2C master can read the status register to see 
		when the I2C slave module is ready to receive data.*/
	unsigned int tx_rdy:1;		/*[28] */
	/*This bit is set to '1' by the ARC to indicate to the slave machine that 
		the I2C slave module is ready to send data.  This bit is cleared by 
		the I2C module when it has sent 4 bytes to the I2C master.  This bit
		is also available in the status register that can be read by the I2C 
		master.   The I2C master can read the status register to see when the
		I2C slave module has data to send.*/
	unsigned int reg_ptr:3;		/*[31:29] */
	/*There are 5 internal registers inside the I2C slave module.  The I2C 
		Master sets this value using the byte that follows the address byte 
		in the I2C data stream.  Register 4 (numbered 0,1,бн4) is the 
		status register.*/
};

struct aml_i2c_reg_slave{
	unsigned int i2c_slave_ctrl;
	unsigned int i2c_slave_tx_data;
	unsigned int i2c_slave_rx_data;
};

struct aml_i2c {
	unsigned int 		i2c_debug;
	unsigned int		cur_slave_addr;
	unsigned int 		wait_count;
	unsigned int 		wait_ack_interval;
	unsigned int 		wait_read_interval;
	unsigned int 		wait_xfer_interval;
	unsigned int 		master_no;/*master a:0 master b:1*/
	#define 			I2C_MASTER_A		0
	#define				I2C_MASTER_B		1
	#define				I2C_MASTER_AO		3
	unsigned char		token_tag[AML_I2C_MAX_TOKENS];
	unsigned int 		msg_flags;

	struct aml_i2c_ops* ops;

	struct aml_i2c_reg_master __iomem* master_regs;
	
//#ifdef CONFIG_I2C_AML_SLAVE
	struct aml_i2c_reg_slave __iomem* slave_regs;
	
	struct aml_pinmux_reg_bit	slave_pinmux;
	unsigned int		slave_dev_addr;
//#endif

	void __iomem		*reg_base;

	struct aml_pinmux_reg_bit	master_pinmux;
		
	int			irq;
	unsigned int		use_pio;/*0: hardware i2c, 1: pio i2c*/
	unsigned int		master_i2c_speed;
};

struct aml_i2c_ops {
     void (*xfer_prepare)(struct aml_i2c *i2c);
	 int  (*do_address)(struct aml_i2c *i2c, unsigned int addr);
	 int  (*read)(struct aml_i2c *i2c, unsigned char *buf, unsigned int len);
	 int  (*write)(struct aml_i2c *i2c, unsigned char *buf, unsigned int len);
	 void (*stop)(struct aml_i2c *i2c);
};

int aml_i2c_init(void);
int aml_i2c_xfer(struct i2c_msg *msgs, int num);

enum aml_i2c_id{
	SOFT_I2C = 0,
	HARD_I2C,	
};

struct i2c_board_info {
	char type[64];
	int i2c_id;
	unsigned short	addr;
	void (*device_init)(void);
	void (*device_uninit)(void);
};

#define I2C_BOARD_INFO(dev_type, dev_addr) \
	.type = dev_type, .addr = (dev_addr)

struct aml_i2c_device {
	struct i2c_borad_info *aml_i2c_boards;
	unsigned dev_num;
};

#ifdef AML_MESON_BOARD_8726M_2010_11_18_V11
//Please refer board schematic for detail pin connection
//@AML8726-M_ARM_DEV_BOARD_2DDR_V1R1.pdf
//port27-> Red	 (0x7F)
//port26-> Green (0xBF)
//port25-> Blue    (0xDF)
#define I2C_LED_RED       (0x7F)
#define I2C_LED_GREEN     (0xBF)
#define I2C_LED_BLUE      (0xDF)

//To set onboard LEDs  on/off 
void board_i2c_led_set(unsigned char byLED, unsigned char byOn);

#endif //AML_MESON_BOARD_8726M_2010_11_18_V11

#endif //__AML_I2C_H__
