Commit e5bb1292 authored by Oleg Dzhimiev's avatar Oleg Dzhimiev
Browse files

1. fixed i2c discover

2. fixed phase adjustment - requires bitstream 0x100
3. tested phase adjustment
parent b59b7efd
Loading
Loading
Loading
Loading
+40 −72
Original line number Original line Diff line number Diff line
@@ -180,7 +180,7 @@ static unsigned short mt9f002_inits[]=
		P_MT9F002_SMIA_PLL_MULTIPLIER,     0x00b4, //
		P_MT9F002_SMIA_PLL_MULTIPLIER,     0x00b4, //
		P_MT9F002_HISPI_CONTROL_STATUS,    0x8400, //
		P_MT9F002_HISPI_CONTROL_STATUS,    0x8400, //
		P_MT9F002_DATAPATH_SELECT,         0x9280, //
		P_MT9F002_DATAPATH_SELECT,         0x9280, //
		P_MT9F002_RESET_REGISTER,          0x001c,
		//P_MT9F002_RESET_REGISTER,          0x001c,
		//P_MT9F002_TEST_PATTERN,            0x0002, // color bars
		//P_MT9F002_TEST_PATTERN,            0x0002, // color bars
		P_MT9F002_ANALOG_GAIN_CODE_GLOBAL, 0x000a,
		P_MT9F002_ANALOG_GAIN_CODE_GLOBAL, 0x000a,
		P_MT9F002_ANALOG_GAIN_CODE_RED,    0x000d,
		P_MT9F002_ANALOG_GAIN_CODE_RED,    0x000d,
@@ -251,6 +251,8 @@ int mt9f002_pgm_detectsensor (int sensor_port, ///< sensor port
    struct sensor_port_config_t *pcfg;
    struct sensor_port_config_t *pcfg;
    const char *name;
    const char *name;
    x393_i2c_device_t * dc;
    x393_i2c_device_t * dc;
    // disable SOF
    x393_sens_sync_mult_t dis_sof = {.d32=0};


    //struct sensor_port_config_t pcfg;
    //struct sensor_port_config_t pcfg;
    //pcfg = pSensorPortConfig[sensor_port];
    //pcfg = pSensorPortConfig[sensor_port];
@@ -277,6 +279,9 @@ int mt9f002_pgm_detectsensor (int sensor_port, ///< sensor port
    	psensor->i2c_addr = dc->slave7;
    	psensor->i2c_addr = dc->slave7;
    }
    }


    dis_sof.dis_sof = 1;
    x393_sens_sync_mult(dis_sof,sensor_port);

    // set control lines
    // set control lines
    sensio_ctl.mrst = 1;
    sensio_ctl.mrst = 1;
    sensio_ctl.mrst_set = 1;
    sensio_ctl.mrst_set = 1;
@@ -293,8 +298,8 @@ int mt9f002_pgm_detectsensor (int sensor_port, ///< sensor port
    sensio_ctl.mmcm_rst = 0;
    sensio_ctl.mmcm_rst = 0;
    x393_sensio_ctrl(sensio_ctl,sensor_port);
    x393_sensio_ctrl(sensio_ctl,sensor_port);


    // what's this? commented out and it still works. 2018/02/13
    // delay until sensor gets responsive to i2c commands
    udelay(50); // is it needed?
    udelay(100);


    X3X3_I2C_RCV2(sensor_port, psensor->i2c_addr, P_REG_MT9F002_MODEL_ID, &i2c_read_dataw);
    X3X3_I2C_RCV2(sensor_port, psensor->i2c_addr, P_REG_MT9F002_MODEL_ID, &i2c_read_dataw);
    dev_dbg(g_dev_ptr,"Read i2c (port = %d, sa7=0x%lx, reg=0x%x) chip ID=%x\n",sensor_port, psensor->i2c_addr, P_REG_MT9F002_MODEL_ID, i2c_read_dataw);
    dev_dbg(g_dev_ptr,"Read i2c (port = %d, sa7=0x%lx, reg=0x%x) chip ID=%x\n",sensor_port, psensor->i2c_addr, P_REG_MT9F002_MODEL_ID, i2c_read_dataw);
@@ -343,7 +348,7 @@ int mt9f002_pgm_detectsensor (int sensor_port, ///< sensor port
int mt9f002_phases_program_phase(int sensor_port, int phase){
int mt9f002_phases_program_phase(int sensor_port, int phase){


	int i;
	int i;
	int read_phase = 0x5555;
	int read_phase = 0;
	struct sensor_port_config_t *pcfg;
	struct sensor_port_config_t *pcfg;
	const char *name;
	const char *name;
	int wr_full;
	int wr_full;
@@ -351,38 +356,13 @@ int mt9f002_phases_program_phase(int sensor_port, int phase){
	pcfg = &pSensorPortConfig[sensor_port];
	pcfg = &pSensorPortConfig[sensor_port];
	name = get_name_by_code(pcfg->sensor[0],DETECT_SENSOR);
	name = get_name_by_code(pcfg->sensor[0],DETECT_SENSOR);


	//x393_xi2c_write_reg(name,sensor_port,0,P_REG_MT9F002_HISPI_TIMING,phase);
	// sa7 is not used anymore

	wr_full = x393_xi2c_ready_wr(sensor_port);
	if (wr_full==0){
		pr_err("{%d} I2C sequencer is FULL1 for target 0x%04x\n",sensor_port,phase);
	}

	X3X3_I2C_SEND2_ASAP(sensor_port,0x0,P_MT9F002_HISPI_TIMING,phase);
	X3X3_I2C_SEND2_ASAP(sensor_port,0x0,P_MT9F002_HISPI_TIMING,phase);
	x393_xi2c_wait_wr(sensor_port);

	for(i=0;i<32;i++){

		wr_full = x393_xi2c_ready_wr(sensor_port);
		if (wr_full==0){
			pr_err("{%d} I2C sequencer is FULL2 for target 0x%04x\n",sensor_port,phase);
		}


	X3X3_I2C_RCV2(sensor_port, 0x10, P_REG_MT9F002_HISPI_TIMING, &read_phase);
	X3X3_I2C_RCV2(sensor_port, 0x10, P_REG_MT9F002_HISPI_TIMING, &read_phase);
		if (read_phase==phase){
	if (read_phase!=phase){
			break;
		pr_err("{%d} i2c write error, target value = 0x%04x, read value = 0x%04x \n",sensor_port,phase,read_phase);
		}
		pr_err("{%d} write error, target value = 0x%04x, read value = 0x%04x \n",sensor_port,phase,read_phase);
		// write retry
		if ((i&0x7)==0x7) {
			pr_err("{%d} write retry: 0x%04x\n",sensor_port,phase);
			X3X3_I2C_SEND2_ASAP(sensor_port,0x0,P_MT9F002_HISPI_TIMING,phase);
			x393_xi2c_wait_wr(sensor_port);
	}
	}


		udelay(100);
	}
	return 0;
	return 0;
}
}


@@ -425,41 +405,36 @@ int mt9f002_phases_read_flags(int sensor_port,int shift){


int mt9f002_phases_scan_lane(int sensor_port, int phase, int shift){
int mt9f002_phases_scan_lane(int sensor_port, int phase, int shift){


	int i,j;
	int i;
	int status;
	int status;
	const int clk_half_phase = 0x4000;
	const int clk_half_phase = 0x4000;


	int value = 0;
	int value = 0;
	bool switched = false;
	bool switched = false;
	// i where switched, 1 - first 8 steps, 2 - second 8 steps
	// i where switched, 1 - first 8 steps (and it's the middle phase),
	//                   2 - second 8 steps
	int i1 = 0;
	int i1 = 0;
	int i2 = 0;//8
	int i2 = 8;
	int im = 0;


	int old_phase = phase;
	int target_phase;
	int target_phase;


	int s[16];

	// 16 values: 8 for CLK phase 0 position CLK, 8 - for CLK phase 4 position
	// 16 values: 8 for CLK phase 0 position CLK, 8 - for CLK phase 4 position
	for(i=0;i<16;i++){
	for(i=0;i<16;i++){


		// clk phase
		// support clk phase range
		if (i==0){
		if (i==0){
			phase += clk_half_phase;
			phase += clk_half_phase;
		}
		}


		// main clk range
		if (i==8){
		if (i==8){
			phase -= clk_half_phase;
			phase -= clk_half_phase;
		}
		}


		target_phase = phase + ((i&0x7)<<(3*shift));
		target_phase = phase + ((i&0x7)<<(3*shift));
		mt9f002_phases_program_phase(sensor_port,target_phase);
		mt9f002_phases_program_phase(sensor_port,target_phase);
		old_phase = target_phase;


		// read status
		status = mt9f002_phases_read_flags(sensor_port,shift);
		status = mt9f002_phases_read_flags(sensor_port,shift);
		s[i] = status;


		if ((i==0)||(i==8)){
		if ((i==0)||(i==8)){
			value = status;
			value = status;
@@ -472,7 +447,7 @@ int mt9f002_phases_scan_lane(int sensor_port, int phase, int shift){
						value = status;
						value = status;
						i1 = i;
						i1 = i;
					}else{
					}else{
						pr_err("{%d} Unexpected phase shift at %d",sensor_port,i);
						pr_err("{%d} Lane D%d: unexpected phase shift at %d\n",sensor_port,shift,i);
					}
					}
				}else{
				}else{
					if (!switched){
					if (!switched){
@@ -480,28 +455,24 @@ int mt9f002_phases_scan_lane(int sensor_port, int phase, int shift){
						value = status;
						value = status;
						i2 = i;
						i2 = i;
					}else{
					}else{
						pr_err("{%d} Unexpected phase shift at %d",sensor_port,i);
						pr_err("{%d} Lane D%d: unexpected phase shift at %d\n",sensor_port,shift,i);
					}
					}
				}
				}
			}
			}
		}
		}
	}
	}


	dev_dbg(g_dev_ptr,"%d %d %d %d %d %d %d %d | %d %d %d %d %d %d %d %d\n",s[0],s[1],s[2],s[3],s[4],s[5],s[6],s[7],s[8],s[9],s[10],s[11],s[12],s[13],s[14],s[15]);
	i1 = i1&0x7;
	dev_dbg(g_dev_ptr,"i1 = %d, i2 = %d\n",i1,i2);
	i2 = i2&0x7;


	//i2 = i2&0x7;
	// just a check
	/*
	if (abs(i2-i1)<2){
	if (i2<i1){
		pr_err("{%d} Warning: optimal phase shift (lane D%d) is probably not correct (difference = %d)",sensor_port,shift,i2);
		i2 += 8;
	}
	}
	*/
	im = ((i1+i2)>>1)&0x7;
	//im = (i2-4)&0x7;


	target_phase = phase + (im<<(3*shift));
	target_phase = phase + (i1<<(3*shift));


	dev_dbg(g_dev_ptr,"mid phase: %d (target phase = 0x%04x)",im,target_phase);
	dev_dbg(g_dev_ptr,"{%d} lane D%d mid phase = %d (target phase = 0x%04x)",sensor_port,shift,i1,target_phase);


	// apply center phase
	// apply center phase
	mt9f002_phases_program_phase(sensor_port,target_phase);
	mt9f002_phases_program_phase(sensor_port,target_phase);
@@ -576,8 +547,7 @@ int mt9f002_pgm_initsensor (int sensor_port, ///< sensor port
{
{
	int i;
	int i;
	int n;
	int n;
	u8 page, haddr, laddr;
	x393_sens_sync_mult_t dis_sof = {.d32=0};
	u16 data;


	//dev_dbg(g_dev_ptr,"{%d}  frame16=%d\n",sensor_port,frame16);
	//dev_dbg(g_dev_ptr,"{%d}  frame16=%d\n",sensor_port,frame16);
	// sensor is silent before init - this check is redundant
	// sensor is silent before init - this check is redundant
@@ -593,24 +563,22 @@ int mt9f002_pgm_initsensor (int sensor_port, ///< sensor port
	n = sizeof(mt9f002_inits)/4; // 4 bytes per pair
	n = sizeof(mt9f002_inits)/4; // 4 bytes per pair


	for(i=0;i<n;i++){
	for(i=0;i<n;i++){

		// sa7 is not used
		//haddr = (mt9f002_inits[2*i]>>8)&0xff;
		X3X3_I2C_SEND2_ASAP(sensor_port,0x0,mt9f002_inits[2*i],mt9f002_inits[2*i+1]);
		//laddr =  mt9f002_inits[2*i]&0xff;
		//data  =  mt9f002_inits[2*i+1];
		//page  = pSensorPortConfig[sensor_port].haddr2rec[0][haddr];
		// write immediately
		//dev_dbg(g_dev_ptr,"{%d} init sensor: writing 0x%04x to register 0x%02x%02x\n",sensor_port,data,haddr,laddr);
		//write_xi2c_reg16(sensor_port,page,laddr,data);

		X3X3_I2C_SEND2_ASAP(sensor_port,sensor->i2c_addr,mt9f002_inits[2*i],mt9f002_inits[2*i+1]);

	}
	}


	// soft reset
	// sa7 is not used
	X3X3_I2C_SEND2_ASAP(sensor_port,0x0,P_MT9F002_RESET_REGISTER,MT9F002_RESET_REGISTER_VALUE);
	// delay (needed?)
	udelay(100);

	// sensor is supposed to be streaming by now
	// sensor is supposed to be streaming by now
	mt9f002_phases_adjust(sensor_port);
	mt9f002_phases_adjust(sensor_port);


	// extra reset?
	// restore SOF (disabled in pgm_detect)
	//X3X3_I2C_SEND2_ASAP(sensor_port,sensor->i2c_addr,P_MT9F002_RESET_REGISTER,0x001c);
	dis_sof.dis_sof = 0;
	x393_sens_sync_mult(dis_sof,sensor_port);


	// init register shadows here
	// init register shadows here


+2 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,8 @@
#define MT9F002_PARTID     0x2E01 ///< MT9F002 PartID register value
#define MT9F002_PARTID     0x2E01 ///< MT9F002 PartID register value
#define MT9F002_I2C_ADDR     0x10 ///< MT9P I2C slave address (7 bit)
#define MT9F002_I2C_ADDR     0x10 ///< MT9P I2C slave address (7 bit)


#define MT9F002_RESET_REGISTER_VALUE 0x001c

/* ON Semi MT9F002 i2c register addresses */
/* ON Semi MT9F002 i2c register addresses */


/*
/*
+6 −5
Original line number Original line Diff line number Diff line
@@ -1176,8 +1176,10 @@ int fpga_register_i2c_pages(int port, int sub_chn, x393_i2c_device_t i2c_dev){


		haddr = (table[i]>>8)&0xff;
		haddr = (table[i]>>8)&0xff;


		dev_dbg(g_dev_ptr,"Registering page %d for haddr= 0x%02x, sa7= 0x%02x\n",line_num, haddr, i2c_dev.slave7);

		if ((table[i]==0xffff)||(i>255)){
		if ((table[i]==0xffff)||(i>255)){
			dev_dbg(g_dev_ptr,"haddr2rec table registered (number of entries: %d)\n",i);
			dev_dbg(g_dev_ptr,"haddr2rec (entries: %d)\n",i);
			break;
			break;
		}
		}


@@ -1186,16 +1188,16 @@ int fpga_register_i2c_pages(int port, int sub_chn, x393_i2c_device_t i2c_dev){


			line_num = i2c_page_alloc(port);
			line_num = i2c_page_alloc(port);
			if (line_num<0){
			if (line_num<0){
				pr_err("{%d} Error registering page %d (haddr = 0x%02x)\n",port,line_num,haddr);
				return line_num;
				return line_num;
			}
			}


			dev_dbg(g_dev_ptr,"Registering page %d for haddr=0x%02x. slave7= 0x%02x\n",line_num, haddr, i2c_dev.slave7);

			//line_num = i2c_dev.slave7;
			//line_num = i2c_dev.slave7;
			//haddr = 0;
			//haddr = 0;


			h2r[haddr] = line_num;
			h2r[haddr] = line_num;
			i2c_page_register(port,line_num);
			// i2c_page_alloc does it
			//i2c_page_register(port,line_num);
			set_xi2c_wrc(&i2c_dev,port,line_num,haddr);
			set_xi2c_wrc(&i2c_dev,port,line_num,haddr);
		}
		}
		i++;
		i++;
@@ -1255,7 +1257,6 @@ int register_i2c_sensor(int ports_mask) ///< bitmask of the sensor ports to use
		    class_mux = xi2c_dev_get(name);
		    class_mux = xi2c_dev_get(name);


		    // TODO: request a line# from fpga table and register it (not class_mux->slave7)
		    // TODO: request a line# from fpga table and register it (not class_mux->slave7)
		    dev_dbg(g_dev_ptr,"Registering page %d for haddr=0x%02x. slave7= 0x%02x\n",class_mux->slave7, 0, class_mux->slave7);
		    i2c_page_register(port, class_mux->slave7);
		    i2c_page_register(port, class_mux->slave7);
		    set_xi2c_wrc(class_mux, port, class_mux->slave7, 0);
		    set_xi2c_wrc(class_mux, port, class_mux->slave7, 0);
		}
		}
+5 −2
Original line number Original line Diff line number Diff line
@@ -52,7 +52,7 @@
#define SYSFS_WRITEONLY           0222
#define SYSFS_WRITEONLY           0222


//#define DRV_NAME "elphel_sensor_i2c"
//#define DRV_NAME "elphel_sensor_i2c"
// FIXME: Warnoings in softtirq.c, do not understand why. using LOCK_BH_SENSORI2C to enable spin_lock_bh, otherwise use spin_lock_irqsave
// FIXME: Warnings in softtirq.c, do not understand why. using LOCK_BH_SENSORI2C to enable spin_lock_bh, otherwise use spin_lock_irqsave
#undef LOCK_BH_SENSORI2C
#undef LOCK_BH_SENSORI2C
struct x393_i2c_device_list {
struct x393_i2c_device_list {
    x393_i2c_device_t i2c_dev;
    x393_i2c_device_t i2c_dev;
@@ -755,6 +755,8 @@ int read_xi2c_fifo(int chn) ///< sensor port
    int fifo_lsb, rslt,i;
    int fifo_lsb, rslt,i;
    x393_i2c_ctltbl_t i2c_cmd;
    x393_i2c_ctltbl_t i2c_cmd;
    x393_status_sens_i2c_t  status;
    x393_status_sens_i2c_t  status;
    x393_cmdseqmux_status_t  status2;

    i2c_autoupdate_status(chn);
    i2c_autoupdate_status(chn);
    status =  x393_sensi2c_status (chn);
    status =  x393_sensi2c_status (chn);
    //	dev_dbg(sdev, "read_xi2c_fifo(%d): status = 0x%08x\n",chn, (int) status.d32);
    //	dev_dbg(sdev, "read_xi2c_fifo(%d): status = 0x%08x\n",chn, (int) status.d32);
@@ -771,6 +773,7 @@ int read_xi2c_fifo(int chn) ///< sensor port
        if (likely(status.i2c_fifo_lsb != fifo_lsb)) break;
        if (likely(status.i2c_fifo_lsb != fifo_lsb)) break;
    }
    }
    dev_dbg(sdev, "read_xi2c_fifo(%d): new status = 0x%08x\n",chn, (int) status.d32);
    dev_dbg(sdev, "read_xi2c_fifo(%d): new status = 0x%08x\n",chn, (int) status.d32);
    status2 = x393_cmdseqmux_status();
    return rslt;
    return rslt;
}
}
EXPORT_SYMBOL_GPL(read_xi2c_fifo);
EXPORT_SYMBOL_GPL(read_xi2c_fifo);