diff options
Diffstat (limited to 'drivers/media/video/ov5642.c')
-rw-r--r-- | drivers/media/video/ov5642.c | 288 |
1 files changed, 181 insertions, 107 deletions
diff --git a/drivers/media/video/ov5642.c b/drivers/media/video/ov5642.c index 349a4ad3ccc1..bb37ec80f274 100644 --- a/drivers/media/video/ov5642.c +++ b/drivers/media/video/ov5642.c | |||
@@ -14,14 +14,16 @@ | |||
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> |
24 | #include <linux/v4l2-mediabus.h> | ||
22 | 25 | ||
23 | #include <media/soc_camera.h> | 26 | #include <media/soc_camera.h> |
24 | #include <media/soc_mediabus.h> | ||
25 | #include <media/v4l2-chip-ident.h> | 27 | #include <media/v4l2-chip-ident.h> |
26 | #include <media/v4l2-subdev.h> | 28 | #include <media/v4l2-subdev.h> |
27 | 29 | ||
@@ -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; |
@@ -855,16 +921,47 @@ static int ov5642_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) | |||
855 | return 0; | 921 | return 0; |
856 | } | 922 | } |
857 | 923 | ||
924 | static int ov5642_g_mbus_config(struct v4l2_subdev *sd, | ||
925 | struct v4l2_mbus_config *cfg) | ||
926 | { | ||
927 | cfg->type = V4L2_MBUS_CSI2; | ||
928 | cfg->flags = V4L2_MBUS_CSI2_2_LANE | V4L2_MBUS_CSI2_CHANNEL_0 | | ||
929 | V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; | ||
930 | |||
931 | return 0; | ||
932 | } | ||
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 | |||
858 | static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { | 952 | static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { |
859 | .s_mbus_fmt = ov5642_s_fmt, | 953 | .s_mbus_fmt = ov5642_s_fmt, |
860 | .g_mbus_fmt = ov5642_g_fmt, | 954 | .g_mbus_fmt = ov5642_g_fmt, |
861 | .try_mbus_fmt = ov5642_try_fmt, | 955 | .try_mbus_fmt = ov5642_try_fmt, |
862 | .enum_mbus_fmt = ov5642_enum_fmt, | 956 | .enum_mbus_fmt = ov5642_enum_fmt, |
957 | .s_crop = ov5642_s_crop, | ||
863 | .g_crop = ov5642_g_crop, | 958 | .g_crop = ov5642_g_crop, |
864 | .cropcap = ov5642_cropcap, | 959 | .cropcap = ov5642_cropcap, |
960 | .g_mbus_config = ov5642_g_mbus_config, | ||
865 | }; | 961 | }; |
866 | 962 | ||
867 | 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, | ||
868 | .g_chip_ident = ov5642_g_chip_ident, | 965 | .g_chip_ident = ov5642_g_chip_ident, |
869 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 966 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
870 | .g_register = ov5642_get_register, | 967 | .g_register = ov5642_get_register, |
@@ -877,28 +974,7 @@ static struct v4l2_subdev_ops ov5642_subdev_ops = { | |||
877 | .video = &ov5642_subdev_video_ops, | 974 | .video = &ov5642_subdev_video_ops, |
878 | }; | 975 | }; |
879 | 976 | ||
880 | /* | 977 | static int ov5642_video_probe(struct i2c_client *client) |
881 | * We have to provide soc-camera operations, but we don't have anything to say | ||
882 | * there. The MIPI CSI2 driver will provide .query_bus_param and .set_bus_param | ||
883 | */ | ||
884 | static unsigned long soc_ov5642_query_bus_param(struct soc_camera_device *icd) | ||
885 | { | ||
886 | return 0; | ||
887 | } | ||
888 | |||
889 | static int soc_ov5642_set_bus_param(struct soc_camera_device *icd, | ||
890 | unsigned long flags) | ||
891 | { | ||
892 | return -EINVAL; | ||
893 | } | ||
894 | |||
895 | static struct soc_camera_ops soc_ov5642_ops = { | ||
896 | .query_bus_param = soc_ov5642_query_bus_param, | ||
897 | .set_bus_param = soc_ov5642_set_bus_param, | ||
898 | }; | ||
899 | |||
900 | static int ov5642_video_probe(struct soc_camera_device *icd, | ||
901 | struct i2c_client *client) | ||
902 | { | 978 | { |
903 | int ret; | 979 | int ret; |
904 | u8 id_high, id_low; | 980 | u8 id_high, id_low; |
@@ -929,16 +1005,9 @@ static int ov5642_probe(struct i2c_client *client, | |||
929 | const struct i2c_device_id *did) | 1005 | const struct i2c_device_id *did) |
930 | { | 1006 | { |
931 | struct ov5642 *priv; | 1007 | struct ov5642 *priv; |
932 | struct soc_camera_device *icd = client->dev.platform_data; | 1008 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
933 | struct soc_camera_link *icl; | ||
934 | int ret; | 1009 | int ret; |
935 | 1010 | ||
936 | if (!icd) { | ||
937 | dev_err(&client->dev, "OV5642: missing soc-camera data!\n"); | ||
938 | return -EINVAL; | ||
939 | } | ||
940 | |||
941 | icl = to_soc_camera_link(icd); | ||
942 | if (!icl) { | 1011 | if (!icl) { |
943 | dev_err(&client->dev, "OV5642: missing platform data!\n"); | 1012 | dev_err(&client->dev, "OV5642: missing platform data!\n"); |
944 | return -EINVAL; | 1013 | return -EINVAL; |
@@ -950,17 +1019,24 @@ static int ov5642_probe(struct i2c_client *client, | |||
950 | 1019 | ||
951 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops); | 1020 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov5642_subdev_ops); |
952 | 1021 | ||
953 | icd->ops = &soc_ov5642_ops; | 1022 | priv->fmt = &ov5642_colour_fmts[0]; |
954 | 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; | ||
955 | 1032 | ||
956 | ret = ov5642_video_probe(icd, client); | 1033 | ret = ov5642_video_probe(client); |
957 | if (ret < 0) | 1034 | if (ret < 0) |
958 | goto error; | 1035 | goto error; |
959 | 1036 | ||
960 | return 0; | 1037 | return 0; |
961 | 1038 | ||
962 | error: | 1039 | error: |
963 | icd->ops = NULL; | ||
964 | kfree(priv); | 1040 | kfree(priv); |
965 | return ret; | 1041 | return ret; |
966 | } | 1042 | } |
@@ -968,10 +1044,8 @@ error: | |||
968 | static int ov5642_remove(struct i2c_client *client) | 1044 | static int ov5642_remove(struct i2c_client *client) |
969 | { | 1045 | { |
970 | struct ov5642 *priv = to_ov5642(client); | 1046 | struct ov5642 *priv = to_ov5642(client); |
971 | struct soc_camera_device *icd = client->dev.platform_data; | 1047 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
972 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
973 | 1048 | ||
974 | icd->ops = NULL; | ||
975 | if (icl->free_bus) | 1049 | if (icl->free_bus) |
976 | icl->free_bus(icl); | 1050 | icl->free_bus(icl); |
977 | kfree(priv); | 1051 | kfree(priv); |