diff options
author | Hans Verkuil <hverkuil@xs4all.nl> | 2009-06-09 16:12:33 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-06-23 02:15:47 -0400 |
commit | f0222c7d860f09a61bec5e500539f28db0184b38 (patch) | |
tree | abcd69a4421985d205ede4df0365c7616d192453 /drivers/media | |
parent | 90135c96869fa0ef3182282b2a661b57fcdb7230 (diff) |
V4L/DVB (12125): v4l2: add new s_config subdev ops and v4l2_i2c_new_subdev_cfg/board calls
Add a new s_config core ops call: this is called with the irq and platform
data to be used to initialize the subdev.
Added new v4l2_i2c_new_subdev_cfg and v4l2_i2c_new_subdev_board calls
that allows you to pass these new arguments.
The existing v4l2_i2c_new_subdev functions were modified to also call
s_config.
In the future the existing v4l2_i2c_new_subdev functions will be replaced
by a single v4l2_i2c_new_subdev function similar to v4l2_i2c_new_subdev_cfg
but without the irq and platform_data arguments.
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/v4l2-common.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index f96475626da7..e7b443c116f0 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c | |||
@@ -802,6 +802,17 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev, | |||
802 | /* Decrease the module use count to match the first try_module_get. */ | 802 | /* Decrease the module use count to match the first try_module_get. */ |
803 | module_put(client->driver->driver.owner); | 803 | module_put(client->driver->driver.owner); |
804 | 804 | ||
805 | if (sd) { | ||
806 | /* We return errors from v4l2_subdev_call only if we have the | ||
807 | callback as the .s_config is not mandatory */ | ||
808 | int err = v4l2_subdev_call(sd, core, s_config, 0, NULL); | ||
809 | |||
810 | if (err && err != -ENOIOCTLCMD) { | ||
811 | v4l2_device_unregister_subdev(sd); | ||
812 | sd = NULL; | ||
813 | } | ||
814 | } | ||
815 | |||
805 | error: | 816 | error: |
806 | /* If we have a client but no subdev, then something went wrong and | 817 | /* If we have a client but no subdev, then something went wrong and |
807 | we must unregister the client. */ | 818 | we must unregister the client. */ |
@@ -852,6 +863,17 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct v4l2_device *v4l2_dev, | |||
852 | /* Decrease the module use count to match the first try_module_get. */ | 863 | /* Decrease the module use count to match the first try_module_get. */ |
853 | module_put(client->driver->driver.owner); | 864 | module_put(client->driver->driver.owner); |
854 | 865 | ||
866 | if (sd) { | ||
867 | /* We return errors from v4l2_subdev_call only if we have the | ||
868 | callback as the .s_config is not mandatory */ | ||
869 | int err = v4l2_subdev_call(sd, core, s_config, 0, NULL); | ||
870 | |||
871 | if (err && err != -ENOIOCTLCMD) { | ||
872 | v4l2_device_unregister_subdev(sd); | ||
873 | sd = NULL; | ||
874 | } | ||
875 | } | ||
876 | |||
855 | error: | 877 | error: |
856 | /* If we have a client but no subdev, then something went wrong and | 878 | /* If we have a client but no subdev, then something went wrong and |
857 | we must unregister the client. */ | 879 | we must unregister the client. */ |
@@ -872,6 +894,89 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev_addr(struct v4l2_device *v4l2_dev | |||
872 | } | 894 | } |
873 | EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev_addr); | 895 | EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev_addr); |
874 | 896 | ||
897 | /* Load an i2c sub-device. */ | ||
898 | struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev, | ||
899 | struct i2c_adapter *adapter, const char *module_name, | ||
900 | struct i2c_board_info *info, const unsigned short *probe_addrs) | ||
901 | { | ||
902 | struct v4l2_subdev *sd = NULL; | ||
903 | struct i2c_client *client; | ||
904 | |||
905 | BUG_ON(!v4l2_dev); | ||
906 | |||
907 | if (module_name) | ||
908 | request_module(module_name); | ||
909 | |||
910 | /* Create the i2c client */ | ||
911 | if (info->addr == 0 && probe_addrs) | ||
912 | client = i2c_new_probed_device(adapter, info, probe_addrs); | ||
913 | else | ||
914 | client = i2c_new_device(adapter, info); | ||
915 | |||
916 | /* Note: by loading the module first we are certain that c->driver | ||
917 | will be set if the driver was found. If the module was not loaded | ||
918 | first, then the i2c core tries to delay-load the module for us, | ||
919 | and then c->driver is still NULL until the module is finally | ||
920 | loaded. This delay-load mechanism doesn't work if other drivers | ||
921 | want to use the i2c device, so explicitly loading the module | ||
922 | is the best alternative. */ | ||
923 | if (client == NULL || client->driver == NULL) | ||
924 | goto error; | ||
925 | |||
926 | /* Lock the module so we can safely get the v4l2_subdev pointer */ | ||
927 | if (!try_module_get(client->driver->driver.owner)) | ||
928 | goto error; | ||
929 | sd = i2c_get_clientdata(client); | ||
930 | |||
931 | /* Register with the v4l2_device which increases the module's | ||
932 | use count as well. */ | ||
933 | if (v4l2_device_register_subdev(v4l2_dev, sd)) | ||
934 | sd = NULL; | ||
935 | /* Decrease the module use count to match the first try_module_get. */ | ||
936 | module_put(client->driver->driver.owner); | ||
937 | |||
938 | if (sd) { | ||
939 | /* We return errors from v4l2_subdev_call only if we have the | ||
940 | callback as the .s_config is not mandatory */ | ||
941 | int err = v4l2_subdev_call(sd, core, s_config, | ||
942 | info->irq, info->platform_data); | ||
943 | |||
944 | if (err && err != -ENOIOCTLCMD) { | ||
945 | v4l2_device_unregister_subdev(sd); | ||
946 | sd = NULL; | ||
947 | } | ||
948 | } | ||
949 | |||
950 | error: | ||
951 | /* If we have a client but no subdev, then something went wrong and | ||
952 | we must unregister the client. */ | ||
953 | if (client && sd == NULL) | ||
954 | i2c_unregister_device(client); | ||
955 | return sd; | ||
956 | } | ||
957 | EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board); | ||
958 | |||
959 | struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev, | ||
960 | struct i2c_adapter *adapter, | ||
961 | const char *module_name, const char *client_type, | ||
962 | int irq, void *platform_data, | ||
963 | u8 addr, const unsigned short *probe_addrs) | ||
964 | { | ||
965 | struct i2c_board_info info; | ||
966 | |||
967 | /* Setup the i2c board info with the device type and | ||
968 | the device address. */ | ||
969 | memset(&info, 0, sizeof(info)); | ||
970 | strlcpy(info.type, client_type, sizeof(info.type)); | ||
971 | info.addr = addr; | ||
972 | info.irq = irq; | ||
973 | info.platform_data = platform_data; | ||
974 | |||
975 | return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, module_name, | ||
976 | &info, probe_addrs); | ||
977 | } | ||
978 | EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_cfg); | ||
979 | |||
875 | /* Return i2c client address of v4l2_subdev. */ | 980 | /* Return i2c client address of v4l2_subdev. */ |
876 | unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd) | 981 | unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd) |
877 | { | 982 | { |