Commit f0222c7d authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

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: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 90135c96
...@@ -802,6 +802,17 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev, ...@@ -802,6 +802,17 @@ struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
/* Decrease the module use count to match the first try_module_get. */ /* Decrease the module use count to match the first try_module_get. */
module_put(client->driver->driver.owner); module_put(client->driver->driver.owner);
if (sd) {
/* We return errors from v4l2_subdev_call only if we have the
callback as the .s_config is not mandatory */
int err = v4l2_subdev_call(sd, core, s_config, 0, NULL);
if (err && err != -ENOIOCTLCMD) {
v4l2_device_unregister_subdev(sd);
sd = NULL;
}
}
error: error:
/* If we have a client but no subdev, then something went wrong and /* If we have a client but no subdev, then something went wrong and
we must unregister the client. */ we must unregister the client. */
...@@ -852,6 +863,17 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct v4l2_device *v4l2_dev, ...@@ -852,6 +863,17 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct v4l2_device *v4l2_dev,
/* Decrease the module use count to match the first try_module_get. */ /* Decrease the module use count to match the first try_module_get. */
module_put(client->driver->driver.owner); module_put(client->driver->driver.owner);
if (sd) {
/* We return errors from v4l2_subdev_call only if we have the
callback as the .s_config is not mandatory */
int err = v4l2_subdev_call(sd, core, s_config, 0, NULL);
if (err && err != -ENOIOCTLCMD) {
v4l2_device_unregister_subdev(sd);
sd = NULL;
}
}
error: error:
/* If we have a client but no subdev, then something went wrong and /* If we have a client but no subdev, then something went wrong and
we must unregister the client. */ we must unregister the client. */
...@@ -872,6 +894,89 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev_addr(struct v4l2_device *v4l2_dev ...@@ -872,6 +894,89 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev_addr(struct v4l2_device *v4l2_dev
} }
EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev_addr); EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev_addr);
/* Load an i2c sub-device. */
struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter, const char *module_name,
struct i2c_board_info *info, const unsigned short *probe_addrs)
{
struct v4l2_subdev *sd = NULL;
struct i2c_client *client;
BUG_ON(!v4l2_dev);
if (module_name)
request_module(module_name);
/* Create the i2c client */
if (info->addr == 0 && probe_addrs)
client = i2c_new_probed_device(adapter, info, probe_addrs);
else
client = i2c_new_device(adapter, info);
/* Note: by loading the module first we are certain that c->driver
will be set if the driver was found. If the module was not loaded
first, then the i2c core tries to delay-load the module for us,
and then c->driver is still NULL until the module is finally
loaded. This delay-load mechanism doesn't work if other drivers
want to use the i2c device, so explicitly loading the module
is the best alternative. */
if (client == NULL || client->driver == NULL)
goto error;
/* Lock the module so we can safely get the v4l2_subdev pointer */
if (!try_module_get(client->driver->driver.owner))
goto error;
sd = i2c_get_clientdata(client);
/* Register with the v4l2_device which increases the module's
use count as well. */
if (v4l2_device_register_subdev(v4l2_dev, sd))
sd = NULL;
/* Decrease the module use count to match the first try_module_get. */
module_put(client->driver->driver.owner);
if (sd) {
/* We return errors from v4l2_subdev_call only if we have the
callback as the .s_config is not mandatory */
int err = v4l2_subdev_call(sd, core, s_config,
info->irq, info->platform_data);
if (err && err != -ENOIOCTLCMD) {
v4l2_device_unregister_subdev(sd);
sd = NULL;
}
}
error:
/* If we have a client but no subdev, then something went wrong and
we must unregister the client. */
if (client && sd == NULL)
i2c_unregister_device(client);
return sd;
}
EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);
struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter,
const char *module_name, const char *client_type,
int irq, void *platform_data,
u8 addr, const unsigned short *probe_addrs)
{
struct i2c_board_info info;
/* Setup the i2c board info with the device type and
the device address. */
memset(&info, 0, sizeof(info));
strlcpy(info.type, client_type, sizeof(info.type));
info.addr = addr;
info.irq = irq;
info.platform_data = platform_data;
return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, module_name,
&info, probe_addrs);
}
EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_cfg);
/* Return i2c client address of v4l2_subdev. */ /* Return i2c client address of v4l2_subdev. */
unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd) unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)
{ {
......
...@@ -153,6 +153,22 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct v4l2_device *v4l2_dev, ...@@ -153,6 +153,22 @@ struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct v4l2_device *v4l2_dev,
struct v4l2_subdev *v4l2_i2c_new_probed_subdev_addr(struct v4l2_device *v4l2_dev, struct v4l2_subdev *v4l2_i2c_new_probed_subdev_addr(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter, struct i2c_adapter *adapter,
const char *module_name, const char *client_type, u8 addr); const char *module_name, const char *client_type, u8 addr);
/* Load an i2c module and return an initialized v4l2_subdev struct.
Only call request_module if module_name != NULL.
The client_type argument is the name of the chip that's on the adapter. */
struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter,
const char *module_name, const char *client_type,
int irq, void *platform_data,
u8 addr, const unsigned short *probe_addrs);
struct i2c_board_info;
struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
struct i2c_adapter *adapter, const char *module_name,
struct i2c_board_info *info, const unsigned short *probe_addrs);
/* Initialize an v4l2_subdev with data from an i2c_client struct */ /* Initialize an v4l2_subdev with data from an i2c_client struct */
void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client, void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
const struct v4l2_subdev_ops *ops); const struct v4l2_subdev_ops *ops);
......
...@@ -79,7 +79,11 @@ struct v4l2_decode_vbi_line { ...@@ -79,7 +79,11 @@ struct v4l2_decode_vbi_line {
not yet implemented) since ops provide proper type-checking. not yet implemented) since ops provide proper type-checking.
*/ */
/* init: initialize the sensor registors to some sort of reasonable default /* s_config: if set, then it is always called by the v4l2_i2c_new_subdev*
functions after the v4l2_subdev was registered. It is used to pass
platform data to the subdev which can be used during initialization.
init: initialize the sensor registors to some sort of reasonable default
values. Do not use for new drivers and should be removed in existing values. Do not use for new drivers and should be removed in existing
drivers. drivers.
...@@ -96,6 +100,7 @@ struct v4l2_decode_vbi_line { ...@@ -96,6 +100,7 @@ struct v4l2_decode_vbi_line {
struct v4l2_subdev_core_ops { struct v4l2_subdev_core_ops {
int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip); int (*g_chip_ident)(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip);
int (*log_status)(struct v4l2_subdev *sd); int (*log_status)(struct v4l2_subdev *sd);
int (*s_config)(struct v4l2_subdev *sd, int irq, void *platform_data);
int (*init)(struct v4l2_subdev *sd, u32 val); int (*init)(struct v4l2_subdev *sd, u32 val);
int (*load_fw)(struct v4l2_subdev *sd); int (*load_fw)(struct v4l2_subdev *sd);
int (*reset)(struct v4l2_subdev *sd, u32 val); int (*reset)(struct v4l2_subdev *sd, u32 val);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment