diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2009-03-18 12:01:06 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-03-30 11:43:30 -0400 |
commit | 14386c2b7793652a656021a3345cff3b0f6771f9 (patch) | |
tree | 86c85efca5742e5b2e23484c2bcb915ce9019e31 /drivers/media/video/ov7670.c | |
parent | 2da9479aaa331bdfaadab0d14f75fd76bfa5e56a (diff) |
V4L/DVB (11113): ov7670: convert to v4l2_subdev
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Acked-by: Jonathan Corbet <corbet@lwn.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/ov7670.c')
-rw-r--r-- | drivers/media/video/ov7670.c | 376 |
1 files changed, 180 insertions, 196 deletions
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c index 003120c07482..78bd430716c8 100644 --- a/drivers/media/video/ov7670.c +++ b/drivers/media/video/ov7670.c | |||
@@ -12,18 +12,22 @@ | |||
12 | */ | 12 | */ |
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/i2c.h> |
16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
17 | #include <linux/videodev2.h> | 17 | #include <linux/videodev2.h> |
18 | #include <media/v4l2-common.h> | 18 | #include <media/v4l2-device.h> |
19 | #include <media/v4l2-chip-ident.h> | 19 | #include <media/v4l2-chip-ident.h> |
20 | #include <linux/i2c.h> | 20 | #include <media/v4l2-i2c-drv-legacy.h> |
21 | 21 | ||
22 | 22 | ||
23 | MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); | 23 | MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); |
24 | MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors"); | 24 | MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors"); |
25 | MODULE_LICENSE("GPL"); | 25 | MODULE_LICENSE("GPL"); |
26 | 26 | ||
27 | static int debug; | ||
28 | module_param(debug, bool, 0644); | ||
29 | MODULE_PARM_DESC(debug, "Debug level (0-1)"); | ||
30 | |||
27 | /* | 31 | /* |
28 | * Basic window sizes. These probably belong somewhere more globally | 32 | * Basic window sizes. These probably belong somewhere more globally |
29 | * useful. | 33 | * useful. |
@@ -189,11 +193,16 @@ MODULE_LICENSE("GPL"); | |||
189 | */ | 193 | */ |
190 | struct ov7670_format_struct; /* coming later */ | 194 | struct ov7670_format_struct; /* coming later */ |
191 | struct ov7670_info { | 195 | struct ov7670_info { |
196 | struct v4l2_subdev sd; | ||
192 | struct ov7670_format_struct *fmt; /* Current format */ | 197 | struct ov7670_format_struct *fmt; /* Current format */ |
193 | unsigned char sat; /* Saturation value */ | 198 | unsigned char sat; /* Saturation value */ |
194 | int hue; /* Hue value */ | 199 | int hue; /* Hue value */ |
195 | }; | 200 | }; |
196 | 201 | ||
202 | static inline struct ov7670_info *to_state(struct v4l2_subdev *sd) | ||
203 | { | ||
204 | return container_of(sd, struct ov7670_info, sd); | ||
205 | } | ||
197 | 206 | ||
198 | 207 | ||
199 | 208 | ||
@@ -400,24 +409,27 @@ static struct regval_list ov7670_fmt_raw[] = { | |||
400 | * Low-level register I/O. | 409 | * Low-level register I/O. |
401 | */ | 410 | */ |
402 | 411 | ||
403 | static int ov7670_read(struct i2c_client *c, unsigned char reg, | 412 | static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg, |
404 | unsigned char *value) | 413 | unsigned char *value) |
405 | { | 414 | { |
415 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
406 | int ret; | 416 | int ret; |
407 | 417 | ||
408 | ret = i2c_smbus_read_byte_data(c, reg); | 418 | ret = i2c_smbus_read_byte_data(client, reg); |
409 | if (ret >= 0) { | 419 | if (ret >= 0) { |
410 | *value = (unsigned char) ret; | 420 | *value = (unsigned char)ret; |
411 | ret = 0; | 421 | ret = 0; |
412 | } | 422 | } |
413 | return ret; | 423 | return ret; |
414 | } | 424 | } |
415 | 425 | ||
416 | 426 | ||
417 | static int ov7670_write(struct i2c_client *c, unsigned char reg, | 427 | static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg, |
418 | unsigned char value) | 428 | unsigned char value) |
419 | { | 429 | { |
420 | int ret = i2c_smbus_write_byte_data(c, reg, value); | 430 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
431 | int ret = i2c_smbus_write_byte_data(client, reg, value); | ||
432 | |||
421 | if (reg == REG_COM7 && (value & COM7_RESET)) | 433 | if (reg == REG_COM7 && (value & COM7_RESET)) |
422 | msleep(2); /* Wait for reset to run */ | 434 | msleep(2); /* Wait for reset to run */ |
423 | return ret; | 435 | return ret; |
@@ -427,10 +439,10 @@ static int ov7670_write(struct i2c_client *c, unsigned char reg, | |||
427 | /* | 439 | /* |
428 | * Write a list of register settings; ff/ff stops the process. | 440 | * Write a list of register settings; ff/ff stops the process. |
429 | */ | 441 | */ |
430 | static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals) | 442 | static int ov7670_write_array(struct v4l2_subdev *sd, struct regval_list *vals) |
431 | { | 443 | { |
432 | while (vals->reg_num != 0xff || vals->value != 0xff) { | 444 | while (vals->reg_num != 0xff || vals->value != 0xff) { |
433 | int ret = ov7670_write(c, vals->reg_num, vals->value); | 445 | int ret = ov7670_write(sd, vals->reg_num, vals->value); |
434 | if (ret < 0) | 446 | if (ret < 0) |
435 | return ret; | 447 | return ret; |
436 | vals++; | 448 | vals++; |
@@ -442,34 +454,35 @@ static int ov7670_write_array(struct i2c_client *c, struct regval_list *vals) | |||
442 | /* | 454 | /* |
443 | * Stuff that knows about the sensor. | 455 | * Stuff that knows about the sensor. |
444 | */ | 456 | */ |
445 | static void ov7670_reset(struct i2c_client *client) | 457 | static int ov7670_reset(struct v4l2_subdev *sd, u32 val) |
446 | { | 458 | { |
447 | ov7670_write(client, REG_COM7, COM7_RESET); | 459 | ov7670_write(sd, REG_COM7, COM7_RESET); |
448 | msleep(1); | 460 | msleep(1); |
461 | return 0; | ||
449 | } | 462 | } |
450 | 463 | ||
451 | 464 | ||
452 | static int ov7670_init(struct i2c_client *client) | 465 | static int ov7670_init(struct v4l2_subdev *sd, u32 val) |
453 | { | 466 | { |
454 | return ov7670_write_array(client, ov7670_default_regs); | 467 | return ov7670_write_array(sd, ov7670_default_regs); |
455 | } | 468 | } |
456 | 469 | ||
457 | 470 | ||
458 | 471 | ||
459 | static int ov7670_detect(struct i2c_client *client) | 472 | static int ov7670_detect(struct v4l2_subdev *sd) |
460 | { | 473 | { |
461 | unsigned char v; | 474 | unsigned char v; |
462 | int ret; | 475 | int ret; |
463 | 476 | ||
464 | ret = ov7670_init(client); | 477 | ret = ov7670_init(sd, 0); |
465 | if (ret < 0) | 478 | if (ret < 0) |
466 | return ret; | 479 | return ret; |
467 | ret = ov7670_read(client, REG_MIDH, &v); | 480 | ret = ov7670_read(sd, REG_MIDH, &v); |
468 | if (ret < 0) | 481 | if (ret < 0) |
469 | return ret; | 482 | return ret; |
470 | if (v != 0x7f) /* OV manuf. id. */ | 483 | if (v != 0x7f) /* OV manuf. id. */ |
471 | return -ENODEV; | 484 | return -ENODEV; |
472 | ret = ov7670_read(client, REG_MIDL, &v); | 485 | ret = ov7670_read(sd, REG_MIDL, &v); |
473 | if (ret < 0) | 486 | if (ret < 0) |
474 | return ret; | 487 | return ret; |
475 | if (v != 0xa2) | 488 | if (v != 0xa2) |
@@ -477,12 +490,12 @@ static int ov7670_detect(struct i2c_client *client) | |||
477 | /* | 490 | /* |
478 | * OK, we know we have an OmniVision chip...but which one? | 491 | * OK, we know we have an OmniVision chip...but which one? |
479 | */ | 492 | */ |
480 | ret = ov7670_read(client, REG_PID, &v); | 493 | ret = ov7670_read(sd, REG_PID, &v); |
481 | if (ret < 0) | 494 | if (ret < 0) |
482 | return ret; | 495 | return ret; |
483 | if (v != 0x76) /* PID + VER = 0x76 / 0x73 */ | 496 | if (v != 0x76) /* PID + VER = 0x76 / 0x73 */ |
484 | return -ENODEV; | 497 | return -ENODEV; |
485 | ret = ov7670_read(client, REG_VER, &v); | 498 | ret = ov7670_read(sd, REG_VER, &v); |
486 | if (ret < 0) | 499 | if (ret < 0) |
487 | return ret; | 500 | return ret; |
488 | if (v != 0x73) /* PID + VER = 0x76 / 0x73 */ | 501 | if (v != 0x73) /* PID + VER = 0x76 / 0x73 */ |
@@ -627,7 +640,7 @@ static struct ov7670_win_size { | |||
627 | /* | 640 | /* |
628 | * Store a set of start/stop values into the camera. | 641 | * Store a set of start/stop values into the camera. |
629 | */ | 642 | */ |
630 | static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop, | 643 | static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop, |
631 | int vstart, int vstop) | 644 | int vstart, int vstop) |
632 | { | 645 | { |
633 | int ret; | 646 | int ret; |
@@ -637,26 +650,26 @@ static int ov7670_set_hw(struct i2c_client *client, int hstart, int hstop, | |||
637 | * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is | 650 | * hstart are in href[2:0], bottom 3 of hstop in href[5:3]. There is |
638 | * a mystery "edge offset" value in the top two bits of href. | 651 | * a mystery "edge offset" value in the top two bits of href. |
639 | */ | 652 | */ |
640 | ret = ov7670_write(client, REG_HSTART, (hstart >> 3) & 0xff); | 653 | ret = ov7670_write(sd, REG_HSTART, (hstart >> 3) & 0xff); |
641 | ret += ov7670_write(client, REG_HSTOP, (hstop >> 3) & 0xff); | 654 | ret += ov7670_write(sd, REG_HSTOP, (hstop >> 3) & 0xff); |
642 | ret += ov7670_read(client, REG_HREF, &v); | 655 | ret += ov7670_read(sd, REG_HREF, &v); |
643 | v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7); | 656 | v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x7); |
644 | msleep(10); | 657 | msleep(10); |
645 | ret += ov7670_write(client, REG_HREF, v); | 658 | ret += ov7670_write(sd, REG_HREF, v); |
646 | /* | 659 | /* |
647 | * Vertical: similar arrangement, but only 10 bits. | 660 | * Vertical: similar arrangement, but only 10 bits. |
648 | */ | 661 | */ |
649 | ret += ov7670_write(client, REG_VSTART, (vstart >> 2) & 0xff); | 662 | ret += ov7670_write(sd, REG_VSTART, (vstart >> 2) & 0xff); |
650 | ret += ov7670_write(client, REG_VSTOP, (vstop >> 2) & 0xff); | 663 | ret += ov7670_write(sd, REG_VSTOP, (vstop >> 2) & 0xff); |
651 | ret += ov7670_read(client, REG_VREF, &v); | 664 | ret += ov7670_read(sd, REG_VREF, &v); |
652 | v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3); | 665 | v = (v & 0xf0) | ((vstop & 0x3) << 2) | (vstart & 0x3); |
653 | msleep(10); | 666 | msleep(10); |
654 | ret += ov7670_write(client, REG_VREF, v); | 667 | ret += ov7670_write(sd, REG_VREF, v); |
655 | return ret; | 668 | return ret; |
656 | } | 669 | } |
657 | 670 | ||
658 | 671 | ||
659 | static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt) | 672 | static int ov7670_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt) |
660 | { | 673 | { |
661 | struct ov7670_format_struct *ofmt; | 674 | struct ov7670_format_struct *ofmt; |
662 | 675 | ||
@@ -671,7 +684,8 @@ static int ov7670_enum_fmt(struct i2c_client *c, struct v4l2_fmtdesc *fmt) | |||
671 | } | 684 | } |
672 | 685 | ||
673 | 686 | ||
674 | static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, | 687 | static int ov7670_try_fmt_internal(struct v4l2_subdev *sd, |
688 | struct v4l2_format *fmt, | ||
675 | struct ov7670_format_struct **ret_fmt, | 689 | struct ov7670_format_struct **ret_fmt, |
676 | struct ov7670_win_size **ret_wsize) | 690 | struct ov7670_win_size **ret_wsize) |
677 | { | 691 | { |
@@ -715,18 +729,23 @@ static int ov7670_try_fmt(struct i2c_client *c, struct v4l2_format *fmt, | |||
715 | return 0; | 729 | return 0; |
716 | } | 730 | } |
717 | 731 | ||
732 | static int ov7670_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) | ||
733 | { | ||
734 | return ov7670_try_fmt_internal(sd, fmt, NULL, NULL); | ||
735 | } | ||
736 | |||
718 | /* | 737 | /* |
719 | * Set a format. | 738 | * Set a format. |
720 | */ | 739 | */ |
721 | static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) | 740 | static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt) |
722 | { | 741 | { |
723 | int ret; | 742 | int ret; |
724 | struct ov7670_format_struct *ovfmt; | 743 | struct ov7670_format_struct *ovfmt; |
725 | struct ov7670_win_size *wsize; | 744 | struct ov7670_win_size *wsize; |
726 | struct ov7670_info *info = i2c_get_clientdata(c); | 745 | struct ov7670_info *info = to_state(sd); |
727 | unsigned char com7, clkrc; | 746 | unsigned char com7, clkrc = 0; |
728 | 747 | ||
729 | ret = ov7670_try_fmt(c, fmt, &ovfmt, &wsize); | 748 | ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize); |
730 | if (ret) | 749 | if (ret) |
731 | return ret; | 750 | return ret; |
732 | /* | 751 | /* |
@@ -735,7 +754,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) | |||
735 | * the colors. | 754 | * the colors. |
736 | */ | 755 | */ |
737 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) { | 756 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565) { |
738 | ret = ov7670_read(c, REG_CLKRC, &clkrc); | 757 | ret = ov7670_read(sd, REG_CLKRC, &clkrc); |
739 | if (ret) | 758 | if (ret) |
740 | return ret; | 759 | return ret; |
741 | } | 760 | } |
@@ -747,20 +766,20 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) | |||
747 | */ | 766 | */ |
748 | com7 = ovfmt->regs[0].value; | 767 | com7 = ovfmt->regs[0].value; |
749 | com7 |= wsize->com7_bit; | 768 | com7 |= wsize->com7_bit; |
750 | ov7670_write(c, REG_COM7, com7); | 769 | ov7670_write(sd, REG_COM7, com7); |
751 | /* | 770 | /* |
752 | * Now write the rest of the array. Also store start/stops | 771 | * Now write the rest of the array. Also store start/stops |
753 | */ | 772 | */ |
754 | ov7670_write_array(c, ovfmt->regs + 1); | 773 | ov7670_write_array(sd, ovfmt->regs + 1); |
755 | ov7670_set_hw(c, wsize->hstart, wsize->hstop, wsize->vstart, | 774 | ov7670_set_hw(sd, wsize->hstart, wsize->hstop, wsize->vstart, |
756 | wsize->vstop); | 775 | wsize->vstop); |
757 | ret = 0; | 776 | ret = 0; |
758 | if (wsize->regs) | 777 | if (wsize->regs) |
759 | ret = ov7670_write_array(c, wsize->regs); | 778 | ret = ov7670_write_array(sd, wsize->regs); |
760 | info->fmt = ovfmt; | 779 | info->fmt = ovfmt; |
761 | 780 | ||
762 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 && ret == 0) | 781 | if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB565 && ret == 0) |
763 | ret = ov7670_write(c, REG_CLKRC, clkrc); | 782 | ret = ov7670_write(sd, REG_CLKRC, clkrc); |
764 | return ret; | 783 | return ret; |
765 | } | 784 | } |
766 | 785 | ||
@@ -768,7 +787,7 @@ static int ov7670_s_fmt(struct i2c_client *c, struct v4l2_format *fmt) | |||
768 | * Implement G/S_PARM. There is a "high quality" mode we could try | 787 | * Implement G/S_PARM. There is a "high quality" mode we could try |
769 | * to do someday; for now, we just do the frame rate tweak. | 788 | * to do someday; for now, we just do the frame rate tweak. |
770 | */ | 789 | */ |
771 | static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms) | 790 | static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) |
772 | { | 791 | { |
773 | struct v4l2_captureparm *cp = &parms->parm.capture; | 792 | struct v4l2_captureparm *cp = &parms->parm.capture; |
774 | unsigned char clkrc; | 793 | unsigned char clkrc; |
@@ -776,7 +795,7 @@ static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms) | |||
776 | 795 | ||
777 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 796 | if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
778 | return -EINVAL; | 797 | return -EINVAL; |
779 | ret = ov7670_read(c, REG_CLKRC, &clkrc); | 798 | ret = ov7670_read(sd, REG_CLKRC, &clkrc); |
780 | if (ret < 0) | 799 | if (ret < 0) |
781 | return ret; | 800 | return ret; |
782 | memset(cp, 0, sizeof(struct v4l2_captureparm)); | 801 | memset(cp, 0, sizeof(struct v4l2_captureparm)); |
@@ -788,7 +807,7 @@ static int ov7670_g_parm(struct i2c_client *c, struct v4l2_streamparm *parms) | |||
788 | return 0; | 807 | return 0; |
789 | } | 808 | } |
790 | 809 | ||
791 | static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms) | 810 | static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) |
792 | { | 811 | { |
793 | struct v4l2_captureparm *cp = &parms->parm.capture; | 812 | struct v4l2_captureparm *cp = &parms->parm.capture; |
794 | struct v4l2_fract *tpf = &cp->timeperframe; | 813 | struct v4l2_fract *tpf = &cp->timeperframe; |
@@ -802,7 +821,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms) | |||
802 | /* | 821 | /* |
803 | * CLKRC has a reserved bit, so let's preserve it. | 822 | * CLKRC has a reserved bit, so let's preserve it. |
804 | */ | 823 | */ |
805 | ret = ov7670_read(c, REG_CLKRC, &clkrc); | 824 | ret = ov7670_read(sd, REG_CLKRC, &clkrc); |
806 | if (ret < 0) | 825 | if (ret < 0) |
807 | return ret; | 826 | return ret; |
808 | if (tpf->numerator == 0 || tpf->denominator == 0) | 827 | if (tpf->numerator == 0 || tpf->denominator == 0) |
@@ -816,7 +835,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms) | |||
816 | clkrc = (clkrc & 0x80) | div; | 835 | clkrc = (clkrc & 0x80) | div; |
817 | tpf->numerator = 1; | 836 | tpf->numerator = 1; |
818 | tpf->denominator = OV7670_FRAME_RATE/div; | 837 | tpf->denominator = OV7670_FRAME_RATE/div; |
819 | return ov7670_write(c, REG_CLKRC, clkrc); | 838 | return ov7670_write(sd, REG_CLKRC, clkrc); |
820 | } | 839 | } |
821 | 840 | ||
822 | 841 | ||
@@ -829,7 +848,7 @@ static int ov7670_s_parm(struct i2c_client *c, struct v4l2_streamparm *parms) | |||
829 | 848 | ||
830 | 849 | ||
831 | 850 | ||
832 | static int ov7670_store_cmatrix(struct i2c_client *client, | 851 | static int ov7670_store_cmatrix(struct v4l2_subdev *sd, |
833 | int matrix[CMATRIX_LEN]) | 852 | int matrix[CMATRIX_LEN]) |
834 | { | 853 | { |
835 | int i, ret; | 854 | int i, ret; |
@@ -839,7 +858,7 @@ static int ov7670_store_cmatrix(struct i2c_client *client, | |||
839 | * Weird crap seems to exist in the upper part of | 858 | * Weird crap seems to exist in the upper part of |
840 | * the sign bits register, so let's preserve it. | 859 | * the sign bits register, so let's preserve it. |
841 | */ | 860 | */ |
842 | ret = ov7670_read(client, REG_CMATRIX_SIGN, &signbits); | 861 | ret = ov7670_read(sd, REG_CMATRIX_SIGN, &signbits); |
843 | signbits &= 0xc0; | 862 | signbits &= 0xc0; |
844 | 863 | ||
845 | for (i = 0; i < CMATRIX_LEN; i++) { | 864 | for (i = 0; i < CMATRIX_LEN; i++) { |
@@ -858,9 +877,9 @@ static int ov7670_store_cmatrix(struct i2c_client *client, | |||
858 | else | 877 | else |
859 | raw = matrix[i] & 0xff; | 878 | raw = matrix[i] & 0xff; |
860 | } | 879 | } |
861 | ret += ov7670_write(client, REG_CMATRIX_BASE + i, raw); | 880 | ret += ov7670_write(sd, REG_CMATRIX_BASE + i, raw); |
862 | } | 881 | } |
863 | ret += ov7670_write(client, REG_CMATRIX_SIGN, signbits); | 882 | ret += ov7670_write(sd, REG_CMATRIX_SIGN, signbits); |
864 | return ret; | 883 | return ret; |
865 | } | 884 | } |
866 | 885 | ||
@@ -943,29 +962,29 @@ static void ov7670_calc_cmatrix(struct ov7670_info *info, | |||
943 | 962 | ||
944 | 963 | ||
945 | 964 | ||
946 | static int ov7670_t_sat(struct i2c_client *client, int value) | 965 | static int ov7670_t_sat(struct v4l2_subdev *sd, int value) |
947 | { | 966 | { |
948 | struct ov7670_info *info = i2c_get_clientdata(client); | 967 | struct ov7670_info *info = to_state(sd); |
949 | int matrix[CMATRIX_LEN]; | 968 | int matrix[CMATRIX_LEN]; |
950 | int ret; | 969 | int ret; |
951 | 970 | ||
952 | info->sat = value; | 971 | info->sat = value; |
953 | ov7670_calc_cmatrix(info, matrix); | 972 | ov7670_calc_cmatrix(info, matrix); |
954 | ret = ov7670_store_cmatrix(client, matrix); | 973 | ret = ov7670_store_cmatrix(sd, matrix); |
955 | return ret; | 974 | return ret; |
956 | } | 975 | } |
957 | 976 | ||
958 | static int ov7670_q_sat(struct i2c_client *client, __s32 *value) | 977 | static int ov7670_q_sat(struct v4l2_subdev *sd, __s32 *value) |
959 | { | 978 | { |
960 | struct ov7670_info *info = i2c_get_clientdata(client); | 979 | struct ov7670_info *info = to_state(sd); |
961 | 980 | ||
962 | *value = info->sat; | 981 | *value = info->sat; |
963 | return 0; | 982 | return 0; |
964 | } | 983 | } |
965 | 984 | ||
966 | static int ov7670_t_hue(struct i2c_client *client, int value) | 985 | static int ov7670_t_hue(struct v4l2_subdev *sd, int value) |
967 | { | 986 | { |
968 | struct ov7670_info *info = i2c_get_clientdata(client); | 987 | struct ov7670_info *info = to_state(sd); |
969 | int matrix[CMATRIX_LEN]; | 988 | int matrix[CMATRIX_LEN]; |
970 | int ret; | 989 | int ret; |
971 | 990 | ||
@@ -973,14 +992,14 @@ static int ov7670_t_hue(struct i2c_client *client, int value) | |||
973 | return -EINVAL; | 992 | return -EINVAL; |
974 | info->hue = value; | 993 | info->hue = value; |
975 | ov7670_calc_cmatrix(info, matrix); | 994 | ov7670_calc_cmatrix(info, matrix); |
976 | ret = ov7670_store_cmatrix(client, matrix); | 995 | ret = ov7670_store_cmatrix(sd, matrix); |
977 | return ret; | 996 | return ret; |
978 | } | 997 | } |
979 | 998 | ||
980 | 999 | ||
981 | static int ov7670_q_hue(struct i2c_client *client, __s32 *value) | 1000 | static int ov7670_q_hue(struct v4l2_subdev *sd, __s32 *value) |
982 | { | 1001 | { |
983 | struct ov7670_info *info = i2c_get_clientdata(client); | 1002 | struct ov7670_info *info = to_state(sd); |
984 | 1003 | ||
985 | *value = info->hue; | 1004 | *value = info->hue; |
986 | return 0; | 1005 | return 0; |
@@ -994,8 +1013,7 @@ static unsigned char ov7670_sm_to_abs(unsigned char v) | |||
994 | { | 1013 | { |
995 | if ((v & 0x80) == 0) | 1014 | if ((v & 0x80) == 0) |
996 | return v + 128; | 1015 | return v + 128; |
997 | else | 1016 | return 128 - (v & 0x7f); |
998 | return 128 - (v & 0x7f); | ||
999 | } | 1017 | } |
1000 | 1018 | ||
1001 | 1019 | ||
@@ -1003,105 +1021,104 @@ static unsigned char ov7670_abs_to_sm(unsigned char v) | |||
1003 | { | 1021 | { |
1004 | if (v > 127) | 1022 | if (v > 127) |
1005 | return v & 0x7f; | 1023 | return v & 0x7f; |
1006 | else | 1024 | return (128 - v) | 0x80; |
1007 | return (128 - v) | 0x80; | ||
1008 | } | 1025 | } |
1009 | 1026 | ||
1010 | static int ov7670_t_brightness(struct i2c_client *client, int value) | 1027 | static int ov7670_t_brightness(struct v4l2_subdev *sd, int value) |
1011 | { | 1028 | { |
1012 | unsigned char com8 = 0, v; | 1029 | unsigned char com8 = 0, v; |
1013 | int ret; | 1030 | int ret; |
1014 | 1031 | ||
1015 | ov7670_read(client, REG_COM8, &com8); | 1032 | ov7670_read(sd, REG_COM8, &com8); |
1016 | com8 &= ~COM8_AEC; | 1033 | com8 &= ~COM8_AEC; |
1017 | ov7670_write(client, REG_COM8, com8); | 1034 | ov7670_write(sd, REG_COM8, com8); |
1018 | v = ov7670_abs_to_sm(value); | 1035 | v = ov7670_abs_to_sm(value); |
1019 | ret = ov7670_write(client, REG_BRIGHT, v); | 1036 | ret = ov7670_write(sd, REG_BRIGHT, v); |
1020 | return ret; | 1037 | return ret; |
1021 | } | 1038 | } |
1022 | 1039 | ||
1023 | static int ov7670_q_brightness(struct i2c_client *client, __s32 *value) | 1040 | static int ov7670_q_brightness(struct v4l2_subdev *sd, __s32 *value) |
1024 | { | 1041 | { |
1025 | unsigned char v = 0; | 1042 | unsigned char v = 0; |
1026 | int ret = ov7670_read(client, REG_BRIGHT, &v); | 1043 | int ret = ov7670_read(sd, REG_BRIGHT, &v); |
1027 | 1044 | ||
1028 | *value = ov7670_sm_to_abs(v); | 1045 | *value = ov7670_sm_to_abs(v); |
1029 | return ret; | 1046 | return ret; |
1030 | } | 1047 | } |
1031 | 1048 | ||
1032 | static int ov7670_t_contrast(struct i2c_client *client, int value) | 1049 | static int ov7670_t_contrast(struct v4l2_subdev *sd, int value) |
1033 | { | 1050 | { |
1034 | return ov7670_write(client, REG_CONTRAS, (unsigned char) value); | 1051 | return ov7670_write(sd, REG_CONTRAS, (unsigned char) value); |
1035 | } | 1052 | } |
1036 | 1053 | ||
1037 | static int ov7670_q_contrast(struct i2c_client *client, __s32 *value) | 1054 | static int ov7670_q_contrast(struct v4l2_subdev *sd, __s32 *value) |
1038 | { | 1055 | { |
1039 | unsigned char v = 0; | 1056 | unsigned char v = 0; |
1040 | int ret = ov7670_read(client, REG_CONTRAS, &v); | 1057 | int ret = ov7670_read(sd, REG_CONTRAS, &v); |
1041 | 1058 | ||
1042 | *value = v; | 1059 | *value = v; |
1043 | return ret; | 1060 | return ret; |
1044 | } | 1061 | } |
1045 | 1062 | ||
1046 | static int ov7670_q_hflip(struct i2c_client *client, __s32 *value) | 1063 | static int ov7670_q_hflip(struct v4l2_subdev *sd, __s32 *value) |
1047 | { | 1064 | { |
1048 | int ret; | 1065 | int ret; |
1049 | unsigned char v = 0; | 1066 | unsigned char v = 0; |
1050 | 1067 | ||
1051 | ret = ov7670_read(client, REG_MVFP, &v); | 1068 | ret = ov7670_read(sd, REG_MVFP, &v); |
1052 | *value = (v & MVFP_MIRROR) == MVFP_MIRROR; | 1069 | *value = (v & MVFP_MIRROR) == MVFP_MIRROR; |
1053 | return ret; | 1070 | return ret; |
1054 | } | 1071 | } |
1055 | 1072 | ||
1056 | 1073 | ||
1057 | static int ov7670_t_hflip(struct i2c_client *client, int value) | 1074 | static int ov7670_t_hflip(struct v4l2_subdev *sd, int value) |
1058 | { | 1075 | { |
1059 | unsigned char v = 0; | 1076 | unsigned char v = 0; |
1060 | int ret; | 1077 | int ret; |
1061 | 1078 | ||
1062 | ret = ov7670_read(client, REG_MVFP, &v); | 1079 | ret = ov7670_read(sd, REG_MVFP, &v); |
1063 | if (value) | 1080 | if (value) |
1064 | v |= MVFP_MIRROR; | 1081 | v |= MVFP_MIRROR; |
1065 | else | 1082 | else |
1066 | v &= ~MVFP_MIRROR; | 1083 | v &= ~MVFP_MIRROR; |
1067 | msleep(10); /* FIXME */ | 1084 | msleep(10); /* FIXME */ |
1068 | ret += ov7670_write(client, REG_MVFP, v); | 1085 | ret += ov7670_write(sd, REG_MVFP, v); |
1069 | return ret; | 1086 | return ret; |
1070 | } | 1087 | } |
1071 | 1088 | ||
1072 | 1089 | ||
1073 | 1090 | ||
1074 | static int ov7670_q_vflip(struct i2c_client *client, __s32 *value) | 1091 | static int ov7670_q_vflip(struct v4l2_subdev *sd, __s32 *value) |
1075 | { | 1092 | { |
1076 | int ret; | 1093 | int ret; |
1077 | unsigned char v = 0; | 1094 | unsigned char v = 0; |
1078 | 1095 | ||
1079 | ret = ov7670_read(client, REG_MVFP, &v); | 1096 | ret = ov7670_read(sd, REG_MVFP, &v); |
1080 | *value = (v & MVFP_FLIP) == MVFP_FLIP; | 1097 | *value = (v & MVFP_FLIP) == MVFP_FLIP; |
1081 | return ret; | 1098 | return ret; |
1082 | } | 1099 | } |
1083 | 1100 | ||
1084 | 1101 | ||
1085 | static int ov7670_t_vflip(struct i2c_client *client, int value) | 1102 | static int ov7670_t_vflip(struct v4l2_subdev *sd, int value) |
1086 | { | 1103 | { |
1087 | unsigned char v = 0; | 1104 | unsigned char v = 0; |
1088 | int ret; | 1105 | int ret; |
1089 | 1106 | ||
1090 | ret = ov7670_read(client, REG_MVFP, &v); | 1107 | ret = ov7670_read(sd, REG_MVFP, &v); |
1091 | if (value) | 1108 | if (value) |
1092 | v |= MVFP_FLIP; | 1109 | v |= MVFP_FLIP; |
1093 | else | 1110 | else |
1094 | v &= ~MVFP_FLIP; | 1111 | v &= ~MVFP_FLIP; |
1095 | msleep(10); /* FIXME */ | 1112 | msleep(10); /* FIXME */ |
1096 | ret += ov7670_write(client, REG_MVFP, v); | 1113 | ret += ov7670_write(sd, REG_MVFP, v); |
1097 | return ret; | 1114 | return ret; |
1098 | } | 1115 | } |
1099 | 1116 | ||
1100 | 1117 | ||
1101 | static struct ov7670_control { | 1118 | static struct ov7670_control { |
1102 | struct v4l2_queryctrl qc; | 1119 | struct v4l2_queryctrl qc; |
1103 | int (*query)(struct i2c_client *c, __s32 *value); | 1120 | int (*query)(struct v4l2_subdev *sd, __s32 *value); |
1104 | int (*tweak)(struct i2c_client *c, int value); | 1121 | int (*tweak)(struct v4l2_subdev *sd, int value); |
1105 | } ov7670_controls[] = | 1122 | } ov7670_controls[] = |
1106 | { | 1123 | { |
1107 | { | 1124 | { |
@@ -1200,7 +1217,7 @@ static struct ov7670_control *ov7670_find_control(__u32 id) | |||
1200 | } | 1217 | } |
1201 | 1218 | ||
1202 | 1219 | ||
1203 | static int ov7670_queryctrl(struct i2c_client *client, | 1220 | static int ov7670_queryctrl(struct v4l2_subdev *sd, |
1204 | struct v4l2_queryctrl *qc) | 1221 | struct v4l2_queryctrl *qc) |
1205 | { | 1222 | { |
1206 | struct ov7670_control *ctrl = ov7670_find_control(qc->id); | 1223 | struct ov7670_control *ctrl = ov7670_find_control(qc->id); |
@@ -1211,161 +1228,128 @@ static int ov7670_queryctrl(struct i2c_client *client, | |||
1211 | return 0; | 1228 | return 0; |
1212 | } | 1229 | } |
1213 | 1230 | ||
1214 | static int ov7670_g_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) | 1231 | static int ov7670_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
1215 | { | 1232 | { |
1216 | struct ov7670_control *octrl = ov7670_find_control(ctrl->id); | 1233 | struct ov7670_control *octrl = ov7670_find_control(ctrl->id); |
1217 | int ret; | 1234 | int ret; |
1218 | 1235 | ||
1219 | if (octrl == NULL) | 1236 | if (octrl == NULL) |
1220 | return -EINVAL; | 1237 | return -EINVAL; |
1221 | ret = octrl->query(client, &ctrl->value); | 1238 | ret = octrl->query(sd, &ctrl->value); |
1222 | if (ret >= 0) | 1239 | if (ret >= 0) |
1223 | return 0; | 1240 | return 0; |
1224 | return ret; | 1241 | return ret; |
1225 | } | 1242 | } |
1226 | 1243 | ||
1227 | static int ov7670_s_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) | 1244 | static int ov7670_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
1228 | { | 1245 | { |
1229 | struct ov7670_control *octrl = ov7670_find_control(ctrl->id); | 1246 | struct ov7670_control *octrl = ov7670_find_control(ctrl->id); |
1230 | int ret; | 1247 | int ret; |
1231 | 1248 | ||
1232 | if (octrl == NULL) | 1249 | if (octrl == NULL) |
1233 | return -EINVAL; | 1250 | return -EINVAL; |
1234 | ret = octrl->tweak(client, ctrl->value); | 1251 | ret = octrl->tweak(sd, ctrl->value); |
1235 | if (ret >= 0) | 1252 | if (ret >= 0) |
1236 | return 0; | 1253 | return 0; |
1237 | return ret; | 1254 | return ret; |
1238 | } | 1255 | } |
1239 | 1256 | ||
1257 | static int ov7670_g_chip_ident(struct v4l2_subdev *sd, | ||
1258 | struct v4l2_dbg_chip_ident *chip) | ||
1259 | { | ||
1260 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
1261 | |||
1262 | return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_OV7670, 0); | ||
1263 | } | ||
1264 | |||
1265 | static int ov7670_command(struct i2c_client *client, unsigned cmd, void *arg) | ||
1266 | { | ||
1267 | return v4l2_subdev_command(i2c_get_clientdata(client), cmd, arg); | ||
1268 | } | ||
1240 | 1269 | ||
1270 | /* ----------------------------------------------------------------------- */ | ||
1241 | 1271 | ||
1272 | static const struct v4l2_subdev_core_ops ov7670_core_ops = { | ||
1273 | .g_chip_ident = ov7670_g_chip_ident, | ||
1274 | .g_ctrl = ov7670_g_ctrl, | ||
1275 | .s_ctrl = ov7670_s_ctrl, | ||
1276 | .queryctrl = ov7670_queryctrl, | ||
1277 | .reset = ov7670_reset, | ||
1278 | .init = ov7670_init, | ||
1279 | }; | ||
1242 | 1280 | ||
1281 | static const struct v4l2_subdev_video_ops ov7670_video_ops = { | ||
1282 | .enum_fmt = ov7670_enum_fmt, | ||
1283 | .try_fmt = ov7670_try_fmt, | ||
1284 | .s_fmt = ov7670_s_fmt, | ||
1285 | .s_parm = ov7670_s_parm, | ||
1286 | .g_parm = ov7670_g_parm, | ||
1287 | }; | ||
1243 | 1288 | ||
1289 | static const struct v4l2_subdev_ops ov7670_ops = { | ||
1290 | .core = &ov7670_core_ops, | ||
1291 | .video = &ov7670_video_ops, | ||
1292 | }; | ||
1244 | 1293 | ||
1245 | /* | 1294 | /* ----------------------------------------------------------------------- */ |
1246 | * Basic i2c stuff. | ||
1247 | */ | ||
1248 | static struct i2c_driver ov7670_driver; | ||
1249 | 1295 | ||
1250 | static int ov7670_attach(struct i2c_adapter *adapter) | 1296 | static int ov7670_probe(struct i2c_client *client, |
1297 | const struct i2c_device_id *id) | ||
1251 | { | 1298 | { |
1252 | int ret; | 1299 | struct v4l2_subdev *sd; |
1253 | struct i2c_client *client; | ||
1254 | struct ov7670_info *info; | 1300 | struct ov7670_info *info; |
1301 | int ret; | ||
1255 | 1302 | ||
1256 | /* | 1303 | /* |
1257 | * For now: only deal with adapters we recognize. | 1304 | * For now: only deal with adapters we recognize. |
1258 | */ | 1305 | */ |
1259 | if (adapter->id != I2C_HW_SMBUS_CAFE) | 1306 | if (client->adapter->id != I2C_HW_SMBUS_CAFE) |
1260 | return -ENODEV; | 1307 | return -ENODEV; |
1261 | 1308 | info = kzalloc(sizeof(struct ov7670_info), GFP_KERNEL); | |
1262 | client = kzalloc(sizeof (struct i2c_client), GFP_KERNEL); | 1309 | if (info == NULL) |
1263 | if (! client) | ||
1264 | return -ENOMEM; | 1310 | return -ENOMEM; |
1265 | client->adapter = adapter; | 1311 | sd = &info->sd; |
1266 | client->addr = OV7670_I2C_ADDR; | 1312 | v4l2_i2c_subdev_init(sd, client, &ov7670_ops); |
1267 | client->driver = &ov7670_driver, | 1313 | |
1268 | strcpy(client->name, "OV7670"); | 1314 | /* Make sure it's an ov7670 */ |
1269 | /* | 1315 | ret = ov7670_detect(sd); |
1270 | * Set up our info structure. | 1316 | if (ret) { |
1271 | */ | 1317 | v4l_dbg(1, debug, client, |
1272 | info = kzalloc(sizeof (struct ov7670_info), GFP_KERNEL); | 1318 | "chip found @ 0x%x (%s) is not an ov7670 chip.\n", |
1273 | if (! info) { | 1319 | client->addr << 1, client->adapter->name); |
1274 | ret = -ENOMEM; | 1320 | kfree(info); |
1275 | goto out_free; | 1321 | return ret; |
1276 | } | 1322 | } |
1323 | v4l_info(client, "chip found @ 0x%02x (%s)\n", | ||
1324 | client->addr << 1, client->adapter->name); | ||
1325 | |||
1277 | info->fmt = &ov7670_formats[0]; | 1326 | info->fmt = &ov7670_formats[0]; |
1278 | info->sat = 128; /* Review this */ | 1327 | info->sat = 128; /* Review this */ |
1279 | i2c_set_clientdata(client, info); | ||
1280 | 1328 | ||
1281 | /* | ||
1282 | * Make sure it's an ov7670 | ||
1283 | */ | ||
1284 | ret = ov7670_detect(client); | ||
1285 | if (ret) | ||
1286 | goto out_free_info; | ||
1287 | ret = i2c_attach_client(client); | ||
1288 | if (ret) | ||
1289 | goto out_free_info; | ||
1290 | return 0; | 1329 | return 0; |
1291 | |||
1292 | out_free_info: | ||
1293 | kfree(info); | ||
1294 | out_free: | ||
1295 | kfree(client); | ||
1296 | return ret; | ||
1297 | } | 1330 | } |
1298 | 1331 | ||
1299 | 1332 | ||
1300 | static int ov7670_detach(struct i2c_client *client) | 1333 | static int ov7670_remove(struct i2c_client *client) |
1301 | { | 1334 | { |
1302 | i2c_detach_client(client); | 1335 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
1303 | kfree(i2c_get_clientdata(client)); | ||
1304 | kfree(client); | ||
1305 | return 0; | ||
1306 | } | ||
1307 | 1336 | ||
1308 | 1337 | v4l2_device_unregister_subdev(sd); | |
1309 | static int ov7670_command(struct i2c_client *client, unsigned int cmd, | 1338 | kfree(to_state(sd)); |
1310 | void *arg) | 1339 | return 0; |
1311 | { | ||
1312 | switch (cmd) { | ||
1313 | case VIDIOC_DBG_G_CHIP_IDENT: | ||
1314 | return v4l2_chip_ident_i2c_client(client, arg, V4L2_IDENT_OV7670, 0); | ||
1315 | |||
1316 | case VIDIOC_INT_RESET: | ||
1317 | ov7670_reset(client); | ||
1318 | return 0; | ||
1319 | |||
1320 | case VIDIOC_INT_INIT: | ||
1321 | return ov7670_init(client); | ||
1322 | |||
1323 | case VIDIOC_ENUM_FMT: | ||
1324 | return ov7670_enum_fmt(client, (struct v4l2_fmtdesc *) arg); | ||
1325 | case VIDIOC_TRY_FMT: | ||
1326 | return ov7670_try_fmt(client, (struct v4l2_format *) arg, NULL, NULL); | ||
1327 | case VIDIOC_S_FMT: | ||
1328 | return ov7670_s_fmt(client, (struct v4l2_format *) arg); | ||
1329 | case VIDIOC_QUERYCTRL: | ||
1330 | return ov7670_queryctrl(client, (struct v4l2_queryctrl *) arg); | ||
1331 | case VIDIOC_S_CTRL: | ||
1332 | return ov7670_s_ctrl(client, (struct v4l2_control *) arg); | ||
1333 | case VIDIOC_G_CTRL: | ||
1334 | return ov7670_g_ctrl(client, (struct v4l2_control *) arg); | ||
1335 | case VIDIOC_S_PARM: | ||
1336 | return ov7670_s_parm(client, (struct v4l2_streamparm *) arg); | ||
1337 | case VIDIOC_G_PARM: | ||
1338 | return ov7670_g_parm(client, (struct v4l2_streamparm *) arg); | ||
1339 | } | ||
1340 | return -EINVAL; | ||
1341 | } | 1340 | } |
1342 | 1341 | ||
1343 | 1342 | static const struct i2c_device_id ov7670_id[] = { | |
1344 | 1343 | { "ov7670", 0 }, | |
1345 | static struct i2c_driver ov7670_driver = { | 1344 | { } |
1346 | .driver = { | 1345 | }; |
1347 | .name = "ov7670", | 1346 | MODULE_DEVICE_TABLE(i2c, ov7670_id); |
1348 | }, | 1347 | |
1349 | .id = I2C_DRIVERID_OV7670, | 1348 | static struct v4l2_i2c_driver_data v4l2_i2c_data = { |
1350 | .attach_adapter = ov7670_attach, | 1349 | .name = "ov7670", |
1351 | .detach_client = ov7670_detach, | 1350 | .command = ov7670_command, |
1352 | .command = ov7670_command, | 1351 | .probe = ov7670_probe, |
1352 | .remove = ov7670_remove, | ||
1353 | .legacy_class = I2C_CLASS_TV_ANALOG, | ||
1354 | .id_table = ov7670_id, | ||
1353 | }; | 1355 | }; |
1354 | |||
1355 | |||
1356 | /* | ||
1357 | * Module initialization | ||
1358 | */ | ||
1359 | static int __init ov7670_mod_init(void) | ||
1360 | { | ||
1361 | printk(KERN_NOTICE "OmniVision ov7670 sensor driver, at your service\n"); | ||
1362 | return i2c_add_driver(&ov7670_driver); | ||
1363 | } | ||
1364 | |||
1365 | static void __exit ov7670_mod_exit(void) | ||
1366 | { | ||
1367 | i2c_del_driver(&ov7670_driver); | ||
1368 | } | ||
1369 | |||
1370 | module_init(ov7670_mod_init); | ||
1371 | module_exit(ov7670_mod_exit); | ||