aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/ov7670.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/ov7670.c')
-rw-r--r--drivers/media/video/ov7670.c366
1 files changed, 325 insertions, 41 deletions
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index 382aa83b73c5..b7d824ee03ea 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -138,6 +138,20 @@ MODULE_LICENSE("GPL");
138#define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */ 138#define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */
139#define COM17_CBAR 0x08 /* DSP Color bar */ 139#define COM17_CBAR 0x08 /* DSP Color bar */
140 140
141/*
142 * This matrix defines how the colors are generated, must be
143 * tweaked to adjust hue and saturation.
144 *
145 * Order: v-red, v-green, v-blue, u-red, u-green, u-blue
146 *
147 * They are nine-bit signed quantities, with the sign bit
148 * stored in 0x58. Sign for v-red is bit 0, and up from there.
149 */
150#define REG_CMATRIX_BASE 0x4f
151#define CMATRIX_LEN 6
152#define REG_CMATRIX_SIGN 0x58
153
154
141#define REG_BRIGHT 0x55 /* Brightness */ 155#define REG_BRIGHT 0x55 /* Brightness */
142#define REG_CONTRAS 0x56 /* Contrast control */ 156#define REG_CONTRAS 0x56 /* Contrast control */
143 157
@@ -160,6 +174,19 @@ MODULE_LICENSE("GPL");
160 174
161 175
162/* 176/*
177 * Information we maintain about a known sensor.
178 */
179struct ov7670_format_struct; /* coming later */
180struct ov7670_info {
181 struct ov7670_format_struct *fmt; /* Current format */
182 unsigned char sat; /* Saturation value */
183 int hue; /* Hue value */
184};
185
186
187
188
189/*
163 * The default register settings, as obtained from OmniVision. There 190 * The default register settings, as obtained from OmniVision. There
164 * is really no making sense of most of these - lots of "reserved" values 191 * is really no making sense of most of these - lots of "reserved" values
165 * and such. 192 * and such.
@@ -179,7 +206,7 @@ static struct regval_list ov7670_default_regs[] = {
179 * 2 = 20fps 206 * 2 = 20fps
180 * 1 = 30fps 207 * 1 = 30fps
181 */ 208 */
182 { REG_CLKRC, 0x1 }, /* OV: clock scale (15 fps) */ 209 { REG_CLKRC, 0x1 }, /* OV: clock scale (30 fps) */
183 { REG_TSLB, 0x04 }, /* OV */ 210 { REG_TSLB, 0x04 }, /* OV */
184 { REG_COM7, 0 }, /* VGA */ 211 { REG_COM7, 0 }, /* VGA */
185 /* 212 /*
@@ -286,10 +313,6 @@ static struct regval_list ov7670_default_regs[] = {
286 { 0x79, 0x05 }, { 0xc8, 0x30 }, 313 { 0x79, 0x05 }, { 0xc8, 0x30 },
287 { 0x79, 0x26 }, 314 { 0x79, 0x26 },
288 315
289 /* Not sure if these should be here */
290 { 0xf1, 0x10 }, { 0x0f, 0x1d },
291 { 0x0f, 0x1f },
292
293 { 0xff, 0xff }, /* END MARKER */ 316 { 0xff, 0xff }, /* END MARKER */
294}; 317};
295 318
@@ -312,6 +335,7 @@ static struct regval_list ov7670_fmt_yuv422[] = {
312 { REG_COM9, 0x18 }, /* 4x gain ceiling; 0x8 is reserved bit */ 335 { REG_COM9, 0x18 }, /* 4x gain ceiling; 0x8 is reserved bit */
313 { 0x4f, 0x80 }, /* "matrix coefficient 1" */ 336 { 0x4f, 0x80 }, /* "matrix coefficient 1" */
314 { 0x50, 0x80 }, /* "matrix coefficient 2" */ 337 { 0x50, 0x80 }, /* "matrix coefficient 2" */
338 { 0x51, 0 }, /* vb */
315 { 0x52, 0x22 }, /* "matrix coefficient 4" */ 339 { 0x52, 0x22 }, /* "matrix coefficient 4" */
316 { 0x53, 0x5e }, /* "matrix coefficient 5" */ 340 { 0x53, 0x5e }, /* "matrix coefficient 5" */
317 { 0x54, 0x80 }, /* "matrix coefficient 6" */ 341 { 0x54, 0x80 }, /* "matrix coefficient 6" */
@@ -327,6 +351,7 @@ static struct regval_list ov7670_fmt_rgb565[] = {
327 { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ 351 { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */
328 { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ 352 { 0x4f, 0xb3 }, /* "matrix coefficient 1" */
329 { 0x50, 0xb3 }, /* "matrix coefficient 2" */ 353 { 0x50, 0xb3 }, /* "matrix coefficient 2" */
354 { 0x51, 0 }, /* vb */
330 { 0x52, 0x3d }, /* "matrix coefficient 4" */ 355 { 0x52, 0x3d }, /* "matrix coefficient 4" */
331 { 0x53, 0xa7 }, /* "matrix coefficient 5" */ 356 { 0x53, 0xa7 }, /* "matrix coefficient 5" */
332 { 0x54, 0xe4 }, /* "matrix coefficient 6" */ 357 { 0x54, 0xe4 }, /* "matrix coefficient 6" */
@@ -342,6 +367,7 @@ static struct regval_list ov7670_fmt_rgb444[] = {
342 { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */ 367 { REG_COM9, 0x38 }, /* 16x gain ceiling; 0x8 is reserved bit */
343 { 0x4f, 0xb3 }, /* "matrix coefficient 1" */ 368 { 0x4f, 0xb3 }, /* "matrix coefficient 1" */
344 { 0x50, 0xb3 }, /* "matrix coefficient 2" */ 369 { 0x50, 0xb3 }, /* "matrix coefficient 2" */
370 { 0x51, 0 }, /* vb */
345 { 0x52, 0x3d }, /* "matrix coefficient 4" */ 371 { 0x52, 0x3d }, /* "matrix coefficient 4" */
346 { 0x53, 0xa7 }, /* "matrix coefficient 5" */ 372 { 0x53, 0xa7 }, /* "matrix coefficient 5" */
347 { 0x54, 0xe4 }, /* "matrix coefficient 6" */ 373 { 0x54, 0xe4 }, /* "matrix coefficient 6" */
@@ -362,7 +388,7 @@ static int ov7670_read(struct i2c_client *c, unsigned char reg,
362 int ret; 388 int ret;
363 389
364 ret = i2c_smbus_read_byte_data(c, reg); 390 ret = i2c_smbus_read_byte_data(c, reg);
365 if (ret > 0) 391 if (ret >= 0)
366 *value = (unsigned char) ret; 392 *value = (unsigned char) ret;
367 return ret; 393 return ret;
368} 394}
@@ -442,28 +468,34 @@ static int ov7670_detect(struct i2c_client *client)
442} 468}
443 469
444 470
445 471/*
446 472 * Store information about the video data format. The color matrix
447 473 * is deeply tied into the format, so keep the relevant values here.
474 * The magic matrix nubmers come from OmniVision.
475 */
448static struct ov7670_format_struct { 476static struct ov7670_format_struct {
449 __u8 *desc; 477 __u8 *desc;
450 __u32 pixelformat; 478 __u32 pixelformat;
451 struct regval_list *regs; 479 struct regval_list *regs;
480 int cmatrix[CMATRIX_LEN];
452} ov7670_formats[] = { 481} ov7670_formats[] = {
453 { 482 {
454 .desc = "YUYV 4:2:2", 483 .desc = "YUYV 4:2:2",
455 .pixelformat = V4L2_PIX_FMT_YUYV, 484 .pixelformat = V4L2_PIX_FMT_YUYV,
456 .regs = ov7670_fmt_yuv422, 485 .regs = ov7670_fmt_yuv422,
486 .cmatrix = { 128, -128, 0, -34, -94, 128 },
457 }, 487 },
458 { 488 {
459 .desc = "RGB 444", 489 .desc = "RGB 444",
460 .pixelformat = V4L2_PIX_FMT_RGB444, 490 .pixelformat = V4L2_PIX_FMT_RGB444,
461 .regs = ov7670_fmt_rgb444, 491 .regs = ov7670_fmt_rgb444,
492 .cmatrix = { 179, -179, 0, -61, -176, 228 },
462 }, 493 },
463 { 494 {
464 .desc = "RGB 565", 495 .desc = "RGB 565",
465 .pixelformat = V4L2_PIX_FMT_RGB565, 496 .pixelformat = V4L2_PIX_FMT_RGB565,
466 .regs = ov7670_fmt_rgb565, 497 .regs = ov7670_fmt_rgb565,
498 .cmatrix = { 179, -179, 0, -61, -176, 228 },
467 }, 499 },
468 /* 500 /*
469 * Pretend we do RGB32. This is here on the assumption that the 501 * Pretend we do RGB32. This is here on the assumption that the
@@ -476,6 +508,7 @@ static struct ov7670_format_struct {
476 .desc = "RGB32 (faked)", 508 .desc = "RGB32 (faked)",
477 .pixelformat = V4L2_PIX_FMT_RGB32, 509 .pixelformat = V4L2_PIX_FMT_RGB32,
478 .regs = ov7670_fmt_rgb444, 510 .regs = ov7670_fmt_rgb444,
511 .cmatrix = { 179, -179, 0, -61, -176, 228 },
479 }, 512 },
480}; 513};
481#define N_OV7670_FMTS (sizeof(ov7670_formats)/sizeof(ov7670_formats[0])) 514#define N_OV7670_FMTS (sizeof(ov7670_formats)/sizeof(ov7670_formats[0]))
@@ -488,6 +521,32 @@ static struct ov7670_format_struct {
488/* 521/*
489 * Then there is the issue of window sizes. Try to capture the info here. 522 * Then there is the issue of window sizes. Try to capture the info here.
490 */ 523 */
524
525/*
526 * QCIF mode is done (by OV) in a very strange way - it actually looks like
527 * VGA with weird scaling options - they do *not* use the canned QCIF mode
528 * which is allegedly provided by the sensor. So here's the weird register
529 * settings.
530 */
531static struct regval_list ov7670_qcif_regs[] = {
532 { REG_COM3, COM3_SCALEEN|COM3_DCWEN },
533 { REG_COM3, COM3_DCWEN },
534 { REG_COM14, COM14_DCWEN | 0x01},
535 { 0x73, 0xf1 },
536 { 0xa2, 0x52 },
537 { 0x7b, 0x1c },
538 { 0x7c, 0x28 },
539 { 0x7d, 0x3c },
540 { 0x7f, 0x69 },
541 { REG_COM9, 0x38 },
542 { 0xa1, 0x0b },
543 { 0x74, 0x19 },
544 { 0x9a, 0x80 },
545 { 0x43, 0x14 },
546 { REG_COM13, 0xc0 },
547 { 0xff, 0xff },
548};
549
491static struct ov7670_win_size { 550static struct ov7670_win_size {
492 int width; 551 int width;
493 int height; 552 int height;
@@ -496,6 +555,7 @@ static struct ov7670_win_size {
496 int hstop; /* that they do not always make complete */ 555 int hstop; /* that they do not always make complete */
497 int vstart; /* sense to humans, but evidently the sensor */ 556 int vstart; /* sense to humans, but evidently the sensor */
498 int vstop; /* will do the right thing... */ 557 int vstop; /* will do the right thing... */
558 struct regval_list *regs; /* Regs to tweak */
499/* h/vref stuff */ 559/* h/vref stuff */
500} ov7670_win_sizes[] = { 560} ov7670_win_sizes[] = {
501 /* VGA */ 561 /* VGA */
@@ -507,6 +567,7 @@ static struct ov7670_win_size {
507 .hstop = 14, /* Omnivision */ 567 .hstop = 14, /* Omnivision */
508 .vstart = 10, 568 .vstart = 10,
509 .vstop = 490, 569 .vstop = 490,
570 .regs = NULL,
510 }, 571 },
511 /* CIF */ 572 /* CIF */
512 { 573 {
@@ -517,6 +578,7 @@ static struct ov7670_win_size {
517 .hstop = 90, 578 .hstop = 90,
518 .vstart = 14, 579 .vstart = 14,
519 .vstop = 494, 580 .vstop = 494,
581 .regs = NULL,
520 }, 582 },
521 /* QVGA */ 583 /* QVGA */
522 { 584 {
@@ -527,6 +589,18 @@ static struct ov7670_win_size {
527 .hstop = 20, 589 .hstop = 20,
528 .vstart = 14, 590 .vstart = 14,
529 .vstop = 494, 591 .vstop = 494,
592 .regs = NULL,
593 },
594 /* QCIF */
595 {
596 .width = QCIF_WIDTH,
597 .height = QCIF_HEIGHT,
598 .com7_bit = COM7_FMT_VGA, /* see comment above */
599 .hstart = 456, /* Empirically determined */
600 .hstop = 24,
601 .vstart = 14,
602 .vstop = 494,
603 .regs = ov7670_qcif_regs,
530 }, 604 },
531}; 605};
532 606
@@ -610,7 +684,7 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt,
610 wsize++) 684 wsize++)
611 if (pix->width >= wsize->width && pix->height >= wsize->height) 685 if (pix->width >= wsize->width && pix->height >= wsize->height)
612 break; 686 break;
613 if (wsize > ov7670_win_sizes + N_WIN_SIZES) 687 if (wsize >= ov7670_win_sizes + N_WIN_SIZES)
614 wsize--; /* Take the smallest one */ 688 wsize--; /* Take the smallest one */
615 if (ret_wsize != NULL) 689 if (ret_wsize != NULL)
616 *ret_wsize = wsize; 690 *ret_wsize = wsize;
@@ -624,7 +698,6 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt,
624 pix->bytesperline *= 2; 698 pix->bytesperline *= 2;
625 pix->sizeimage = pix->height*pix->bytesperline; 699 pix->sizeimage = pix->height*pix->bytesperline;
626 return 0; 700 return 0;
627
628} 701}
629 702
630/* 703/*
@@ -635,6 +708,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
635 int ret; 708 int ret;
636 struct ov7670_format_struct *ovfmt; 709 struct ov7670_format_struct *ovfmt;
637 struct ov7670_win_size *wsize; 710 struct ov7670_win_size *wsize;
711 struct ov7670_info *info = i2c_get_clientdata(c);
638 unsigned char com7; 712 unsigned char com7;
639 713
640 ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize); 714 ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize);
@@ -655,6 +729,10 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
655 ov7670_write_array(c, ovfmt->regs + 1); 729 ov7670_write_array(c, ovfmt->regs + 1);
656 ov7670_set_hw(c, wsize->hstart, wsize->hstop, wsize->vstart, 730 ov7670_set_hw(c, wsize->hstart, wsize->hstop, wsize->vstart,
657 wsize->vstop); 731 wsize->vstop);
732 ret = 0;
733 if (wsize->regs)
734 ret = ov7670_write_array(c, wsize->regs);
735 info->fmt = ovfmt;
658 return 0; 736 return 0;
659} 737}
660 738
@@ -662,6 +740,168 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt)
662 * Code for dealing with controls. 740 * Code for dealing with controls.
663 */ 741 */
664 742
743
744
745
746
747static int ov7670_store_cmatrix(struct i2c_client *client,
748 int matrix[CMATRIX_LEN])
749{
750 int i, ret;
751 unsigned char signbits;
752
753 /*
754 * Weird crap seems to exist in the upper part of
755 * the sign bits register, so let's preserve it.
756 */
757 ret = ov7670_read(client, REG_CMATRIX_SIGN, &signbits);
758 signbits &= 0xc0;
759
760 for (i = 0; i < CMATRIX_LEN; i++) {
761 unsigned char raw;
762
763 if (matrix[i] < 0) {
764 signbits |= (1 << i);
765 if (matrix[i] < -255)
766 raw = 0xff;
767 else
768 raw = (-1 * matrix[i]) & 0xff;
769 }
770 else {
771 if (matrix[i] > 255)
772 raw = 0xff;
773 else
774 raw = matrix[i] & 0xff;
775 }
776 ret += ov7670_write(client, REG_CMATRIX_BASE + i, raw);
777 }
778 ret += ov7670_write(client, REG_CMATRIX_SIGN, signbits);
779 return ret;
780}
781
782
783/*
784 * Hue also requires messing with the color matrix. It also requires
785 * trig functions, which tend not to be well supported in the kernel.
786 * So here is a simple table of sine values, 0-90 degrees, in steps
787 * of five degrees. Values are multiplied by 1000.
788 *
789 * The following naive approximate trig functions require an argument
790 * carefully limited to -180 <= theta <= 180.
791 */
792#define SIN_STEP 5
793static const int ov7670_sin_table[] = {
794 0, 87, 173, 258, 342, 422,
795 499, 573, 642, 707, 766, 819,
796 866, 906, 939, 965, 984, 996,
797 1000
798};
799
800static int ov7670_sine(int theta)
801{
802 int chs = 1;
803 int sine;
804
805 if (theta < 0) {
806 theta = -theta;
807 chs = -1;
808 }
809 if (theta <= 90)
810 sine = ov7670_sin_table[theta/SIN_STEP];
811 else {
812 theta -= 90;
813 sine = 1000 - ov7670_sin_table[theta/SIN_STEP];
814 }
815 return sine*chs;
816}
817
818static int ov7670_cosine(int theta)
819{
820 theta = 90 - theta;
821 if (theta > 180)
822 theta -= 360;
823 else if (theta < -180)
824 theta += 360;
825 return ov7670_sine(theta);
826}
827
828
829
830
831static void ov7670_calc_cmatrix(struct ov7670_info *info,
832 int matrix[CMATRIX_LEN])
833{
834 int i;
835 /*
836 * Apply the current saturation setting first.
837 */
838 for (i = 0; i < CMATRIX_LEN; i++)
839 matrix[i] = (info->fmt->cmatrix[i]*info->sat) >> 7;
840 /*
841 * Then, if need be, rotate the hue value.
842 */
843 if (info->hue != 0) {
844 int sinth, costh, tmpmatrix[CMATRIX_LEN];
845
846 memcpy(tmpmatrix, matrix, CMATRIX_LEN*sizeof(int));
847 sinth = ov7670_sine(info->hue);
848 costh = ov7670_cosine(info->hue);
849
850 matrix[0] = (matrix[3]*sinth + matrix[0]*costh)/1000;
851 matrix[1] = (matrix[4]*sinth + matrix[1]*costh)/1000;
852 matrix[2] = (matrix[5]*sinth + matrix[2]*costh)/1000;
853 matrix[3] = (matrix[3]*costh - matrix[0]*sinth)/1000;
854 matrix[4] = (matrix[4]*costh - matrix[1]*sinth)/1000;
855 matrix[5] = (matrix[5]*costh - matrix[2]*sinth)/1000;
856 }
857}
858
859
860
861static int ov7670_t_sat(struct i2c_client *client, int value)
862{
863 struct ov7670_info *info = i2c_get_clientdata(client);
864 int matrix[CMATRIX_LEN];
865 int ret;
866
867 info->sat = value;
868 ov7670_calc_cmatrix(info, matrix);
869 ret = ov7670_store_cmatrix(client, matrix);
870 return ret;
871}
872
873static int ov7670_q_sat(struct i2c_client *client, __s32 *value)
874{
875 struct ov7670_info *info = i2c_get_clientdata(client);
876
877 *value = info->sat;
878 return 0;
879}
880
881static int ov7670_t_hue(struct i2c_client *client, int value)
882{
883 struct ov7670_info *info = i2c_get_clientdata(client);
884 int matrix[CMATRIX_LEN];
885 int ret;
886
887 if (value < -180 || value > 180)
888 return -EINVAL;
889 info->hue = value;
890 ov7670_calc_cmatrix(info, matrix);
891 ret = ov7670_store_cmatrix(client, matrix);
892 return ret;
893}
894
895
896static int ov7670_q_hue(struct i2c_client *client, __s32 *value)
897{
898 struct ov7670_info *info = i2c_get_clientdata(client);
899
900 *value = info->hue;
901 return 0;
902}
903
904
665/* 905/*
666 * Some weird registers seem to store values in a sign/magnitude format! 906 * Some weird registers seem to store values in a sign/magnitude format!
667 */ 907 */
@@ -682,38 +922,43 @@ static unsigned char ov7670_abs_to_sm(unsigned char v)
682 return (128 - v) | 0x80; 922 return (128 - v) | 0x80;
683} 923}
684 924
685static int ov7670_t_brightness(struct i2c_client *client, unsigned char value) 925static int ov7670_t_brightness(struct i2c_client *client, int value)
686{ 926{
687 unsigned char com8; 927 unsigned char com8, v;
688 int ret; 928 int ret;
689 929
690 ov7670_read(client, REG_COM8, &com8); 930 ov7670_read(client, REG_COM8, &com8);
691 com8 &= ~COM8_AEC; 931 com8 &= ~COM8_AEC;
692 ov7670_write(client, REG_COM8, com8); 932 ov7670_write(client, REG_COM8, com8);
693 value = ov7670_abs_to_sm(value); 933 v = ov7670_abs_to_sm(value);
694 ret = ov7670_write(client, REG_BRIGHT, value); 934 ret = ov7670_write(client, REG_BRIGHT, v);
695 return ret; 935 return ret;
696} 936}
697 937
698static int ov7670_q_brightness(struct i2c_client *client, unsigned char *value) 938static int ov7670_q_brightness(struct i2c_client *client, __s32 *value)
699{ 939{
700 int ret; 940 unsigned char v;
701 ret = ov7670_read(client, REG_BRIGHT, value); 941 int ret = ov7670_read(client, REG_BRIGHT, &v);
702 *value = ov7670_sm_to_abs(*value); 942
943 *value = ov7670_sm_to_abs(v);
703 return ret; 944 return ret;
704} 945}
705 946
706static int ov7670_t_contrast(struct i2c_client *client, unsigned char value) 947static int ov7670_t_contrast(struct i2c_client *client, int value)
707{ 948{
708 return ov7670_write(client, REG_CONTRAS, value); 949 return ov7670_write(client, REG_CONTRAS, (unsigned char) value);
709} 950}
710 951
711static int ov7670_q_contrast(struct i2c_client *client, unsigned char *value) 952static int ov7670_q_contrast(struct i2c_client *client, __s32 *value)
712{ 953{
713 return ov7670_read(client, REG_CONTRAS, value); 954 unsigned char v;
955 int ret = ov7670_read(client, REG_CONTRAS, &v);
956
957 *value = v;
958 return ret;
714} 959}
715 960
716static int ov7670_q_hflip(struct i2c_client *client, unsigned char *value) 961static int ov7670_q_hflip(struct i2c_client *client, __s32 *value)
717{ 962{
718 int ret; 963 int ret;
719 unsigned char v; 964 unsigned char v;
@@ -724,7 +969,7 @@ static int ov7670_q_hflip(struct i2c_client *client, unsigned char *value)
724} 969}
725 970
726 971
727static int ov7670_t_hflip(struct i2c_client *client, unsigned char value) 972static int ov7670_t_hflip(struct i2c_client *client, int value)
728{ 973{
729 unsigned char v; 974 unsigned char v;
730 int ret; 975 int ret;
@@ -741,7 +986,7 @@ static int ov7670_t_hflip(struct i2c_client *client, unsigned char value)
741 986
742 987
743 988
744static int ov7670_q_vflip(struct i2c_client *client, unsigned char *value) 989static int ov7670_q_vflip(struct i2c_client *client, __s32 *value)
745{ 990{
746 int ret; 991 int ret;
747 unsigned char v; 992 unsigned char v;
@@ -752,7 +997,7 @@ static int ov7670_q_vflip(struct i2c_client *client, unsigned char *value)
752} 997}
753 998
754 999
755static int ov7670_t_vflip(struct i2c_client *client, unsigned char value) 1000static int ov7670_t_vflip(struct i2c_client *client, int value)
756{ 1001{
757 unsigned char v; 1002 unsigned char v;
758 int ret; 1003 int ret;
@@ -770,8 +1015,8 @@ static int ov7670_t_vflip(struct i2c_client *client, unsigned char value)
770 1015
771static struct ov7670_control { 1016static struct ov7670_control {
772 struct v4l2_queryctrl qc; 1017 struct v4l2_queryctrl qc;
773 int (*query)(struct i2c_client *c, unsigned char *value); 1018 int (*query)(struct i2c_client *c, __s32 *value);
774 int (*tweak)(struct i2c_client *c, unsigned char value); 1019 int (*tweak)(struct i2c_client *c, int value);
775} ov7670_controls[] = 1020} ov7670_controls[] =
776{ 1021{
777 { 1022 {
@@ -804,6 +1049,34 @@ static struct ov7670_control {
804 }, 1049 },
805 { 1050 {
806 .qc = { 1051 .qc = {
1052 .id = V4L2_CID_SATURATION,
1053 .type = V4L2_CTRL_TYPE_INTEGER,
1054 .name = "Saturation",
1055 .minimum = 0,
1056 .maximum = 256,
1057 .step = 1,
1058 .default_value = 0x80,
1059 .flags = V4L2_CTRL_FLAG_SLIDER
1060 },
1061 .tweak = ov7670_t_sat,
1062 .query = ov7670_q_sat,
1063 },
1064 {
1065 .qc = {
1066 .id = V4L2_CID_HUE,
1067 .type = V4L2_CTRL_TYPE_INTEGER,
1068 .name = "HUE",
1069 .minimum = -180,
1070 .maximum = 180,
1071 .step = 5,
1072 .default_value = 0,
1073 .flags = V4L2_CTRL_FLAG_SLIDER
1074 },
1075 .tweak = ov7670_t_hue,
1076 .query = ov7670_q_hue,
1077 },
1078 {
1079 .qc = {
807 .id = V4L2_CID_VFLIP, 1080 .id = V4L2_CID_VFLIP,
808 .type = V4L2_CTRL_TYPE_BOOLEAN, 1081 .type = V4L2_CTRL_TYPE_BOOLEAN,
809 .name = "Vertical flip", 1082 .name = "Vertical flip",
@@ -857,25 +1130,26 @@ static int ov7670_g_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
857{ 1130{
858 struct ov7670_control *octrl = ov7670_find_control(ctrl->id); 1131 struct ov7670_control *octrl = ov7670_find_control(ctrl->id);
859 int ret; 1132 int ret;
860 unsigned char v;
861 1133
862 if (octrl == NULL) 1134 if (octrl == NULL)
863 return -EINVAL; 1135 return -EINVAL;
864 ret = octrl->query(client, &v); 1136 ret = octrl->query(client, &ctrl->value);
865 if (ret >= 0) { 1137 if (ret >= 0)
866 ctrl->value = v;
867 return 0; 1138 return 0;
868 }
869 return ret; 1139 return ret;
870} 1140}
871 1141
872static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) 1142static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
873{ 1143{
874 struct ov7670_control *octrl = ov7670_find_control(ctrl->id); 1144 struct ov7670_control *octrl = ov7670_find_control(ctrl->id);
1145 int ret;
875 1146
876 if (octrl == NULL) 1147 if (octrl == NULL)
877 return -EINVAL; 1148 return -EINVAL;
878 return octrl->tweak(client, ctrl->value); 1149 ret = octrl->tweak(client, ctrl->value);
1150 if (ret >= 0)
1151 return 0;
1152 return ret;
879} 1153}
880 1154
881 1155
@@ -883,7 +1157,6 @@ static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
883 1157
884 1158
885 1159
886
887/* 1160/*
888 * Basic i2c stuff. 1161 * Basic i2c stuff.
889 */ 1162 */
@@ -893,15 +1166,14 @@ static int ov7670_attach(struct i2c_adapter *adapter)
893{ 1166{
894 int ret; 1167 int ret;
895 struct i2c_client *client; 1168 struct i2c_client *client;
1169 struct ov7670_info *info;
896 1170
897 printk(KERN_ERR "ov7670 attach, id = %d\n", adapter->id);
898 /* 1171 /*
899 * For now: only deal with adapters we recognize. 1172 * For now: only deal with adapters we recognize.
900 */ 1173 */
901 if (adapter->id != I2C_HW_SMBUS_CAFE) 1174 if (adapter->id != I2C_HW_SMBUS_CAFE)
902 return -ENODEV; 1175 return -ENODEV;
903 1176
904 printk(KERN_ERR "ov7670 accepting\n");
905 client = kzalloc(sizeof (struct i2c_client), GFP_KERNEL); 1177 client = kzalloc(sizeof (struct i2c_client), GFP_KERNEL);
906 if (! client) 1178 if (! client)
907 return -ENOMEM; 1179 return -ENOMEM;
@@ -909,18 +1181,29 @@ static int ov7670_attach(struct i2c_adapter *adapter)
909 client->addr = OV7670_I2C_ADDR; 1181 client->addr = OV7670_I2C_ADDR;
910 client->driver = &ov7670_driver, 1182 client->driver = &ov7670_driver,
911 strcpy(client->name, "OV7670"); 1183 strcpy(client->name, "OV7670");
912 /* Do we need clientdata? */ 1184 /*
1185 * Set up our info structure.
1186 */
1187 info = kzalloc(sizeof (struct ov7670_info), GFP_KERNEL);
1188 if (! info) {
1189 ret = -ENOMEM;
1190 goto out_free;
1191 }
1192 info->fmt = &ov7670_formats[0];
1193 info->sat = 128; /* Review this */
1194 i2c_set_clientdata(client, info);
913 1195
914 /* 1196 /*
915 * Make sure it's an ov7670 1197 * Make sure it's an ov7670
916 */ 1198 */
917 ret = ov7670_detect(client); 1199 ret = ov7670_detect(client);
918 printk(KERN_ERR "detect result is %d\n", ret);
919 if (ret) 1200 if (ret)
920 goto out_free; 1201 goto out_free_info;
921 i2c_attach_client(client); 1202 i2c_attach_client(client);
922 return 0; 1203 return 0;
923 1204
1205 out_free_info:
1206 kfree(info);
924 out_free: 1207 out_free:
925 kfree(client); 1208 kfree(client);
926 return ret; 1209 return ret;
@@ -930,6 +1213,7 @@ static int ov7670_attach(struct i2c_adapter *adapter)
930static int ov7670_detach(struct i2c_client *client) 1213static int ov7670_detach(struct i2c_client *client)
931{ 1214{
932 i2c_detach_client(client); 1215 i2c_detach_client(client);
1216 kfree(i2c_get_clientdata(client));
933 kfree(client); 1217 kfree(client);
934 return 0; 1218 return 0;
935} 1219}