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: Hans de Goede <j.w.r.degoede@hhs.nl>
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
This commit is contained in:
Hans de Goede 2008-07-16 15:29:11 -03:00 committed by Mauro Carvalho Chehab
parent 66f358211d
commit a975a5279e

View file

@ -48,7 +48,6 @@ struct sd {
unsigned char fr_h_sz; /* size of frame header */
char sensor; /* Type of image sensor chip */
char sensor_has_gain;
#define SENSOR_HV7131R 0
#define SENSOR_OV6650 1
#define SENSOR_OV7630 2
@ -57,6 +56,8 @@ struct sd {
#define SENSOR_PAS202 5
#define SENSOR_TAS5110 6
#define SENSOR_TAS5130CXX 7
char sensor_has_gain;
__u8 sensor_addr;
};
#define COMP2 0x8f
@ -495,21 +496,14 @@ static void setbrightness(struct gspca_dev *gspca_dev)
__u8 value;
switch (sd->sensor) {
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_OV6650:
case SENSOR_OV7630_3:
case SENSOR_OV7630: {
__u8 i2cOV[] =
{0xa0, 0x21, 0x06, 0x36, 0xbd, 0x06, 0xf6, 0x16};
{0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10};
/* change reg 0x06 */
i2cOV[1] = sd->sensor_addr;
i2cOV[3] = sd->brightness;
if (i2c_w(gspca_dev, i2cOV) < 0)
goto err;
@ -579,6 +573,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
static void setsensorgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
unsigned char gain = sd->gain;
switch (sd->sensor) {
@ -586,23 +581,20 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
__u8 i2c[] =
{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
i2c[4] = 255 - sd->gain;
i2c[4] = 255 - gain;
if (i2c_w(gspca_dev, i2c) < 0)
goto err;
break;
}
case SENSOR_OV6650: {
__u8 i2c[] = {0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
i2c[3] = sd->gain >> 3;
if (i2c_w(gspca_dev, i2c) < 0)
goto err;
break;
}
case SENSOR_OV6650:
gain >>= 1;
/* fall thru */
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)
goto err;
break;
@ -652,9 +644,10 @@ static void setexposure(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x19, &reg, 1);
break;
}
case SENSOR_OV6650: {
/* The ov6650 has 2 registers which both influence exposure,
first there is register 11, whose low nibble sets the no fps
case SENSOR_OV6650:
case SENSOR_OV7630_3: {
/* 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)
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
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;
/* ov6645 datasheet says reg10_max is 9a, but that uses
tline * 2 * reg10 as formula for calculating texpo, the
ov6650 probably uses the same formula as the 7730 which uses
tline * 4 * reg10, which explains why the reg10max we've
found experimentally for the ov6650 is exactly half that of
the ov6645. */
const int reg10_max = 0x4d;
the ov6645. The ov7630 datasheet says the max is 0x41. */
const int reg10_max = (sd->sensor == SENSOR_OV6650)? 0x4d:0x41;
reg11 = (60 * sd->exposure + 999) / 1000;
if (reg11 < 1)
@ -686,40 +679,18 @@ static void setexposure(struct gspca_dev *gspca_dev)
/* 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)
reg10 = reg10_max;
/* Write reg 10 and reg11 low nibble */
i2c[3] = reg10;
i2c[4] |= reg11 - 1;
if (i2c_w(gspca_dev, i2c) < 0)
PDEBUG(D_ERR, "i2c error exposure");
break;
}
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;
/* Don't allow this to get below 10 when using autogain, the
steps become very large (relatively) when below 10 causing
the image to oscilate from much too dark, to much too bright
and back again. */
if (sd->autogain && reg10 < 10)
reg10 = 10;
else if (reg10 > reg10_max)
reg10 = reg10_max;
/* Write reg 10 and reg11 low nibble */
i2c[1] = sd->sensor_addr;
i2c[3] = reg10;
i2c[4] |= reg11 - 1;
if (i2c_w(gspca_dev, i2c) < 0)
@ -770,8 +741,11 @@ static void do_autogain(struct gspca_dev *gspca_dev)
sd->autogain_ignore_frames--;
else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
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;
}
}
/* this function is called at probe time */
@ -814,6 +788,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
case 0x6011: /* SN9C101 - SN9C101G */
sd->sensor = SENSOR_OV6650;
sd->sensor_has_gain = 1;
sd->sensor_addr = 0x60;
sd->sd_desc.nctrls = 4;
sd->sd_desc.dq_callback = do_autogain;
sif = 1;
@ -822,9 +797,11 @@ static int sd_config(struct gspca_dev *gspca_dev,
case 0x602c: /* SN9C102 */
case 0x602e: /* SN9C102 */
sd->sensor = SENSOR_OV7630;
sd->sensor_addr = 0x21;
break;
case 0x60b0: /* SN9C103 */
sd->sensor = SENSOR_OV7630_3;
sd->sensor_addr = 0x21;
sd->fr_h_sz = 18; /* size of frame header */
sd->sensor_has_gain = 1;
sd->sd_desc.nctrls = 4;