diff options
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/gspca/sonixb.c | 54 |
1 files changed, 43 insertions, 11 deletions
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index c0ce21fe85f7..7303df0dc16b 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -121,8 +121,8 @@ static struct ctrl sd_ctrls[] = { .id = V4L2_CID_EXPOSURE, .type = V4L2_CTRL_TYPE_INTEGER, .name = "Exposure", -#define EXPOSURE_DEF 0 -#define EXPOSURE_KNEE 176 /* 10 fps */ +#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */ +#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */ .minimum = 0, .maximum = 255, .step = 1, @@ -611,8 +611,6 @@ static void setgain(struct gspca_dev *gspca_dev) static void setexposure(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - /* translate 0 - 255 to a number of fps in a 30 - 1 scale */ - int fps = 30 - sd->exposure * 29 / 255; switch (sd->sensor) { case SENSOR_TAS5110: { @@ -621,19 +619,53 @@ static void setexposure(struct gspca_dev *gspca_dev) /* register 19's high nibble contains the sn9c10x clock divider The high nibble configures the no fps according to the formula: 60 / high_nibble. With a maximum of 30 fps */ - reg = 60 / fps; - if (reg > 15) + reg = 120 * sd->exposure / 1000; + if (reg < 2) + reg = 2; + else if (reg > 15) reg = 15; reg = (reg << 4) | 0x0b; reg_w(gspca_dev, 0x19, ®, 1); break; } case SENSOR_OV6650: { - __u8 i2c[] = {0xa0, 0x60, 0x11, 0xc0, 0x00, 0x00, 0x00, 0x10}; - i2c[3] = 30 / fps - 1; - if (i2c[3] > 15) - i2c[3] = 15; - i2c[3] |= 0xc0; + /* The ov6650 has 2 registers which both influence exposure, + first there is register 11, whose low nibble sets the no fps + according to: fps = 30 / (low_nibble + 1) + + The fps configures the maximum exposure setting, but it is + possible to use less exposure then what the fps maximum + allows by setting register 10. register 10 configures the + actual exposure as quotient of the full exposure, with 0 + being no exposure at all (not very usefull) and reg10_max + being max exposure possible at that framerate. + + 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}; + 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) + 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; |