diff options
Diffstat (limited to 'drivers/media/video/ov772x.c')
-rw-r--r-- | drivers/media/video/ov772x.c | 381 |
1 files changed, 226 insertions, 155 deletions
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c index 0bce255168bd..eccb40ab7fec 100644 --- a/drivers/media/video/ov772x.c +++ b/drivers/media/video/ov772x.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/videodev2.h> | 23 | #include <linux/videodev2.h> |
24 | #include <media/v4l2-chip-ident.h> | 24 | #include <media/v4l2-chip-ident.h> |
25 | #include <media/v4l2-common.h> | 25 | #include <media/v4l2-subdev.h> |
26 | #include <media/soc_camera.h> | 26 | #include <media/soc_camera.h> |
27 | #include <media/ov772x.h> | 27 | #include <media/ov772x.h> |
28 | 28 | ||
@@ -382,11 +382,10 @@ struct regval_list { | |||
382 | }; | 382 | }; |
383 | 383 | ||
384 | struct ov772x_color_format { | 384 | struct ov772x_color_format { |
385 | char *name; | 385 | const struct soc_camera_data_format *format; |
386 | __u32 fourcc; | 386 | u8 dsp3; |
387 | u8 dsp3; | 387 | u8 com3; |
388 | u8 com3; | 388 | u8 com7; |
389 | u8 com7; | ||
390 | }; | 389 | }; |
391 | 390 | ||
392 | struct ov772x_win_size { | 391 | struct ov772x_win_size { |
@@ -398,14 +397,15 @@ struct ov772x_win_size { | |||
398 | }; | 397 | }; |
399 | 398 | ||
400 | struct ov772x_priv { | 399 | struct ov772x_priv { |
400 | struct v4l2_subdev subdev; | ||
401 | struct ov772x_camera_info *info; | 401 | struct ov772x_camera_info *info; |
402 | struct i2c_client *client; | ||
403 | struct soc_camera_device icd; | ||
404 | const struct ov772x_color_format *fmt; | 402 | const struct ov772x_color_format *fmt; |
405 | const struct ov772x_win_size *win; | 403 | const struct ov772x_win_size *win; |
406 | int model; | 404 | int model; |
407 | unsigned int flag_vflip:1; | 405 | unsigned short flag_vflip:1; |
408 | unsigned int flag_hflip:1; | 406 | unsigned short flag_hflip:1; |
407 | /* band_filter = COM8[5] ? 256 - BDBASE : 0 */ | ||
408 | unsigned short band_filter; | ||
409 | }; | 409 | }; |
410 | 410 | ||
411 | #define ENDMARKER { 0xff, 0xff } | 411 | #define ENDMARKER { 0xff, 0xff } |
@@ -481,43 +481,43 @@ static const struct soc_camera_data_format ov772x_fmt_lists[] = { | |||
481 | */ | 481 | */ |
482 | static const struct ov772x_color_format ov772x_cfmts[] = { | 482 | static const struct ov772x_color_format ov772x_cfmts[] = { |
483 | { | 483 | { |
484 | SETFOURCC(YUYV), | 484 | .format = &ov772x_fmt_lists[0], |
485 | .dsp3 = 0x0, | 485 | .dsp3 = 0x0, |
486 | .com3 = SWAP_YUV, | 486 | .com3 = SWAP_YUV, |
487 | .com7 = OFMT_YUV, | 487 | .com7 = OFMT_YUV, |
488 | }, | 488 | }, |
489 | { | 489 | { |
490 | SETFOURCC(YVYU), | 490 | .format = &ov772x_fmt_lists[1], |
491 | .dsp3 = UV_ON, | 491 | .dsp3 = UV_ON, |
492 | .com3 = SWAP_YUV, | 492 | .com3 = SWAP_YUV, |
493 | .com7 = OFMT_YUV, | 493 | .com7 = OFMT_YUV, |
494 | }, | 494 | }, |
495 | { | 495 | { |
496 | SETFOURCC(UYVY), | 496 | .format = &ov772x_fmt_lists[2], |
497 | .dsp3 = 0x0, | 497 | .dsp3 = 0x0, |
498 | .com3 = 0x0, | 498 | .com3 = 0x0, |
499 | .com7 = OFMT_YUV, | 499 | .com7 = OFMT_YUV, |
500 | }, | 500 | }, |
501 | { | 501 | { |
502 | SETFOURCC(RGB555), | 502 | .format = &ov772x_fmt_lists[3], |
503 | .dsp3 = 0x0, | 503 | .dsp3 = 0x0, |
504 | .com3 = SWAP_RGB, | 504 | .com3 = SWAP_RGB, |
505 | .com7 = FMT_RGB555 | OFMT_RGB, | 505 | .com7 = FMT_RGB555 | OFMT_RGB, |
506 | }, | 506 | }, |
507 | { | 507 | { |
508 | SETFOURCC(RGB555X), | 508 | .format = &ov772x_fmt_lists[4], |
509 | .dsp3 = 0x0, | 509 | .dsp3 = 0x0, |
510 | .com3 = 0x0, | 510 | .com3 = 0x0, |
511 | .com7 = FMT_RGB555 | OFMT_RGB, | 511 | .com7 = FMT_RGB555 | OFMT_RGB, |
512 | }, | 512 | }, |
513 | { | 513 | { |
514 | SETFOURCC(RGB565), | 514 | .format = &ov772x_fmt_lists[5], |
515 | .dsp3 = 0x0, | 515 | .dsp3 = 0x0, |
516 | .com3 = SWAP_RGB, | 516 | .com3 = SWAP_RGB, |
517 | .com7 = FMT_RGB565 | OFMT_RGB, | 517 | .com7 = FMT_RGB565 | OFMT_RGB, |
518 | }, | 518 | }, |
519 | { | 519 | { |
520 | SETFOURCC(RGB565X), | 520 | .format = &ov772x_fmt_lists[6], |
521 | .dsp3 = 0x0, | 521 | .dsp3 = 0x0, |
522 | .com3 = 0x0, | 522 | .com3 = 0x0, |
523 | .com7 = FMT_RGB565 | OFMT_RGB, | 523 | .com7 = FMT_RGB565 | OFMT_RGB, |
@@ -570,6 +570,15 @@ static const struct v4l2_queryctrl ov772x_controls[] = { | |||
570 | .step = 1, | 570 | .step = 1, |
571 | .default_value = 0, | 571 | .default_value = 0, |
572 | }, | 572 | }, |
573 | { | ||
574 | .id = V4L2_CID_BAND_STOP_FILTER, | ||
575 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
576 | .name = "Band-stop filter", | ||
577 | .minimum = 0, | ||
578 | .maximum = 256, | ||
579 | .step = 1, | ||
580 | .default_value = 0, | ||
581 | }, | ||
573 | }; | 582 | }; |
574 | 583 | ||
575 | 584 | ||
@@ -577,6 +586,12 @@ static const struct v4l2_queryctrl ov772x_controls[] = { | |||
577 | * general function | 586 | * general function |
578 | */ | 587 | */ |
579 | 588 | ||
589 | static struct ov772x_priv *to_ov772x(const struct i2c_client *client) | ||
590 | { | ||
591 | return container_of(i2c_get_clientdata(client), struct ov772x_priv, | ||
592 | subdev); | ||
593 | } | ||
594 | |||
580 | static int ov772x_write_array(struct i2c_client *client, | 595 | static int ov772x_write_array(struct i2c_client *client, |
581 | const struct regval_list *vals) | 596 | const struct regval_list *vals) |
582 | { | 597 | { |
@@ -617,58 +632,29 @@ static int ov772x_reset(struct i2c_client *client) | |||
617 | * soc_camera_ops function | 632 | * soc_camera_ops function |
618 | */ | 633 | */ |
619 | 634 | ||
620 | static int ov772x_init(struct soc_camera_device *icd) | 635 | static int ov772x_s_stream(struct v4l2_subdev *sd, int enable) |
621 | { | 636 | { |
622 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 637 | struct i2c_client *client = sd->priv; |
623 | int ret = 0; | 638 | struct ov772x_priv *priv = to_ov772x(client); |
624 | 639 | ||
625 | if (priv->info->link.power) { | 640 | if (!enable) { |
626 | ret = priv->info->link.power(&priv->client->dev, 1); | 641 | ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE); |
627 | if (ret < 0) | 642 | return 0; |
628 | return ret; | ||
629 | } | 643 | } |
630 | 644 | ||
631 | if (priv->info->link.reset) | ||
632 | ret = priv->info->link.reset(&priv->client->dev); | ||
633 | |||
634 | return ret; | ||
635 | } | ||
636 | |||
637 | static int ov772x_release(struct soc_camera_device *icd) | ||
638 | { | ||
639 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | ||
640 | int ret = 0; | ||
641 | |||
642 | if (priv->info->link.power) | ||
643 | ret = priv->info->link.power(&priv->client->dev, 0); | ||
644 | |||
645 | return ret; | ||
646 | } | ||
647 | |||
648 | static int ov772x_start_capture(struct soc_camera_device *icd) | ||
649 | { | ||
650 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | ||
651 | |||
652 | if (!priv->win || !priv->fmt) { | 645 | if (!priv->win || !priv->fmt) { |
653 | dev_err(&icd->dev, "norm or win select error\n"); | 646 | dev_err(&client->dev, "norm or win select error\n"); |
654 | return -EPERM; | 647 | return -EPERM; |
655 | } | 648 | } |
656 | 649 | ||
657 | ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, 0); | 650 | ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, 0); |
658 | 651 | ||
659 | dev_dbg(&icd->dev, | 652 | dev_dbg(&client->dev, "format %s, win %s\n", |
660 | "format %s, win %s\n", priv->fmt->name, priv->win->name); | 653 | priv->fmt->format->name, priv->win->name); |
661 | 654 | ||
662 | return 0; | 655 | return 0; |
663 | } | 656 | } |
664 | 657 | ||
665 | static int ov772x_stop_capture(struct soc_camera_device *icd) | ||
666 | { | ||
667 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | ||
668 | ov772x_mask_set(priv->client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE); | ||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | static int ov772x_set_bus_param(struct soc_camera_device *icd, | 658 | static int ov772x_set_bus_param(struct soc_camera_device *icd, |
673 | unsigned long flags) | 659 | unsigned long flags) |
674 | { | 660 | { |
@@ -677,8 +663,9 @@ static int ov772x_set_bus_param(struct soc_camera_device *icd, | |||
677 | 663 | ||
678 | static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd) | 664 | static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd) |
679 | { | 665 | { |
680 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 666 | struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd)); |
681 | struct soc_camera_link *icl = &priv->info->link; | 667 | struct ov772x_priv *priv = i2c_get_clientdata(client); |
668 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
682 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | | 669 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | |
683 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | | 670 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | |
684 | SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth; | 671 | SOCAM_DATA_ACTIVE_HIGH | priv->info->buswidth; |
@@ -686,10 +673,10 @@ static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd) | |||
686 | return soc_camera_apply_sensor_flags(icl, flags); | 673 | return soc_camera_apply_sensor_flags(icl, flags); |
687 | } | 674 | } |
688 | 675 | ||
689 | static int ov772x_get_control(struct soc_camera_device *icd, | 676 | static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
690 | struct v4l2_control *ctrl) | ||
691 | { | 677 | { |
692 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 678 | struct i2c_client *client = sd->priv; |
679 | struct ov772x_priv *priv = to_ov772x(client); | ||
693 | 680 | ||
694 | switch (ctrl->id) { | 681 | switch (ctrl->id) { |
695 | case V4L2_CID_VFLIP: | 682 | case V4L2_CID_VFLIP: |
@@ -698,14 +685,17 @@ static int ov772x_get_control(struct soc_camera_device *icd, | |||
698 | case V4L2_CID_HFLIP: | 685 | case V4L2_CID_HFLIP: |
699 | ctrl->value = priv->flag_hflip; | 686 | ctrl->value = priv->flag_hflip; |
700 | break; | 687 | break; |
688 | case V4L2_CID_BAND_STOP_FILTER: | ||
689 | ctrl->value = priv->band_filter; | ||
690 | break; | ||
701 | } | 691 | } |
702 | return 0; | 692 | return 0; |
703 | } | 693 | } |
704 | 694 | ||
705 | static int ov772x_set_control(struct soc_camera_device *icd, | 695 | static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) |
706 | struct v4l2_control *ctrl) | ||
707 | { | 696 | { |
708 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 697 | struct i2c_client *client = sd->priv; |
698 | struct ov772x_priv *priv = to_ov772x(client); | ||
709 | int ret = 0; | 699 | int ret = 0; |
710 | u8 val; | 700 | u8 val; |
711 | 701 | ||
@@ -715,24 +705,48 @@ static int ov772x_set_control(struct soc_camera_device *icd, | |||
715 | priv->flag_vflip = ctrl->value; | 705 | priv->flag_vflip = ctrl->value; |
716 | if (priv->info->flags & OV772X_FLAG_VFLIP) | 706 | if (priv->info->flags & OV772X_FLAG_VFLIP) |
717 | val ^= VFLIP_IMG; | 707 | val ^= VFLIP_IMG; |
718 | ret = ov772x_mask_set(priv->client, COM3, VFLIP_IMG, val); | 708 | ret = ov772x_mask_set(client, COM3, VFLIP_IMG, val); |
719 | break; | 709 | break; |
720 | case V4L2_CID_HFLIP: | 710 | case V4L2_CID_HFLIP: |
721 | val = ctrl->value ? HFLIP_IMG : 0x00; | 711 | val = ctrl->value ? HFLIP_IMG : 0x00; |
722 | priv->flag_hflip = ctrl->value; | 712 | priv->flag_hflip = ctrl->value; |
723 | if (priv->info->flags & OV772X_FLAG_HFLIP) | 713 | if (priv->info->flags & OV772X_FLAG_HFLIP) |
724 | val ^= HFLIP_IMG; | 714 | val ^= HFLIP_IMG; |
725 | ret = ov772x_mask_set(priv->client, COM3, HFLIP_IMG, val); | 715 | ret = ov772x_mask_set(client, COM3, HFLIP_IMG, val); |
716 | break; | ||
717 | case V4L2_CID_BAND_STOP_FILTER: | ||
718 | if ((unsigned)ctrl->value > 256) | ||
719 | ctrl->value = 256; | ||
720 | if (ctrl->value == priv->band_filter) | ||
721 | break; | ||
722 | if (!ctrl->value) { | ||
723 | /* Switch the filter off, it is on now */ | ||
724 | ret = ov772x_mask_set(client, BDBASE, 0xff, 0xff); | ||
725 | if (!ret) | ||
726 | ret = ov772x_mask_set(client, COM8, | ||
727 | BNDF_ON_OFF, 0); | ||
728 | } else { | ||
729 | /* Switch the filter on, set AEC low limit */ | ||
730 | val = 256 - ctrl->value; | ||
731 | ret = ov772x_mask_set(client, COM8, | ||
732 | BNDF_ON_OFF, BNDF_ON_OFF); | ||
733 | if (!ret) | ||
734 | ret = ov772x_mask_set(client, BDBASE, | ||
735 | 0xff, val); | ||
736 | } | ||
737 | if (!ret) | ||
738 | priv->band_filter = ctrl->value; | ||
726 | break; | 739 | break; |
727 | } | 740 | } |
728 | 741 | ||
729 | return ret; | 742 | return ret; |
730 | } | 743 | } |
731 | 744 | ||
732 | static int ov772x_get_chip_id(struct soc_camera_device *icd, | 745 | static int ov772x_g_chip_ident(struct v4l2_subdev *sd, |
733 | struct v4l2_dbg_chip_ident *id) | 746 | struct v4l2_dbg_chip_ident *id) |
734 | { | 747 | { |
735 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 748 | struct i2c_client *client = sd->priv; |
749 | struct ov772x_priv *priv = to_ov772x(client); | ||
736 | 750 | ||
737 | id->ident = priv->model; | 751 | id->ident = priv->model; |
738 | id->revision = 0; | 752 | id->revision = 0; |
@@ -741,17 +755,17 @@ static int ov772x_get_chip_id(struct soc_camera_device *icd, | |||
741 | } | 755 | } |
742 | 756 | ||
743 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 757 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
744 | static int ov772x_get_register(struct soc_camera_device *icd, | 758 | static int ov772x_g_register(struct v4l2_subdev *sd, |
745 | struct v4l2_dbg_register *reg) | 759 | struct v4l2_dbg_register *reg) |
746 | { | 760 | { |
747 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 761 | struct i2c_client *client = sd->priv; |
748 | int ret; | 762 | int ret; |
749 | 763 | ||
750 | reg->size = 1; | 764 | reg->size = 1; |
751 | if (reg->reg > 0xff) | 765 | if (reg->reg > 0xff) |
752 | return -EINVAL; | 766 | return -EINVAL; |
753 | 767 | ||
754 | ret = i2c_smbus_read_byte_data(priv->client, reg->reg); | 768 | ret = i2c_smbus_read_byte_data(client, reg->reg); |
755 | if (ret < 0) | 769 | if (ret < 0) |
756 | return ret; | 770 | return ret; |
757 | 771 | ||
@@ -760,21 +774,20 @@ static int ov772x_get_register(struct soc_camera_device *icd, | |||
760 | return 0; | 774 | return 0; |
761 | } | 775 | } |
762 | 776 | ||
763 | static int ov772x_set_register(struct soc_camera_device *icd, | 777 | static int ov772x_s_register(struct v4l2_subdev *sd, |
764 | struct v4l2_dbg_register *reg) | 778 | struct v4l2_dbg_register *reg) |
765 | { | 779 | { |
766 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 780 | struct i2c_client *client = sd->priv; |
767 | 781 | ||
768 | if (reg->reg > 0xff || | 782 | if (reg->reg > 0xff || |
769 | reg->val > 0xff) | 783 | reg->val > 0xff) |
770 | return -EINVAL; | 784 | return -EINVAL; |
771 | 785 | ||
772 | return i2c_smbus_write_byte_data(priv->client, reg->reg, reg->val); | 786 | return i2c_smbus_write_byte_data(client, reg->reg, reg->val); |
773 | } | 787 | } |
774 | #endif | 788 | #endif |
775 | 789 | ||
776 | static const struct ov772x_win_size* | 790 | static const struct ov772x_win_size *ov772x_select_win(u32 width, u32 height) |
777 | ov772x_select_win(u32 width, u32 height) | ||
778 | { | 791 | { |
779 | __u32 diff; | 792 | __u32 diff; |
780 | const struct ov772x_win_size *win; | 793 | const struct ov772x_win_size *win; |
@@ -793,9 +806,10 @@ ov772x_select_win(u32 width, u32 height) | |||
793 | return win; | 806 | return win; |
794 | } | 807 | } |
795 | 808 | ||
796 | static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | 809 | static int ov772x_set_params(struct i2c_client *client, |
797 | u32 pixfmt) | 810 | u32 *width, u32 *height, u32 pixfmt) |
798 | { | 811 | { |
812 | struct ov772x_priv *priv = to_ov772x(client); | ||
799 | int ret = -EINVAL; | 813 | int ret = -EINVAL; |
800 | u8 val; | 814 | u8 val; |
801 | int i; | 815 | int i; |
@@ -805,7 +819,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | |||
805 | */ | 819 | */ |
806 | priv->fmt = NULL; | 820 | priv->fmt = NULL; |
807 | for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) { | 821 | for (i = 0; i < ARRAY_SIZE(ov772x_cfmts); i++) { |
808 | if (pixfmt == ov772x_cfmts[i].fourcc) { | 822 | if (pixfmt == ov772x_cfmts[i].format->fourcc) { |
809 | priv->fmt = ov772x_cfmts + i; | 823 | priv->fmt = ov772x_cfmts + i; |
810 | break; | 824 | break; |
811 | } | 825 | } |
@@ -816,12 +830,12 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | |||
816 | /* | 830 | /* |
817 | * select win | 831 | * select win |
818 | */ | 832 | */ |
819 | priv->win = ov772x_select_win(width, height); | 833 | priv->win = ov772x_select_win(*width, *height); |
820 | 834 | ||
821 | /* | 835 | /* |
822 | * reset hardware | 836 | * reset hardware |
823 | */ | 837 | */ |
824 | ov772x_reset(priv->client); | 838 | ov772x_reset(client); |
825 | 839 | ||
826 | /* | 840 | /* |
827 | * Edge Ctrl | 841 | * Edge Ctrl |
@@ -835,17 +849,17 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | |||
835 | * Remove it when manual mode. | 849 | * Remove it when manual mode. |
836 | */ | 850 | */ |
837 | 851 | ||
838 | ret = ov772x_mask_set(priv->client, DSPAUTO, EDGE_ACTRL, 0x00); | 852 | ret = ov772x_mask_set(client, DSPAUTO, EDGE_ACTRL, 0x00); |
839 | if (ret < 0) | 853 | if (ret < 0) |
840 | goto ov772x_set_fmt_error; | 854 | goto ov772x_set_fmt_error; |
841 | 855 | ||
842 | ret = ov772x_mask_set(priv->client, | 856 | ret = ov772x_mask_set(client, |
843 | EDGE_TRSHLD, EDGE_THRESHOLD_MASK, | 857 | EDGE_TRSHLD, EDGE_THRESHOLD_MASK, |
844 | priv->info->edgectrl.threshold); | 858 | priv->info->edgectrl.threshold); |
845 | if (ret < 0) | 859 | if (ret < 0) |
846 | goto ov772x_set_fmt_error; | 860 | goto ov772x_set_fmt_error; |
847 | 861 | ||
848 | ret = ov772x_mask_set(priv->client, | 862 | ret = ov772x_mask_set(client, |
849 | EDGE_STRNGT, EDGE_STRENGTH_MASK, | 863 | EDGE_STRNGT, EDGE_STRENGTH_MASK, |
850 | priv->info->edgectrl.strength); | 864 | priv->info->edgectrl.strength); |
851 | if (ret < 0) | 865 | if (ret < 0) |
@@ -857,13 +871,13 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | |||
857 | * | 871 | * |
858 | * set upper and lower limit | 872 | * set upper and lower limit |
859 | */ | 873 | */ |
860 | ret = ov772x_mask_set(priv->client, | 874 | ret = ov772x_mask_set(client, |
861 | EDGE_UPPER, EDGE_UPPER_MASK, | 875 | EDGE_UPPER, EDGE_UPPER_MASK, |
862 | priv->info->edgectrl.upper); | 876 | priv->info->edgectrl.upper); |
863 | if (ret < 0) | 877 | if (ret < 0) |
864 | goto ov772x_set_fmt_error; | 878 | goto ov772x_set_fmt_error; |
865 | 879 | ||
866 | ret = ov772x_mask_set(priv->client, | 880 | ret = ov772x_mask_set(client, |
867 | EDGE_LOWER, EDGE_LOWER_MASK, | 881 | EDGE_LOWER, EDGE_LOWER_MASK, |
868 | priv->info->edgectrl.lower); | 882 | priv->info->edgectrl.lower); |
869 | if (ret < 0) | 883 | if (ret < 0) |
@@ -873,7 +887,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | |||
873 | /* | 887 | /* |
874 | * set size format | 888 | * set size format |
875 | */ | 889 | */ |
876 | ret = ov772x_write_array(priv->client, priv->win->regs); | 890 | ret = ov772x_write_array(client, priv->win->regs); |
877 | if (ret < 0) | 891 | if (ret < 0) |
878 | goto ov772x_set_fmt_error; | 892 | goto ov772x_set_fmt_error; |
879 | 893 | ||
@@ -882,7 +896,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | |||
882 | */ | 896 | */ |
883 | val = priv->fmt->dsp3; | 897 | val = priv->fmt->dsp3; |
884 | if (val) { | 898 | if (val) { |
885 | ret = ov772x_mask_set(priv->client, | 899 | ret = ov772x_mask_set(client, |
886 | DSP_CTRL3, UV_MASK, val); | 900 | DSP_CTRL3, UV_MASK, val); |
887 | if (ret < 0) | 901 | if (ret < 0) |
888 | goto ov772x_set_fmt_error; | 902 | goto ov772x_set_fmt_error; |
@@ -901,7 +915,7 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | |||
901 | if (priv->flag_hflip) | 915 | if (priv->flag_hflip) |
902 | val ^= HFLIP_IMG; | 916 | val ^= HFLIP_IMG; |
903 | 917 | ||
904 | ret = ov772x_mask_set(priv->client, | 918 | ret = ov772x_mask_set(client, |
905 | COM3, SWAP_MASK | IMG_MASK, val); | 919 | COM3, SWAP_MASK | IMG_MASK, val); |
906 | if (ret < 0) | 920 | if (ret < 0) |
907 | goto ov772x_set_fmt_error; | 921 | goto ov772x_set_fmt_error; |
@@ -910,47 +924,99 @@ static int ov772x_set_params(struct ov772x_priv *priv, u32 width, u32 height, | |||
910 | * set COM7 | 924 | * set COM7 |
911 | */ | 925 | */ |
912 | val = priv->win->com7_bit | priv->fmt->com7; | 926 | val = priv->win->com7_bit | priv->fmt->com7; |
913 | ret = ov772x_mask_set(priv->client, | 927 | ret = ov772x_mask_set(client, |
914 | COM7, (SLCT_MASK | FMT_MASK | OFMT_MASK), | 928 | COM7, (SLCT_MASK | FMT_MASK | OFMT_MASK), |
915 | val); | 929 | val); |
916 | if (ret < 0) | 930 | if (ret < 0) |
917 | goto ov772x_set_fmt_error; | 931 | goto ov772x_set_fmt_error; |
918 | 932 | ||
933 | /* | ||
934 | * set COM8 | ||
935 | */ | ||
936 | if (priv->band_filter) { | ||
937 | ret = ov772x_mask_set(client, COM8, BNDF_ON_OFF, 1); | ||
938 | if (!ret) | ||
939 | ret = ov772x_mask_set(client, BDBASE, | ||
940 | 0xff, 256 - priv->band_filter); | ||
941 | if (ret < 0) | ||
942 | goto ov772x_set_fmt_error; | ||
943 | } | ||
944 | |||
945 | *width = priv->win->width; | ||
946 | *height = priv->win->height; | ||
947 | |||
919 | return ret; | 948 | return ret; |
920 | 949 | ||
921 | ov772x_set_fmt_error: | 950 | ov772x_set_fmt_error: |
922 | 951 | ||
923 | ov772x_reset(priv->client); | 952 | ov772x_reset(client); |
924 | priv->win = NULL; | 953 | priv->win = NULL; |
925 | priv->fmt = NULL; | 954 | priv->fmt = NULL; |
926 | 955 | ||
927 | return ret; | 956 | return ret; |
928 | } | 957 | } |
929 | 958 | ||
930 | static int ov772x_set_crop(struct soc_camera_device *icd, | 959 | static int ov772x_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
931 | struct v4l2_rect *rect) | ||
932 | { | 960 | { |
933 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 961 | a->c.left = 0; |
962 | a->c.top = 0; | ||
963 | a->c.width = VGA_WIDTH; | ||
964 | a->c.height = VGA_HEIGHT; | ||
965 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
934 | 966 | ||
935 | if (!priv->fmt) | 967 | return 0; |
936 | return -EINVAL; | 968 | } |
937 | 969 | ||
938 | return ov772x_set_params(priv, rect->width, rect->height, | 970 | static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) |
939 | priv->fmt->fourcc); | 971 | { |
972 | a->bounds.left = 0; | ||
973 | a->bounds.top = 0; | ||
974 | a->bounds.width = VGA_WIDTH; | ||
975 | a->bounds.height = VGA_HEIGHT; | ||
976 | a->defrect = a->bounds; | ||
977 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
978 | a->pixelaspect.numerator = 1; | ||
979 | a->pixelaspect.denominator = 1; | ||
980 | |||
981 | return 0; | ||
940 | } | 982 | } |
941 | 983 | ||
942 | static int ov772x_set_fmt(struct soc_camera_device *icd, | 984 | static int ov772x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) |
943 | struct v4l2_format *f) | 985 | { |
986 | struct i2c_client *client = sd->priv; | ||
987 | struct ov772x_priv *priv = to_ov772x(client); | ||
988 | struct v4l2_pix_format *pix = &f->fmt.pix; | ||
989 | |||
990 | if (!priv->win || !priv->fmt) { | ||
991 | u32 width = VGA_WIDTH, height = VGA_HEIGHT; | ||
992 | int ret = ov772x_set_params(client, &width, &height, | ||
993 | V4L2_PIX_FMT_YUYV); | ||
994 | if (ret < 0) | ||
995 | return ret; | ||
996 | } | ||
997 | |||
998 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
999 | |||
1000 | pix->width = priv->win->width; | ||
1001 | pix->height = priv->win->height; | ||
1002 | pix->pixelformat = priv->fmt->format->fourcc; | ||
1003 | pix->colorspace = priv->fmt->format->colorspace; | ||
1004 | pix->field = V4L2_FIELD_NONE; | ||
1005 | |||
1006 | return 0; | ||
1007 | } | ||
1008 | |||
1009 | static int ov772x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f) | ||
944 | { | 1010 | { |
945 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 1011 | struct i2c_client *client = sd->priv; |
946 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1012 | struct v4l2_pix_format *pix = &f->fmt.pix; |
947 | 1013 | ||
948 | return ov772x_set_params(priv, pix->width, pix->height, | 1014 | return ov772x_set_params(client, &pix->width, &pix->height, |
949 | pix->pixelformat); | 1015 | pix->pixelformat); |
950 | } | 1016 | } |
951 | 1017 | ||
952 | static int ov772x_try_fmt(struct soc_camera_device *icd, | 1018 | static int ov772x_try_fmt(struct v4l2_subdev *sd, |
953 | struct v4l2_format *f) | 1019 | struct v4l2_format *f) |
954 | { | 1020 | { |
955 | struct v4l2_pix_format *pix = &f->fmt.pix; | 1021 | struct v4l2_pix_format *pix = &f->fmt.pix; |
956 | const struct ov772x_win_size *win; | 1022 | const struct ov772x_win_size *win; |
@@ -967,9 +1033,10 @@ static int ov772x_try_fmt(struct soc_camera_device *icd, | |||
967 | return 0; | 1033 | return 0; |
968 | } | 1034 | } |
969 | 1035 | ||
970 | static int ov772x_video_probe(struct soc_camera_device *icd) | 1036 | static int ov772x_video_probe(struct soc_camera_device *icd, |
1037 | struct i2c_client *client) | ||
971 | { | 1038 | { |
972 | struct ov772x_priv *priv = container_of(icd, struct ov772x_priv, icd); | 1039 | struct ov772x_priv *priv = to_ov772x(client); |
973 | u8 pid, ver; | 1040 | u8 pid, ver; |
974 | const char *devname; | 1041 | const char *devname; |
975 | 1042 | ||
@@ -986,7 +1053,7 @@ static int ov772x_video_probe(struct soc_camera_device *icd) | |||
986 | */ | 1053 | */ |
987 | if (SOCAM_DATAWIDTH_10 != priv->info->buswidth && | 1054 | if (SOCAM_DATAWIDTH_10 != priv->info->buswidth && |
988 | SOCAM_DATAWIDTH_8 != priv->info->buswidth) { | 1055 | SOCAM_DATAWIDTH_8 != priv->info->buswidth) { |
989 | dev_err(&icd->dev, "bus width error\n"); | 1056 | dev_err(&client->dev, "bus width error\n"); |
990 | return -ENODEV; | 1057 | return -ENODEV; |
991 | } | 1058 | } |
992 | 1059 | ||
@@ -996,8 +1063,8 @@ static int ov772x_video_probe(struct soc_camera_device *icd) | |||
996 | /* | 1063 | /* |
997 | * check and show product ID and manufacturer ID | 1064 | * check and show product ID and manufacturer ID |
998 | */ | 1065 | */ |
999 | pid = i2c_smbus_read_byte_data(priv->client, PID); | 1066 | pid = i2c_smbus_read_byte_data(client, PID); |
1000 | ver = i2c_smbus_read_byte_data(priv->client, VER); | 1067 | ver = i2c_smbus_read_byte_data(client, VER); |
1001 | 1068 | ||
1002 | switch (VERSION(pid, ver)) { | 1069 | switch (VERSION(pid, ver)) { |
1003 | case OV7720: | 1070 | case OV7720: |
@@ -1009,69 +1076,77 @@ static int ov772x_video_probe(struct soc_camera_device *icd) | |||
1009 | priv->model = V4L2_IDENT_OV7725; | 1076 | priv->model = V4L2_IDENT_OV7725; |
1010 | break; | 1077 | break; |
1011 | default: | 1078 | default: |
1012 | dev_err(&icd->dev, | 1079 | dev_err(&client->dev, |
1013 | "Product ID error %x:%x\n", pid, ver); | 1080 | "Product ID error %x:%x\n", pid, ver); |
1014 | return -ENODEV; | 1081 | return -ENODEV; |
1015 | } | 1082 | } |
1016 | 1083 | ||
1017 | dev_info(&icd->dev, | 1084 | dev_info(&client->dev, |
1018 | "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", | 1085 | "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", |
1019 | devname, | 1086 | devname, |
1020 | pid, | 1087 | pid, |
1021 | ver, | 1088 | ver, |
1022 | i2c_smbus_read_byte_data(priv->client, MIDH), | 1089 | i2c_smbus_read_byte_data(client, MIDH), |
1023 | i2c_smbus_read_byte_data(priv->client, MIDL)); | 1090 | i2c_smbus_read_byte_data(client, MIDL)); |
1024 | |||
1025 | return soc_camera_video_start(icd); | ||
1026 | } | ||
1027 | 1091 | ||
1028 | static void ov772x_video_remove(struct soc_camera_device *icd) | 1092 | return 0; |
1029 | { | ||
1030 | soc_camera_video_stop(icd); | ||
1031 | } | 1093 | } |
1032 | 1094 | ||
1033 | static struct soc_camera_ops ov772x_ops = { | 1095 | static struct soc_camera_ops ov772x_ops = { |
1034 | .owner = THIS_MODULE, | ||
1035 | .probe = ov772x_video_probe, | ||
1036 | .remove = ov772x_video_remove, | ||
1037 | .init = ov772x_init, | ||
1038 | .release = ov772x_release, | ||
1039 | .start_capture = ov772x_start_capture, | ||
1040 | .stop_capture = ov772x_stop_capture, | ||
1041 | .set_crop = ov772x_set_crop, | ||
1042 | .set_fmt = ov772x_set_fmt, | ||
1043 | .try_fmt = ov772x_try_fmt, | ||
1044 | .set_bus_param = ov772x_set_bus_param, | 1096 | .set_bus_param = ov772x_set_bus_param, |
1045 | .query_bus_param = ov772x_query_bus_param, | 1097 | .query_bus_param = ov772x_query_bus_param, |
1046 | .controls = ov772x_controls, | 1098 | .controls = ov772x_controls, |
1047 | .num_controls = ARRAY_SIZE(ov772x_controls), | 1099 | .num_controls = ARRAY_SIZE(ov772x_controls), |
1048 | .get_control = ov772x_get_control, | 1100 | }; |
1049 | .set_control = ov772x_set_control, | 1101 | |
1050 | .get_chip_id = ov772x_get_chip_id, | 1102 | static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { |
1103 | .g_ctrl = ov772x_g_ctrl, | ||
1104 | .s_ctrl = ov772x_s_ctrl, | ||
1105 | .g_chip_ident = ov772x_g_chip_ident, | ||
1051 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 1106 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
1052 | .get_register = ov772x_get_register, | 1107 | .g_register = ov772x_g_register, |
1053 | .set_register = ov772x_set_register, | 1108 | .s_register = ov772x_s_register, |
1054 | #endif | 1109 | #endif |
1055 | }; | 1110 | }; |
1056 | 1111 | ||
1112 | static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { | ||
1113 | .s_stream = ov772x_s_stream, | ||
1114 | .g_fmt = ov772x_g_fmt, | ||
1115 | .s_fmt = ov772x_s_fmt, | ||
1116 | .try_fmt = ov772x_try_fmt, | ||
1117 | .cropcap = ov772x_cropcap, | ||
1118 | .g_crop = ov772x_g_crop, | ||
1119 | }; | ||
1120 | |||
1121 | static struct v4l2_subdev_ops ov772x_subdev_ops = { | ||
1122 | .core = &ov772x_subdev_core_ops, | ||
1123 | .video = &ov772x_subdev_video_ops, | ||
1124 | }; | ||
1125 | |||
1057 | /* | 1126 | /* |
1058 | * i2c_driver function | 1127 | * i2c_driver function |
1059 | */ | 1128 | */ |
1060 | 1129 | ||
1061 | static int ov772x_probe(struct i2c_client *client, | 1130 | static int ov772x_probe(struct i2c_client *client, |
1062 | const struct i2c_device_id *did) | 1131 | const struct i2c_device_id *did) |
1063 | { | 1132 | { |
1064 | struct ov772x_priv *priv; | 1133 | struct ov772x_priv *priv; |
1065 | struct ov772x_camera_info *info; | 1134 | struct ov772x_camera_info *info; |
1066 | struct soc_camera_device *icd; | 1135 | struct soc_camera_device *icd = client->dev.platform_data; |
1067 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); | 1136 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
1137 | struct soc_camera_link *icl; | ||
1068 | int ret; | 1138 | int ret; |
1069 | 1139 | ||
1070 | if (!client->dev.platform_data) | 1140 | if (!icd) { |
1141 | dev_err(&client->dev, "OV772X: missing soc-camera data!\n"); | ||
1071 | return -EINVAL; | 1142 | return -EINVAL; |
1143 | } | ||
1072 | 1144 | ||
1073 | info = container_of(client->dev.platform_data, | 1145 | icl = to_soc_camera_link(icd); |
1074 | struct ov772x_camera_info, link); | 1146 | if (!icl) |
1147 | return -EINVAL; | ||
1148 | |||
1149 | info = container_of(icl, struct ov772x_camera_info, link); | ||
1075 | 1150 | ||
1076 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { | 1151 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { |
1077 | dev_err(&adapter->dev, | 1152 | dev_err(&adapter->dev, |
@@ -1084,20 +1159,15 @@ static int ov772x_probe(struct i2c_client *client, | |||
1084 | if (!priv) | 1159 | if (!priv) |
1085 | return -ENOMEM; | 1160 | return -ENOMEM; |
1086 | 1161 | ||
1087 | priv->info = info; | 1162 | priv->info = info; |
1088 | priv->client = client; | ||
1089 | i2c_set_clientdata(client, priv); | ||
1090 | 1163 | ||
1091 | icd = &priv->icd; | 1164 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov772x_subdev_ops); |
1092 | icd->ops = &ov772x_ops; | ||
1093 | icd->control = &client->dev; | ||
1094 | icd->width_max = MAX_WIDTH; | ||
1095 | icd->height_max = MAX_HEIGHT; | ||
1096 | icd->iface = priv->info->link.bus_id; | ||
1097 | 1165 | ||
1098 | ret = soc_camera_device_register(icd); | 1166 | icd->ops = &ov772x_ops; |
1099 | 1167 | ||
1168 | ret = ov772x_video_probe(icd, client); | ||
1100 | if (ret) { | 1169 | if (ret) { |
1170 | icd->ops = NULL; | ||
1101 | i2c_set_clientdata(client, NULL); | 1171 | i2c_set_clientdata(client, NULL); |
1102 | kfree(priv); | 1172 | kfree(priv); |
1103 | } | 1173 | } |
@@ -1107,9 +1177,10 @@ static int ov772x_probe(struct i2c_client *client, | |||
1107 | 1177 | ||
1108 | static int ov772x_remove(struct i2c_client *client) | 1178 | static int ov772x_remove(struct i2c_client *client) |
1109 | { | 1179 | { |
1110 | struct ov772x_priv *priv = i2c_get_clientdata(client); | 1180 | struct ov772x_priv *priv = to_ov772x(client); |
1181 | struct soc_camera_device *icd = client->dev.platform_data; | ||
1111 | 1182 | ||
1112 | soc_camera_device_unregister(&priv->icd); | 1183 | icd->ops = NULL; |
1113 | i2c_set_clientdata(client, NULL); | 1184 | i2c_set_clientdata(client, NULL); |
1114 | kfree(priv); | 1185 | kfree(priv); |
1115 | return 0; | 1186 | return 0; |