module i2c_touch_controller (		
							iRSTN,
							iI2C_CLK,
							iI2C_CLK_OUT,
							iI2C_GO,
							oI2C_END,					
							oI2C_ACK,					
							oREG_CONTROL,								
							oREG_X1_MB,								
							oREG_X1_LB,								
							oREG_Y1_MB,								
							oREG_Y1_LB,								
							oREG_X2_MB,								
							oREG_X2_LB,								
							oREG_Y2_MB,								
							oREG_Y2_LB,								
							oREG_TOUCH_COUNT,								
							oREG_GESTURE,								
							I2C_SDAT,
							I2C_SCLK
);

`include "i2c_touch_param.h"

//=======================================================
//  PORT declarations
//=======================================================
//	Host Side
input				              iRSTN;
input				              iI2C_CLK, iI2C_CLK_OUT;
input	      			        iI2C_GO;
output	reg		            oI2C_END;
output	  			          oI2C_ACK;
output	reg [7:0]	        oREG_CONTROL;			
output	reg [7:0]	        oREG_X1_MB;				
output	reg [7:0]	        oREG_X1_LB;				
output	reg [7:0]	        oREG_Y1_MB;				
output	reg [7:0]	        oREG_Y1_LB;				
output	reg [7:0]	        oREG_X2_MB;				
output	reg [7:0]	        oREG_X2_LB;				
output	reg [7:0]	        oREG_Y2_MB;				
output	reg [7:0]	        oREG_Y2_LB;				
output	reg [7:0]	        oREG_TOUCH_COUNT;	
output	reg [7:0]	        oREG_GESTURE;			
//	I2C Side              
inout				              I2C_SDAT;
output				            I2C_SCLK;

//=======================================================
//  REG/WIRE declarations
//=======================================================
reg  	[3:0]		i2c_count;
reg  	[3:0]		reg_num;
reg  	[2:0]		i2c_state;
reg           non_first;
reg           i2c_clk_en, i2c_clk_zero;
reg           sdo;
reg           ack_slave_w, ack_subaddress, ack_slave_r;
wire          end_reg;


//=======================================================
//  Structural coding
//=======================================================
assign I2C_SCLK = i2c_clk_en ? i2c_clk_zero ? 1'b0 : iI2C_CLK_OUT : 1'b1;
assign I2C_SDAT = sdo ? 1'bz : 1'b0;
assign oI2C_ACK = ack_slave_w || ack_subaddress || ack_slave_r;
assign end_reg = reg_num == 4'd12;


always @ (posedge iI2C_CLK or negedge iRSTN) 
	if (!iRSTN) 
	begin
		oI2C_END <= 1'b0;
    i2c_count <= 4'd0;
    reg_num <= 4'd0;
    i2c_state <= START;
    non_first <= 1'b0;
		sdo <= 1'b1; 
		i2c_clk_en <= 1'b0;
		i2c_clk_zero <= 1'b0;
  end
	else if (iI2C_GO)
	begin
		case (i2c_state)
			START : begin
				 sdo <= 1'b0;
				 if (non_first)
					 i2c_state <= S_ADDR_R;
				 else
					 i2c_state <= S_ADDR_W;
			end
			S_ADDR_W : begin
				 i2c_clk_en <= 1'b1; 
		     if (i2c_count[3])
		     	 if (i2c_count[0])
		     	 begin
		     	 	 i2c_state <= R_ADDR_W;
		     	 	 i2c_count <= 4'd0;
		     	 	 i2c_clk_zero <= 1'b0;
		     	 end
		     	 else
		     	 begin
		     	 	 sdo <= 1'b1;
		     	 	 i2c_count <= i2c_count + 4'd1;
		     	 	 i2c_clk_zero <= 1'b1;
		     	 end
		     else
		     begin
				   sdo <= WRITE_SLAVE[~i2c_count];
		       i2c_count <= i2c_count + 4'd1;
				 end
			end
			R_ADDR_W : begin
		     if (i2c_count[3])
		     	 if (i2c_count[0])
		     	 begin
		     	 	 i2c_state <= STOP;
		     	 	 i2c_count <= 4'd0;
		     	 	 i2c_clk_zero <= 1'b0;
		     	 end
		     	 else
		     	 begin
		     	 	 sdo <= 1'b1;
		     	 	 i2c_count <= i2c_count + 4'd1;
		     	 	 i2c_clk_zero <= 1'b1;
		     	 end
		     else
		     begin
				   sdo <= REG_START[~i2c_count];
		       i2c_count <= i2c_count + 4'd1;
				 end
			end
			S_ADDR_R : begin
				 i2c_clk_en <= 1'b1; 
		     if (i2c_count[3])
		     	 if (i2c_count[1])
		     	 begin
		     	 	 i2c_state <= DATA_R;
		     	 	 i2c_count <= 4'd0;
		     	 end
		     	 else
		     	 begin
		     	 	 i2c_count <= i2c_count + 4'd1;
             if (i2c_count[0])
		     	 	   i2c_clk_zero <= 1'b0;
		     	   else
		     	   begin		     	 	 
		     	     sdo <= 1'b1;
		     	 	   i2c_clk_zero <= 1'b1;
		     	 	 end
		     	 end
		     else
		     begin
				   sdo <= READ_SLAVE[~i2c_count];
		       i2c_count <= i2c_count + 4'd1;
				 end
			end
			DATA_R : begin
		     if (i2c_count[3])
		     	 if (i2c_count[0])
		     	 begin
		     	 	 i2c_count <= 4'd0;
		     	 	 reg_num <= reg_num + 4'd1;
		     	 	 i2c_clk_zero <= 1'b0;
		     	 end
		     	 else
		     	 begin
		     	 	 sdo <= 1'b1;
		     	 	 i2c_count <= i2c_count + 4'd1;
		     	 	 i2c_clk_zero <= 1'b1;
		     	 end
		     else
		     begin
		     	 if (&i2c_count[2:0])
		     	 begin
		     	 	 if (end_reg)
		     	 	 begin
				     	 i2c_state <= STOP;
				     	 reg_num <= 4'd0;
				     end
				     else
				       sdo <= 1'b0;
		       end
		       i2c_count <= i2c_count + 4'd1;
				 end
			end
			STOP : begin
				 if (non_first)
		     	 if (i2c_count[1])
		     	 begin
		     	 	 i2c_state	<= START;
		     	 	 sdo <= 1'b1; 
		     	 	 oI2C_END <= 1'b0;
		     	 	 i2c_count <= 4'd0; 
		     	 end
		     	 else
		     	 begin
		     	 	 i2c_count <= i2c_count + 4'd1;
		     	 	 if (i2c_count[0])
		     	   begin
		     	 	   oI2C_END <= 1'b1;
               i2c_clk_en <= 1'b0; 
               i2c_clk_zero <= 1'b0;	
	     	     end
		     	   else
		     	   begin
		     	 	   sdo <= 1'b0; 
		     	 	   i2c_clk_zero <= 1'b1;
		     	   end
		     	 end
				 else
				 begin
		     	 if (i2c_count[0])
		     	 begin
		     	 	 i2c_state	<= START;
             sdo <= 1'b1;		     	 	 
             i2c_count <= 4'd0;
		     	 	 non_first <= 1'b1;
		     	 end
		     	 else
		     	 begin
		     	 	 sdo <= 1'b0;
		     	 	 i2c_clk_en <= 1'b0;
		     	 	 i2c_count <= i2c_count + 4'd1;
		     	 end
         end
		  end			
		endcase			
  end

always @ (posedge iI2C_CLK_OUT) 
	if (iI2C_GO)
	begin
		case (i2c_state)
			R_ADDR_W : begin
		     if (~|i2c_count[3:0])
		     	 ack_slave_w <= I2C_SDAT;
		  end
			S_ADDR_R : begin
		     if (i2c_count[3] && i2c_count[1])
		     	 ack_slave_r <= I2C_SDAT;
			end
			DATA_R : begin
				if (!i2c_count[3])
          case (reg_num)
            4'd0  : oREG_CONTROL <= {oREG_CONTROL[6:0],I2C_SDAT};
            4'd3  : oREG_X1_MB <= {oREG_X1_MB[6:0],I2C_SDAT};
            4'd4  : oREG_X1_LB <= {oREG_X1_LB[6:0],I2C_SDAT};
            4'd5  : oREG_Y1_MB <= {oREG_Y1_MB[6:0],I2C_SDAT};
            4'd6  : oREG_Y1_LB <= {oREG_Y1_LB[6:0],I2C_SDAT};
            4'd7  : oREG_X2_MB <= {oREG_X2_MB[6:0],I2C_SDAT};
            4'd8  : oREG_X2_LB <= {oREG_X2_LB[6:0],I2C_SDAT};
            4'd9  : oREG_Y2_MB <= {oREG_Y2_MB[6:0],I2C_SDAT};
            4'd10 : oREG_Y2_LB <= {oREG_Y2_LB[6:0],I2C_SDAT};
            4'd11 : oREG_TOUCH_COUNT <= {oREG_TOUCH_COUNT[6:0],I2C_SDAT};
            4'd12 : oREG_GESTURE <= {oREG_GESTURE[6:0],I2C_SDAT};          
          endcase
			end
		  STOP : begin
				 if (!non_first && !i2c_count[0])
		     	 	 ack_subaddress <= I2C_SDAT;
		  end
		endcase			
  end		

endmodule