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

V4L/DVB (9821): v4l2-common: add i2c helper functions

Add helper functions to load i2c sub-devices, integrating them
into the v4l2-framework.
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 2a1fcdf0
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#include <asm/div64.h> #include <asm/div64.h>
#define __OLD_VIDIOC_ /* To allow fixing old calls*/ #define __OLD_VIDIOC_ /* To allow fixing old calls*/
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h> #include <media/v4l2-chip-ident.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
...@@ -801,4 +802,116 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver ...@@ -801,4 +802,116 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver
return err != -ENOMEM ? 0 : err; return err != -ENOMEM ? 0 : err;
} }
EXPORT_SYMBOL(v4l2_i2c_attach); EXPORT_SYMBOL(v4l2_i2c_attach);
void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
const struct v4l2_subdev_ops *ops)
{
v4l2_subdev_init(sd, ops);
/* the owner is the same as the i2c_client's driver owner */
sd->owner = client->driver->driver.owner;
/* i2c_client and v4l2_subdev point to one another */
v4l2_set_subdevdata(sd, client);
i2c_set_clientdata(client, sd);
/* initialize name */
snprintf(sd->name, sizeof(sd->name), "%s %d-%04x",
client->driver->driver.name, i2c_adapter_id(client->adapter),
client->addr);
}
EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
/* Load an i2c sub-device. It assumes that i2c_get_adapdata(adapter)
returns the v4l2_device and that i2c_get_clientdata(client)
returns the v4l2_subdev. */
struct v4l2_subdev *v4l2_i2c_new_subdev(struct i2c_adapter *adapter,
const char *module_name, const char *client_type, u8 addr)
{
struct v4l2_device *dev = i2c_get_adapdata(adapter);
struct v4l2_subdev *sd = NULL;
struct i2c_client *client;
struct i2c_board_info info;
BUG_ON(!dev);
#ifdef MODULE
if (module_name)
request_module(module_name);
#endif
/* 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;
/* Create the i2c client */
client = i2c_new_device(adapter, &info);
/* Note: it is possible in the future that
c->driver is NULL if the driver is still being loaded.
We need better support from the kernel so that we
can easily wait for the load to finish. */
if (client == NULL || client->driver == NULL)
return NULL;
/* Lock the module so we can safely get the v4l2_subdev pointer */
if (!try_module_get(client->driver->driver.owner))
return NULL;
sd = i2c_get_clientdata(client);
/* Register with the v4l2_device which increases the module's
use count as well. */
if (v4l2_device_register_subdev(dev, sd))
sd = NULL;
/* Decrease the module use count to match the first try_module_get. */
module_put(client->driver->driver.owner);
return sd;
}
EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
/* Probe and load an i2c sub-device. It assumes that i2c_get_adapdata(adapter)
returns the v4l2_device and that i2c_get_clientdata(client)
returns the v4l2_subdev. */
struct v4l2_subdev *v4l2_i2c_new_probed_subdev(struct i2c_adapter *adapter,
const char *module_name, const char *client_type,
const unsigned short *addrs)
{
struct v4l2_device *dev = i2c_get_adapdata(adapter);
struct v4l2_subdev *sd = NULL;
struct i2c_client *client = NULL;
struct i2c_board_info info;
BUG_ON(!dev);
#ifdef MODULE
if (module_name)
request_module(module_name);
#endif
/* 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));
/* Probe and create the i2c client */
client = i2c_new_probed_device(adapter, &info, addrs);
/* Note: it is possible in the future that
c->driver is NULL if the driver is still being loaded.
We need better support from the kernel so that we
can easily wait for the load to finish. */
if (client == NULL || client->driver == NULL)
return NULL;
/* Lock the module so we can safely get the v4l2_subdev pointer */
if (!try_module_get(client->driver->driver.owner))
return NULL;
sd = i2c_get_clientdata(client);
/* Register with the v4l2_device which increases the module's
use count as well. */
if (v4l2_device_register_subdev(dev, sd))
sd = NULL;
/* Decrease the module use count to match the first try_module_get. */
module_put(client->driver->driver.owner);
return sd;
}
EXPORT_SYMBOL_GPL(v4l2_i2c_new_probed_subdev);
#endif #endif
...@@ -57,6 +57,29 @@ ...@@ -57,6 +57,29 @@
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/* These printk constructs can be used with v4l2_device and v4l2_subdev */
#define v4l2_printk(level, dev, fmt, arg...) \
printk(level "%s: " fmt, (dev)->name , ## arg)
#define v4l2_err(dev, fmt, arg...) \
v4l2_printk(KERN_ERR, dev, fmt , ## arg)
#define v4l2_warn(dev, fmt, arg...) \
v4l2_printk(KERN_WARNING, dev, fmt , ## arg)
#define v4l2_info(dev, fmt, arg...) \
v4l2_printk(KERN_INFO, dev, fmt , ## arg)
/* These three macros assume that the debug level is set with a module
parameter called 'debug'. */
#define v4l2_dbg(level, debug, dev, fmt, arg...) \
do { \
if (debug >= (level)) \
v4l2_printk(KERN_DEBUG, dev, fmt , ## arg); \
} while (0)
/* ------------------------------------------------------------------------- */
/* Priority helper functions */ /* Priority helper functions */
struct v4l2_prio_state { struct v4l2_prio_state {
...@@ -104,11 +127,29 @@ struct i2c_driver; ...@@ -104,11 +127,29 @@ struct i2c_driver;
struct i2c_adapter; struct i2c_adapter;
struct i2c_client; struct i2c_client;
struct i2c_device_id; struct i2c_device_id;
struct v4l2_device;
struct v4l2_subdev;
struct v4l2_subdev_ops;
int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver, int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver,
const char *name, const char *name,
int (*probe)(struct i2c_client *, const struct i2c_device_id *)); int (*probe)(struct i2c_client *, const struct i2c_device_id *));
/* 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(struct i2c_adapter *adapter,
const char *module_name, const char *client_type, u8 addr);
/* Probe and 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_probed_subdev(struct i2c_adapter *adapter,
const char *module_name, const char *client_type,
const unsigned short *addrs);
/* Initialize an v4l2_subdev with data from an i2c_client struct */
void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
const struct v4l2_subdev_ops *ops);
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
/* Internal ioctls */ /* Internal ioctls */
......
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