V4L/DVB: gspca_sonixb: pas106: fixup bright ctrl and add gain and exposure ctrls
authorHans de Goede <hdegoede@redhat.com>
Wed, 10 Feb 2010 21:57:40 +0000 (18:57 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 26 Feb 2010 18:11:09 +0000 (15:11 -0300)
Fixup brightness ctrl and add gain and exposure ctrls for PAS106B sensors,
this allows enabling autogain (done), and makes the cam usable in low light
conditions.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/gspca/sonixb.c

index 81a7dd6..43a7721 100644 (file)
@@ -188,8 +188,8 @@ static const struct ctrl sd_ctrls[] = {
                        .id = V4L2_CID_EXPOSURE,
                        .type = V4L2_CTRL_TYPE_INTEGER,
                        .name = "Exposure",
-#define EXPOSURE_DEF  66 /*  33 ms / 30 fps (except on PAS202) */
-#define EXPOSURE_KNEE 200 /* 100 ms / 10 fps (except on PAS202) */
+#define EXPOSURE_DEF  66 /*  33 ms / 30 fps (except on PASXXX) */
+#define EXPOSURE_KNEE 200 /* 100 ms / 10 fps (except on PASXXX) */
                        .minimum = 0,
                        .maximum = 1023,
                        .step = 1,
@@ -408,6 +408,30 @@ static const __u8 initPas106[] = {
        0x18, 0x10, 0x02, 0x02, 0x09, 0x07
 };
 /* compression 0x86 mckinit1 0x2b */
+
+/* "Known" PAS106B registers:
+  0x02 clock divider
+  0x03 Variable framerate bits 4-11
+  0x04 Var framerate bits 0-3, one must leave the 4 msb's at 0 !!
+       The variable framerate control must never be set lower then 300,
+       which sets the framerate at 90 / reg02, otherwise vsync is lost.
+  0x05 Shutter Time Line Offset, this can be used as an exposure control:
+       0 = use full frame time, 255 = no exposure at all
+       Note this may never be larger then "var-framerate control" / 2 - 2.
+       When var-framerate control is < 514, no exposure is reached at the max
+       allowed value for the framerate control value, rather then at 255.
+  0x06 Shutter Time Pixel Offset, like reg05 this influences exposure, but
+       only a very little bit, leave at 0xcd
+  0x07 offset sign bit (bit0 1 > negative offset)
+  0x08 offset
+  0x09 Blue Gain
+  0x0a Green1 Gain
+  0x0b Green2 Gain
+  0x0c Red Gain
+  0x0e Global gain
+  0x13 Write 1 to commit settings to sensor
+*/
+
 static const __u8 pas106_sensor_init[][8] = {
        /* Pixel Clock Divider 6 */
        { 0xa1, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x14 },
@@ -532,7 +556,7 @@ SENS(initHv7131, NULL, hv7131_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, 0),
 SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60),
 SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3,
        F_GAIN, 0, 0x21),
-SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_SIF, NO_EXPO|NO_FREQ,
+SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_GAIN|F_SIF, NO_FREQ,
        0),
 SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, F_GAIN,
        NO_FREQ, 0),
@@ -628,26 +652,19 @@ static void setbrightness(struct gspca_dev *gspca_dev)
                        goto err;
                break;
            }
-       case SENSOR_PAS106: {
-               __u8 i2c1[] =
-                       {0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14};
-
-               i2c1[3] = sd->brightness >> 3;
-               i2c1[2] = 0x0e;
-               if (i2c_w(gspca_dev, i2c1) < 0)
-                       goto err;
-               i2c1[3] = 0x01;
-               i2c1[2] = 0x13;
-               if (i2c_w(gspca_dev, i2c1) < 0)
-                       goto err;
-               break;
-           }
+       case SENSOR_PAS106:
        case SENSOR_PAS202: {
                __u8 i2cpbright[] =
                        {0xb0, 0x40, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x16};
-               const __u8 i2cpdoit[] =
+               __u8 i2cpdoit[] =
                        {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16};
 
+               /* PAS106 uses reg 7 and 8 instead of b and c */
+               if (sd->sensor == SENSOR_PAS106) {
+                       i2cpbright[2] = 7;
+                       i2cpdoit[2] = 0x13;
+               }
+
                if (sd->brightness < 127) {
                        /* change reg 0x0b, signreg */
                        i2cpbright[3] = 0x01;
@@ -709,18 +726,28 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
                        goto err;
                break;
            }
+       case SENSOR_PAS106:
        case SENSOR_PAS202: {
                __u8 i2cpgain[] =
-                       {0xa0, 0x40, 0x10, 0x00, 0x00, 0x00, 0x63, 0x15};
+                       {0xa0, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x15};
                __u8 i2cpcolorgain[] =
                        {0xc0, 0x40, 0x07, 0x00, 0x00, 0x00, 0x00, 0x15};
-               const __u8 i2cpdoit[] =
-                       {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x63, 0x16};
+               __u8 i2cpdoit[] =
+                       {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16};
+
+               /* PAS106 uses different regs (and has split green gains) */
+               if (sd->sensor == SENSOR_PAS106) {
+                       i2cpgain[2] = 0x0e;
+                       i2cpcolorgain[0] = 0xd0;
+                       i2cpcolorgain[2] = 0x09;
+                       i2cpdoit[2] = 0x13;
+               }
 
                i2cpgain[3] = sd->gain >> 3;
                i2cpcolorgain[3] = sd->gain >> 4;
                i2cpcolorgain[4] = sd->gain >> 4;
                i2cpcolorgain[5] = sd->gain >> 4;
+               i2cpcolorgain[6] = sd->gain >> 4;
 
                if (i2c_w(gspca_dev, i2cpgain) < 0)
                        goto err;
@@ -883,6 +910,38 @@ static void setexposure(struct gspca_dev *gspca_dev)
                        goto err;
                break;
            }
+       case SENSOR_PAS106: {
+               __u8 i2cpframerate[] =
+                       {0xb1, 0x40, 0x03, 0x00, 0x00, 0x00, 0x00, 0x14};
+               __u8 i2cpexpo[] =
+                       {0xa1, 0x40, 0x05, 0x00, 0x00, 0x00, 0x00, 0x14};
+               const __u8 i2cpdoit[] =
+                       {0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14};
+               int framerate_ctrl;
+
+               /* For values below 150 use partial frame exposure, above
+                  that use framerate ctrl */
+               if (sd->exposure < 150) {
+                       i2cpexpo[3] = 150 - sd->exposure;
+                       framerate_ctrl = 300;
+               } else {
+                       /* The PAS106's exposure control goes from 0 - 4095,
+                          but anything below 300 causes vsync issues, so scale
+                          our 150-1023 to 300-4095 */
+                       framerate_ctrl = (sd->exposure - 150) * 1000 / 230 +
+                                        300;
+               }
+
+               i2cpframerate[3] = framerate_ctrl >> 4;
+               i2cpframerate[4] = framerate_ctrl & 0x0f;
+               if (i2c_w(gspca_dev, i2cpframerate) < 0)
+                       goto err;
+               if (i2c_w(gspca_dev, i2cpexpo) < 0)
+                       goto err;
+               if (i2c_w(gspca_dev, i2cpdoit) < 0)
+                       goto err;
+               break;
+           }
        }
        return;
 err: