Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a975a527 authored by Hans de Goede's avatar Hans de Goede Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (8366): gspca: Better code for ov6650 and ov7630.



sonixb:   Common code between ov6650 and ov7630.
          Fix brightness oscillation with ov6650 sensor.

Signed-off-by: default avatarHans de Goede <j.w.r.degoede@hhs.nl>
Signed-off-by: default avatarJean-Francois Moine <moinejf@free.fr>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 66f35821
Loading
Loading
Loading
Loading
+34 −57
Original line number Original line Diff line number Diff line
@@ -48,7 +48,6 @@ struct sd {


	unsigned char fr_h_sz;		/* size of frame header */
	unsigned char fr_h_sz;		/* size of frame header */
	char sensor;			/* Type of image sensor chip */
	char sensor;			/* Type of image sensor chip */
	char sensor_has_gain;
#define SENSOR_HV7131R 0
#define SENSOR_HV7131R 0
#define SENSOR_OV6650 1
#define SENSOR_OV6650 1
#define SENSOR_OV7630 2
#define SENSOR_OV7630 2
@@ -57,6 +56,8 @@ struct sd {
#define SENSOR_PAS202 5
#define SENSOR_PAS202 5
#define SENSOR_TAS5110 6
#define SENSOR_TAS5110 6
#define SENSOR_TAS5130CXX 7
#define SENSOR_TAS5130CXX 7
	char sensor_has_gain;
	__u8 sensor_addr;
};
};


#define COMP2 0x8f
#define COMP2 0x8f
@@ -495,21 +496,14 @@ static void setbrightness(struct gspca_dev *gspca_dev)
	__u8 value;
	__u8 value;


	switch (sd->sensor) {
	switch (sd->sensor) {
	case SENSOR_OV6650: {
	case  SENSOR_OV6650:
		__u8 i2cOV6650[] =
			{0xa0, 0x60, 0x06, 0x11, 0x99, 0x04, 0x94, 0x15};

		i2cOV6650[3] = sd->brightness;
		if (i2c_w(gspca_dev, i2cOV6650) < 0)
			 goto err;
		break;
	    }
	case  SENSOR_OV7630_3:
	case  SENSOR_OV7630_3:
	case  SENSOR_OV7630: {
	case  SENSOR_OV7630: {
		__u8 i2cOV[] =
		__u8 i2cOV[] =
			{0xa0, 0x21, 0x06, 0x36, 0xbd, 0x06, 0xf6, 0x16};
			{0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};


		/* change reg 0x06 */
		/* change reg 0x06 */
		i2cOV[1] = sd->sensor_addr;
		i2cOV[3] = sd->brightness;
		i2cOV[3] = sd->brightness;
		if (i2c_w(gspca_dev, i2cOV) < 0)
		if (i2c_w(gspca_dev, i2cOV) < 0)
			goto err;
			goto err;
@@ -579,6 +573,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
static void setsensorgain(struct gspca_dev *gspca_dev)
static void setsensorgain(struct gspca_dev *gspca_dev)
{
{
	struct sd *sd = (struct sd *) gspca_dev;
	struct sd *sd = (struct sd *) gspca_dev;
	unsigned char gain = sd->gain;


	switch (sd->sensor) {
	switch (sd->sensor) {


@@ -586,23 +581,20 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
		__u8 i2c[] =
		__u8 i2c[] =
			{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
			{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};


		i2c[4] = 255 - sd->gain;
		i2c[4] = 255 - gain;
		if (i2c_w(gspca_dev, i2c) < 0)
		if (i2c_w(gspca_dev, i2c) < 0)
			goto err;
			goto err;
		break;
		break;
	    }
	    }
	case SENSOR_OV6650: {
		__u8 i2c[] = {0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};


		i2c[3] = sd->gain >> 3;
	case SENSOR_OV6650:
		if (i2c_w(gspca_dev, i2c) < 0)
		gain >>= 1;
			goto err;
		/* fall thru */
		break;
	    }
	case SENSOR_OV7630_3: {
	case SENSOR_OV7630_3: {
		__u8 i2c[] = {0xa0, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
		__u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};


		i2c[3] = sd->gain >> 2;
		i2c[1] = sd->sensor_addr;
		i2c[3] = gain >> 2;
		if (i2c_w(gspca_dev, i2c) < 0)
		if (i2c_w(gspca_dev, i2c) < 0)
			goto err;
			goto err;
		break;
		break;
@@ -652,9 +644,10 @@ static void setexposure(struct gspca_dev *gspca_dev)
		reg_w(gspca_dev, 0x19, &reg, 1);
		reg_w(gspca_dev, 0x19, &reg, 1);
		break;
		break;
	    }
	    }
	case SENSOR_OV6650: {
	case SENSOR_OV6650:
		/* The ov6650 has 2 registers which both influence exposure,
	case SENSOR_OV7630_3: {
		   first there is register 11, whose low nibble sets the no fps
		/* The ov6650 / ov7630 have 2 registers which both influence
		   exposure, register 11, whose low nibble sets the nr off fps
		   according to: fps = 30 / (low_nibble + 1)
		   according to: fps = 30 / (low_nibble + 1)


		   The fps configures the maximum exposure setting, but it is
		   The fps configures the maximum exposure setting, but it is
@@ -667,15 +660,15 @@ static void setexposure(struct gspca_dev *gspca_dev)
		   The code maps our 0 - 510 ms exposure ctrl to these 2
		   The code maps our 0 - 510 ms exposure ctrl to these 2
		   registers, trying to keep fps as high as possible.
		   registers, trying to keep fps as high as possible.
		*/
		*/
		__u8 i2c[] = {0xb0, 0x60, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
		__u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
		int reg10, reg11;
		int reg10, reg11;
		/* ov6645 datasheet says reg10_max is 9a, but that uses
		/* ov6645 datasheet says reg10_max is 9a, but that uses
		   tline * 2 * reg10 as formula for calculating texpo, the
		   tline * 2 * reg10 as formula for calculating texpo, the
		   ov6650 probably uses the same formula as the 7730 which uses
		   ov6650 probably uses the same formula as the 7730 which uses
		   tline * 4 * reg10, which explains why the reg10max we've
		   tline * 4 * reg10, which explains why the reg10max we've
		   found experimentally for the ov6650 is exactly half that of
		   found experimentally for the ov6650 is exactly half that of
		   the ov6645. */
		   the ov6645. The ov7630 datasheet says the max is 0x41. */
		const int reg10_max = 0x4d;
		const int reg10_max = (sd->sensor == SENSOR_OV6650)? 0x4d:0x41;


		reg11 = (60 * sd->exposure + 999) / 1000;
		reg11 = (60 * sd->exposure + 999) / 1000;
		if (reg11 < 1)
		if (reg11 < 1)
@@ -686,40 +679,18 @@ static void setexposure(struct gspca_dev *gspca_dev)
		/* frame exposure time in ms = 1000 * reg11 / 30    ->
		/* frame exposure time in ms = 1000 * reg11 / 30    ->
		reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
		reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
		reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
		reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
		if (reg10 < 1) /* 0 is a valid value, but is very _black_ */
			reg10 = 1;
		else if (reg10 > reg10_max)
			reg10 = reg10_max;


		/* Write reg 10 and reg11 low nibble */
		/* Don't allow this to get below 10 when using autogain, the
		i2c[3] = reg10;
		   steps become very large (relatively) when below 10 causing
		i2c[4] |= reg11 - 1;
		   the image to oscilate from much too dark, to much too bright
		if (i2c_w(gspca_dev, i2c) < 0)
		   and back again. */
			PDEBUG(D_ERR, "i2c error exposure");
		if (sd->autogain && reg10 < 10)
		break;
			reg10 = 10;
	    }
	case SENSOR_OV7630_3: {
		__u8 i2c[] = {0xb0, 0x21, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10};
		int reg10, reg11;
		/* No clear idea why, but setting reg10 above this value
		   results in no change */
		const int reg10_max = 0x4d;

		reg11 = (60 * sd->exposure + 999) / 1000;
		if (reg11 < 1)
			reg11 = 1;
		else if (reg11 > 16)
			reg11 = 16;

		/* frame exposure time in ms = 1000 * reg11 / 30    ->
		reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */
		reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11);
		if (reg10 < 1) /* 0 is a valid value, but is very _black_ */
			reg10 = 1;
		else if (reg10 > reg10_max)
		else if (reg10 > reg10_max)
			reg10 = reg10_max;
			reg10 = reg10_max;


		/* Write reg 10 and reg11 low nibble */
		/* Write reg 10 and reg11 low nibble */
		i2c[1] = sd->sensor_addr;
		i2c[3] = reg10;
		i2c[3] = reg10;
		i2c[4] |= reg11 - 1;
		i2c[4] |= reg11 - 1;
		if (i2c_w(gspca_dev, i2c) < 0)
		if (i2c_w(gspca_dev, i2c) < 0)
@@ -770,9 +741,12 @@ static void do_autogain(struct gspca_dev *gspca_dev)
		sd->autogain_ignore_frames--;
		sd->autogain_ignore_frames--;
	else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
	else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
			sd->brightness * DESIRED_AVG_LUM / 127,
			sd->brightness * DESIRED_AVG_LUM / 127,
			AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE))
			AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE)) {
		PDEBUG(D_FRAM, "autogain: gain changed: gain: %d expo: %d\n",
			(int)sd->gain, (int)sd->exposure);
		sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
		sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
	}
	}
}


/* this function is called at probe time */
/* this function is called at probe time */
static int sd_config(struct gspca_dev *gspca_dev,
static int sd_config(struct gspca_dev *gspca_dev,
@@ -814,6 +788,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
		case 0x6011:			/* SN9C101 - SN9C101G */
		case 0x6011:			/* SN9C101 - SN9C101G */
			sd->sensor = SENSOR_OV6650;
			sd->sensor = SENSOR_OV6650;
			sd->sensor_has_gain = 1;
			sd->sensor_has_gain = 1;
			sd->sensor_addr = 0x60;
			sd->sd_desc.nctrls = 4;
			sd->sd_desc.nctrls = 4;
			sd->sd_desc.dq_callback = do_autogain;
			sd->sd_desc.dq_callback = do_autogain;
			sif = 1;
			sif = 1;
@@ -822,9 +797,11 @@ static int sd_config(struct gspca_dev *gspca_dev,
		case 0x602c:			/* SN9C102 */
		case 0x602c:			/* SN9C102 */
		case 0x602e:			/* SN9C102 */
		case 0x602e:			/* SN9C102 */
			sd->sensor = SENSOR_OV7630;
			sd->sensor = SENSOR_OV7630;
			sd->sensor_addr = 0x21;
			break;
			break;
		case 0x60b0:			/* SN9C103 */
		case 0x60b0:			/* SN9C103 */
			sd->sensor = SENSOR_OV7630_3;
			sd->sensor = SENSOR_OV7630_3;
			sd->sensor_addr = 0x21;
			sd->fr_h_sz = 18;	/* size of frame header */
			sd->fr_h_sz = 18;	/* size of frame header */
			sd->sensor_has_gain = 1;
			sd->sensor_has_gain = 1;
			sd->sd_desc.nctrls = 4;
			sd->sd_desc.nctrls = 4;