[i2c] [patch 2.6.19-rc6 9/11] i2c driver "new style" binding
David Brownell
david-b at pacbell.net
Mon Nov 27 23:40:10 CET 2006
> It doesn't. I got v2.6.19-rc6 out of git, applied the above patch, and
> applied the patchset, and it still fails on patch 9. Where is
> i2c_do_add_adapter() supposed to come from?
I see what happened ... that's version 0 of this patch, not the current
version; it didn't even include the Signed-Off-By line.
That sometimes happens when keeping older versions around. On the
other hand, it's better than what happens when you _don't_ have the
around, and have to recover ... ;)
This version should work properly ... it's the one I'm running right
now on an x86_64 and ARM (OMAP OSK).
- Dave
======================= CUT HERE
Kick in standard driver model probe mechanisms, by adding "new style"
I2C enumeration that works without SMBUS_QUICK support from controllers,
and devices.
- Provide a new call, i2c_register_adapter(), to register an adapter
using a specific I2C bus number. Since I2C devices are identified
as pairs { bus number, device address }, this is needed to ensure
that the right bus number is used.
- Define "struct i2c_board_info", used to declare I2C devices along
with previously missing information like what IRQ they issue, and
a pointer to be stored in platform_data. An I2C_BOARD_INFO() macro
packages the mandatory information.
- Provide a new call, i2c_register_board_info(), letting board-specific
arch_initcall() level code declare the board info for I2C devices that
are hooked up with staticallly defined I2C bus numbers (like those
from most system-on-chip processors).
- When an adapter is registered, consult that static registered board
information and use it to create device nodes that can be bound to
"new style" drivers using probe().
- Provide a pair of calls, i2c_new_device() and i2c_unregister_device(),
to support more dynamic declaration of that board info. For example,
a PCI card with an embedded adapter, with a config eeprom and a few
other i2c devices, could use this to declare those i2c devices.
- All that new stuff has kerneldoc. (Too bad the rest of I2C doesn't!)
- Move some init_completion() calls earlier, to where they belong.
With this patch, "new style" drivers and configuration are working, and
systems that don't support SMBUS_QUICK can work. Plus, two longstanding
omissions in the I2C stack are resolved: drivers no longer need to add
board-specific code to handle either (a) irqs issued by i2c chips, or
(b) board-specific configuration, such as which chip variant is used.
Signed-off-by: David Brownell <dbrownell at users.sourceforge.net>
---
Includes some bugfixes (those IDR calls are strange!) and, per Greg's
suggestion, a macro for board init.
drivers/i2c/i2c-core.c | 388 ++++++++++++++++++++++++++++++++++++-------------
include/linux/i2c.h | 61 +++++++
2 files changed, 353 insertions(+), 96 deletions(-)
Index: g26/include/linux/i2c.h
===================================================================
--- g26.orig/include/linux/i2c.h 2006-11-25 14:12:33.000000000 -0800
+++ g26/include/linux/i2c.h 2006-11-25 14:12:33.000000000 -0800
@@ -163,6 +163,7 @@ struct i2c_client {
int usage_count; /* How many accesses currently */
/* to the client */
struct device dev; /* the device structure */
+ int irq; /* irq issued by device (or -1) */
struct list_head list;
char name[I2C_NAME_SIZE];
struct completion released;
@@ -184,6 +185,65 @@ static inline void i2c_set_clientdata (s
dev_set_drvdata (&dev->dev, data);
}
+/**
+ * struct i2c_board_info - template for device creation
+ * @driver: identifies the driver to be bound to the device
+ * @dev_addr: stored in i2c_client.addr
+ * @bus_num: usually matches i2c_client.adapter->nr
+ * @platform_data: stored in i2c_client.dev.platform_data
+ * @irq: stored in i2c_client.irq
+
+ * I2C doesn't actually support hardware probing, although controllers and
+ * devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's
+ * a device at a given address. Drivers commonly need more information than
+ * that, such as chip configuration, associated IRQ, and more.
+ *
+ * i2c_board_info is used to build tables of information listing I2C devices
+ * that are present. This information is used to grow the driver model tree
+ * for "new style" I2C drivers. For mainboards this is done statically using
+ * i2c_register_board_info(), where @bus_num represents an adapter that isn't
+ * yet available. For add-on boards, i2c_new_device() does this dynamically
+ * with the adapter already known.
+ */
+struct i2c_board_info {
+ char driver[KOBJ_NAME_LEN];
+ short bus_num;
+ unsigned short dev_addr;
+ void *platform_data;
+ int irq;
+};
+
+/**
+ * I2C_BOARD_INFO - macro used to list an i2c device and its driver
+ * @driver_name: identifies the driver to use with the device
+ * @busnum: numbers the bus to which the device is connected; ignored
+ * when i2c_new_device() explicitly idenfies that bus.
+ * @devaddr: the device's address on the bus.
+ *
+ * This macro initializes mandatory fields of a struct i2c_board_info,
+ * declaring what has been provided on a particular board. Optional
+ * fields (such as the associated irq, or device-specific platform_data)
+ * are provided using conventional syntax.
+ */
+#define I2C_BOARD_INFO(driver_name,busnum,devaddr) \
+ .driver = driver_name, .bus_num = busnum, .dev_addr = devaddr
+
+
+/* Add-on boards should register/unregister their devices; e.g. a board
+ * with integrated I2C, a config eeprom, sensors, and a codec that's
+ * used in conjunction with the primary hardware.
+ */
+extern struct i2c_client *
+i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);
+
+extern void i2c_unregister_device(struct i2c_client *);
+
+/* Mainboard arch_initcall() code should register all its I2C devices.
+ * This is done at arch_initcall time; add-on boards do use other calls.
+ */
+extern int
+i2c_register_board_info(struct i2c_board_info const *info, unsigned n);
+
/*
* The following structs are for those who like to implement new bus drivers:
* i2c_algorithm is the interface to a class of hardware solutions which can
@@ -295,6 +355,7 @@ struct i2c_client_address_data {
*/
extern int i2c_add_adapter(struct i2c_adapter *);
extern int i2c_del_adapter(struct i2c_adapter *);
+extern int i2c_register_adapter(struct i2c_adapter *);
extern int i2c_register_driver(struct module *, struct i2c_driver *);
extern int i2c_del_driver(struct i2c_driver *);
Index: g26/drivers/i2c/i2c-core.c
===================================================================
--- g26.orig/drivers/i2c/i2c-core.c 2006-11-25 14:12:33.000000000 -0800
+++ g26/drivers/i2c/i2c-core.c 2006-11-25 14:47:26.000000000 -0800
@@ -155,35 +155,6 @@ struct bus_type i2c_bus_type = {
/* ------------------------------------------------------------------------- */
-/* I2C bus adapters -- one roots each I2C or SMBUS segment */
-
-static void i2c_adapter_class_dev_release(struct class_device *dev)
-{
- struct i2c_adapter *adap = class_dev_to_i2c_adapter(dev);
- complete(&adap->class_dev_released);
-}
-
-static ssize_t show_adapter_name(struct class_device *cdev, char *buf)
-{
- struct i2c_adapter *adap = class_dev_to_i2c_adapter(cdev);
- return sprintf(buf, "%s\n", adap->name);
-}
-
-static struct class_device_attribute adapter_attrs[] = {
- __ATTR(name, S_IRUGO, show_adapter_name, NULL),
- { },
-};
-
-struct class i2c_adapter_class = {
- .name = "i2c-adapter",
- .owner = THIS_MODULE,
- .class_dev_attrs = adapter_attrs,
- .release = &i2c_adapter_class_dev_release,
-};
-
-/* ------------------------------------------------------------------------- */
-
-
static void i2c_client_release(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -196,15 +167,7 @@ static ssize_t show_client_name(struct d
return sprintf(buf, "%s\n", client->name);
}
-/*
- * We can't use the DEVICE_ATTR() macro here as we want the same filename for a
- * different type of a device. So beware if the DEVICE_ATTR() macro ever
- * changes, this definition will also have to change.
- */
-static struct device_attribute dev_attr_client_name = {
- .attr = {.name = "name", .mode = S_IRUGO, .owner = THIS_MODULE },
- .show = &show_client_name,
-};
+DEVICE_ATTR(name, S_IRUGO, show_client_name, NULL);
/* modalias helps with coldplug: modprobe $(cat /sys/devices/.../modalias)
* it's a convention across all Linux devices.
@@ -212,7 +175,7 @@ static struct device_attribute dev_attr_
DEVICE_ATTR(modalias, S_IRUGO, show_client_name, NULL);
static /*const*/ struct attribute *i2c_dev_attrs[] = {
- &dev_attr_client_name.attr,
+ &dev_attr_name.attr,
&dev_attr_modalias.attr,
NULL,
};
@@ -222,7 +185,53 @@ static const struct attribute_group i2c_
};
-static void i2c_unregister_device(struct i2c_client *client)
+/**
+ * i2c_new_device - instantiate an i2c device for use with new style driver
+ * @adap: the adapter managing the device
+ * @info: describes one I2C device
+ *
+ * Create a device to work with a new style i2c driver, where binding is
+ * handled by driver model probe()/remove() methods.
+ *
+ * This returns the new i2c client, which may be saved for later use with
+ * i2c_unregister_device(), or NULL to indicate an error.
+ */
+struct i2c_client *
+i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
+{
+ struct i2c_client *client;
+ int status;
+
+ client = kzalloc(sizeof *client, SLAB_KERNEL);
+ if (!client)
+ return NULL;
+
+ client->adapter = adap;
+
+ strlcpy(client->name, info->driver, sizeof client->name);
+ client->dev.platform_data = info->platform_data;
+ client->addr = info->dev_addr;
+ client->irq = info->irq;
+
+ /* a new style driver may be bound to this device when we
+ * return from this function, or any later moment (e.g. maybe
+ * it hotplugged).
+ */
+ status = i2c_attach_client(client);
+ if (status < 0) {
+ kfree(client);
+ client = NULL;
+ }
+ return client;
+}
+EXPORT_SYMBOL_GPL(i2c_new_device);
+
+
+/**
+ * i2c_unregister_device - reverse effect of i2c_new_device()
+ * @client: value returned from i2c_new_device()
+ */
+void i2c_unregister_device(struct i2c_client *client)
{
struct i2c_adapter *adap = client->adapter;
struct i2c_driver *driver = client->driver;
@@ -247,75 +256,148 @@ static void i2c_unregister_device(struct
/* now remove the device, and free its memory */
status = i2c_detach_client(client);
if (status < 0)
- dev_err(&adap->dev, "detach failed (%d) for client [%s] "
+ dev_err(adap->class_dev.dev,
+ "detach failed (%d) for client [%s] "
"at address 0x%02x\n",
status, client->name, client->addr);
else
put_device(&client->dev);
}
+EXPORT_SYMBOL_GPL(i2c_unregister_device);
+static int first_dynamic_bus_num = 0;
-/* ------------------------------------------------------------------------- */
-/*
- * i2c_add_adapter is called from within the algorithm layer,
- * when a new hw adapter registers. A new device is register to be
- * available for clients.
+#ifdef CONFIG_I2C /* modules can't register static board_info */
+
+struct boardinfo {
+ struct list_head list;
+ unsigned n_board_info;
+ struct i2c_board_info board_info[0];
+};
+
+static LIST_HEAD(board_list);
+static DECLARE_MUTEX(board_lock);
+
+
+/**
+ * i2c_register_board_info - statically declare I2C devices
+ * @info: vector of i2c device descriptors
+ * @len: how many descriptors in the vector
+ *
+ * Systems with the I2C core statically configured can declare tables of board
+ * info as they initialize. This should be done in board-specific init code
+ * near arch_initcall() time, or equivalent, before any I2C adapter drivers are
+ * registered. For example, mainboard init code could define several devices,
+ * as could the init code for each daughterboard in a board stack.
+ *
+ * The I2C devices will be created later, after the adapter for the relevant bus
+ * has been registered. After that moment, standard driver model tools are used
+ * to bind "new style" I2C drivers to the devices.
+ *
+ * The board info passed can safely be __initdata, but be careful of embedded
+ * pointers (for platform_data, functions, etc) since that won't be copied.
*/
+int __init
+i2c_register_board_info(struct i2c_board_info const *info, unsigned len)
+{
+ struct boardinfo *bi;
+ int i;
-int i2c_add_adapter(struct i2c_adapter *adap)
+ bi = kmalloc(sizeof(*bi) + len * sizeof *info, GFP_KERNEL);
+ if (!bi)
+ return -ENOMEM;
+ bi->n_board_info = len;
+ memcpy(bi->board_info, info, len * sizeof *info);
+
+ /* assign dynamic bus numbers after the last static one */
+ for (i = 0; i < len; i++, info++) {
+ if (info->bus_num >= first_dynamic_bus_num)
+ first_dynamic_bus_num = info->bus_num + 1;
+ }
+
+ down(&board_lock);
+ list_add_tail(&bi->list, &board_list);
+ up(&board_lock);
+ return 0;
+}
+
+static void scan_static_board_info(struct i2c_adapter *adap)
{
- struct device *dev = adap->class_dev.dev;
- int id, res = 0;
- struct list_head *item;
- struct i2c_driver *driver;
+ struct boardinfo *bi;
- mutex_lock(&core_lists);
+ down(&board_lock);
+ list_for_each_entry(bi, &board_list, list) {
+ struct i2c_board_info *chip = bi->board_info;
+ unsigned n;
- if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) {
- res = -ENOMEM;
- goto out_unlock;
+ for (n = bi->n_board_info; n > 0; n--, chip++) {
+ if (chip->bus_num != adap->nr)
+ continue;
+ (void) i2c_new_device(adap, chip);
+ }
}
+ up(&board_lock);
+}
+
+#else /* i2c core is modular */
+static inline void scan_static_board_info(struct i2c_adapter *adap) {}
+#endif
+
+
+/* ------------------------------------------------------------------------- */
+
+/* I2C bus adapters -- one roots each I2C or SMBUS segment */
+
+static void i2c_adapter_class_dev_release(struct class_device *dev)
+{
+ struct i2c_adapter *adap = class_dev_to_i2c_adapter(dev);
+ complete(&adap->class_dev_released);
+}
+
+static ssize_t show_adapter_name(struct class_device *cdev, char *buf)
+{
+ struct i2c_adapter *adap = class_dev_to_i2c_adapter(cdev);
+ return sprintf(buf, "%s\n", adap->name);
+}
+
+static struct class_device_attribute adapter_attrs[] = {
+ __ATTR(name, S_IRUGO, show_adapter_name, NULL),
+ { },
+};
+
+struct class i2c_adapter_class = {
+ .name = "i2c-adapter",
+ .owner = THIS_MODULE,
+ .class_dev_attrs = adapter_attrs,
+ .release = &i2c_adapter_class_dev_release,
+};
- res = idr_get_new(&i2c_adapter_idr, adap, &id);
- if (res < 0) {
- if (res == -EAGAIN)
- res = -ENOMEM;
- goto out_unlock;
- }
- adap->nr = id & MAX_ID_MASK;
+static int __i2c_register_adapter(struct i2c_adapter *adap)
+{
+ struct device *dev = adap->class_dev.dev;
+ int res = 0;
+ struct list_head *item;
+ struct i2c_driver *driver;
+
+ if (!dev)
+ return -ENODEV;
+
+ init_completion(&adap->dev_released);
+ init_completion(&adap->class_dev_released);
mutex_init(&adap->bus_lock);
mutex_init(&adap->clist_lock);
- list_add_tail(&adap->list,&adapters);
INIT_LIST_HEAD(&adap->clients);
- /* Caller must have zero-initialized adap->class_dev, then
- * initialized adap->class_dev.dev as the real device so we
- * can properly add this adapter to the i2c_adapter class.
- *
- * As a **TEMPORARY migration aid** we create a platform
- * device for drivers that don't yet use the driver model.
- * Expect this to vanish by January 2008.
- */
- if (!dev) {
- printk(KERN_WARNING "I2C bus '%s' has no device; "
- "convert it to the driver model\n",
- adap->name);
- adap->legacy_hack = platform_device_register_simple(
- "legacy_i2c_adapter", adap->nr, NULL, 0);
- if (adap->legacy_hack) {
- dev = &adap->legacy_hack->dev;
- adap->class_dev.dev = dev;
- } else {
- res = -ENODEV;
- goto out_unlock;
- }
- }
-
sprintf(adap->class_dev.class_id, "i2c-%d", adap->nr);
adap->class_dev.class = &i2c_adapter_class;
+
+ mutex_lock(&core_lists);
+
+ list_add_tail(&adap->list,&adapters);
+
res = class_device_register(&adap->class_dev);
if (res)
goto out_list;
@@ -323,7 +405,11 @@ int i2c_add_adapter(struct i2c_adapter *
dev_dbg(dev, "adapter %s [%s] registered\n",
adap->class_dev.class_id, adap->name);
- /* inform drivers of new adapters */
+ /* create devices for new style drivers */
+ if (adap->nr < first_dynamic_bus_num)
+ scan_static_board_info(adap);
+
+ /* let legacy drivers scan this bus for devices */
list_for_each(item,&drivers) {
driver = list_entry(item, struct i2c_driver, list);
if (driver->attach_adapter)
@@ -343,6 +429,114 @@ out_list:
}
+/**
+ * i2c_add_adapter - declare i2c adapter, use dynamic bus number
+ * @adap: the adapter to add (with adap->class_dev.dev initialized)
+ *
+ * This routine is used to declare an I2C adapter when its bus number
+ * doesn't matter. Examples: for I2C adapters dynamically added by
+ * USB links or PCI plugin cards.
+ *
+ * Note that there is temporary support for legacy "non driver model"
+ * adapters, without a device initialized for the class device. This
+ * will be removed in the future.
+ *
+ * When this returns zero, a new bus number was allocated and stored
+ * in adap->nr, and the specified adapter became available for clients.
+ * Otherwise, a negative errno value is returned.
+ */
+int i2c_add_adapter(struct i2c_adapter *adap)
+{
+ int id, res = 0;
+
+retry:
+ if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
+ return -ENOMEM;
+
+ mutex_lock(&core_lists);
+ /* "above" here means "above or equal to", sigh */
+ res = idr_get_new_above(&i2c_adapter_idr, adap,
+ first_dynamic_bus_num, &id);
+ adap->nr = id;
+ mutex_unlock(&core_lists);
+ if (res < 0) {
+ if (res == -EAGAIN)
+ goto retry;
+ return res;
+ }
+
+ /* As a **TEMPORARY migration aid** we create a platform
+ * device for drivers that don't yet use the driver model.
+ * Expect this to vanish by sometime in 2008.
+ */
+ if (!adap->class_dev.dev) {
+ printk(KERN_WARNING "I2C bus '%s' has no device; "
+ "convert it to the driver model\n",
+ adap->name);
+ adap->legacy_hack = platform_device_register_simple(
+ "legacy_i2c_adapter", adap->nr, NULL, 0);
+ if (adap->legacy_hack)
+ adap->class_dev.dev = &adap->legacy_hack->dev;
+ else {
+ mutex_lock(&core_lists);
+ idr_remove(&i2c_adapter_idr, adap->nr);
+ mutex_unlock(&core_lists);
+ return -ENODEV;
+ }
+ }
+
+ if (res == 0)
+ res = __i2c_register_adapter(adap);
+ return res;
+}
+EXPORT_SYMBOL_GPL(i2c_add_adapter);
+
+/**
+ * i2c_register_adapter - declare i2c adapter, use static bus number
+ * @adap: the adapter to register (with adap->nr and adap->class_dev.dev
+ * initialized)
+ *
+ * This routine is used to declare an I2C adapter when its bus number
+ * matters. Example: for I2C adapters from system-on-chip CPUs, or
+ * otherwise built in to the system's mainboard, and where i2c_board_info
+ * is used to properly configure I2C devices..
+ *
+ * When this returns zero, the specified adapter became available for
+ * clients using the bus number provided in adap->nr. Otherwise, a
+ * negative errno value is returned.
+ */
+int i2c_register_adapter(struct i2c_adapter *adap)
+{
+ int id;
+ int status;
+
+ if (adap->nr & ~MAX_ID_MASK)
+ return -EINVAL;
+
+retry:
+ if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0)
+ return -ENOMEM;
+
+ mutex_lock(&core_lists);
+ /* "above" here means "above or equal to", sigh;
+ * we need the "equal to" result to force the result
+ */
+ status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id);
+ if (status == 0 && id != adap->nr) {
+ status = -EBUSY;
+ idr_remove(&i2c_adapter_idr, id);
+ }
+ mutex_unlock(&core_lists);
+ if (status == -EAGAIN)
+ goto retry;
+
+ if (status == 0)
+ status = __i2c_register_adapter(adap);
+ return status;
+}
+EXPORT_SYMBOL_GPL(i2c_register_adapter);
+
+
int i2c_del_adapter(struct i2c_adapter *adap)
{
struct device *dev = adap->class_dev.dev;
@@ -399,8 +593,6 @@ int i2c_del_adapter(struct i2c_adapter *
}
/* clean up the sysfs representation */
- init_completion(&adap->dev_released);
- init_completion(&adap->class_dev_released);
class_device_unregister(&adap->class_dev);
list_del(&adap->list);
@@ -408,7 +600,7 @@ int i2c_del_adapter(struct i2c_adapter *
wait_for_completion(&adap->dev_released);
wait_for_completion(&adap->class_dev_released);
- /* free dynamically allocated bus id */
+ /* free bus id */
idr_remove(&i2c_adapter_idr, adap->nr);
dev_dbg(dev, "adapter %s [%s] unregistered\n",
@@ -418,6 +610,7 @@ int i2c_del_adapter(struct i2c_adapter *
mutex_unlock(&core_lists);
return res;
}
+EXPORT_SYMBOL(i2c_del_adapter);
/* ------------------------------------------------------------------------- */
@@ -441,7 +634,10 @@ int i2c_register_driver(struct module *o
}
}
- /* add the driver to the list of i2c drivers in the driver core */
+ /* add the driver to the list of i2c drivers in the driver core;
+ * new style drivers will be probed existing but unbound devices
+ * when this returns.
+ */
driver->driver.owner = owner;
driver->driver.bus = &i2c_bus_type;
@@ -567,10 +763,13 @@ int i2c_attach_client(struct i2c_client
client->usage_count = 0;
client->dev.parent = adapter->class_dev.dev;
- client->dev.driver = &client->driver->driver;
+ if (client->driver)
+ client->dev.driver = &client->driver->driver;
client->dev.bus = &i2c_bus_type;
client->dev.release = &i2c_client_release;
+ init_completion(&client->released);
+
snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id),
"%d-%04x", i2c_adapter_id(adapter), client->addr);
res = device_register(&client->dev);
@@ -594,7 +793,6 @@ int i2c_attach_client(struct i2c_client
return 0;
out_unregister:
- init_completion(&client->released); /* Needed? */
device_unregister(&client->dev);
wait_for_completion(&client->released);
out_list:
@@ -630,7 +828,6 @@ int i2c_detach_client(struct i2c_client
mutex_lock(&adapter->clist_lock);
list_del(&client->list);
- init_completion(&client->released);
sysfs_remove_group(&client->dev.kobj, &i2c_dev_attr_group);
device_unregister(&client->dev);
mutex_unlock(&adapter->clist_lock);
@@ -737,6 +934,7 @@ int i2c_transfer(struct i2c_adapter * ad
if (adap->algo->master_xfer) {
#ifdef DEBUG
+if(0)
for (ret = 0; ret < num; ret++) {
dev_dbg(dev, "master_xfer[%d] %c, addr=0x%02x, "
"len=%d\n", ret, msgs[ret].flags & I2C_M_RD ?
@@ -1313,8 +1511,6 @@ s32 i2c_smbus_xfer(struct i2c_adapter *
EXPORT_SYMBOL_GPL(i2c_adapter_class);
EXPORT_SYMBOL_GPL(i2c_bus_type);
-EXPORT_SYMBOL(i2c_add_adapter);
-EXPORT_SYMBOL(i2c_del_adapter);
EXPORT_SYMBOL(i2c_del_driver);
EXPORT_SYMBOL(i2c_attach_client);
EXPORT_SYMBOL(i2c_detach_client);
More information about the i2c
mailing list