aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca/spca561.c
diff options
context:
space:
mode:
authorJean-Francois Moine <moinejf@free.fr>2008-09-03 15:47:30 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-09-03 17:36:34 -0400
commit6c9d3c59e6fdb8dfadaf7ba38f1d0b64ff066b36 (patch)
tree0bf575ddbaddcea670bd183853bd7a490023a448 /drivers/media/video/gspca/spca561.c
parent5bb0f21a46281b021897d2c56d50685c1939b5ee (diff)
V4L/DVB (8669): gspca: Add white balance control for spca561 rev 012A.
Signed-off-by: Jean-Francois Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/gspca/spca561.c')
-rw-r--r--drivers/media/video/gspca/spca561.c110
1 files changed, 92 insertions, 18 deletions
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
index 1073ac3d2ec6..02e274452c46 100644
--- a/drivers/media/video/gspca/spca561.c
+++ b/drivers/media/video/gspca/spca561.c
@@ -34,6 +34,7 @@ struct sd {
34 34
35 unsigned short contrast; 35 unsigned short contrast;
36 __u8 brightness; 36 __u8 brightness;
37 __u8 white;
37 __u8 autogain; 38 __u8 autogain;
38 39
39 __u8 chip_revision; 40 __u8 chip_revision;
@@ -46,11 +47,12 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
46static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); 47static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
47static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); 48static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
48static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); 49static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
50static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val);
51static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val);
49static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); 52static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
50static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); 53static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
51 54
52static struct ctrl sd_ctrls[] = { 55static struct ctrl sd_ctrls[] = {
53#define SD_BRIGHTNESS 0
54 { 56 {
55 { 57 {
56 .id = V4L2_CID_BRIGHTNESS, 58 .id = V4L2_CID_BRIGHTNESS,
@@ -59,12 +61,12 @@ static struct ctrl sd_ctrls[] = {
59 .minimum = 0, 61 .minimum = 0,
60 .maximum = 63, 62 .maximum = 63,
61 .step = 1, 63 .step = 1,
62 .default_value = 32, 64#define BRIGHTNESS_DEF 32
65 .default_value = BRIGHTNESS_DEF,
63 }, 66 },
64 .set = sd_setbrightness, 67 .set = sd_setbrightness,
65 .get = sd_getbrightness, 68 .get = sd_getbrightness,
66 }, 69 },
67#define SD_CONTRAST 1
68 { 70 {
69 { 71 {
70 .id = V4L2_CID_CONTRAST, 72 .id = V4L2_CID_CONTRAST,
@@ -73,12 +75,26 @@ static struct ctrl sd_ctrls[] = {
73 .minimum = 0, 75 .minimum = 0,
74 .maximum = 0x3fff, 76 .maximum = 0x3fff,
75 .step = 1, 77 .step = 1,
76 .default_value = 0x2000, 78#define CONTRAST_DEF 0x2000
79 .default_value = CONTRAST_DEF,
77 }, 80 },
78 .set = sd_setcontrast, 81 .set = sd_setcontrast,
79 .get = sd_getcontrast, 82 .get = sd_getcontrast,
80 }, 83 },
81#define SD_AUTOGAIN 2 84 {
85 {
86 .id = V4L2_CID_DO_WHITE_BALANCE,
87 .type = V4L2_CTRL_TYPE_INTEGER,
88 .name = "While Balance",
89 .minimum = 0,
90 .maximum = 0x7f,
91 .step = 1,
92#define WHITE_DEF 40
93 .default_value = WHITE_DEF,
94 },
95 .set = sd_setwhite,
96 .get = sd_getwhite,
97 },
82 { 98 {
83 { 99 {
84 .id = V4L2_CID_AUTOGAIN, 100 .id = V4L2_CID_AUTOGAIN,
@@ -87,7 +103,8 @@ static struct ctrl sd_ctrls[] = {
87 .minimum = 0, 103 .minimum = 0,
88 .maximum = 1, 104 .maximum = 1,
89 .step = 1, 105 .step = 1,
90 .default_value = 1, 106#define AUTOGAIN_DEF 1
107 .default_value = AUTOGAIN_DEF,
91 }, 108 },
92 .set = sd_setautogain, 109 .set = sd_setautogain,
93 .get = sd_getautogain, 110 .get = sd_getautogain,
@@ -438,7 +455,7 @@ static const __u16 spca561_init_data[][2] = {
438 {0x0035, 0x8801}, /* 0x14 - set gain general */ 455 {0x0035, 0x8801}, /* 0x14 - set gain general */
439 {0x001f, 0x8805}, /* 0x14 */ 456 {0x001f, 0x8805}, /* 0x14 */
440 {0x0000, 0x8800}, 457 {0x0000, 0x8800},
441 {0x0030, 0x8112}, 458 {0x000e, 0x8112}, /* white balance - was 30 */
442 {} 459 {}
443}; 460};
444 461
@@ -478,9 +495,10 @@ static const __u16 Pb100_2map8300[][2] = {
478}; 495};
479 496
480static const __u16 spca561_161rev12A_data1[][2] = { 497static const __u16 spca561_161rev12A_data1[][2] = {
481 {0x21, 0x8118}, 498 {0x29, 0x8118}, /* white balance - was 21 */
482 {0x01, 0x8114}, 499 {0x08, 0x8114}, /* white balance - was 01 */
483 {0x00, 0x8112}, 500 {0x0e, 0x8112}, /* white balance - was 00 */
501 {0x00, 0x8102}, /* white balance - new */
484 {0x92, 0x8804}, 502 {0x92, 0x8804},
485 {0x04, 0x8802}, /* windows uses 08 */ 503 {0x04, 0x8802}, /* windows uses 08 */
486 {} 504 {}
@@ -505,14 +523,16 @@ static const __u16 spca561_161rev12A_data2[][2] = {
505 {0xb0, 0x8603}, 523 {0xb0, 0x8603},
506 524
507 /* sensor gains */ 525 /* sensor gains */
526 {0x07, 0x8601}, /* white balance - new */
527 {0x07, 0x8602}, /* white balance - new */
508 {0x00, 0x8610}, /* *red */ 528 {0x00, 0x8610}, /* *red */
509 {0x00, 0x8611}, /* 3f *green */ 529 {0x00, 0x8611}, /* 3f *green */
510 {0x00, 0x8612}, /* green *blue */ 530 {0x00, 0x8612}, /* green *blue */
511 {0x00, 0x8613}, /* blue *green */ 531 {0x00, 0x8613}, /* blue *green */
512 {0x35, 0x8614}, /* green *red */ 532 {0x43, 0x8614}, /* green *red - white balance - was 0x35 */
513 {0x35, 0x8615}, /* 40 *green */ 533 {0x40, 0x8615}, /* 40 *green - white balance - was 0x35 */
514 {0x35, 0x8616}, /* 7a *blue */ 534 {0x71, 0x8616}, /* 7a *blue - white balance - was 0x35 */
515 {0x35, 0x8617}, /* 40 *green */ 535 {0x40, 0x8617}, /* 40 *green - white balance - was 0x35 */
516 536
517 {0x0c, 0x8620}, /* 0c */ 537 {0x0c, 0x8620}, /* 0c */
518 {0xc8, 0x8631}, /* c8 */ 538 {0xc8, 0x8631}, /* c8 */
@@ -527,6 +547,7 @@ static const __u16 spca561_161rev12A_data2[][2] = {
527 {0xdf, 0x863c}, /* df */ 547 {0xdf, 0x863c}, /* df */
528 {0xf0, 0x8505}, 548 {0xf0, 0x8505},
529 {0x32, 0x850a}, 549 {0x32, 0x850a},
550 {0x99, 0x8700}, /* - white balance - new */
530 {} 551 {}
531}; 552};
532 553
@@ -588,9 +609,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
588 cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; 609 cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
589 610
590 sd->chip_revision = id->driver_info; 611 sd->chip_revision = id->driver_info;
591 sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; 612 sd->brightness = BRIGHTNESS_DEF;
592 sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; 613 sd->contrast = CONTRAST_DEF;
593 sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value; 614 sd->autogain = AUTOGAIN_DEF;
615 sd->white = WHITE_DEF;
594 return 0; 616 return 0;
595} 617}
596 618
@@ -628,15 +650,18 @@ static void setcontrast(struct gspca_dev *gspca_dev)
628 reg_w_val(dev, lowb, 0x8653); 650 reg_w_val(dev, lowb, 0x8653);
629 reg_w_val(dev, lowb, 0x8654); 651 reg_w_val(dev, lowb, 0x8654);
630 break; 652 break;
631 case Rev012A: { 653 default: {
654/* case Rev012A: { */
632 __u8 Reg8391[] = 655 __u8 Reg8391[] =
633 { 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 }; 656 { 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 };
634 657
635 /* Write camera sensor settings */ 658 /* Write camera sensor settings */
636 expotimes = (sd->contrast >> 5) & 0x07ff; 659 expotimes = (sd->contrast >> 5) & 0x07ff;
660 /* exposure is in 8309 2b, range 0120 - 5720 */
637 Reg8391[0] = expotimes & 0xff; /* exposure */ 661 Reg8391[0] = expotimes & 0xff; /* exposure */
638 Reg8391[1] = 0x18 | (expotimes >> 8); 662 Reg8391[1] = 0x18 | (expotimes >> 8);
639 Reg8391[2] = sd->brightness; /* gain */ 663 Reg8391[2] = sd->brightness; /* gain */
664 /* gain in 8335, 2b range 0000 - 2400 */
640 reg_w_buf(gspca_dev, 0x8391, Reg8391, 8); 665 reg_w_buf(gspca_dev, 0x8391, Reg8391, 8);
641 reg_w_buf(gspca_dev, 0x8390, Reg8391, 8); 666 reg_w_buf(gspca_dev, 0x8390, Reg8391, 8);
642 break; 667 break;
@@ -644,6 +669,34 @@ static void setcontrast(struct gspca_dev *gspca_dev)
644 } 669 }
645} 670}
646 671
672static void setwhite(struct gspca_dev *gspca_dev)
673{
674 struct sd *sd = (struct sd *) gspca_dev;
675 __u16 white;
676 __u8 reg8614, reg8616;
677
678 switch (sd->chip_revision) {
679 case Rev072A:
680 /* no such hardware */
681 break;
682 default:
683/* case Rev012A: */
684 white = sd->white;
685 if (sd->white == 0) {
686 PDEBUG(D_CONF, "Discarding null whiteness");
687 break;
688 }
689 /* try to emulate MS-win as possible */
690 if (white < 0x45)
691 reg8616 = white;
692 else
693 reg8616 = 0x93 + (white >> 2);
694 reg8614 = 0x28 + (white >> 4);
695 reg_w_val(gspca_dev->dev, reg8616, 0x8616);
696 reg_w_val(gspca_dev->dev, reg8614, 0x8614);
697 }
698}
699
647static void setautogain(struct gspca_dev *gspca_dev) 700static void setautogain(struct gspca_dev *gspca_dev)
648{ 701{
649 struct sd *sd = (struct sd *) gspca_dev; 702 struct sd *sd = (struct sd *) gspca_dev;
@@ -714,6 +767,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
714 reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20); 767 reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20);
715 reg_w_val(gspca_dev->dev, 0x850b, 0x03); 768 reg_w_val(gspca_dev->dev, 0x850b, 0x03);
716 setcontrast(gspca_dev); 769 setcontrast(gspca_dev);
770 setwhite(gspca_dev);
717 break; 771 break;
718 } 772 }
719} 773}
@@ -721,6 +775,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
721static void sd_stopN(struct gspca_dev *gspca_dev) 775static void sd_stopN(struct gspca_dev *gspca_dev)
722{ 776{
723 reg_w_val(gspca_dev->dev, 0x8112, 0x20); 777 reg_w_val(gspca_dev->dev, 0x8112, 0x20);
778 reg_w_val(gspca_dev->dev, 0x8102, 0x00); /* white balance - new */
724} 779}
725 780
726static void sd_stop0(struct gspca_dev *gspca_dev) 781static void sd_stop0(struct gspca_dev *gspca_dev)
@@ -968,6 +1023,25 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
968 return 0; 1023 return 0;
969} 1024}
970 1025
1026/* white balance - new */
1027static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val)
1028{
1029 struct sd *sd = (struct sd *) gspca_dev;
1030
1031 sd->white = val;
1032 if (gspca_dev->streaming)
1033 setwhite(gspca_dev);
1034 return 0;
1035}
1036
1037static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val)
1038{
1039 struct sd *sd = (struct sd *) gspca_dev;
1040
1041 *val = sd->white;
1042 return 0;
1043}
1044
971/* sub-driver description */ 1045/* sub-driver description */
972static const struct sd_desc sd_desc = { 1046static const struct sd_desc sd_desc = {
973 .name = MODULE_NAME, 1047 .name = MODULE_NAME,