aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2010-02-17 09:59:19 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-02-26 13:11:09 -0500
commit5fb2dde28122e74bbab9dae3cc04bcbc8c08b332 (patch)
treeaaea47e29bf8a3783d5112c5000b3d4974f27e67 /drivers/media
parent0e4b91c30605ae030d4ff63c5160e54c1bc2682c (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>
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/video/gspca/pac7302.c105
-rw-r--r--drivers/media/video/gspca/pac_common.h9
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);
128static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); 121static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
129 122
130static const struct ctrl sd_ctrls[] = { 123static 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() */
383static const __u8 page3_7302[] = { 371static 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)
653static void setexposure(struct gspca_dev *gspca_dev) 641static 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
33static const unsigned char pac_sof_marker[5] = 32static const unsigned char pac_sof_marker[5] =
34 { 0xff, 0xff, 0x00, 0xff, 0x96 }; 33 { 0xff, 0xff, 0x00, 0xff, 0x96 };