From 352da9820e5506e3b8496e6052a2ad9c488efae8 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:17 +0200 Subject: i2c: Kill client_register and client_unregister methods These methods were useful in the legacy binding model but no longer in the new (standard) binding model. There are no users left so we can drop them. Signed-off-by: Jean Delvare Cc: David Brownell diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 8d07ed3..9163dad 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -368,8 +368,7 @@ Who: Krzysztof Piotr Oledzki --------------------------- -What: i2c_attach_client(), i2c_detach_client(), i2c_driver->detach_client(), - i2c_adapter->client_register(), i2c_adapter->client_unregister +What: i2c_attach_client(), i2c_detach_client(), i2c_driver->detach_client() When: 2.6.30 Check: i2c_attach_client i2c_detach_client Why: Deprecated by the new (standard) device driver binding model. Use diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 5ed622e..fc18fdb 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -308,14 +308,6 @@ void i2c_unregister_device(struct i2c_client *client) return; } - if (adapter->client_unregister) { - if (adapter->client_unregister(client)) { - dev_warn(&client->dev, - "client_unregister [%s] failed\n", - client->name); - } - } - mutex_lock(&adapter->clist_lock); list_del(&client->list); mutex_unlock(&adapter->clist_lock); @@ -855,14 +847,6 @@ int i2c_attach_client(struct i2c_client *client) dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", client->name, dev_name(&client->dev)); - if (adapter->client_register) { - if (adapter->client_register(client)) { - dev_dbg(&adapter->dev, "client_register " - "failed for client [%s] at 0x%02x\n", - client->name, client->addr); - } - } - return 0; out_err: @@ -875,17 +859,6 @@ EXPORT_SYMBOL(i2c_attach_client); int i2c_detach_client(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; - int res = 0; - - if (adapter->client_unregister) { - res = adapter->client_unregister(client); - if (res) { - dev_err(&client->dev, - "client_unregister [%s] failed, " - "client not detached\n", client->name); - goto out; - } - } mutex_lock(&adapter->clist_lock); list_del(&client->list); @@ -895,8 +868,7 @@ int i2c_detach_client(struct i2c_client *client) device_unregister(&client->dev); wait_for_completion(&client->released); - out: - return res; + return 0; } EXPORT_SYMBOL(i2c_detach_client); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index ad25805..b3f4606 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -352,10 +352,6 @@ struct i2c_adapter { const struct i2c_algorithm *algo; /* the algorithm to access the bus */ void *algo_data; - /* --- administration stuff. */ - int (*client_register)(struct i2c_client *) __deprecated; - int (*client_unregister)(struct i2c_client *) __deprecated; - /* data fields that are valid for all devices */ u8 level; /* nesting level for lockdep */ struct mutex bus_lock; -- cgit v0.10.2 From 729d6dd571464954f625e6b80950d9e4e3bd94f7 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:18 +0200 Subject: i2c: Get rid of the legacy binding model We converted all the legacy i2c drivers so we can finally get rid of the legacy binding model. Hooray! Signed-off-by: Jean Delvare Cc: David Brownell diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 9163dad..f8cd450 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -368,15 +368,6 @@ Who: Krzysztof Piotr Oledzki --------------------------- -What: i2c_attach_client(), i2c_detach_client(), i2c_driver->detach_client() -When: 2.6.30 -Check: i2c_attach_client i2c_detach_client -Why: Deprecated by the new (standard) device driver binding model. Use - i2c_driver->probe() and ->remove() instead. -Who: Jean Delvare - ---------------------------- - What: fscher and fscpos drivers When: June 2009 Why: Deprecated by the new fschmd driver. diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index c1a06f9..7860aaf 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -126,19 +126,9 @@ different) configuration information, as do drivers handling chip variants that can't be distinguished by protocol probing, or which need some board specific information to operate correctly. -Accordingly, the I2C stack now has two models for associating I2C devices -with their drivers: the original "legacy" model, and a newer one that's -fully compatible with the Linux 2.6 driver model. These models do not mix, -since the "legacy" model requires drivers to create "i2c_client" device -objects after SMBus style probing, while the Linux driver model expects -drivers to be given such device objects in their probe() routines. -The legacy model is deprecated now and will soon be removed, so we no -longer document it here. - - -Standard Driver Model Binding ("New Style") -------------------------------------------- +Device/Driver Binding +--------------------- System infrastructure, typically board-specific initialization code or boot firmware, reports what I2C devices exist. For example, there may be @@ -201,7 +191,7 @@ a given I2C bus. This is for example the case of hardware monitoring devices on a PC's SMBus. In that case, you may want to let your driver detect supported devices automatically. This is how the legacy model was working, and is now available as an extension to the standard -driver model (so that we can finally get rid of the legacy model.) +driver model. You simply have to define a detect callback which will attempt to identify supported devices (returning 0 for supported ones and -ENODEV diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index fc18fdb..dc8bc91 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -43,6 +43,7 @@ static DEFINE_IDR(i2c_adapter_idr); #define is_newstyle_driver(d) ((d)->probe || (d)->remove || (d)->detect) +static int i2c_attach_client(struct i2c_client *client); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); /* ------------------------------------------------------------------------- */ @@ -83,10 +84,6 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct i2c_client *client = to_i2c_client(dev); - /* by definition, legacy drivers can't hotplug */ - if (dev->driver) - return 0; - if (add_uevent_var(env, "MODALIAS=%s%s", I2C_MODULE_PREFIX, client->name)) return -ENOMEM; @@ -455,7 +452,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); - /* create pre-declared device nodes for new-style drivers */ + /* create pre-declared device nodes */ if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); @@ -617,26 +614,9 @@ int i2c_del_adapter(struct i2c_adapter *adap) if (res) goto out_unlock; - /* detach any active clients. This must be done first, because - * it can fail; in which case we give up. */ + /* Detach any active clients */ list_for_each_entry_safe_reverse(client, _n, &adap->clients, list) { - struct i2c_driver *driver; - - driver = client->driver; - - /* new style, follow standard driver model */ - if (!driver || is_newstyle_driver(driver)) { - i2c_unregister_device(client); - continue; - } - - /* legacy drivers create and remove clients themselves */ - if ((res = driver->detach_client(client))) { - dev_err(&adap->dev, "detach_client failed for client " - "[%s] at address 0x%02x\n", client->name, - client->addr); - goto out_unlock; - } + i2c_unregister_device(client); } /* clean up the sysfs representation */ @@ -680,11 +660,7 @@ static int __attach_adapter(struct device *dev, void *data) /* * An i2c_driver is used with one or more i2c_client (device) nodes to access - * i2c slave chips, on a bus instance associated with some i2c_adapter. There - * are two models for binding the driver to its device: "new style" drivers - * follow the standard Linux driver model and just respond to probe() calls - * issued if the driver core sees they match(); "legacy" drivers create device - * nodes themselves. + * i2c slave chips, on a bus instance associated with some i2c_adapter. */ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) @@ -695,21 +671,11 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) if (unlikely(WARN_ON(!i2c_bus_type.p))) return -EAGAIN; - /* new style driver methods can't mix with legacy ones */ - if (is_newstyle_driver(driver)) { - if (driver->detach_adapter || driver->detach_client) { - printk(KERN_WARNING - "i2c-core: driver [%s] is confused\n", - driver->driver.name); - return -EINVAL; - } - } - /* add the driver to the list of i2c drivers in the driver core */ driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type; - /* for new style drivers, when registration returns the driver core + /* When registration returns, the driver core * will have called probe() for all matching-but-unbound devices. */ res = driver_register(&driver->driver); @@ -748,29 +714,11 @@ static int __detach_adapter(struct device *dev, void *data) if (is_newstyle_driver(driver)) return 0; - /* Have a look at each adapter, if clients of this driver are still - * attached. If so, detach them to be able to kill the driver - * afterwards. - */ if (driver->detach_adapter) { if (driver->detach_adapter(adapter)) dev_err(&adapter->dev, "detach_adapter failed for driver [%s]\n", driver->driver.name); - } else { - struct i2c_client *client, *_n; - - list_for_each_entry_safe(client, _n, &adapter->clients, list) { - if (client->driver != driver) - continue; - dev_dbg(&adapter->dev, - "detaching client [%s] at 0x%02x\n", - client->name, client->addr); - if (driver->detach_client(client)) - dev_err(&adapter->dev, "detach_client " - "failed for client [%s] at 0x%02x\n", - client->name, client->addr); - } } return 0; @@ -812,7 +760,7 @@ static int i2c_check_addr(struct i2c_adapter *adapter, int addr) return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr); } -int i2c_attach_client(struct i2c_client *client) +static int i2c_attach_client(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; int res; @@ -854,23 +802,6 @@ out_err: "(%d)\n", client->name, client->addr, res); return res; } -EXPORT_SYMBOL(i2c_attach_client); - -int i2c_detach_client(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - - mutex_lock(&adapter->clist_lock); - list_del(&client->list); - mutex_unlock(&adapter->clist_lock); - - init_completion(&client->released); - device_unregister(&client->dev); - wait_for_completion(&client->released); - - return 0; -} -EXPORT_SYMBOL(i2c_detach_client); /** * i2c_use_client - increments the reference count of the i2c client structure diff --git a/include/linux/i2c.h b/include/linux/i2c.h index b3f4606..43a3545 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -100,9 +100,8 @@ extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, * @class: What kind of i2c device we instantiate (for detect) * @attach_adapter: Callback for bus addition (for legacy drivers) * @detach_adapter: Callback for bus removal (for legacy drivers) - * @detach_client: Callback for device removal (for legacy drivers) - * @probe: Callback for device binding (new-style drivers) - * @remove: Callback for device unbinding (new-style drivers) + * @probe: Callback for device binding + * @remove: Callback for device unbinding * @shutdown: Callback for device shutdown * @suspend: Callback for device suspend * @resume: Callback for device resume @@ -137,26 +136,14 @@ struct i2c_driver { int id; unsigned int class; - /* Notifies the driver that a new bus has appeared. This routine - * can be used by the driver to test if the bus meets its conditions - * & seek for the presence of the chip(s) it supports. If found, it - * registers the client(s) that are on the bus to the i2c admin. via - * i2c_attach_client. (LEGACY I2C DRIVERS ONLY) + /* Notifies the driver that a new bus has appeared or is about to be + * removed. You should avoid using this if you can, it will probably + * be removed in a near future. */ int (*attach_adapter)(struct i2c_adapter *); int (*detach_adapter)(struct i2c_adapter *); - /* tells the driver that a client is about to be deleted & gives it - * the chance to remove its private data. Also, if the client struct - * has been dynamically allocated by the driver in the function above, - * it must be freed here. (LEGACY I2C DRIVERS ONLY) - */ - int (*detach_client)(struct i2c_client *) __deprecated; - - /* Standard driver model interfaces, for "new style" i2c drivers. - * With the driver model, device enumeration is NEVER done by drivers; - * it's done by infrastructure. (NEW STYLE DRIVERS ONLY) - */ + /* Standard driver model interfaces */ int (*probe)(struct i2c_client *, const struct i2c_device_id *); int (*remove)(struct i2c_client *); @@ -248,11 +235,10 @@ static inline void i2c_set_clientdata(struct i2c_client *dev, void *data) * that, such as chip type, configuration, associated IRQ, and so on. * * 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(); bus numbers identify adapters that aren't - * yet available. For add-on boards, i2c_new_device() does this dynamically - * with the adapter already known. + * that are present. This information is used to grow the driver model tree. + * For mainboards this is done statically using i2c_register_board_info(); + * bus numbers identify adapters that aren't yet available. For add-on boards, + * i2c_new_device() does this dynamically with the adapter already known. */ struct i2c_board_info { char type[I2C_NAME_SIZE]; @@ -425,11 +411,6 @@ static inline int i2c_add_driver(struct i2c_driver *driver) return i2c_register_driver(THIS_MODULE, driver); } -/* These are deprecated, your driver should use the standard .probe() - * and .remove() methods instead. */ -extern int __deprecated i2c_attach_client(struct i2c_client *); -extern int __deprecated i2c_detach_client(struct i2c_client *); - extern struct i2c_client *i2c_use_client(struct i2c_client *client); extern void i2c_release_client(struct i2c_client *client); -- cgit v0.10.2 From 36789b5ea52bba961122b45f4383f553ec3b5a6c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:18 +0200 Subject: i2c: Drop i2c_probe function The legacy i2c_probe() function has no users left, get rid of it. Signed-off-by: Jean Delvare Cc: David Brownell diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index dc8bc91..d484389 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1032,144 +1032,7 @@ EXPORT_SYMBOL(i2c_master_recv); * Will not work for 10-bit addresses! * ---------------------------------------------------- */ -static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind, - int (*found_proc) (struct i2c_adapter *, int, int)) -{ - int err; - - /* Make sure the address is valid */ - if (addr < 0x03 || addr > 0x77) { - dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n", - addr); - return -EINVAL; - } - - /* Skip if already in use */ - if (i2c_check_addr(adapter, addr)) - return 0; - - /* Make sure there is something at this address, unless forced */ - if (kind < 0) { - if (i2c_smbus_xfer(adapter, addr, 0, 0, 0, - I2C_SMBUS_QUICK, NULL) < 0) - return 0; - - /* prevent 24RF08 corruption */ - if ((addr & ~0x0f) == 0x50) - i2c_smbus_xfer(adapter, addr, 0, 0, 0, - I2C_SMBUS_QUICK, NULL); - } - - /* Finally call the custom detection function */ - err = found_proc(adapter, addr, kind); - /* -ENODEV can be returned if there is a chip at the given address - but it isn't supported by this chip driver. We catch it here as - this isn't an error. */ - if (err == -ENODEV) - err = 0; - - if (err) - dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)\n", - addr, err); - return err; -} - -int i2c_probe(struct i2c_adapter *adapter, - const struct i2c_client_address_data *address_data, - int (*found_proc) (struct i2c_adapter *, int, int)) -{ - int i, err; - int adap_id = i2c_adapter_id(adapter); - - /* Force entries are done first, and are not affected by ignore - entries */ - if (address_data->forces) { - const unsigned short * const *forces = address_data->forces; - int kind; - - for (kind = 0; forces[kind]; kind++) { - for (i = 0; forces[kind][i] != I2C_CLIENT_END; - i += 2) { - if (forces[kind][i] == adap_id - || forces[kind][i] == ANY_I2C_BUS) { - dev_dbg(&adapter->dev, "found force " - "parameter for adapter %d, " - "addr 0x%02x, kind %d\n", - adap_id, forces[kind][i + 1], - kind); - err = i2c_probe_address(adapter, - forces[kind][i + 1], - kind, found_proc); - if (err) - return err; - } - } - } - } - - /* Stop here if we can't use SMBUS_QUICK */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) { - if (address_data->probe[0] == I2C_CLIENT_END - && address_data->normal_i2c[0] == I2C_CLIENT_END) - return 0; - - dev_dbg(&adapter->dev, "SMBus Quick command not supported, " - "can't probe for chips\n"); - return -EOPNOTSUPP; - } - - /* Probe entries are done second, and are not affected by ignore - entries either */ - for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) { - if (address_data->probe[i] == adap_id - || address_data->probe[i] == ANY_I2C_BUS) { - dev_dbg(&adapter->dev, "found probe parameter for " - "adapter %d, addr 0x%02x\n", adap_id, - address_data->probe[i + 1]); - err = i2c_probe_address(adapter, - address_data->probe[i + 1], - -1, found_proc); - if (err) - return err; - } - } - - /* Normal entries are done last, unless shadowed by an ignore entry */ - for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) { - int j, ignore; - - ignore = 0; - for (j = 0; address_data->ignore[j] != I2C_CLIENT_END; - j += 2) { - if ((address_data->ignore[j] == adap_id || - address_data->ignore[j] == ANY_I2C_BUS) - && address_data->ignore[j + 1] - == address_data->normal_i2c[i]) { - dev_dbg(&adapter->dev, "found ignore " - "parameter for adapter %d, " - "addr 0x%02x\n", adap_id, - address_data->ignore[j + 1]); - ignore = 1; - break; - } - } - if (ignore) - continue; - - dev_dbg(&adapter->dev, "found normal entry for adapter %d, " - "addr 0x%02x\n", adap_id, - address_data->normal_i2c[i]); - err = i2c_probe_address(adapter, address_data->normal_i2c[i], - -1, found_proc); - if (err) - return err; - } - - return 0; -} -EXPORT_SYMBOL(i2c_probe); -/* Separate detection function for new-style drivers */ static int i2c_detect_address(struct i2c_client *temp_client, int kind, struct i2c_driver *driver) { diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 43a3545..db25a87 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -419,14 +419,6 @@ extern void i2c_release_client(struct i2c_client *client); extern void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg); -/* Detect function. It iterates over all possible addresses itself. - * It will only call found_proc if some client is connected at the - * specific address (unless a 'force' matched); - */ -extern int i2c_probe(struct i2c_adapter *adapter, - const struct i2c_client_address_data *address_data, - int (*found_proc) (struct i2c_adapter *, int, int)); - extern struct i2c_adapter *i2c_get_adapter(int id); extern void i2c_put_adapter(struct i2c_adapter *adap); -- cgit v0.10.2 From f8a227e8ac19c2d3e189833b8518b1805d9b443c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:18 +0200 Subject: i2c: Merge i2c_attach_client into i2c_new_device Now that i2c_attach_client is no longer exported, it doesn't need to be a separate function. Merge it into its only user, i2c_new_device. Signed-off-by: Jean Delvare Cc: David Brownell diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index d484389..06c428b 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -43,7 +43,7 @@ static DEFINE_IDR(i2c_adapter_idr); #define is_newstyle_driver(d) ((d)->probe || (d)->remove || (d)->detect) -static int i2c_attach_client(struct i2c_client *client); +static int i2c_check_addr(struct i2c_adapter *adapter, int addr); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); /* ------------------------------------------------------------------------- */ @@ -237,15 +237,17 @@ EXPORT_SYMBOL(i2c_verify_client); /** - * i2c_new_device - instantiate an i2c device for use with a new style driver + * i2c_new_device - instantiate an i2c device * @adap: the adapter managing the device * @info: describes one I2C device; bus_num is ignored * Context: can sleep * - * Create a device to work with a new style i2c driver, where binding is - * handled through driver model probe()/remove() methods. This call is not - * appropriate for use by mainboad initialization logic, which usually runs - * during an arch_initcall() long before any i2c_adapter could exist. + * Create an i2c device. Binding is handled through driver model + * probe()/remove() methods. A driver may be bound to this device when we + * return from this function, or any later moment (e.g. maybe hotplugging will + * load the driver module). This call is not appropriate for use by mainboard + * initialization logic, which usually runs during an arch_initcall() long + * before any i2c_adapter could exist. * * This returns the new i2c client, which may be saved for later use with * i2c_unregister_device(); or NULL to indicate an error. @@ -273,17 +275,40 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) strlcpy(client->name, info->type, sizeof(client->name)); - /* a new style driver may be bound to this device when we - * return from this function, or any later moment (e.g. maybe - * hotplugging will load the driver module). and the device - * refcount model is the standard driver model one. - */ - status = i2c_attach_client(client); - if (status < 0) { - kfree(client); - client = NULL; - } + /* Check for address business */ + status = i2c_check_addr(adap, client->addr); + if (status) + goto out_err; + + client->dev.parent = &client->adapter->dev; + client->dev.bus = &i2c_bus_type; + + if (client->driver && !is_newstyle_driver(client->driver)) { + client->dev.release = i2c_client_release; + dev_set_uevent_suppress(&client->dev, 1); + } else + client->dev.release = i2c_client_dev_release; + + dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), + client->addr); + status = device_register(&client->dev); + if (status) + goto out_err; + + mutex_lock(&adap->clist_lock); + list_add_tail(&client->list, &adap->clients); + mutex_unlock(&adap->clist_lock); + + dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n", + client->name, dev_name(&client->dev)); + return client; + +out_err: + dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x " + "(%d)\n", client->name, client->addr, status); + kfree(client); + return NULL; } EXPORT_SYMBOL_GPL(i2c_new_device); @@ -760,49 +785,6 @@ static int i2c_check_addr(struct i2c_adapter *adapter, int addr) return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr); } -static int i2c_attach_client(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - int res; - - /* Check for address business */ - res = i2c_check_addr(adapter, client->addr); - if (res) - return res; - - client->dev.parent = &client->adapter->dev; - client->dev.bus = &i2c_bus_type; - - if (client->driver) - client->dev.driver = &client->driver->driver; - - if (client->driver && !is_newstyle_driver(client->driver)) { - client->dev.release = i2c_client_release; - dev_set_uevent_suppress(&client->dev, 1); - } else - client->dev.release = i2c_client_dev_release; - - dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adapter), - client->addr); - res = device_register(&client->dev); - if (res) - goto out_err; - - mutex_lock(&adapter->clist_lock); - list_add_tail(&client->list, &adapter->clients); - mutex_unlock(&adapter->clist_lock); - - dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", - client->name, dev_name(&client->dev)); - - return 0; - -out_err: - dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " - "(%d)\n", client->name, client->addr, res); - return res; -} - /** * i2c_use_client - increments the reference count of the i2c client structure * @client: the client being referenced -- cgit v0.10.2 From 1e40ac12dab22d98d0178e87364cf4e36862809c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:19 +0200 Subject: i2c: Kill is_newstyle_driver Legacy i2c drivers are gone, all drivers are new-style now, so there is no point to check. Signed-off-by: Jean Delvare Cc: David Brownell diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 06c428b..95fb997 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -41,8 +41,6 @@ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); -#define is_newstyle_driver(d) ((d)->probe || (d)->remove || (d)->detect) - static int i2c_check_addr(struct i2c_adapter *adapter, int addr); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); @@ -64,12 +62,6 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) struct i2c_client *client = to_i2c_client(dev); struct i2c_driver *driver = to_i2c_driver(drv); - /* make legacy i2c drivers bypass driver model probing entirely; - * such drivers scan each i2c adapter/bus themselves. - */ - if (!is_newstyle_driver(driver)) - return 0; - /* match on an id table if there is one */ if (driver->id_table) return i2c_match_id(driver->id_table, client) != NULL; @@ -172,12 +164,6 @@ static int i2c_device_resume(struct device *dev) return driver->resume(to_i2c_client(dev)); } -static void i2c_client_release(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - complete(&client->released); -} - static void i2c_client_dev_release(struct device *dev) { kfree(to_i2c_client(dev)); @@ -282,12 +268,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->dev.parent = &client->adapter->dev; client->dev.bus = &i2c_bus_type; - - if (client->driver && !is_newstyle_driver(client->driver)) { - client->dev.release = i2c_client_release; - dev_set_uevent_suppress(&client->dev, 1); - } else - client->dev.release = i2c_client_dev_release; + client->dev.release = i2c_client_dev_release; dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), client->addr); @@ -321,14 +302,6 @@ EXPORT_SYMBOL_GPL(i2c_new_device); void i2c_unregister_device(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; - struct i2c_driver *driver = client->driver; - - if (driver && !is_newstyle_driver(driver)) { - dev_err(&client->dev, "can't unregister devices " - "with legacy drivers\n"); - WARN_ON(1); - return; - } mutex_lock(&adapter->clist_lock); list_del(&client->list); @@ -736,9 +709,6 @@ static int __detach_adapter(struct device *dev, void *data) i2c_unregister_device(client); } - if (is_newstyle_driver(driver)) - return 0; - if (driver->detach_adapter) { if (driver->detach_adapter(adapter)) dev_err(&adapter->dev, diff --git a/include/linux/i2c.h b/include/linux/i2c.h index db25a87..28b2728 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -180,7 +180,6 @@ struct i2c_driver { * @irq: indicates the IRQ generated by this device (if any) * @list: list of active/busy clients (DEPRECATED) * @detected: member of an i2c_driver.clients list - * @released: used to synchronize client releases & detaches and references * * An i2c_client identifies a single device (i.e. chip) connected to an * i2c bus. The behaviour exposed to Linux is defined by the driver @@ -198,7 +197,6 @@ struct i2c_client { int irq; /* irq issued by device */ struct list_head list; /* DEPRECATED */ struct list_head detected; - struct completion released; }; #define to_i2c_client(d) container_of(d, struct i2c_client, dev) -- cgit v0.10.2 From e549c2b54dd90a056d6824b885d438b7437874f0 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:19 +0200 Subject: i2c: Kill the redundant client list We used to maintain our own per-adapter list of i2c clients, but this is redundant with what the driver core does, and no longer needed. Just drop the redundant list. Signed-off-by: Jean Delvare Cc: David Brownell diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 95fb997..b1fd00d 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -276,10 +276,6 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) if (status) goto out_err; - mutex_lock(&adap->clist_lock); - list_add_tail(&client->list, &adap->clients); - mutex_unlock(&adap->clist_lock); - dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n", client->name, dev_name(&client->dev)); @@ -301,12 +297,6 @@ EXPORT_SYMBOL_GPL(i2c_new_device); */ void i2c_unregister_device(struct i2c_client *client) { - struct i2c_adapter *adapter = client->adapter; - - mutex_lock(&adapter->clist_lock); - list_del(&client->list); - mutex_unlock(&adapter->clist_lock); - device_unregister(&client->dev); } EXPORT_SYMBOL_GPL(i2c_unregister_device); @@ -432,8 +422,6 @@ static int i2c_register_adapter(struct i2c_adapter *adap) return -EAGAIN; mutex_init(&adap->bus_lock); - mutex_init(&adap->clist_lock); - INIT_LIST_HEAD(&adap->clients); mutex_lock(&core_lock); @@ -583,6 +571,14 @@ static int i2c_do_del_adapter(struct device_driver *d, void *data) return res; } +static int __unregister_client(struct device *dev, void *dummy) +{ + struct i2c_client *client = i2c_verify_client(dev); + if (client) + i2c_unregister_device(client); + return 0; +} + /** * i2c_del_adapter - unregister I2C adapter * @adap: the adapter being unregistered @@ -593,7 +589,6 @@ static int i2c_do_del_adapter(struct device_driver *d, void *data) */ int i2c_del_adapter(struct i2c_adapter *adap) { - struct i2c_client *client, *_n; int res = 0; mutex_lock(&core_lock); @@ -612,10 +607,9 @@ int i2c_del_adapter(struct i2c_adapter *adap) if (res) goto out_unlock; - /* Detach any active clients */ - list_for_each_entry_safe_reverse(client, _n, &adap->clients, list) { - i2c_unregister_device(client); - } + /* Detach any active clients. This can't fail, thus we do not + checking the returned value. */ + res = device_for_each_child(&adap->dev, NULL, __unregister_client); /* clean up the sysfs representation */ init_completion(&adap->dev_released); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 28b2728..5f81576 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -178,7 +178,6 @@ struct i2c_driver { * @driver: device's driver, hence pointer to access routines * @dev: Driver model device node for the slave. * @irq: indicates the IRQ generated by this device (if any) - * @list: list of active/busy clients (DEPRECATED) * @detected: member of an i2c_driver.clients list * * An i2c_client identifies a single device (i.e. chip) connected to an @@ -195,7 +194,6 @@ struct i2c_client { struct i2c_driver *driver; /* and our access routines */ struct device dev; /* the device structure */ int irq; /* irq issued by device */ - struct list_head list; /* DEPRECATED */ struct list_head detected; }; #define to_i2c_client(d) container_of(d, struct i2c_client, dev) @@ -339,14 +337,12 @@ struct i2c_adapter { /* data fields that are valid for all devices */ u8 level; /* nesting level for lockdep */ struct mutex bus_lock; - struct mutex clist_lock; int timeout; /* in jiffies */ int retries; struct device dev; /* the adapter device */ int nr; - struct list_head clients; /* DEPRECATED */ char name[48]; struct completion dev_released; }; -- cgit v0.10.2 From 35fc37f8188177e3ba3e7f99a6e3300e490e9181 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:19 +0200 Subject: i2c: Limit core locking to the necessary sections The i2c-core code tends to hold the core lock for longer than it should. Limit locking to the necessary sections for both performance and clarity. This is also a requirement to support I2C multiplexers in the future. Signed-off-by: Jean Delvare Tested-by: Rodolfo Giometti Cc: David Brownell diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index b1fd00d..a2f1cd3 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -38,6 +38,9 @@ #include "i2c-core.h" +/* core_lock protects i2c_adapter_idr, and guarantees + that device detection, deletion of detected devices, and attach_adapter + and detach_adapter calls are serialized */ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); @@ -418,13 +421,13 @@ static int i2c_register_adapter(struct i2c_adapter *adap) int res = 0, dummy; /* Can't register until after driver model init */ - if (unlikely(WARN_ON(!i2c_bus_type.p))) - return -EAGAIN; + if (unlikely(WARN_ON(!i2c_bus_type.p))) { + res = -EAGAIN; + goto out_list; + } mutex_init(&adap->bus_lock); - mutex_lock(&core_lock); - /* Set default timeout to 1 second if not already set */ if (adap->timeout == 0) adap->timeout = HZ; @@ -443,16 +446,18 @@ static int i2c_register_adapter(struct i2c_adapter *adap) i2c_scan_static_board_info(adap); /* Notify drivers */ + mutex_lock(&core_lock); dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, i2c_do_add_adapter); - -out_unlock: mutex_unlock(&core_lock); - return res; + + return 0; out_list: + mutex_lock(&core_lock); idr_remove(&i2c_adapter_idr, adap->nr); - goto out_unlock; + mutex_unlock(&core_lock); + return res; } /** @@ -590,22 +595,25 @@ static int __unregister_client(struct device *dev, void *dummy) int i2c_del_adapter(struct i2c_adapter *adap) { int res = 0; - - mutex_lock(&core_lock); + struct i2c_adapter *found; /* First make sure that this adapter was ever added */ - if (idr_find(&i2c_adapter_idr, adap->nr) != adap) { + mutex_lock(&core_lock); + found = idr_find(&i2c_adapter_idr, adap->nr); + mutex_unlock(&core_lock); + if (found != adap) { pr_debug("i2c-core: attempting to delete unregistered " "adapter [%s]\n", adap->name); - res = -EINVAL; - goto out_unlock; + return -EINVAL; } /* Tell drivers about this removal */ + mutex_lock(&core_lock); res = bus_for_each_drv(&i2c_bus_type, NULL, adap, i2c_do_del_adapter); + mutex_unlock(&core_lock); if (res) - goto out_unlock; + return res; /* Detach any active clients. This can't fail, thus we do not checking the returned value. */ @@ -619,7 +627,9 @@ int i2c_del_adapter(struct i2c_adapter *adap) wait_for_completion(&adap->dev_released); /* free bus id */ + mutex_lock(&core_lock); idr_remove(&i2c_adapter_idr, adap->nr); + mutex_unlock(&core_lock); dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); @@ -627,9 +637,7 @@ int i2c_del_adapter(struct i2c_adapter *adap) added again */ memset(&adap->dev, 0, sizeof(adap->dev)); - out_unlock: - mutex_unlock(&core_lock); - return res; + return 0; } EXPORT_SYMBOL(i2c_del_adapter); @@ -674,16 +682,15 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) if (res) return res; - mutex_lock(&core_lock); - pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); INIT_LIST_HEAD(&driver->clients); /* Walk the adapters that are already present */ + mutex_lock(&core_lock); class_for_each_device(&i2c_adapter_class, NULL, driver, __attach_adapter); - mutex_unlock(&core_lock); + return 0; } EXPORT_SYMBOL(i2c_register_driver); @@ -721,14 +728,12 @@ static int __detach_adapter(struct device *dev, void *data) void i2c_del_driver(struct i2c_driver *driver) { mutex_lock(&core_lock); - class_for_each_device(&i2c_adapter_class, NULL, driver, __detach_adapter); + mutex_unlock(&core_lock); driver_unregister(&driver->driver); pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); - - mutex_unlock(&core_lock); } EXPORT_SYMBOL(i2c_del_driver); -- cgit v0.10.2 From 99cd8e25875a109455b709b5a41d4891b8d8e58e Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:20 +0200 Subject: i2c: Add a sysfs interface to instantiate devices Add a sysfs interface to instantiate and delete I2C devices. This is primarily a replacement of the force_* module parameters implemented by some i2c drivers. These module parameters were implemented internally by the I2C_CLIENT_INSMOD* macros, which don't scale well. This can also be used when developing a driver on a self-soldered board which doesn't yet have proper I2C device declaration at the platform level, and presumably for various debugging situations. Signed-off-by: Jean Delvare Cc: David Brownell diff --git a/Documentation/i2c/instantiating-devices b/Documentation/i2c/instantiating-devices index b55ce57..c740b7b 100644 --- a/Documentation/i2c/instantiating-devices +++ b/Documentation/i2c/instantiating-devices @@ -165,3 +165,47 @@ was done there. Two significant differences are: Once again, method 3 should be avoided wherever possible. Explicit device instantiation (methods 1 and 2) is much preferred for it is safer and faster. + + +Method 4: Instantiate from user-space +------------------------------------- + +In general, the kernel should know which I2C devices are connected and +what addresses they live at. However, in certain cases, it does not, so a +sysfs interface was added to let the user provide the information. This +interface is made of 2 attribute files which are created in every I2C bus +directory: new_device and delete_device. Both files are write only and you +must write the right parameters to them in order to properly instantiate, +respectively delete, an I2C device. + +File new_device takes 2 parameters: the name of the I2C device (a string) +and the address of the I2C device (a number, typically expressed in +hexadecimal starting with 0x, but can also be expressed in decimal.) + +File delete_device takes a single parameter: the address of the I2C +device. As no two devices can live at the same address on a given I2C +segment, the address is sufficient to uniquely identify the device to be +deleted. + +Example: +# echo eeprom 0x50 > /sys/class/i2c-adapter/i2c-3/new_device + +While this interface should only be used when in-kernel device declaration +can't be done, there is a variety of cases where it can be helpful: +* The I2C driver usually detects devices (method 3 above) but the bus + segment your device lives on doesn't have the proper class bit set and + thus detection doesn't trigger. +* The I2C driver usually detects devices, but your device lives at an + unexpected address. +* The I2C driver usually detects devices, but your device is not detected, + either because the detection routine is too strict, or because your + device is not officially supported yet but you know it is compatible. +* You are developing a driver on a test board, where you soldered the I2C + device yourself. + +This interface is a replacement for the force_* module parameters some I2C +drivers implement. Being implemented in i2c-core rather than in each +device driver individually, it is much more efficient, and also has the +advantage that you do not have to reload the driver to change a setting. +You can also instantiate the device before the driver is loaded or even +available, and you don't need to know what driver the device needs. diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index a2f1cd3..eb084fa 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -38,11 +38,12 @@ #include "i2c-core.h" -/* core_lock protects i2c_adapter_idr, and guarantees +/* core_lock protects i2c_adapter_idr, userspace_devices, and guarantees that device detection, deletion of detected devices, and attach_adapter and detach_adapter calls are serialized */ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); +static LIST_HEAD(userspace_devices); static int i2c_check_addr(struct i2c_adapter *adapter, int addr); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); @@ -373,8 +374,128 @@ show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%s\n", adap->name); } +/* + * Let users instantiate I2C devices through sysfs. This can be used when + * platform initialization code doesn't contain the proper data for + * whatever reason. Also useful for drivers that do device detection and + * detection fails, either because the device uses an unexpected address, + * or this is a compatible device with different ID register values. + * + * Parameter checking may look overzealous, but we really don't want + * the user to provide incorrect parameters. + */ +static ssize_t +i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_adapter *adap = to_i2c_adapter(dev); + struct i2c_board_info info; + struct i2c_client *client; + char *blank, end; + int res; + + dev_warn(dev, "The new_device interface is still experimental " + "and may change in a near future\n"); + memset(&info, 0, sizeof(struct i2c_board_info)); + + blank = strchr(buf, ' '); + if (!blank) { + dev_err(dev, "%s: Missing parameters\n", "new_device"); + return -EINVAL; + } + if (blank - buf > I2C_NAME_SIZE - 1) { + dev_err(dev, "%s: Invalid device name\n", "new_device"); + return -EINVAL; + } + memcpy(info.type, buf, blank - buf); + + /* Parse remaining parameters, reject extra parameters */ + res = sscanf(++blank, "%hi%c", &info.addr, &end); + if (res < 1) { + dev_err(dev, "%s: Can't parse I2C address\n", "new_device"); + return -EINVAL; + } + if (res > 1 && end != '\n') { + dev_err(dev, "%s: Extra parameters\n", "new_device"); + return -EINVAL; + } + + if (info.addr < 0x03 || info.addr > 0x77) { + dev_err(dev, "%s: Invalid I2C address 0x%hx\n", "new_device", + info.addr); + return -EINVAL; + } + + client = i2c_new_device(adap, &info); + if (!client) + return -EEXIST; + + /* Keep track of the added device */ + mutex_lock(&core_lock); + list_add_tail(&client->detected, &userspace_devices); + mutex_unlock(&core_lock); + dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", + info.type, info.addr); + + return count; +} + +/* + * And of course let the users delete the devices they instantiated, if + * they got it wrong. This interface can only be used to delete devices + * instantiated by i2c_sysfs_new_device above. This guarantees that we + * don't delete devices to which some kernel code still has references. + * + * Parameter checking may look overzealous, but we really don't want + * the user to delete the wrong device. + */ +static ssize_t +i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_adapter *adap = to_i2c_adapter(dev); + struct i2c_client *client, *next; + unsigned short addr; + char end; + int res; + + /* Parse parameters, reject extra parameters */ + res = sscanf(buf, "%hi%c", &addr, &end); + if (res < 1) { + dev_err(dev, "%s: Can't parse I2C address\n", "delete_device"); + return -EINVAL; + } + if (res > 1 && end != '\n') { + dev_err(dev, "%s: Extra parameters\n", "delete_device"); + return -EINVAL; + } + + /* Make sure the device was added through sysfs */ + res = -ENOENT; + mutex_lock(&core_lock); + list_for_each_entry_safe(client, next, &userspace_devices, detected) { + if (client->addr == addr && client->adapter == adap) { + dev_info(dev, "%s: Deleting device %s at 0x%02hx\n", + "delete_device", client->name, client->addr); + + list_del(&client->detected); + i2c_unregister_device(client); + res = count; + break; + } + } + mutex_unlock(&core_lock); + + if (res < 0) + dev_err(dev, "%s: Can't find device in list\n", + "delete_device"); + return res; +} + static struct device_attribute i2c_adapter_attrs[] = { __ATTR(name, S_IRUGO, show_adapter_name, NULL), + __ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device), + __ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device), { }, }; diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 5f81576..844d266 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -178,7 +178,8 @@ struct i2c_driver { * @driver: device's driver, hence pointer to access routines * @dev: Driver model device node for the slave. * @irq: indicates the IRQ generated by this device (if any) - * @detected: member of an i2c_driver.clients list + * @detected: member of an i2c_driver.clients list or i2c-core's + * userspace_devices list * * An i2c_client identifies a single device (i.e. chip) connected to an * i2c bus. The behaviour exposed to Linux is defined by the driver -- cgit v0.10.2 From f18c41daea14baee11252da268cdf5dcd57c7c10 Mon Sep 17 00:00:00 2001 From: Rodolfo Giometti Date: Fri, 19 Jun 2009 16:58:20 +0200 Subject: i2c: Use rwsem instead of mutex for board info By using rwsem we can easily manage recursive calls of i2c_scan_static_board_info() function without breaking the locking. Signed-off-by: Rodolfo Giometti Signed-off-by: Jean Delvare diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c index ffb35f0..a26a34a 100644 --- a/drivers/i2c/i2c-boardinfo.c +++ b/drivers/i2c/i2c-boardinfo.c @@ -18,6 +18,7 @@ #include #include +#include #include "i2c-core.h" @@ -25,7 +26,7 @@ /* These symbols are exported ONLY FOR the i2c core. * No other users will be supported. */ -DEFINE_MUTEX(__i2c_board_lock); +DECLARE_RWSEM(__i2c_board_lock); EXPORT_SYMBOL_GPL(__i2c_board_lock); LIST_HEAD(__i2c_board_list); @@ -63,7 +64,7 @@ i2c_register_board_info(int busnum, { int status; - mutex_lock(&__i2c_board_lock); + down_write(&__i2c_board_lock); /* dynamic bus numbers will be assigned after the last static one */ if (busnum >= __i2c_first_dynamic_bus_num) @@ -84,7 +85,7 @@ i2c_register_board_info(int busnum, list_add_tail(&devinfo->list, &__i2c_board_list); } - mutex_unlock(&__i2c_board_lock); + up_write(&__i2c_board_lock); return status; } diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index eb084fa..0e45c29 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "i2c-core.h" @@ -509,7 +510,7 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter) { struct i2c_devinfo *devinfo; - mutex_lock(&__i2c_board_lock); + down_read(&__i2c_board_lock); list_for_each_entry(devinfo, &__i2c_board_list, list) { if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, @@ -518,7 +519,7 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter) "Can't create device at 0x%02x\n", devinfo->board_info.addr); } - mutex_unlock(&__i2c_board_lock); + up_read(&__i2c_board_lock); } static int i2c_do_add_adapter(struct device_driver *d, void *data) diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h index cd5bff8..9f9c57f 100644 --- a/drivers/i2c/i2c-core.h +++ b/drivers/i2c/i2c-core.h @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + struct i2c_devinfo { struct list_head list; int busnum; @@ -25,7 +27,7 @@ struct i2c_devinfo { /* board_lock protects board_list and first_dynamic_bus_num. * only i2c core components are allowed to use these symbols. */ -extern struct mutex __i2c_board_lock; +extern struct rw_semaphore __i2c_board_lock; extern struct list_head __i2c_board_list; extern int __i2c_first_dynamic_bus_num; -- cgit v0.10.2 From 23af8400571ac4431fac0caefeac18f8aef490df Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 19 Jun 2009 16:58:20 +0200 Subject: i2c: Don't advertise i2c functions when not available Surround i2c function declarations with ifdefs, so that they aren't advertised when i2c-core isn't actually built. That way, drivers using these functions unconditionally will result in an immediate build failure, rather than a late linking failure which is harder to figure out. Signed-off-by: Jean Delvare Cc: Mark Brown Cc: Paul Mundt diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 844d266..bc17f7f 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -47,6 +47,7 @@ struct i2c_driver; union i2c_smbus_data; struct i2c_board_info; +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) /* * The master routines are the ones normally used to transmit data to devices * on a bus (or read from them). Apart from two basic transfer functions to @@ -93,6 +94,7 @@ extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, u8 length, const u8 *values); +#endif /* I2C */ /** * struct i2c_driver - represent an I2C device driver @@ -260,6 +262,7 @@ struct i2c_board_info { .type = dev_type, .addr = (dev_addr) +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) /* 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. @@ -283,6 +286,7 @@ extern struct i2c_client * i2c_new_dummy(struct i2c_adapter *adap, u16 address); extern void i2c_unregister_device(struct i2c_client *); +#endif /* I2C */ /* Mainboard arch_initcall() code should register all its I2C devices. * This is done at arch_initcall time, before declaring any i2c adapters. @@ -299,7 +303,7 @@ i2c_register_board_info(int busnum, struct i2c_board_info const *info, { return 0; } -#endif +#endif /* I2C_BOARDINFO */ /* * The following structs are for those who like to implement new bus drivers: @@ -394,6 +398,7 @@ struct i2c_client_address_data { /* administration... */ +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) extern int i2c_add_adapter(struct i2c_adapter *); extern int i2c_del_adapter(struct i2c_adapter *); extern int i2c_add_numbered_adapter(struct i2c_adapter *); @@ -435,6 +440,7 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap) { return adap->nr; } +#endif /* I2C */ #endif /* __KERNEL__ */ /** -- cgit v0.10.2 From c70366732f67dbdb32f7fe9c6aa59299b76feca6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 19 Jun 2009 16:58:21 +0200 Subject: i2c: New macro to initialize i2c address lists on the fly For video4linux we sometimes need to probe for a single i2c address. Normally you would do it like this: static const unsigned short addrs[] = { addr, I2C_CLIENT_END }; client = i2c_new_probed_device(adapter, &info, addrs); This is a bit awkward and I came up with this macro: #define V4L2_I2C_ADDRS(addr, addrs...) \ ((const unsigned short []){ addr, ## addrs, I2C_CLIENT_END }) This can construct a list of one or more i2c addresses on the fly. But this is something that really belongs in i2c.h, renamed to I2C_ADDRS. With this macro we can just do: client = i2c_new_probed_device(adapter, &info, I2C_ADDRS(addr)); Note that this can also be used to initialize an array: static const unsigned short addrs[] = I2C_ADDRS(0x2a, 0x2c); Whether you want to is another matter, but it works. This functionality is also available in the oldest supported gcc (3.2). Signed-off-by: Hans Verkuil Signed-off-by: Jean Delvare diff --git a/include/linux/i2c.h b/include/linux/i2c.h index bc17f7f..f4784c0 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -393,6 +393,10 @@ struct i2c_client_address_data { /* The numbers to use to set I2C bus address */ #define ANY_I2C_BUS 0xffff +/* Construct an I2C_CLIENT_END-terminated array of i2c addresses */ +#define I2C_ADDRS(addr, addrs...) \ + ((const unsigned short []){ addr, ## addrs, I2C_CLIENT_END }) + /* ----- functions exported by i2c.o */ -- cgit v0.10.2