diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-04 18:20:37 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-04 18:20:37 -0400 |
| commit | c81406d6423416f1e18a8a41a3b7ac415fdf13d3 (patch) | |
| tree | a0a41d81d102670cc37b0ce5e8373b66f09b27e1 /drivers | |
| parent | f5fa05d97252b23b12749a7cd02710870c0762b0 (diff) | |
| parent | 6629dcff19470a894ce294d0adb9cbab94ee1fb9 (diff) | |
Merge branch 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging
* 'i2c-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jdelvare/staging:
i2c-core: Use per-adapter userspace device lists
i2c: Fix probing of FSC hardware monitoring chips
i2c-core: Erase pointer to clientdata on removal
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/i2c/i2c-core.c | 63 |
1 files changed, 40 insertions, 23 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 3202a86f420e..c2258a51fe0c 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
| @@ -40,12 +40,11 @@ | |||
| 40 | #include "i2c-core.h" | 40 | #include "i2c-core.h" |
| 41 | 41 | ||
| 42 | 42 | ||
| 43 | /* core_lock protects i2c_adapter_idr, userspace_devices, and guarantees | 43 | /* core_lock protects i2c_adapter_idr, and guarantees |
| 44 | that device detection, deletion of detected devices, and attach_adapter | 44 | that device detection, deletion of detected devices, and attach_adapter |
| 45 | and detach_adapter calls are serialized */ | 45 | and detach_adapter calls are serialized */ |
| 46 | static DEFINE_MUTEX(core_lock); | 46 | static DEFINE_MUTEX(core_lock); |
| 47 | static DEFINE_IDR(i2c_adapter_idr); | 47 | static DEFINE_IDR(i2c_adapter_idr); |
| 48 | static LIST_HEAD(userspace_devices); | ||
| 49 | 48 | ||
| 50 | static struct device_type i2c_client_type; | 49 | static struct device_type i2c_client_type; |
| 51 | static int i2c_check_addr(struct i2c_adapter *adapter, int addr); | 50 | static int i2c_check_addr(struct i2c_adapter *adapter, int addr); |
| @@ -117,8 +116,10 @@ static int i2c_device_probe(struct device *dev) | |||
| 117 | dev_dbg(dev, "probe\n"); | 116 | dev_dbg(dev, "probe\n"); |
| 118 | 117 | ||
| 119 | status = driver->probe(client, i2c_match_id(driver->id_table, client)); | 118 | status = driver->probe(client, i2c_match_id(driver->id_table, client)); |
| 120 | if (status) | 119 | if (status) { |
| 121 | client->driver = NULL; | 120 | client->driver = NULL; |
| 121 | i2c_set_clientdata(client, NULL); | ||
| 122 | } | ||
| 122 | return status; | 123 | return status; |
| 123 | } | 124 | } |
| 124 | 125 | ||
| @@ -139,8 +140,10 @@ static int i2c_device_remove(struct device *dev) | |||
| 139 | dev->driver = NULL; | 140 | dev->driver = NULL; |
| 140 | status = 0; | 141 | status = 0; |
| 141 | } | 142 | } |
| 142 | if (status == 0) | 143 | if (status == 0) { |
| 143 | client->driver = NULL; | 144 | client->driver = NULL; |
| 145 | i2c_set_clientdata(client, NULL); | ||
| 146 | } | ||
| 144 | return status; | 147 | return status; |
| 145 | } | 148 | } |
| 146 | 149 | ||
| @@ -538,9 +541,9 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, | |||
| 538 | return -EEXIST; | 541 | return -EEXIST; |
| 539 | 542 | ||
| 540 | /* Keep track of the added device */ | 543 | /* Keep track of the added device */ |
| 541 | mutex_lock(&core_lock); | 544 | i2c_lock_adapter(adap); |
| 542 | list_add_tail(&client->detected, &userspace_devices); | 545 | list_add_tail(&client->detected, &adap->userspace_clients); |
| 543 | mutex_unlock(&core_lock); | 546 | i2c_unlock_adapter(adap); |
| 544 | dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", | 547 | dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", |
| 545 | info.type, info.addr); | 548 | info.type, info.addr); |
| 546 | 549 | ||
| @@ -579,9 +582,10 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, | |||
| 579 | 582 | ||
| 580 | /* Make sure the device was added through sysfs */ | 583 | /* Make sure the device was added through sysfs */ |
| 581 | res = -ENOENT; | 584 | res = -ENOENT; |
| 582 | mutex_lock(&core_lock); | 585 | i2c_lock_adapter(adap); |
| 583 | list_for_each_entry_safe(client, next, &userspace_devices, detected) { | 586 | list_for_each_entry_safe(client, next, &adap->userspace_clients, |
| 584 | if (client->addr == addr && client->adapter == adap) { | 587 | detected) { |
| 588 | if (client->addr == addr) { | ||
| 585 | dev_info(dev, "%s: Deleting device %s at 0x%02hx\n", | 589 | dev_info(dev, "%s: Deleting device %s at 0x%02hx\n", |
| 586 | "delete_device", client->name, client->addr); | 590 | "delete_device", client->name, client->addr); |
| 587 | 591 | ||
| @@ -591,7 +595,7 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, | |||
| 591 | break; | 595 | break; |
| 592 | } | 596 | } |
| 593 | } | 597 | } |
| 594 | mutex_unlock(&core_lock); | 598 | i2c_unlock_adapter(adap); |
| 595 | 599 | ||
| 596 | if (res < 0) | 600 | if (res < 0) |
| 597 | dev_err(dev, "%s: Can't find device in list\n", | 601 | dev_err(dev, "%s: Can't find device in list\n", |
| @@ -673,6 +677,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) | |||
| 673 | } | 677 | } |
| 674 | 678 | ||
| 675 | rt_mutex_init(&adap->bus_lock); | 679 | rt_mutex_init(&adap->bus_lock); |
| 680 | INIT_LIST_HEAD(&adap->userspace_clients); | ||
| 676 | 681 | ||
| 677 | /* Set default timeout to 1 second if not already set */ | 682 | /* Set default timeout to 1 second if not already set */ |
| 678 | if (adap->timeout == 0) | 683 | if (adap->timeout == 0) |
| @@ -875,14 +880,15 @@ int i2c_del_adapter(struct i2c_adapter *adap) | |||
| 875 | return res; | 880 | return res; |
| 876 | 881 | ||
| 877 | /* Remove devices instantiated from sysfs */ | 882 | /* Remove devices instantiated from sysfs */ |
| 878 | list_for_each_entry_safe(client, next, &userspace_devices, detected) { | 883 | i2c_lock_adapter(adap); |
| 879 | if (client->adapter == adap) { | 884 | list_for_each_entry_safe(client, next, &adap->userspace_clients, |
| 880 | dev_dbg(&adap->dev, "Removing %s at 0x%x\n", | 885 | detected) { |
| 881 | client->name, client->addr); | 886 | dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name, |
| 882 | list_del(&client->detected); | 887 | client->addr); |
| 883 | i2c_unregister_device(client); | 888 | list_del(&client->detected); |
| 884 | } | 889 | i2c_unregister_device(client); |
| 885 | } | 890 | } |
| 891 | i2c_unlock_adapter(adap); | ||
| 886 | 892 | ||
| 887 | /* Detach any active clients. This can't fail, thus we do not | 893 | /* Detach any active clients. This can't fail, thus we do not |
| 888 | checking the returned value. */ | 894 | checking the returned value. */ |
| @@ -1260,12 +1266,23 @@ static int i2c_detect_address(struct i2c_client *temp_client, | |||
| 1260 | return 0; | 1266 | return 0; |
| 1261 | 1267 | ||
| 1262 | /* Make sure there is something at this address */ | 1268 | /* Make sure there is something at this address */ |
| 1263 | if (i2c_smbus_xfer(adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) < 0) | 1269 | if (addr == 0x73 && (adapter->class & I2C_CLASS_HWMON)) { |
| 1264 | return 0; | 1270 | /* Special probe for FSC hwmon chips */ |
| 1271 | union i2c_smbus_data dummy; | ||
| 1265 | 1272 | ||
| 1266 | /* Prevent 24RF08 corruption */ | 1273 | if (i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_READ, 0, |
| 1267 | if ((addr & ~0x0f) == 0x50) | 1274 | I2C_SMBUS_BYTE_DATA, &dummy) < 0) |
| 1268 | i2c_smbus_xfer(adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL); | 1275 | return 0; |
| 1276 | } else { | ||
| 1277 | if (i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_WRITE, 0, | ||
| 1278 | I2C_SMBUS_QUICK, NULL) < 0) | ||
| 1279 | return 0; | ||
| 1280 | |||
| 1281 | /* Prevent 24RF08 corruption */ | ||
| 1282 | if ((addr & ~0x0f) == 0x50) | ||
| 1283 | i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_WRITE, 0, | ||
| 1284 | I2C_SMBUS_QUICK, NULL); | ||
| 1285 | } | ||
| 1269 | 1286 | ||
| 1270 | /* Finally call the custom detection function */ | 1287 | /* Finally call the custom detection function */ |
| 1271 | memset(&info, 0, sizeof(struct i2c_board_info)); | 1288 | memset(&info, 0, sizeof(struct i2c_board_info)); |
