diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/i2c-core.c | 92 |
1 files changed, 48 insertions, 44 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index d0175f4f8fc6..f489683fd15f 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -35,7 +35,6 @@ #include <linux/completion.h> #include <linux/hardirq.h> #include <linux/irqflags.h> -#include <linux/semaphore.h> #include <asm/uaccess.h> #include "i2c-core.h" @@ -646,6 +645,16 @@ EXPORT_SYMBOL(i2c_del_adapter); /* ------------------------------------------------------------------------- */ +static int __attach_adapter(struct device *dev, void *data) +{ + struct i2c_adapter *adapter = to_i2c_adapter(dev); + struct i2c_driver *driver = data; + + driver->attach_adapter(adapter); + + return 0; +} + /* * 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 @@ -686,21 +695,49 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); /* legacy drivers scan i2c busses directly */ - if (driver->attach_adapter) { - struct i2c_adapter *adapter; + if (driver->attach_adapter) + class_for_each_device(&i2c_adapter_class, driver, + __attach_adapter); - down(&i2c_adapter_class.sem); - list_for_each_entry(adapter, &i2c_adapter_class.devices, - dev.node) { - driver->attach_adapter(adapter); + mutex_unlock(&core_lock); + return 0; +} +EXPORT_SYMBOL(i2c_register_driver); + +static int __detach_adapter(struct device *dev, void *data) +{ + struct i2c_adapter *adapter = to_i2c_adapter(dev); + struct i2c_driver *driver = data; + + /* 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 list_head *item, *_n; + struct i2c_client *client; + + list_for_each_safe(item, _n, &adapter->clients) { + client = list_entry(item, struct i2c_client, 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); } - up(&i2c_adapter_class.sem); } - mutex_unlock(&core_lock); return 0; } -EXPORT_SYMBOL(i2c_register_driver); /** * i2c_del_driver - unregister I2C driver @@ -709,46 +746,13 @@ EXPORT_SYMBOL(i2c_register_driver); */ void i2c_del_driver(struct i2c_driver *driver) { - struct list_head *item2, *_n; - struct i2c_client *client; - struct i2c_adapter *adap; - mutex_lock(&core_lock); /* new-style driver? */ if (is_newstyle_driver(driver)) goto unregister; - /* 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. - */ - down(&i2c_adapter_class.sem); - list_for_each_entry(adap, &i2c_adapter_class.devices, dev.node) { - if (driver->detach_adapter) { - if (driver->detach_adapter(adap)) { - dev_err(&adap->dev, "detach_adapter failed " - "for driver [%s]\n", - driver->driver.name); - } - } else { - list_for_each_safe(item2, _n, &adap->clients) { - client = list_entry(item2, struct i2c_client, list); - if (client->driver != driver) - continue; - dev_dbg(&adap->dev, "detaching client [%s] " - "at 0x%02x\n", client->name, - client->addr); - if (driver->detach_client(client)) { - dev_err(&adap->dev, "detach_client " - "failed for client [%s] at " - "0x%02x\n", client->name, - client->addr); - } - } - } - } - up(&i2c_adapter_class.sem); + class_for_each_device(&i2c_adapter_class, driver, __detach_adapter); unregister: driver_unregister(&driver->driver); |