V4L/DVB (8366): gspca: Better code for ov6650 and ov7630.
authorHans de Goede <j.w.r.degoede@hhs.nl>
Wed, 16 Jul 2008 18:29:11 +0000 (15:29 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Sun, 20 Jul 2008 10:27:19 +0000 (07:27 -0300)
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>
drivers/media/video/gspca/sonixb.c

index 51435e3dbb1020489b39ac0e3a18bae4912c78fa..4625a464a547e996dd8b7917c00430a53c68546e 100644 (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 @@ err:
 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;