diff options
| author | Hans de Goede <hdegoede@redhat.com> | 2010-02-17 09:59:19 -0500 |
|---|---|---|
| committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-02-26 13:11:09 -0500 |
| commit | 5fb2dde28122e74bbab9dae3cc04bcbc8c08b332 (patch) | |
| tree | aaea47e29bf8a3783d5112c5000b3d4974f27e67 | |
| parent | 0e4b91c30605ae030d4ff63c5160e54c1bc2682c (diff) | |
V4L/DVB: gspca_pac7302: much improved exposure control
My experience with fixing up the controls for the PAS sensors in
sonixb, has lead me to re-investigate the exposure control for the
pac7302. I've now found a regular exposure register in register bank 3
(which seems to be the sensor registers bank), and with this added a proper
fine grained exposure control. This patch also updates the do_autogain
function to work properly with this new finer grained control.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
| -rw-r--r-- | drivers/media/video/gspca/pac7302.c | 105 | ||||
| -rw-r--r-- | drivers/media/video/gspca/pac_common.h | 9 |
2 files changed, 54 insertions, 60 deletions
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c index 19f0cd892dba..2a68220d1ada 100644 --- a/drivers/media/video/gspca/pac7302.c +++ b/drivers/media/video/gspca/pac7302.c | |||
| @@ -24,33 +24,26 @@ | |||
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | /* Some documentation about various registers as determined by trial and error. | 26 | /* Some documentation about various registers as determined by trial and error. |
| 27 | When the register addresses differ between the 7202 and the 7311 the 2 | ||
| 28 | different addresses are written as 7302addr/7311addr, when one of the 2 | ||
| 29 | addresses is a - sign that register description is not valid for the | ||
| 30 | matching IC. | ||
| 31 | 27 | ||
| 32 | Register page 1: | 28 | Register page 1: |
| 33 | 29 | ||
| 34 | Address Description | 30 | Address Description |
| 35 | -/0x08 Unknown compressor related, must always be 8 except when not | ||
| 36 | in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 ! | ||
| 37 | -/0x1b Auto white balance related, bit 0 is AWB enable (inverted) | ||
| 38 | bits 345 seem to toggle per color gains on/off (inverted) | ||
| 39 | 0x78 Global control, bit 6 controls the LED (inverted) | 31 | 0x78 Global control, bit 6 controls the LED (inverted) |
| 40 | -/0x80 JPEG compression ratio ? Best not touched | ||
| 41 | 32 | ||
| 42 | Register page 3/4: | 33 | Register page 3: |
| 43 | 34 | ||
| 44 | Address Description | 35 | Address Description |
| 45 | 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on | 36 | 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on |
| 46 | the 7302, so one of 3, 6, 9, ..., except when between 6 and 12? | 37 | the 7302, so one of 3, 6, 9, ..., except when between 6 and 12? |
| 47 | -/0x0f Master gain 1-245, low value = high gain | 38 | 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps |
| 48 | 0x10/- Master gain 0-31 | 39 | 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps, |
| 49 | -/0x10 Another gain 0-15, limited influence (1-2x gain I guess) | 40 | 63 -> ~27 fps, the 2 msb's must always be 1 !! |
| 41 | 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0: | ||
| 42 | 1 -> ~30 fps, 2 -> ~20 fps | ||
| 43 | 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time | ||
| 44 | 0x0f Exposure bit 8, 0-448, 448 = no exposure at all | ||
| 45 | 0x10 Master gain 0-31 | ||
| 50 | 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused | 46 | 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused |
| 51 | -/0x27 Seems to toggle various gains on / off, Setting bit 7 seems to | ||
| 52 | completely disable the analog amplification block. Set to 0x68 | ||
| 53 | for max gain, 0x14 for minimal gain. | ||
| 54 | 47 | ||
| 55 | The registers are accessed in the following functions: | 48 | The registers are accessed in the following functions: |
| 56 | 49 | ||
| @@ -89,8 +82,8 @@ struct sd { | |||
| 89 | unsigned char red_balance; | 82 | unsigned char red_balance; |
| 90 | unsigned char blue_balance; | 83 | unsigned char blue_balance; |
| 91 | unsigned char gain; | 84 | unsigned char gain; |
| 92 | unsigned char exposure; | ||
| 93 | unsigned char autogain; | 85 | unsigned char autogain; |
| 86 | unsigned short exposure; | ||
| 94 | __u8 hflip; | 87 | __u8 hflip; |
| 95 | __u8 vflip; | 88 | __u8 vflip; |
| 96 | u8 flags; | 89 | u8 flags; |
| @@ -128,7 +121,6 @@ static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); | |||
| 128 | static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); | 121 | static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); |
| 129 | 122 | ||
| 130 | static const struct ctrl sd_ctrls[] = { | 123 | static const struct ctrl sd_ctrls[] = { |
| 131 | /* This control is pac7302 only */ | ||
| 132 | { | 124 | { |
| 133 | { | 125 | { |
| 134 | .id = V4L2_CID_BRIGHTNESS, | 126 | .id = V4L2_CID_BRIGHTNESS, |
| @@ -144,7 +136,6 @@ static const struct ctrl sd_ctrls[] = { | |||
| 144 | .set = sd_setbrightness, | 136 | .set = sd_setbrightness, |
| 145 | .get = sd_getbrightness, | 137 | .get = sd_getbrightness, |
| 146 | }, | 138 | }, |
| 147 | /* This control is for both the 7302 and the 7311 */ | ||
| 148 | { | 139 | { |
| 149 | { | 140 | { |
| 150 | .id = V4L2_CID_CONTRAST, | 141 | .id = V4L2_CID_CONTRAST, |
| @@ -160,7 +151,6 @@ static const struct ctrl sd_ctrls[] = { | |||
| 160 | .set = sd_setcontrast, | 151 | .set = sd_setcontrast, |
| 161 | .get = sd_getcontrast, | 152 | .get = sd_getcontrast, |
| 162 | }, | 153 | }, |
| 163 | /* This control is pac7302 only */ | ||
| 164 | { | 154 | { |
| 165 | { | 155 | { |
| 166 | .id = V4L2_CID_SATURATION, | 156 | .id = V4L2_CID_SATURATION, |
| @@ -218,7 +208,6 @@ static const struct ctrl sd_ctrls[] = { | |||
| 218 | .set = sd_setbluebalance, | 208 | .set = sd_setbluebalance, |
| 219 | .get = sd_getbluebalance, | 209 | .get = sd_getbluebalance, |
| 220 | }, | 210 | }, |
| 221 | /* All controls below are for both the 7302 and the 7311 */ | ||
| 222 | { | 211 | { |
| 223 | { | 212 | { |
| 224 | .id = V4L2_CID_GAIN, | 213 | .id = V4L2_CID_GAIN, |
| @@ -241,11 +230,10 @@ static const struct ctrl sd_ctrls[] = { | |||
| 241 | .type = V4L2_CTRL_TYPE_INTEGER, | 230 | .type = V4L2_CTRL_TYPE_INTEGER, |
| 242 | .name = "Exposure", | 231 | .name = "Exposure", |
| 243 | .minimum = 0, | 232 | .minimum = 0, |
| 244 | #define EXPOSURE_MAX 255 | 233 | .maximum = 1023, |
| 245 | .maximum = EXPOSURE_MAX, | ||
| 246 | .step = 1, | 234 | .step = 1, |
| 247 | #define EXPOSURE_DEF 16 /* 32 ms / 30 fps */ | 235 | #define EXPOSURE_DEF 66 /* 33 ms / 30 fps */ |
| 248 | #define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */ | 236 | #define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */ |
| 249 | .default_value = EXPOSURE_DEF, | 237 | .default_value = EXPOSURE_DEF, |
| 250 | }, | 238 | }, |
| 251 | .set = sd_setexposure, | 239 | .set = sd_setexposure, |
| @@ -381,7 +369,7 @@ static const __u8 start_7302[] = { | |||
| 381 | #define SKIP 0xaa | 369 | #define SKIP 0xaa |
| 382 | /* page 3 - the value SKIP says skip the index - see reg_w_page() */ | 370 | /* page 3 - the value SKIP says skip the index - see reg_w_page() */ |
| 383 | static const __u8 page3_7302[] = { | 371 | static const __u8 page3_7302[] = { |
| 384 | 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16, | 372 | 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16, |
| 385 | 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00, | 373 | 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00, |
| 386 | 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 374 | 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 387 | 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00, | 375 | 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00, |
| @@ -653,23 +641,39 @@ static void setgain(struct gspca_dev *gspca_dev) | |||
| 653 | static void setexposure(struct gspca_dev *gspca_dev) | 641 | static void setexposure(struct gspca_dev *gspca_dev) |
| 654 | { | 642 | { |
| 655 | struct sd *sd = (struct sd *) gspca_dev; | 643 | struct sd *sd = (struct sd *) gspca_dev; |
| 656 | __u8 reg; | 644 | __u8 clockdiv; |
| 657 | 645 | __u16 exposure; | |
| 658 | /* register 2 of frame 3/4 contains the clock divider configuring the | 646 | |
| 659 | no fps according to the formula: 60 / reg. sd->exposure is the | 647 | /* register 2 of frame 3 contains the clock divider configuring the |
| 660 | desired exposure time in ms. */ | 648 | no fps according to the formula: 90 / reg. sd->exposure is the |
| 661 | reg = 120 * sd->exposure / 1000; | 649 | desired exposure time in 0.5 ms. */ |
| 662 | if (reg < 2) | 650 | clockdiv = (90 * sd->exposure + 1999) / 2000; |
| 663 | reg = 2; | 651 | |
| 664 | else if (reg > 63) | 652 | /* Note clockdiv = 3 also works, but when running at 30 fps, depending |
| 665 | reg = 63; | 653 | on the scene being recorded, the camera switches to another |
| 666 | 654 | quantization table for certain JPEG blocks, and we don't know how | |
| 667 | /* On the pac7302 reg2 MUST be a multiple of 3, so round it to | 655 | to decompress these blocks. So we cap the framerate at 15 fps */ |
| 668 | the nearest multiple of 3, except when between 6 and 12? */ | 656 | if (clockdiv < 6) |
| 669 | if (reg < 6 || reg > 12) | 657 | clockdiv = 6; |
| 670 | reg = ((reg + 1) / 3) * 3; | 658 | else if (clockdiv > 63) |
| 659 | clockdiv = 63; | ||
| 660 | |||
| 661 | /* reg2 MUST be a multiple of 3, except when between 6 and 12? | ||
| 662 | Always round up, otherwise we cannot get the desired frametime | ||
| 663 | using the partial frame time exposure control */ | ||
| 664 | if (clockdiv < 6 || clockdiv > 12) | ||
| 665 | clockdiv = ((clockdiv + 2) / 3) * 3; | ||
| 666 | |||
| 667 | /* frame exposure time in ms = 1000 * clockdiv / 90 -> | ||
| 668 | exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */ | ||
| 669 | exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv); | ||
| 670 | /* 0 = use full frametime, 448 = no exposure, reverse it */ | ||
| 671 | exposure = 448 - exposure; | ||
| 672 | |||
| 671 | reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ | 673 | reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ |
| 672 | reg_w(gspca_dev, 0x02, reg); | 674 | reg_w(gspca_dev, 0x02, clockdiv); |
| 675 | reg_w(gspca_dev, 0x0e, exposure & 0xff); | ||
| 676 | reg_w(gspca_dev, 0x0f, exposure >> 8); | ||
| 673 | 677 | ||
| 674 | /* load registers to sensor (Bit 0, auto clear) */ | 678 | /* load registers to sensor (Bit 0, auto clear) */ |
| 675 | reg_w(gspca_dev, 0x11, 0x01); | 679 | reg_w(gspca_dev, 0x11, 0x01); |
| @@ -756,22 +760,13 @@ static void do_autogain(struct gspca_dev *gspca_dev) | |||
| 756 | { | 760 | { |
| 757 | struct sd *sd = (struct sd *) gspca_dev; | 761 | struct sd *sd = (struct sd *) gspca_dev; |
| 758 | int avg_lum = atomic_read(&sd->avg_lum); | 762 | int avg_lum = atomic_read(&sd->avg_lum); |
| 759 | int desired_lum, deadzone; | 763 | int desired_lum; |
| 764 | const int deadzone = 30; | ||
| 760 | 765 | ||
| 761 | if (avg_lum == -1) | 766 | if (avg_lum == -1) |
| 762 | return; | 767 | return; |
| 763 | 768 | ||
| 764 | desired_lum = 270 + sd->brightness * 4; | 769 | desired_lum = 270 + sd->brightness; |
| 765 | /* Hack hack, with the 7202 the first exposure step is | ||
| 766 | pretty large, so if we're about to make the first | ||
| 767 | exposure increase make the deadzone large to avoid | ||
| 768 | oscilating */ | ||
| 769 | if (desired_lum > avg_lum && sd->gain == GAIN_DEF && | ||
| 770 | sd->exposure > EXPOSURE_DEF && | ||
| 771 | sd->exposure < 42) | ||
| 772 | deadzone = 90; | ||
| 773 | else | ||
| 774 | deadzone = 30; | ||
| 775 | 770 | ||
| 776 | if (sd->autogain_ignore_frames > 0) | 771 | if (sd->autogain_ignore_frames > 0) |
| 777 | sd->autogain_ignore_frames--; | 772 | sd->autogain_ignore_frames--; |
diff --git a/drivers/media/video/gspca/pac_common.h b/drivers/media/video/gspca/pac_common.h index 20f67d9b8c06..8462a7c1a338 100644 --- a/drivers/media/video/gspca/pac_common.h +++ b/drivers/media/video/gspca/pac_common.h | |||
| @@ -24,11 +24,10 @@ | |||
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | /* We calculate the autogain at the end of the transfer of a frame, at this | 26 | /* We calculate the autogain at the end of the transfer of a frame, at this |
| 27 | moment a frame with the old settings is being transmitted, and a frame is | 27 | moment a frame with the old settings is being captured and transmitted. So |
| 28 | being captured with the old settings. So if we adjust the autogain we must | 28 | if we adjust the gain or exposure we must ignore atleast the next frame for |
| 29 | ignore atleast the 2 next frames for the new settings to come into effect | 29 | the new settings to come into effect before doing any other adjustments. */ |
| 30 | before doing any other adjustments */ | 30 | #define PAC_AUTOGAIN_IGNORE_FRAMES 2 |
| 31 | #define PAC_AUTOGAIN_IGNORE_FRAMES 3 | ||
| 32 | 31 | ||
| 33 | static const unsigned char pac_sof_marker[5] = | 32 | static const unsigned char pac_sof_marker[5] = |
| 34 | { 0xff, 0xff, 0x00, 0xff, 0x96 }; | 33 | { 0xff, 0xff, 0x00, 0xff, 0x96 }; |
