diff options
Diffstat (limited to 'drivers/media/video/ov9740.c')
-rw-r--r-- | drivers/media/video/ov9740.c | 151 |
1 files changed, 55 insertions, 96 deletions
diff --git a/drivers/media/video/ov9740.c b/drivers/media/video/ov9740.c index edd1ffcca30..d9a9f7174f7 100644 --- a/drivers/media/video/ov9740.c +++ b/drivers/media/video/ov9740.c | |||
@@ -14,8 +14,11 @@ | |||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/i2c.h> | 15 | #include <linux/i2c.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <media/v4l2-chip-ident.h> | 17 | #include <linux/v4l2-mediabus.h> |
18 | |||
18 | #include <media/soc_camera.h> | 19 | #include <media/soc_camera.h> |
20 | #include <media/v4l2-chip-ident.h> | ||
21 | #include <media/v4l2-ctrls.h> | ||
19 | 22 | ||
20 | #define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev) | 23 | #define to_ov9740(sd) container_of(sd, struct ov9740_priv, subdev) |
21 | 24 | ||
@@ -192,6 +195,7 @@ struct ov9740_reg { | |||
192 | 195 | ||
193 | struct ov9740_priv { | 196 | struct ov9740_priv { |
194 | struct v4l2_subdev subdev; | 197 | struct v4l2_subdev subdev; |
198 | struct v4l2_ctrl_handler hdl; | ||
195 | 199 | ||
196 | int ident; | 200 | int ident; |
197 | u16 model; | 201 | u16 model; |
@@ -392,27 +396,6 @@ static enum v4l2_mbus_pixelcode ov9740_codes[] = { | |||
392 | V4L2_MBUS_FMT_YUYV8_2X8, | 396 | V4L2_MBUS_FMT_YUYV8_2X8, |
393 | }; | 397 | }; |
394 | 398 | ||
395 | static const struct v4l2_queryctrl ov9740_controls[] = { | ||
396 | { | ||
397 | .id = V4L2_CID_VFLIP, | ||
398 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
399 | .name = "Flip Vertically", | ||
400 | .minimum = 0, | ||
401 | .maximum = 1, | ||
402 | .step = 1, | ||
403 | .default_value = 0, | ||
404 | }, | ||
405 | { | ||
406 | .id = V4L2_CID_HFLIP, | ||
407 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
408 | .name = "Flip Horizontally", | ||
409 | .minimum = 0, | ||
410 | .maximum = 1, | ||
411 | .step = 1, | ||
412 | .default_value = 0, | ||
413 | }, | ||
414 | }; | ||
415 | |||
416 | /* read a register */ | 399 | /* read a register */ |
417 | static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val) | 400 | static int ov9740_reg_read(struct i2c_client *client, u16 reg, u8 *val) |
418 | { | 401 | { |
@@ -560,25 +543,6 @@ static int ov9740_s_stream(struct v4l2_subdev *sd, int enable) | |||
560 | return ret; | 543 | return ret; |
561 | } | 544 | } |
562 | 545 | ||
563 | /* Alter bus settings on camera side */ | ||
564 | static int ov9740_set_bus_param(struct soc_camera_device *icd, | ||
565 | unsigned long flags) | ||
566 | { | ||
567 | return 0; | ||
568 | } | ||
569 | |||
570 | /* Request bus settings on camera side */ | ||
571 | static unsigned long ov9740_query_bus_param(struct soc_camera_device *icd) | ||
572 | { | ||
573 | struct soc_camera_link *icl = to_soc_camera_link(icd); | ||
574 | |||
575 | unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER | | ||
576 | SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH | | ||
577 | SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8; | ||
578 | |||
579 | return soc_camera_apply_sensor_flags(icl, flags); | ||
580 | } | ||
581 | |||
582 | /* select nearest higher resolution for capture */ | 546 | /* select nearest higher resolution for capture */ |
583 | static void ov9740_res_roundup(u32 *width, u32 *height) | 547 | static void ov9740_res_roundup(u32 *width, u32 *height) |
584 | { | 548 | { |
@@ -788,36 +752,18 @@ static int ov9740_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a) | |||
788 | return 0; | 752 | return 0; |
789 | } | 753 | } |
790 | 754 | ||
791 | /* Get status of additional camera capabilities */ | ||
792 | static int ov9740_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | ||
793 | { | ||
794 | struct ov9740_priv *priv = to_ov9740(sd); | ||
795 | |||
796 | switch (ctrl->id) { | ||
797 | case V4L2_CID_VFLIP: | ||
798 | ctrl->value = priv->flag_vflip; | ||
799 | break; | ||
800 | case V4L2_CID_HFLIP: | ||
801 | ctrl->value = priv->flag_hflip; | ||
802 | break; | ||
803 | default: | ||
804 | return -EINVAL; | ||
805 | } | ||
806 | |||
807 | return 0; | ||
808 | } | ||
809 | |||
810 | /* Set status of additional camera capabilities */ | 755 | /* Set status of additional camera capabilities */ |
811 | static int ov9740_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl) | 756 | static int ov9740_s_ctrl(struct v4l2_ctrl *ctrl) |
812 | { | 757 | { |
813 | struct ov9740_priv *priv = to_ov9740(sd); | 758 | struct ov9740_priv *priv = |
759 | container_of(ctrl->handler, struct ov9740_priv, hdl); | ||
814 | 760 | ||
815 | switch (ctrl->id) { | 761 | switch (ctrl->id) { |
816 | case V4L2_CID_VFLIP: | 762 | case V4L2_CID_VFLIP: |
817 | priv->flag_vflip = ctrl->value; | 763 | priv->flag_vflip = ctrl->val; |
818 | break; | 764 | break; |
819 | case V4L2_CID_HFLIP: | 765 | case V4L2_CID_HFLIP: |
820 | priv->flag_hflip = ctrl->value; | 766 | priv->flag_hflip = ctrl->val; |
821 | break; | 767 | break; |
822 | default: | 768 | default: |
823 | return -EINVAL; | 769 | return -EINVAL; |
@@ -890,18 +836,13 @@ static int ov9740_set_register(struct v4l2_subdev *sd, | |||
890 | } | 836 | } |
891 | #endif | 837 | #endif |
892 | 838 | ||
893 | static int ov9740_video_probe(struct soc_camera_device *icd, | 839 | static int ov9740_video_probe(struct i2c_client *client) |
894 | struct i2c_client *client) | ||
895 | { | 840 | { |
896 | struct v4l2_subdev *sd = i2c_get_clientdata(client); | 841 | struct v4l2_subdev *sd = i2c_get_clientdata(client); |
897 | struct ov9740_priv *priv = to_ov9740(sd); | 842 | struct ov9740_priv *priv = to_ov9740(sd); |
898 | u8 modelhi, modello; | 843 | u8 modelhi, modello; |
899 | int ret; | 844 | int ret; |
900 | 845 | ||
901 | /* We must have a parent by now. And it cannot be a wrong one. */ | ||
902 | BUG_ON(!icd->parent || | ||
903 | to_soc_camera_host(icd->parent)->nr != icd->iface); | ||
904 | |||
905 | /* | 846 | /* |
906 | * check and show product ID and manufacturer ID | 847 | * check and show product ID and manufacturer ID |
907 | */ | 848 | */ |
@@ -942,25 +883,33 @@ err: | |||
942 | return ret; | 883 | return ret; |
943 | } | 884 | } |
944 | 885 | ||
945 | static struct soc_camera_ops ov9740_ops = { | 886 | /* Request bus settings on camera side */ |
946 | .set_bus_param = ov9740_set_bus_param, | 887 | static int ov9740_g_mbus_config(struct v4l2_subdev *sd, |
947 | .query_bus_param = ov9740_query_bus_param, | 888 | struct v4l2_mbus_config *cfg) |
948 | .controls = ov9740_controls, | 889 | { |
949 | .num_controls = ARRAY_SIZE(ov9740_controls), | 890 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
950 | }; | 891 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
892 | |||
893 | cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | | ||
894 | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | | ||
895 | V4L2_MBUS_DATA_ACTIVE_HIGH; | ||
896 | cfg->type = V4L2_MBUS_PARALLEL; | ||
897 | cfg->flags = soc_camera_apply_board_flags(icl, cfg); | ||
898 | |||
899 | return 0; | ||
900 | } | ||
951 | 901 | ||
952 | static struct v4l2_subdev_video_ops ov9740_video_ops = { | 902 | static struct v4l2_subdev_video_ops ov9740_video_ops = { |
953 | .s_stream = ov9740_s_stream, | 903 | .s_stream = ov9740_s_stream, |
954 | .s_mbus_fmt = ov9740_s_fmt, | 904 | .s_mbus_fmt = ov9740_s_fmt, |
955 | .try_mbus_fmt = ov9740_try_fmt, | 905 | .try_mbus_fmt = ov9740_try_fmt, |
956 | .enum_mbus_fmt = ov9740_enum_fmt, | 906 | .enum_mbus_fmt = ov9740_enum_fmt, |
957 | .cropcap = ov9740_cropcap, | 907 | .cropcap = ov9740_cropcap, |
958 | .g_crop = ov9740_g_crop, | 908 | .g_crop = ov9740_g_crop, |
909 | .g_mbus_config = ov9740_g_mbus_config, | ||
959 | }; | 910 | }; |
960 | 911 | ||
961 | static struct v4l2_subdev_core_ops ov9740_core_ops = { | 912 | static struct v4l2_subdev_core_ops ov9740_core_ops = { |
962 | .g_ctrl = ov9740_g_ctrl, | ||
963 | .s_ctrl = ov9740_s_ctrl, | ||
964 | .g_chip_ident = ov9740_g_chip_ident, | 913 | .g_chip_ident = ov9740_g_chip_ident, |
965 | .s_power = ov9740_s_power, | 914 | .s_power = ov9740_s_power, |
966 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 915 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
@@ -974,6 +923,10 @@ static struct v4l2_subdev_ops ov9740_subdev_ops = { | |||
974 | .video = &ov9740_video_ops, | 923 | .video = &ov9740_video_ops, |
975 | }; | 924 | }; |
976 | 925 | ||
926 | static const struct v4l2_ctrl_ops ov9740_ctrl_ops = { | ||
927 | .s_ctrl = ov9740_s_ctrl, | ||
928 | }; | ||
929 | |||
977 | /* | 930 | /* |
978 | * i2c_driver function | 931 | * i2c_driver function |
979 | */ | 932 | */ |
@@ -981,16 +934,9 @@ static int ov9740_probe(struct i2c_client *client, | |||
981 | const struct i2c_device_id *did) | 934 | const struct i2c_device_id *did) |
982 | { | 935 | { |
983 | struct ov9740_priv *priv; | 936 | struct ov9740_priv *priv; |
984 | struct soc_camera_device *icd = client->dev.platform_data; | 937 | struct soc_camera_link *icl = soc_camera_i2c_to_link(client); |
985 | struct soc_camera_link *icl; | ||
986 | int ret; | 938 | int ret; |
987 | 939 | ||
988 | if (!icd) { | ||
989 | dev_err(&client->dev, "Missing soc-camera data!\n"); | ||
990 | return -EINVAL; | ||
991 | } | ||
992 | |||
993 | icl = to_soc_camera_link(icd); | ||
994 | if (!icl) { | 940 | if (!icl) { |
995 | dev_err(&client->dev, "Missing platform_data for driver\n"); | 941 | dev_err(&client->dev, "Missing platform_data for driver\n"); |
996 | return -EINVAL; | 942 | return -EINVAL; |
@@ -1003,12 +949,24 @@ static int ov9740_probe(struct i2c_client *client, | |||
1003 | } | 949 | } |
1004 | 950 | ||
1005 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops); | 951 | v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops); |
952 | v4l2_ctrl_handler_init(&priv->hdl, 13); | ||
953 | v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops, | ||
954 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
955 | v4l2_ctrl_new_std(&priv->hdl, &ov9740_ctrl_ops, | ||
956 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
957 | priv->subdev.ctrl_handler = &priv->hdl; | ||
958 | if (priv->hdl.error) { | ||
959 | int err = priv->hdl.error; | ||
1006 | 960 | ||
1007 | icd->ops = &ov9740_ops; | 961 | kfree(priv); |
962 | return err; | ||
963 | } | ||
1008 | 964 | ||
1009 | ret = ov9740_video_probe(icd, client); | 965 | ret = ov9740_video_probe(client); |
966 | if (!ret) | ||
967 | ret = v4l2_ctrl_handler_setup(&priv->hdl); | ||
1010 | if (ret < 0) { | 968 | if (ret < 0) { |
1011 | icd->ops = NULL; | 969 | v4l2_ctrl_handler_free(&priv->hdl); |
1012 | kfree(priv); | 970 | kfree(priv); |
1013 | } | 971 | } |
1014 | 972 | ||
@@ -1019,8 +977,9 @@ static int ov9740_remove(struct i2c_client *client) | |||
1019 | { | 977 | { |
1020 | struct ov9740_priv *priv = i2c_get_clientdata(client); | 978 | struct ov9740_priv *priv = i2c_get_clientdata(client); |
1021 | 979 | ||
980 | v4l2_device_unregister_subdev(&priv->subdev); | ||
981 | v4l2_ctrl_handler_free(&priv->hdl); | ||
1022 | kfree(priv); | 982 | kfree(priv); |
1023 | |||
1024 | return 0; | 983 | return 0; |
1025 | } | 984 | } |
1026 | 985 | ||