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>
This commit is contained in:
parent
90135c9686
commit
f0222c7d86
|
@ -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,
|
||||||
/* 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
|
||||||
}
|
}
|
||||||
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,
|
||||||
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 {
|
||||||
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 {
|
||||||
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);
|
||||||
|
|
Loading…
Reference in New Issue