aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2010-02-03 12:37:30 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-02-26 13:11:08 -0500
commit82e839c9c5f79c4e55dc1b6ecb2cf1c055f753c5 (patch)
treefda2c7a17923f3f5866857b80d6c5f9c179e208e /drivers/media/video
parent26984b09952d01afabaa38e747fbee083dde0374 (diff)
V4L/DVB: gspca_sonixb: pas202: fixup brightness ctrl and add gain and exposure ctrls
Fixup brightness ctrl and add gain and exposure ctrls for PAS202BCB 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>
Diffstat (limited to 'drivers/media/video')
-rw-r--r--drivers/media/video/gspca/sonixb.c170
1 files changed, 122 insertions, 48 deletions
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index dc2d88cdd4a2..66fffa345e7b 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -176,7 +176,7 @@ static const struct ctrl sd_ctrls[] = {
176 .maximum = 255, 176 .maximum = 255,
177 .step = 1, 177 .step = 1,
178#define GAIN_DEF 127 178#define GAIN_DEF 127
179#define GAIN_KNEE 200 179#define GAIN_KNEE 230
180 .default_value = GAIN_DEF, 180 .default_value = GAIN_DEF,
181 }, 181 },
182 .set = sd_setgain, 182 .set = sd_setgain,
@@ -188,10 +188,10 @@ static const struct ctrl sd_ctrls[] = {
188 .id = V4L2_CID_EXPOSURE, 188 .id = V4L2_CID_EXPOSURE,
189 .type = V4L2_CTRL_TYPE_INTEGER, 189 .type = V4L2_CTRL_TYPE_INTEGER,
190 .name = "Exposure", 190 .name = "Exposure",
191#define EXPOSURE_DEF 33 /* 33 ms / 30 fps */ 191#define EXPOSURE_DEF 66 /* 33 ms / 30 fps (except on PAS202) */
192#define EXPOSURE_KNEE 100 /* 100 ms / 10 fps */ 192#define EXPOSURE_KNEE 200 /* 100 ms / 10 fps (except on PAS202) */
193 .minimum = 0, 193 .minimum = 0,
194 .maximum = 511, 194 .maximum = 1023,
195 .step = 1, 195 .step = 1,
196 .default_value = EXPOSURE_DEF, 196 .default_value = EXPOSURE_DEF,
197 .flags = 0, 197 .flags = 0,
@@ -454,31 +454,41 @@ static const __u8 initPas202[] = {
454 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 454 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00,
455 0x00, 0x00, 455 0x00, 0x00,
456 0x00, 0x00, 0x00, 0x06, 0x03, 0x0a, 456 0x00, 0x00, 0x00, 0x06, 0x03, 0x0a,
457 0x28, 0x1e, 0x28, 0x89, 0x20, 457 0x28, 0x1e, 0x20, 0x89, 0x20,
458 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c 458 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
459}; 459};
460
461/* "Known" PAS202BCB registers:
462 0x02 clock divider
463 0x04 Variable framerate bits 6-11 (*)
464 0x05 Var framerate bits 0-5, one must leave the 2 msb's at 0 !!
465 0x07 Blue Gain
466 0x08 Green Gain
467 0x09 Red Gain
468 0x0b offset sign bit (bit0 1 > negative offset)
469 0x0c offset
470 0x0e Unknown image is slightly brighter when bit 0 is 0, if reg0f is 0 too,
471 leave at 1 otherwise we get a jump in our exposure control
472 0x0f Exposure 0-255, 0 = use full frame time, 255 = no exposure at all
473 0x10 Master gain 0 - 31
474 0x11 write 1 to apply changes
475 (*) The variable framerate control must never be set lower then 500
476 which sets the framerate at 30 / reg02, otherwise vsync is lost.
477*/
460static const __u8 pas202_sensor_init[][8] = { 478static const __u8 pas202_sensor_init[][8] = {
461 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10}, 479 /* Set the clock divider to 4 -> 30 / 4 = 7.5 fps, we would like
480 to set it lower, but for some reason the bridge starts missing
481 vsync's then */
482 {0xa0, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x10},
462 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10}, 483 {0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
463 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10}, 484 {0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
464 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x00, 0x32, 0x10}, 485 {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x01, 0x32, 0x10},
465 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10}, 486 {0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
466 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10}, 487 {0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
467 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10}, 488 {0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
468 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10}, 489 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
469 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10}, 490 {0xa0, 0x40, 0x03, 0x56, 0x01, 0x00, 0x63, 0x10},
470 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10}, 491 {0xa0, 0x40, 0x11, 0x01, 0x01, 0x00, 0x63, 0x10},
471 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x10},
472 {0xb0, 0x40, 0x0e, 0x00, 0x3d, 0x00, 0x63, 0x10},
473
474 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
475 {0xa0, 0x40, 0x10, 0x08, 0x3d, 0x00, 0x63, 0x15},
476 {0xa0, 0x40, 0x02, 0x04, 0x3d, 0x00, 0x63, 0x16},
477 {0xa0, 0x40, 0x11, 0x01, 0x3d, 0x00, 0x63, 0x16},
478 {0xb0, 0x40, 0x0e, 0x00, 0x31, 0x00, 0x63, 0x16},
479 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
480 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15},
481 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16},
482}; 492};
483 493
484static const __u8 initTas5110c[] = { 494static const __u8 initTas5110c[] = {
@@ -524,8 +534,8 @@ SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3,
524 F_GAIN, 0, 0x21), 534 F_GAIN, 0, 0x21),
525SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_SIF, NO_EXPO|NO_FREQ, 535SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_SIF, NO_EXPO|NO_FREQ,
526 0), 536 0),
527SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, 0, 537SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, F_GAIN,
528 NO_EXPO|NO_FREQ, 0), 538 NO_FREQ, 0),
529SENS(initTas5110c, NULL, tas5110_sensor_init, NULL, NULL, 539SENS(initTas5110c, NULL, tas5110_sensor_init, NULL, NULL,
530 F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0), 540 F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0),
531SENS(initTas5110d, NULL, tas5110_sensor_init, NULL, NULL, 541SENS(initTas5110d, NULL, tas5110_sensor_init, NULL, NULL,
@@ -633,27 +643,20 @@ static void setbrightness(struct gspca_dev *gspca_dev)
633 break; 643 break;
634 } 644 }
635 case SENSOR_PAS202: { 645 case SENSOR_PAS202: {
636 /* __u8 i2cpexpo1[] = 646 __u8 i2cpbright[] =
637 {0xb0, 0x40, 0x04, 0x07, 0x2a, 0x00, 0x63, 0x16}; */ 647 {0xb0, 0x40, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x16};
638 __u8 i2cpexpo[] = 648 const __u8 i2cpdoit[] =
639 {0xb0, 0x40, 0x0e, 0x01, 0xab, 0x00, 0x63, 0x16}; 649 {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16};
640 __u8 i2cp202[] = 650
641 {0xa0, 0x40, 0x10, 0x0e, 0x31, 0x00, 0x63, 0x15}; 651 if (sd->brightness < 127) {
642 static __u8 i2cpdoit[] = 652 /* change reg 0x0b, signreg */
643 {0xa0, 0x40, 0x11, 0x01, 0x31, 0x00, 0x63, 0x16}; 653 i2cpbright[3] = 0x01;
644 654 /* set reg 0x0c, offset */
645 /* change reg 0x10 */ 655 i2cpbright[4] = 127 - sd->brightness;
646 i2cpexpo[4] = 0xff - sd->brightness; 656 } else
647/* if(i2c_w(gspca_dev,i2cpexpo1) < 0) 657 i2cpbright[4] = sd->brightness - 127;
648 goto err; */ 658
649/* if(i2c_w(gspca_dev,i2cpdoit) < 0) 659 if (i2c_w(gspca_dev, i2cpbright) < 0)
650 goto err; */
651 if (i2c_w(gspca_dev, i2cpexpo) < 0)
652 goto err;
653 if (i2c_w(gspca_dev, i2cpdoit) < 0)
654 goto err;
655 i2cp202[3] = sd->brightness >> 3;
656 if (i2c_w(gspca_dev, i2cp202) < 0)
657 goto err; 660 goto err;
658 if (i2c_w(gspca_dev, i2cpdoit) < 0) 661 if (i2c_w(gspca_dev, i2cpdoit) < 0)
659 goto err; 662 goto err;
@@ -706,6 +709,27 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
706 goto err; 709 goto err;
707 break; 710 break;
708 } 711 }
712 case SENSOR_PAS202: {
713 __u8 i2cpgain[] =
714 {0xa0, 0x40, 0x10, 0x00, 0x00, 0x00, 0x63, 0x15};
715 __u8 i2cpcolorgain[] =
716 {0xc0, 0x40, 0x07, 0x00, 0x00, 0x00, 0x00, 0x15};
717 const __u8 i2cpdoit[] =
718 {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x63, 0x16};
719
720 i2cpgain[3] = sd->gain >> 3;
721 i2cpcolorgain[3] = sd->gain >> 4;
722 i2cpcolorgain[4] = sd->gain >> 4;
723 i2cpcolorgain[5] = sd->gain >> 4;
724
725 if (i2c_w(gspca_dev, i2cpgain) < 0)
726 goto err;
727 if (i2c_w(gspca_dev, i2cpcolorgain) < 0)
728 goto err;
729 if (i2c_w(gspca_dev, i2cpdoit) < 0)
730 goto err;
731 break;
732 }
709 } 733 }
710 return; 734 return;
711err: 735err:
@@ -779,7 +803,7 @@ static void setexposure(struct gspca_dev *gspca_dev)
779 } else 803 } else
780 reg10_max = 0x41; 804 reg10_max = 0x41;
781 805
782 reg11 = (30 * sd->exposure + 999) / 1000; 806 reg11 = (15 * sd->exposure + 999) / 1000;
783 if (reg11 < 1) 807 if (reg11 < 1)
784 reg11 = 1; 808 reg11 = 1;
785 else if (reg11 > 16) 809 else if (reg11 > 16)
@@ -791,8 +815,8 @@ static void setexposure(struct gspca_dev *gspca_dev)
791 reg11 = 3; 815 reg11 = 3;
792 816
793 /* frame exposure time in ms = 1000 * reg11 / 30 -> 817 /* frame exposure time in ms = 1000 * reg11 / 30 ->
794 reg10 = sd->exposure * reg10_max / (1000 * reg11 / 30) */ 818 reg10 = (sd->exposure / 2) * reg10_max / (1000 * reg11 / 30) */
795 reg10 = (sd->exposure * 30 * reg10_max) / (1000 * reg11); 819 reg10 = (sd->exposure * 15 * reg10_max) / (1000 * reg11);
796 820
797 /* Don't allow this to get below 10 when using autogain, the 821 /* Don't allow this to get below 10 when using autogain, the
798 steps become very large (relatively) when below 10 causing 822 steps become very large (relatively) when below 10 causing
@@ -815,10 +839,53 @@ static void setexposure(struct gspca_dev *gspca_dev)
815 if (i2c_w(gspca_dev, i2c) == 0) 839 if (i2c_w(gspca_dev, i2c) == 0)
816 sd->reg11 = reg11; 840 sd->reg11 = reg11;
817 else 841 else
818 PDEBUG(D_ERR, "i2c error exposure"); 842 goto err;
843 break;
844 }
845 case SENSOR_PAS202: {
846 __u8 i2cpframerate[] =
847 {0xb0, 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x16};
848 __u8 i2cpexpo[] =
849 {0xa0, 0x40, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x16};
850 const __u8 i2cpdoit[] =
851 {0xa0, 0x40, 0x11, 0x01, 0x00, 0x00, 0x00, 0x16};
852 int framerate_ctrl;
853
854 /* The exposure knee for the autogain algorithm is 200
855 (100 ms / 10 fps on other sensors), for values below this
856 use the control for setting the partial frame expose time,
857 above that use variable framerate. This way we run at max
858 framerate (640x480@7.5 fps, 320x240@10fps) until the knee
859 is reached. Using the variable framerate control above 200
860 is better then playing around with both clockdiv + partial
861 frame exposure times (like we are doing with the ov chips),
862 as that sometimes leads to jumps in the exposure control,
863 which are bad for auto exposure. */
864 if (sd->exposure < 200) {
865 i2cpexpo[3] = 255 - (sd->exposure * 255) / 200;
866 framerate_ctrl = 500;
867 } else {
868 /* The PAS202's exposure control goes from 0 - 4095,
869 but anything below 500 causes vsync issues, so scale
870 our 200-1023 to 500-4095 */
871 framerate_ctrl = (sd->exposure - 200) * 1000 / 229 +
872 500;
873 }
874
875 i2cpframerate[3] = framerate_ctrl >> 6;
876 i2cpframerate[4] = framerate_ctrl & 0x3f;
877 if (i2c_w(gspca_dev, i2cpframerate) < 0)
878 goto err;
879 if (i2c_w(gspca_dev, i2cpexpo) < 0)
880 goto err;
881 if (i2c_w(gspca_dev, i2cpdoit) < 0)
882 goto err;
819 break; 883 break;
820 } 884 }
821 } 885 }
886 return;
887err:
888 PDEBUG(D_ERR, "i2c error exposure");
822} 889}
823 890
824static void setfreq(struct gspca_dev *gspca_dev) 891static void setfreq(struct gspca_dev *gspca_dev)
@@ -965,9 +1032,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
965 reg12_19[6] = sn9c10x[0x18 - 1] | (mode << 4); 1032 reg12_19[6] = sn9c10x[0x18 - 1] | (mode << 4);
966 /* Special cases where reg 17 and or 19 value depends on mode */ 1033 /* Special cases where reg 17 and or 19 value depends on mode */
967 switch (sd->sensor) { 1034 switch (sd->sensor) {
968 case SENSOR_PAS202:
969 reg12_19[5] = mode ? 0x24 : 0x20;
970 break;
971 case SENSOR_TAS5130CXX: 1035 case SENSOR_TAS5130CXX:
972 /* probably not mode specific at all most likely the upper 1036 /* probably not mode specific at all most likely the upper
973 nibble of 0x19 is exposure (clock divider) just as with 1037 nibble of 0x19 is exposure (clock divider) just as with
@@ -1003,6 +1067,16 @@ static int sd_start(struct gspca_dev *gspca_dev)
1003 sensor_data[sd->sensor].sensor_bridge_init_size[ 1067 sensor_data[sd->sensor].sensor_bridge_init_size[
1004 sd->bridge]); 1068 sd->bridge]);
1005 1069
1070 /* Mode specific sensor setup */
1071 switch (sd->sensor) {
1072 case SENSOR_PAS202: {
1073 const __u8 i2cpclockdiv[] =
1074 {0xa0, 0x40, 0x02, 0x03, 0x00, 0x00, 0x00, 0x10};
1075 /* clockdiv from 4 to 3 (7.5 -> 10 fps) when in low res mode */
1076 if (mode)
1077 i2c_w(gspca_dev, i2cpclockdiv);
1078 }
1079 }
1006 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */ 1080 /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
1007 reg_w(gspca_dev, 0x15, &reg12_19[3], 2); 1081 reg_w(gspca_dev, 0x15, &reg12_19[3], 2);
1008 /* compression register */ 1082 /* compression register */