diff options
-rw-r--r-- | drivers/i2c/i2c-core.c | 65 | ||||
-rw-r--r-- | include/linux/i2c.h | 1 |
2 files changed, 62 insertions, 4 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index a2ad83ad0f53..3aac1b5c7cbd 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -41,6 +41,7 @@ static LIST_HEAD(drivers); | |||
41 | static DEFINE_MUTEX(core_lists); | 41 | static DEFINE_MUTEX(core_lists); |
42 | static DEFINE_IDR(i2c_adapter_idr); | 42 | static DEFINE_IDR(i2c_adapter_idr); |
43 | 43 | ||
44 | #define is_newstyle_driver(d) ((d)->probe || (d)->remove) | ||
44 | 45 | ||
45 | /* ------------------------------------------------------------------------- */ | 46 | /* ------------------------------------------------------------------------- */ |
46 | 47 | ||
@@ -52,7 +53,7 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) | |||
52 | /* make legacy i2c drivers bypass driver model probing entirely; | 53 | /* make legacy i2c drivers bypass driver model probing entirely; |
53 | * such drivers scan each i2c adapter/bus themselves. | 54 | * such drivers scan each i2c adapter/bus themselves. |
54 | */ | 55 | */ |
55 | if (!driver->probe) | 56 | if (!is_newstyle_driver(driver)) |
56 | return 0; | 57 | return 0; |
57 | 58 | ||
58 | /* new style drivers use the same kind of driver matching policy | 59 | /* new style drivers use the same kind of driver matching policy |
@@ -100,7 +101,24 @@ static int i2c_device_probe(struct device *dev) | |||
100 | 101 | ||
101 | static int i2c_device_remove(struct device *dev) | 102 | static int i2c_device_remove(struct device *dev) |
102 | { | 103 | { |
103 | return 0; | 104 | struct i2c_client *client = to_i2c_client(dev); |
105 | struct i2c_driver *driver; | ||
106 | int status; | ||
107 | |||
108 | if (!dev->driver) | ||
109 | return 0; | ||
110 | |||
111 | driver = to_i2c_driver(dev->driver); | ||
112 | if (driver->remove) { | ||
113 | dev_dbg(dev, "remove\n"); | ||
114 | status = driver->remove(client); | ||
115 | } else { | ||
116 | dev->driver = NULL; | ||
117 | status = 0; | ||
118 | } | ||
119 | if (status == 0) | ||
120 | client->driver = NULL; | ||
121 | return status; | ||
104 | } | 122 | } |
105 | 123 | ||
106 | static void i2c_device_shutdown(struct device *dev) | 124 | static void i2c_device_shutdown(struct device *dev) |
@@ -177,6 +195,26 @@ struct bus_type i2c_bus_type = { | |||
177 | .resume = i2c_device_resume, | 195 | .resume = i2c_device_resume, |
178 | }; | 196 | }; |
179 | 197 | ||
198 | static void i2c_unregister_device(struct i2c_client *client) | ||
199 | { | ||
200 | struct i2c_adapter *adapter = client->adapter; | ||
201 | struct i2c_driver *driver = client->driver; | ||
202 | |||
203 | if (driver && !is_newstyle_driver(driver)) { | ||
204 | dev_err(&client->dev, "can't unregister devices " | ||
205 | "with legacy drivers\n"); | ||
206 | WARN_ON(1); | ||
207 | return; | ||
208 | } | ||
209 | |||
210 | mutex_lock(&adapter->clist_lock); | ||
211 | list_del(&client->list); | ||
212 | mutex_unlock(&adapter->clist_lock); | ||
213 | |||
214 | device_unregister(&client->dev); | ||
215 | } | ||
216 | |||
217 | |||
180 | /* ------------------------------------------------------------------------- */ | 218 | /* ------------------------------------------------------------------------- */ |
181 | 219 | ||
182 | /* I2C bus adapters -- one roots each I2C or SMBUS segment */ | 220 | /* I2C bus adapters -- one roots each I2C or SMBUS segment */ |
@@ -310,9 +348,19 @@ int i2c_del_adapter(struct i2c_adapter *adap) | |||
310 | /* detach any active clients. This must be done first, because | 348 | /* detach any active clients. This must be done first, because |
311 | * it can fail; in which case we give up. */ | 349 | * it can fail; in which case we give up. */ |
312 | list_for_each_safe(item, _n, &adap->clients) { | 350 | list_for_each_safe(item, _n, &adap->clients) { |
351 | struct i2c_driver *driver; | ||
352 | |||
313 | client = list_entry(item, struct i2c_client, list); | 353 | client = list_entry(item, struct i2c_client, list); |
354 | driver = client->driver; | ||
314 | 355 | ||
315 | if ((res=client->driver->detach_client(client))) { | 356 | /* new style, follow standard driver model */ |
357 | if (!driver || is_newstyle_driver(driver)) { | ||
358 | i2c_unregister_device(client); | ||
359 | continue; | ||
360 | } | ||
361 | |||
362 | /* legacy drivers create and remove clients themselves */ | ||
363 | if ((res = driver->detach_client(client))) { | ||
316 | dev_err(&adap->dev, "detach_client failed for client " | 364 | dev_err(&adap->dev, "detach_client failed for client " |
317 | "[%s] at address 0x%02x\n", client->name, | 365 | "[%s] at address 0x%02x\n", client->name, |
318 | client->addr); | 366 | client->addr); |
@@ -355,7 +403,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) | |||
355 | int res; | 403 | int res; |
356 | 404 | ||
357 | /* new style driver methods can't mix with legacy ones */ | 405 | /* new style driver methods can't mix with legacy ones */ |
358 | if (driver->probe) { | 406 | if (is_newstyle_driver(driver)) { |
359 | if (driver->attach_adapter || driver->detach_adapter | 407 | if (driver->attach_adapter || driver->detach_adapter |
360 | || driver->detach_client) { | 408 | || driver->detach_client) { |
361 | printk(KERN_WARNING | 409 | printk(KERN_WARNING |
@@ -392,6 +440,10 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) | |||
392 | } | 440 | } |
393 | EXPORT_SYMBOL(i2c_register_driver); | 441 | EXPORT_SYMBOL(i2c_register_driver); |
394 | 442 | ||
443 | /** | ||
444 | * i2c_del_driver - unregister I2C driver | ||
445 | * @driver: the driver being unregistered | ||
446 | */ | ||
395 | int i2c_del_driver(struct i2c_driver *driver) | 447 | int i2c_del_driver(struct i2c_driver *driver) |
396 | { | 448 | { |
397 | struct list_head *item1, *item2, *_n; | 449 | struct list_head *item1, *item2, *_n; |
@@ -402,6 +454,10 @@ int i2c_del_driver(struct i2c_driver *driver) | |||
402 | 454 | ||
403 | mutex_lock(&core_lists); | 455 | mutex_lock(&core_lists); |
404 | 456 | ||
457 | /* new-style driver? */ | ||
458 | if (is_newstyle_driver(driver)) | ||
459 | goto unregister; | ||
460 | |||
405 | /* Have a look at each adapter, if clients of this driver are still | 461 | /* Have a look at each adapter, if clients of this driver are still |
406 | * attached. If so, detach them to be able to kill the driver | 462 | * attached. If so, detach them to be able to kill the driver |
407 | * afterwards. | 463 | * afterwards. |
@@ -434,6 +490,7 @@ int i2c_del_driver(struct i2c_driver *driver) | |||
434 | } | 490 | } |
435 | } | 491 | } |
436 | 492 | ||
493 | unregister: | ||
437 | driver_unregister(&driver->driver); | 494 | driver_unregister(&driver->driver); |
438 | list_del(&driver->list); | 495 | list_del(&driver->list); |
439 | pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); | 496 | pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); |
diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 8dcccc0f4822..6802c3a0a3a3 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h | |||
@@ -130,6 +130,7 @@ struct i2c_driver { | |||
130 | * it's done by infrastructure. (NEW STYLE DRIVERS ONLY) | 130 | * it's done by infrastructure. (NEW STYLE DRIVERS ONLY) |
131 | */ | 131 | */ |
132 | int (*probe)(struct i2c_client *); | 132 | int (*probe)(struct i2c_client *); |
133 | int (*remove)(struct i2c_client *); | ||
133 | 134 | ||
134 | /* driver model interfaces that don't relate to enumeration */ | 135 | /* driver model interfaces that don't relate to enumeration */ |
135 | void (*shutdown)(struct i2c_client *); | 136 | void (*shutdown)(struct i2c_client *); |