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:
Родитель
66f358211d
Коммит
a975a5279e
|
@ -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 @@ err:
|
||||||
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, ®, 1);
|
reg_w(gspca_dev, 0x19, ®, 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;
|
/* Don't allow this to get below 10 when using autogain, the
|
||||||
else if (reg10 > reg10_max)
|
steps become very large (relatively) when below 10 causing
|
||||||
reg10 = reg10_max;
|
the image to oscilate from much too dark, to much too bright
|
||||||
|
and back again. */
|
||||||
/* Write reg 10 and reg11 low nibble */
|
if (sd->autogain && reg10 < 10)
|
||||||
i2c[3] = reg10;
|
reg10 = 10;
|
||||||
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;
|
|
||||||
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,8 +741,11 @@ 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 */
|
||||||
|
@ -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;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче