diff options
author | Bastian Hecht <hechtb@googlemail.com> | 2011-09-08 12:15:24 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-11-03 16:29:05 -0400 |
commit | 171f1a48bb3f95e3ecb37ecd6e8577118d601460 (patch) | |
tree | 1e3dcbd0ea5dd18ac3df7f56d5c68425c00c6834 /drivers/media/video/ov5642.c | |
parent | 95d20109ad6478ecea5e93ba191270fb645d52c7 (diff) |
[media] media: ov5642: Add support for arbitrary resolution
This patch adds the ability to get arbitrary resolutions with a width
up to 2592 and a height up to 720 pixels instead of the standard 1280x720
only.
Signed-off-by: Bastian Hecht <hechtb@gmail.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/ov5642.c')
-rw-r--r-- | drivers/media/video/ov5642.c | 240 |
1 files changed, 167 insertions, 73 deletions
diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c index 54178cbeabb4..bb37ec80f274 100644 --- a/drivers/media/video/ov5642.c +++ b/drivers/media/video/ov5642.c | |||
@@ -14,8 +14,10 @@ | |||
14 | * published by the Free Software Foundation. | 14 | * published by the Free Software Foundation. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/bitops.h> | ||
17 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
18 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
20 | #include <linux/kernel.h> | ||
19 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
20 | #include <linux/videodev2.h> | 22 | #include <linux/videodev2.h> |
21 | #include <linux/module.h> | 23 | #include <linux/module.h> |
@@ -35,7 +37,7 @@ | |||
35 | #define REG_WINDOW_START_Y_LOW 0x3803 | 37 | #define REG_WINDOW_START_Y_LOW 0x3803 |
36 | #define REG_WINDOW_WIDTH_HIGH 0x3804 | 38 | #define REG_WINDOW_WIDTH_HIGH 0x3804 |
37 | #define REG_WINDOW_WIDTH_LOW 0x3805 | 39 | #define REG_WINDOW_WIDTH_LOW 0x3805 |
38 | #define REG_WINDOW_HEIGHT_HIGH 0x3806 | 40 | #define REG_WINDOW_HEIGHT_HIGH 0x3806 |
39 | #define REG_WINDOW_HEIGHT_LOW 0x3807 | 41 | #define REG_WINDOW_HEIGHT_LOW 0x3807 |
40 | #define REG_OUT_WIDTH_HIGH 0x3808 | 42 | #define REG_OUT_WIDTH_HIGH 0x3808 |
41 | #define REG_OUT_WIDTH_LOW 0x3809 | 43 | #define REG_OUT_WIDTH_LOW 0x3809 |
@@ -45,19 +47,44 @@ | |||
45 | #define REG_OUT_TOTAL_WIDTH_LOW 0x380d | 47 | #define REG_OUT_TOTAL_WIDTH_LOW 0x380d |
46 | #define REG_OUT_TOTAL_HEIGHT_HIGH 0x380e | 48 | #define REG_OUT_TOTAL_HEIGHT_HIGH 0x380e |
47 | #define REG_OUT_TOTAL_HEIGHT_LOW 0x380f | 49 | #define REG_OUT_TOTAL_HEIGHT_LOW 0x380f |
50 | #define REG_OUTPUT_FORMAT 0x4300 | ||
51 | #define REG_ISP_CTRL_01 0x5001 | ||
52 | #define REG_AVG_WINDOW_END_X_HIGH 0x5682 | ||
53 | #define REG_AVG_WINDOW_END_X_LOW 0x5683 | ||
54 | #define REG_AVG_WINDOW_END_Y_HIGH 0x5686 | ||
55 | #define REG_AVG_WINDOW_END_Y_LOW 0x5687 | ||
56 | |||
57 | /* active pixel array size */ | ||
58 | #define OV5642_SENSOR_SIZE_X 2592 | ||
59 | #define OV5642_SENSOR_SIZE_Y 1944 | ||
48 | 60 | ||
49 | /* | 61 | /* |
50 | * define standard resolution. | 62 | * About OV5642 resolution, cropping and binning: |
51 | * Works currently only for up to 720 lines | 63 | * This sensor supports it all, at least in the feature description. |
52 | * eg. 320x240, 640x480, 800x600, 1280x720, 2048x720 | 64 | * Unfortunately, no combination of appropriate registers settings could make |
65 | * the chip work the intended way. As it works with predefined register lists, | ||
66 | * some undocumented registers are presumably changed there to achieve their | ||
67 | * goals. | ||
68 | * This driver currently only works for resolutions up to 720 lines with a | ||
69 | * 1:1 scale. Hopefully these restrictions will be removed in the future. | ||
53 | */ | 70 | */ |
71 | #define OV5642_MAX_WIDTH OV5642_SENSOR_SIZE_X | ||
72 | #define OV5642_MAX_HEIGHT 720 | ||
54 | 73 | ||
55 | #define OV5642_WIDTH 1280 | 74 | /* default sizes */ |
56 | #define OV5642_HEIGHT 720 | 75 | #define OV5642_DEFAULT_WIDTH 1280 |
57 | #define OV5642_TOTAL_WIDTH 3200 | 76 | #define OV5642_DEFAULT_HEIGHT OV5642_MAX_HEIGHT |
58 | #define OV5642_TOTAL_HEIGHT 2000 | 77 | |
59 | #define OV5642_SENSOR_SIZE_X 2592 | 78 | /* minimum extra blanking */ |
60 | #define OV5642_SENSOR_SIZE_Y 1944 | 79 | #define BLANKING_EXTRA_WIDTH 500 |
80 | #define BLANKING_EXTRA_HEIGHT 20 | ||
81 | |||
82 | /* | ||
83 | * the sensor's autoexposure is buggy when setting total_height low. | ||
84 | * It tries to expose longer than 1 frame period without taking care of it | ||
85 | * and this leads to weird output. So we set 1000 lines as minimum. | ||
86 | */ | ||
87 | #define BLANKING_MIN_HEIGHT 1000 | ||
61 | 88 | ||
62 | struct regval_list { | 89 | struct regval_list { |
63 | u16 reg_num; | 90 | u16 reg_num; |
@@ -582,6 +609,11 @@ struct ov5642_datafmt { | |||
582 | struct ov5642 { | 609 | struct ov5642 { |
583 | struct v4l2_subdev subdev; | 610 | struct v4l2_subdev subdev; |
584 | const struct ov5642_datafmt *fmt; | 611 | const struct ov5642_datafmt *fmt; |
612 | struct v4l2_rect crop_rect; | ||
613 | |||
614 | /* blanking information */ | ||
615 | int total_width; | ||
616 | int total_height; | ||
585 | }; | 617 | }; |
586 | 618 | ||
587 | static const struct ov5642_datafmt ov5642_colour_fmts[] = { | 619 | static const struct ov5642_datafmt ov5642_colour_fmts[] = { |
@@ -642,6 +674,21 @@ static int reg_write(struct i2c_client *client, u16 reg, u8 val) | |||
642 | 674 | ||
643 | return 0; | 675 | return 0; |
644 | } | 676 | } |
677 | |||
678 | /* | ||
679 | * convenience function to write 16 bit register values that are split up | ||
680 | * into two consecutive high and low parts | ||
681 | */ | ||
682 | static int reg_write16(struct i2c_client *client, u16 reg, u16 val16) | ||
683 | { | ||
684 | int ret; | ||
685 | |||
686 | ret = reg_write(client, reg, val16 >> 8); | ||
687 | if (ret) | ||
688 | return ret; | ||
689 | return reg_write(client, reg + 1, val16 & 0x00ff); | ||
690 | } | ||
691 | |||
645 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 692 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
646 | static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) | 693 | static int ov5642_get_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) |
647 | { | 694 | { |
@@ -685,58 +732,55 @@ static int ov5642_write_array(struct i2c_client *client, | |||
685 | return 0; | 732 | return 0; |
686 | } | 733 | } |
687 | 734 | ||
688 | static int ov5642_set_resolution(struct i2c_client *client) | 735 | static int ov5642_set_resolution(struct v4l2_subdev *sd) |
689 | { | 736 | { |
737 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
738 | struct ov5642 *priv = to_ov5642(client); | ||
739 | int width = priv->crop_rect.width; | ||
740 | int height = priv->crop_rect.height; | ||
741 | int total_width = priv->total_width; | ||
742 | int total_height = priv->total_height; | ||
743 | int start_x = (OV5642_SENSOR_SIZE_X - width) / 2; | ||
744 | int start_y = (OV5642_SENSOR_SIZE_Y - height) / 2; | ||
690 | int ret; | 745 | int ret; |
691 | u8 start_x_high = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) >> 8; | ||
692 | u8 start_x_low = ((OV5642_SENSOR_SIZE_X - OV5642_WIDTH) / 2) & 0xff; | ||
693 | u8 start_y_high = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) >> 8; | ||
694 | u8 start_y_low = ((OV5642_SENSOR_SIZE_Y - OV5642_HEIGHT) / 2) & 0xff; | ||
695 | |||
696 | u8 width_high = OV5642_WIDTH >> 8; | ||
697 | u8 width_low = OV5642_WIDTH & 0xff; | ||
698 | u8 height_high = OV5642_HEIGHT >> 8; | ||
699 | u8 height_low = OV5642_HEIGHT & 0xff; | ||
700 | |||
701 | u8 total_width_high = OV5642_TOTAL_WIDTH >> 8; | ||
702 | u8 total_width_low = OV5642_TOTAL_WIDTH & 0xff; | ||
703 | u8 total_height_high = OV5642_TOTAL_HEIGHT >> 8; | ||
704 | u8 total_height_low = OV5642_TOTAL_HEIGHT & 0xff; | ||
705 | |||
706 | ret = reg_write(client, REG_WINDOW_START_X_HIGH, start_x_high); | ||
707 | if (!ret) | ||
708 | ret = reg_write(client, REG_WINDOW_START_X_LOW, start_x_low); | ||
709 | if (!ret) | ||
710 | ret = reg_write(client, REG_WINDOW_START_Y_HIGH, start_y_high); | ||
711 | if (!ret) | ||
712 | ret = reg_write(client, REG_WINDOW_START_Y_LOW, start_y_low); | ||
713 | 746 | ||
747 | /* | ||
748 | * This should set the starting point for cropping. | ||
749 | * Doesn't work so far. | ||
750 | */ | ||
751 | ret = reg_write16(client, REG_WINDOW_START_X_HIGH, start_x); | ||
714 | if (!ret) | 752 | if (!ret) |
715 | ret = reg_write(client, REG_WINDOW_WIDTH_HIGH, width_high); | 753 | ret = reg_write16(client, REG_WINDOW_START_Y_HIGH, start_y); |
716 | if (!ret) | 754 | if (!ret) { |
717 | ret = reg_write(client, REG_WINDOW_WIDTH_LOW , width_low); | 755 | priv->crop_rect.left = start_x; |
718 | if (!ret) | 756 | priv->crop_rect.top = start_y; |
719 | ret = reg_write(client, REG_WINDOW_HEIGHT_HIGH, height_high); | 757 | } |
720 | if (!ret) | ||
721 | ret = reg_write(client, REG_WINDOW_HEIGHT_LOW, height_low); | ||
722 | 758 | ||
723 | if (!ret) | 759 | if (!ret) |
724 | ret = reg_write(client, REG_OUT_WIDTH_HIGH, width_high); | 760 | ret = reg_write16(client, REG_WINDOW_WIDTH_HIGH, width); |
725 | if (!ret) | 761 | if (!ret) |
726 | ret = reg_write(client, REG_OUT_WIDTH_LOW , width_low); | 762 | ret = reg_write16(client, REG_WINDOW_HEIGHT_HIGH, height); |
727 | if (!ret) | 763 | if (ret) |
728 | ret = reg_write(client, REG_OUT_HEIGHT_HIGH, height_high); | 764 | return ret; |
765 | priv->crop_rect.width = width; | ||
766 | priv->crop_rect.height = height; | ||
767 | |||
768 | /* Set the output window size. Only 1:1 scale is supported so far. */ | ||
769 | ret = reg_write16(client, REG_OUT_WIDTH_HIGH, width); | ||
729 | if (!ret) | 770 | if (!ret) |
730 | ret = reg_write(client, REG_OUT_HEIGHT_LOW, height_low); | 771 | ret = reg_write16(client, REG_OUT_HEIGHT_HIGH, height); |
731 | 772 | ||
773 | /* Total width = output size + blanking */ | ||
732 | if (!ret) | 774 | if (!ret) |
733 | ret = reg_write(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width_high); | 775 | ret = reg_write16(client, REG_OUT_TOTAL_WIDTH_HIGH, total_width); |
734 | if (!ret) | 776 | if (!ret) |
735 | ret = reg_write(client, REG_OUT_TOTAL_WIDTH_LOW, total_width_low); | 777 | ret = reg_write16(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height); |
778 | |||
779 | /* Sets the window for AWB calculations */ | ||
736 | if (!ret) | 780 | if (!ret) |
737 | ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_HIGH, total_height_high); | 781 | ret = reg_write16(client, REG_AVG_WINDOW_END_X_HIGH, width); |
738 | if (!ret) | 782 | if (!ret) |
739 | ret = reg_write(client, REG_OUT_TOTAL_HEIGHT_LOW, total_height_low); | 783 | ret = reg_write16(client, REG_AVG_WINDOW_END_Y_HIGH, height); |
740 | 784 | ||
741 | return ret; | 785 | return ret; |
742 | } | 786 | } |
@@ -744,18 +788,18 @@ static int ov5642_set_resolution(struct i2c_client *client) | |||
744 | static int ov5642_try_fmt(struct v4l2_subdev *sd, | 788 | static int ov5642_try_fmt(struct v4l2_subdev *sd, |
745 | struct v4l2_mbus_framefmt *mf) | 789 | struct v4l2_mbus_framefmt *mf) |
746 | { | 790 | { |
791 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
792 | struct ov5642 *priv = to_ov5642(client); | ||
747 | const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code); | 793 | const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code); |
748 | 794 | ||
749 | dev_dbg(sd->v4l2_dev->dev, "%s(%u) width: %u heigth: %u\n", | 795 | mf->width = priv->crop_rect.width; |
750 | __func__, mf->code, mf->width, mf->height); | 796 | mf->height = priv->crop_rect.height; |
751 | 797 | ||
752 | if (!fmt) { | 798 | if (!fmt) { |
753 | mf->code = ov5642_colour_fmts[0].code; | 799 | mf->code = ov5642_colour_fmts[0].code; |
754 | mf->colorspace = ov5642_colour_fmts[0].colorspace; | 800 | mf->colorspace = ov5642_colour_fmts[0].colorspace; |
755 | } | 801 | } |
756 | 802 | ||
757 | mf->width = OV5642_WIDTH; | ||
758 | mf->height = OV5642_HEIGHT; | ||
759 | mf->field = V4L2_FIELD_NONE; | 803 | mf->field = V4L2_FIELD_NONE; |
760 | 804 | ||
761 | return 0; | 805 | return 0; |
@@ -767,20 +811,13 @@ static int ov5642_s_fmt(struct v4l2_subdev *sd, | |||
767 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 811 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
768 | struct ov5642 *priv = to_ov5642(client); | 812 | struct ov5642 *priv = to_ov5642(client); |
769 | 813 | ||
770 | dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); | ||
771 | |||
772 | /* MIPI CSI could have changed the format, double-check */ | 814 | /* MIPI CSI could have changed the format, double-check */ |
773 | if (!ov5642_find_datafmt(mf->code)) | 815 | if (!ov5642_find_datafmt(mf->code)) |
774 | return -EINVAL; | 816 | return -EINVAL; |
775 | 817 | ||
776 | ov5642_try_fmt(sd, mf); | 818 | ov5642_try_fmt(sd, mf); |
777 | |||
778 | priv->fmt = ov5642_find_datafmt(mf->code); | 819 | priv->fmt = ov5642_find_datafmt(mf->code); |
779 | 820 | ||
780 | ov5642_write_array(client, ov5642_default_regs_init); | ||
781 | ov5642_set_resolution(client); | ||
782 | ov5642_write_array(client, ov5642_default_regs_finalise); | ||
783 | |||
784 | return 0; | 821 | return 0; |
785 | } | 822 | } |
786 | 823 | ||
@@ -794,8 +831,8 @@ static int ov5642_g_fmt(struct v4l2_subdev *sd, | |||
794 | 831 | ||
795 | mf->code = fmt->code; | 832 | mf->code = fmt->code; |
796 | mf->colorspace = fmt->colorspace; | 833 | mf->colorspace = fmt->colorspace; |
797 | mf->width = OV5642_WIDTH; | 834 | mf->width = priv->crop_rect.width; |
798 | mf->height = OV5642_HEIGHT; | 835 | mf->height = priv->crop_rect.height; |
799 | mf->field = V4L2_FIELD_NONE; | 836 | mf->field = V4L2_FIELD_NONE; |
800 | 837 | ||
801 | return 0; | 838 | return 0; |
@@ -828,15 +865,44 @@ static int ov5642_g_chip_ident(struct v4l2_subdev *sd, | |||
828 | return 0; | 865 | return 0; |
829 | } | 866 | } |
830 | 867 | ||
868 | static int ov5642_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | ||
869 | { | ||
870 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
871 | struct ov5642 *priv = to_ov5642(client); | ||
872 | struct v4l2_rect *rect = &a->c; | ||
873 | int ret; | ||
874 | |||
875 | v4l_bound_align_image(&rect->width, 48, OV5642_MAX_WIDTH, 1, | ||
876 | &rect->height, 32, OV5642_MAX_HEIGHT, 1, 0); | ||
877 | |||
878 | priv->crop_rect.width = rect->width; | ||
879 | priv->crop_rect.height = rect->height; | ||
880 | priv->total_width = rect->width + BLANKING_EXTRA_WIDTH; | ||
881 | priv->total_height = max_t(int, rect->height + | ||
882 | BLANKING_EXTRA_HEIGHT, | ||
883 | BLANKING_MIN_HEIGHT); | ||
884 | priv->crop_rect.width = rect->width; | ||
885 | priv->crop_rect.height = rect->height; | ||
886 | |||
887 | ret = ov5642_write_array(client, ov5642_default_regs_init); | ||
888 | if (!ret) | ||
889 | ret = ov5642_set_resolution(sd); | ||
890 | if (!ret) | ||
891 | ret = ov5642_write_array(client, ov5642_default_regs_finalise); | ||
892 | |||
893 | return ret; | ||
894 | } | ||
895 | |||
831 | static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | 896 | static int ov5642_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) |
832 | { | 897 | { |
898 | struct i2c_client *client = v4l2_get_subdevdata(sd); | ||
899 | struct ov5642 *priv = to_ov5642(client); | ||
833 | struct v4l2_rect *rect = &a->c; | 900 | struct v4l2_rect *rect = &a->c; |
834 | 901 | ||
835 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 902 | if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
836 | rect->top = 0; | 903 | return -EINVAL; |
837 | rect->left = 0; | 904 | |
838 | rect->width = OV5642_WIDTH; | 905 | *rect = priv->crop_rect; |
839 | rect->height = OV5642_HEIGHT; | ||
840 | 906 | ||
841 | return 0; | 907 | return 0; |
842 | } | 908 | } |
@@ -845,8 +911,8 @@ static int ov5642_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
845 | { | 911 | { |
846 | a->bounds.left = 0; | 912 | a->bounds.left = 0; |
847 | a->bounds.top = 0; | 913 | a->bounds.top = 0; |
848 | a->bounds.width = OV5642_WIDTH; | 914 | a->bounds.width = OV5642_MAX_WIDTH; |
849 | a->bounds.height = OV5642_HEIGHT; | 915 | a->bounds.height = OV5642_MAX_HEIGHT; |
850 | a->defrect = a->bounds; | 916 | a->defrect = a->bounds; |
851 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 917 | a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
852 | a->pixelaspect.numerator = 1; | 918 | a->pixelaspect.numerator = 1; |
@@ -859,24 +925,43 @@ static int ov5642_g_mbus_config(struct v4l2_subdev *sd, | |||
859 | struct v4l2_mbus_config *cfg) | 925 | struct v4l2_mbus_config *cfg) |
860 | { | 926 | { |
861 | cfg->type = V4L2_MBUS_CSI2; | 927 | cfg->type = V4L2_MBUS_CSI2; |
862 | cfg->flags = V4L2_MBUS_CSI2_2_LANE | | 928 | cfg->flags = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | |
863 | V4L2_MBUS_CSI2_CHANNEL_0 | | 929 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; |
864 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; | ||
865 | 930 | ||
866 | return 0; | 931 | return 0; |
867 | } | 932 | } |
868 | 933 | ||
934 | static int ov5642_s_power(struct v4l2_subdev *sd, int on) | ||
935 | { | ||
936 | struct i2c_client *client; | ||
937 | int ret; | ||
938 | |||
939 | if (!on) | ||
940 | return 0; | ||
941 | |||
942 | client = v4l2_get_subdevdata(sd); | ||
943 | ret = ov5642_write_array(client, ov5642_default_regs_init); | ||
944 | if (!ret) | ||
945 | ret = ov5642_set_resolution(sd); | ||
946 | if (!ret) | ||
947 | ret = ov5642_write_array(client, ov5642_default_regs_finalise); | ||
948 | |||
949 | return ret; | ||
950 | } | ||
951 | |||
869 | static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { | 952 | static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { |
870 | .s_mbus_fmt = ov5642_s_fmt, | 953 | .s_mbus_fmt = ov5642_s_fmt, |
871 | .g_mbus_fmt = ov5642_g_fmt, | 954 | .g_mbus_fmt = ov5642_g_fmt, |
872 | .try_mbus_fmt = ov5642_try_fmt, | 955 | .try_mbus_fmt = ov5642_try_fmt, |
873 | .enum_mbus_fmt = ov5642_enum_fmt, | 956 | .enum_mbus_fmt = ov5642_enum_fmt, |
957 | .s_crop = ov5642_s_crop, | ||
874 | .g_crop = ov5642_g_crop, | 958 | .g_crop = ov5642_g_crop, |
875 | .cropcap = ov5642_cropcap, | 959 | .cropcap = ov5642_cropcap, |
876 | .g_mbus_config = ov5642_g_mbus_config, | 960 | .g_mbus_config = ov5642_g_mbus_config, |
877 | }; | 961 | }; |
878 | 962 | ||
879 | static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { | 963 | static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { |
964 | .s_power = ov5642_s_power, | ||
880 | .g_chip_ident = ov5642_g_chip_ident, | 965 | .g_chip_ident = ov5642_g_chip_ident, |
881 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 966 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
882 | .g_register = ov5642_get_register, | 967 | .g_register = ov5642_get_register, |
@@ -934,7 +1019,16 @@ static int ov5642_probe(struct i2c_client *client, | |||
934 | 1019 | ||
935 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops); | 1020 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops); |
936 | 1021 | ||
937 | priv->fmt = &ov5642_colour_fmts[0]; | 1022 | priv->fmt = &ov5642_colour_fmts[0]; |
1023 | |||
1024 | priv->crop_rect.width = OV5642_DEFAULT_WIDTH; | ||
1025 | priv->crop_rect.height = OV5642_DEFAULT_HEIGHT; | ||
1026 | priv->crop_rect.left = (OV5642_MAX_WIDTH - OV5642_DEFAULT_WIDTH) / 2; | ||
1027 | priv->crop_rect.top = (OV5642_MAX_HEIGHT - OV5642_DEFAULT_HEIGHT) / 2; | ||
1028 | priv->crop_rect.width = OV5642_DEFAULT_WIDTH; | ||
1029 | priv->crop_rect.height = OV5642_DEFAULT_HEIGHT; | ||
1030 | priv->total_width = OV5642_DEFAULT_WIDTH + BLANKING_EXTRA_WIDTH; | ||
1031 | priv->total_height = BLANKING_MIN_HEIGHT; | ||
938 | 1032 | ||
939 | ret = ov5642_video_probe(client); | 1033 | ret = ov5642_video_probe(client); |
940 | if (ret < 0) | 1034 | if (ret < 0) |