diff options
author | Jean Delvare <khali@linux-fr.org> | 2008-07-14 16:38:36 -0400 |
---|---|---|
committer | Jean Delvare <khali@mahadeva.delvare> | 2008-07-14 16:38:36 -0400 |
commit | 4735c98f8447acb1c8977e2b8024640f7bf36dd6 (patch) | |
tree | 7f7c65b1feef6a0213caa20218cd6080488cc62b /drivers/i2c | |
parent | 8508159e2f3b82bf109f0ec77bcbd8ff3f3a7e17 (diff) |
i2c: Add detection capability to new-style drivers
Add a mechanism to let new-style i2c drivers optionally autodetect
devices they would support on selected buses and ask i2c-core to
instantiate them. This is a replacement for legacy i2c drivers, much
cleaner.
Where drivers had to implement both a legacy i2c_driver and a
new-style i2c_driver so far, this mechanism makes it possible to get
rid of the legacy i2c_driver and implement both enumerated and
detected device support with just one (new-style) i2c_driver.
Here is a quick conversion guide for these drivers, step by step:
* Delete the legacy driver definition, registration and removal.
Delete the attach_adapter and detach_client methods of the legacy
driver.
* Change the prototype of the legacy detect function from
static int foo_detect(struct i2c_adapter *adapter, int address, int kind);
to
static int foo_detect(struct i2c_client *client, int kind,
struct i2c_board_info *info);
* Set the new-style driver detect callback to this new function, and
set its address_data to &addr_data (addr_data is generally provided
by I2C_CLIENT_INSMOD.)
* Add the appropriate class to the new-style driver. This is
typically the class the legacy attach_adapter method was checking
for. Class checking is now mandatory (done by i2c-core.) See
<linux/i2c.h> for the list of available classes.
* Remove the i2c_client allocation and freeing from the detect
function. A pre-allocated client is now handed to you by i2c-core,
and is freed automatically.
* Make the detect function fill the type field of the i2c_board_info
structure it was passed as a parameter, and return 0, on success. If
the detection fails, return -ENODEV.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/i2c-core.c | 223 |
1 files changed, 212 insertions, 11 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 5e249d758828..0a79f7661017 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -42,7 +42,9 @@ | |||
42 | static DEFINE_MUTEX(core_lock); | 42 | static DEFINE_MUTEX(core_lock); |
43 | static DEFINE_IDR(i2c_adapter_idr); | 43 | static DEFINE_IDR(i2c_adapter_idr); |
44 | 44 | ||
45 | #define is_newstyle_driver(d) ((d)->probe || (d)->remove) | 45 | #define is_newstyle_driver(d) ((d)->probe || (d)->remove || (d)->detect) |
46 | |||
47 | static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); | ||
46 | 48 | ||
47 | /* ------------------------------------------------------------------------- */ | 49 | /* ------------------------------------------------------------------------- */ |
48 | 50 | ||
@@ -418,6 +420,10 @@ static int i2c_do_add_adapter(struct device_driver *d, void *data) | |||
418 | struct i2c_driver *driver = to_i2c_driver(d); | 420 | struct i2c_driver *driver = to_i2c_driver(d); |
419 | struct i2c_adapter *adap = data; | 421 | struct i2c_adapter *adap = data; |
420 | 422 | ||
423 | /* Detect supported devices on that bus, and instantiate them */ | ||
424 | i2c_detect(adap, driver); | ||
425 | |||
426 | /* Let legacy drivers scan this bus for matching devices */ | ||
421 | if (driver->attach_adapter) { | 427 | if (driver->attach_adapter) { |
422 | /* We ignore the return code; if it fails, too bad */ | 428 | /* We ignore the return code; if it fails, too bad */ |
423 | driver->attach_adapter(adap); | 429 | driver->attach_adapter(adap); |
@@ -457,7 +463,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) | |||
457 | if (adap->nr < __i2c_first_dynamic_bus_num) | 463 | if (adap->nr < __i2c_first_dynamic_bus_num) |
458 | i2c_scan_static_board_info(adap); | 464 | i2c_scan_static_board_info(adap); |
459 | 465 | ||
460 | /* let legacy drivers scan this bus for matching devices */ | 466 | /* Notify drivers */ |
461 | dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, | 467 | dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, |
462 | i2c_do_add_adapter); | 468 | i2c_do_add_adapter); |
463 | 469 | ||
@@ -563,8 +569,19 @@ static int i2c_do_del_adapter(struct device_driver *d, void *data) | |||
563 | { | 569 | { |
564 | struct i2c_driver *driver = to_i2c_driver(d); | 570 | struct i2c_driver *driver = to_i2c_driver(d); |
565 | struct i2c_adapter *adapter = data; | 571 | struct i2c_adapter *adapter = data; |
572 | struct i2c_client *client, *_n; | ||
566 | int res; | 573 | int res; |
567 | 574 | ||
575 | /* Remove the devices we created ourselves */ | ||
576 | list_for_each_entry_safe(client, _n, &driver->clients, detected) { | ||
577 | if (client->adapter == adapter) { | ||
578 | dev_dbg(&adapter->dev, "Removing %s at 0x%x\n", | ||
579 | client->name, client->addr); | ||
580 | list_del(&client->detected); | ||
581 | i2c_unregister_device(client); | ||
582 | } | ||
583 | } | ||
584 | |||
568 | if (!driver->detach_adapter) | 585 | if (!driver->detach_adapter) |
569 | return 0; | 586 | return 0; |
570 | res = driver->detach_adapter(adapter); | 587 | res = driver->detach_adapter(adapter); |
@@ -651,7 +668,11 @@ static int __attach_adapter(struct device *dev, void *data) | |||
651 | struct i2c_adapter *adapter = to_i2c_adapter(dev); | 668 | struct i2c_adapter *adapter = to_i2c_adapter(dev); |
652 | struct i2c_driver *driver = data; | 669 | struct i2c_driver *driver = data; |
653 | 670 | ||
654 | driver->attach_adapter(adapter); | 671 | i2c_detect(adapter, driver); |
672 | |||
673 | /* Legacy drivers scan i2c busses directly */ | ||
674 | if (driver->attach_adapter) | ||
675 | driver->attach_adapter(adapter); | ||
655 | 676 | ||
656 | return 0; | 677 | return 0; |
657 | } | 678 | } |
@@ -695,10 +716,9 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) | |||
695 | 716 | ||
696 | pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); | 717 | pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); |
697 | 718 | ||
698 | /* legacy drivers scan i2c busses directly */ | 719 | INIT_LIST_HEAD(&driver->clients); |
699 | if (driver->attach_adapter) | 720 | /* Walk the adapters that are already present */ |
700 | class_for_each_device(&i2c_adapter_class, driver, | 721 | class_for_each_device(&i2c_adapter_class, driver, __attach_adapter); |
701 | __attach_adapter); | ||
702 | 722 | ||
703 | mutex_unlock(&core_lock); | 723 | mutex_unlock(&core_lock); |
704 | return 0; | 724 | return 0; |
@@ -709,6 +729,17 @@ static int __detach_adapter(struct device *dev, void *data) | |||
709 | { | 729 | { |
710 | struct i2c_adapter *adapter = to_i2c_adapter(dev); | 730 | struct i2c_adapter *adapter = to_i2c_adapter(dev); |
711 | struct i2c_driver *driver = data; | 731 | struct i2c_driver *driver = data; |
732 | struct i2c_client *client, *_n; | ||
733 | |||
734 | list_for_each_entry_safe(client, _n, &driver->clients, detected) { | ||
735 | dev_dbg(&adapter->dev, "Removing %s at 0x%x\n", | ||
736 | client->name, client->addr); | ||
737 | list_del(&client->detected); | ||
738 | i2c_unregister_device(client); | ||
739 | } | ||
740 | |||
741 | if (is_newstyle_driver(driver)) | ||
742 | return 0; | ||
712 | 743 | ||
713 | /* Have a look at each adapter, if clients of this driver are still | 744 | /* Have a look at each adapter, if clients of this driver are still |
714 | * attached. If so, detach them to be able to kill the driver | 745 | * attached. If so, detach them to be able to kill the driver |
@@ -747,10 +778,7 @@ void i2c_del_driver(struct i2c_driver *driver) | |||
747 | { | 778 | { |
748 | mutex_lock(&core_lock); | 779 | mutex_lock(&core_lock); |
749 | 780 | ||
750 | /* legacy driver? */ | 781 | class_for_each_device(&i2c_adapter_class, driver, __detach_adapter); |
751 | if (!is_newstyle_driver(driver)) | ||
752 | class_for_each_device(&i2c_adapter_class, driver, | ||
753 | __detach_adapter); | ||
754 | 782 | ||
755 | driver_unregister(&driver->driver); | 783 | driver_unregister(&driver->driver); |
756 | pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); | 784 | pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); |
@@ -1205,6 +1233,179 @@ int i2c_probe(struct i2c_adapter *adapter, | |||
1205 | } | 1233 | } |
1206 | EXPORT_SYMBOL(i2c_probe); | 1234 | EXPORT_SYMBOL(i2c_probe); |
1207 | 1235 | ||
1236 | /* Separate detection function for new-style drivers */ | ||
1237 | static int i2c_detect_address(struct i2c_client *temp_client, int kind, | ||
1238 | struct i2c_driver *driver) | ||
1239 | { | ||
1240 | struct i2c_board_info info; | ||
1241 | struct i2c_adapter *adapter = temp_client->adapter; | ||
1242 | int addr = temp_client->addr; | ||
1243 | int err; | ||
1244 | |||
1245 | /* Make sure the address is valid */ | ||
1246 | if (addr < 0x03 || addr > 0x77) { | ||
1247 | dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n", | ||
1248 | addr); | ||
1249 | return -EINVAL; | ||
1250 | } | ||
1251 | |||
1252 | /* Skip if already in use */ | ||
1253 | if (i2c_check_addr(adapter, addr)) | ||
1254 | return 0; | ||
1255 | |||
1256 | /* Make sure there is something at this address, unless forced */ | ||
1257 | if (kind < 0) { | ||
1258 | if (i2c_smbus_xfer(adapter, addr, 0, 0, 0, | ||
1259 | I2C_SMBUS_QUICK, NULL) < 0) | ||
1260 | return 0; | ||
1261 | |||
1262 | /* prevent 24RF08 corruption */ | ||
1263 | if ((addr & ~0x0f) == 0x50) | ||
1264 | i2c_smbus_xfer(adapter, addr, 0, 0, 0, | ||
1265 | I2C_SMBUS_QUICK, NULL); | ||
1266 | } | ||
1267 | |||
1268 | /* Finally call the custom detection function */ | ||
1269 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1270 | info.addr = addr; | ||
1271 | err = driver->detect(temp_client, kind, &info); | ||
1272 | if (err) { | ||
1273 | /* -ENODEV is returned if the detection fails. We catch it | ||
1274 | here as this isn't an error. */ | ||
1275 | return err == -ENODEV ? 0 : err; | ||
1276 | } | ||
1277 | |||
1278 | /* Consistency check */ | ||
1279 | if (info.type[0] == '\0') { | ||
1280 | dev_err(&adapter->dev, "%s detection function provided " | ||
1281 | "no name for 0x%x\n", driver->driver.name, | ||
1282 | addr); | ||
1283 | } else { | ||
1284 | struct i2c_client *client; | ||
1285 | |||
1286 | /* Detection succeeded, instantiate the device */ | ||
1287 | dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n", | ||
1288 | info.type, info.addr); | ||
1289 | client = i2c_new_device(adapter, &info); | ||
1290 | if (client) | ||
1291 | list_add_tail(&client->detected, &driver->clients); | ||
1292 | else | ||
1293 | dev_err(&adapter->dev, "Failed creating %s at 0x%02x\n", | ||
1294 | info.type, info.addr); | ||
1295 | } | ||
1296 | return 0; | ||
1297 | } | ||
1298 | |||
1299 | static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) | ||
1300 | { | ||
1301 | const struct i2c_client_address_data *address_data; | ||
1302 | struct i2c_client *temp_client; | ||
1303 | int i, err = 0; | ||
1304 | int adap_id = i2c_adapter_id(adapter); | ||
1305 | |||
1306 | address_data = driver->address_data; | ||
1307 | if (!driver->detect || !address_data) | ||
1308 | return 0; | ||
1309 | |||
1310 | /* Set up a temporary client to help detect callback */ | ||
1311 | temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); | ||
1312 | if (!temp_client) | ||
1313 | return -ENOMEM; | ||
1314 | temp_client->adapter = adapter; | ||
1315 | |||
1316 | /* Force entries are done first, and are not affected by ignore | ||
1317 | entries */ | ||
1318 | if (address_data->forces) { | ||
1319 | const unsigned short * const *forces = address_data->forces; | ||
1320 | int kind; | ||
1321 | |||
1322 | for (kind = 0; forces[kind]; kind++) { | ||
1323 | for (i = 0; forces[kind][i] != I2C_CLIENT_END; | ||
1324 | i += 2) { | ||
1325 | if (forces[kind][i] == adap_id | ||
1326 | || forces[kind][i] == ANY_I2C_BUS) { | ||
1327 | dev_dbg(&adapter->dev, "found force " | ||
1328 | "parameter for adapter %d, " | ||
1329 | "addr 0x%02x, kind %d\n", | ||
1330 | adap_id, forces[kind][i + 1], | ||
1331 | kind); | ||
1332 | temp_client->addr = forces[kind][i + 1]; | ||
1333 | err = i2c_detect_address(temp_client, | ||
1334 | kind, driver); | ||
1335 | if (err) | ||
1336 | goto exit_free; | ||
1337 | } | ||
1338 | } | ||
1339 | } | ||
1340 | } | ||
1341 | |||
1342 | /* Stop here if we can't use SMBUS_QUICK */ | ||
1343 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) { | ||
1344 | if (address_data->probe[0] == I2C_CLIENT_END | ||
1345 | && address_data->normal_i2c[0] == I2C_CLIENT_END) | ||
1346 | goto exit_free; | ||
1347 | |||
1348 | dev_warn(&adapter->dev, "SMBus Quick command not supported, " | ||
1349 | "can't probe for chips\n"); | ||
1350 | err = -EOPNOTSUPP; | ||
1351 | goto exit_free; | ||
1352 | } | ||
1353 | |||
1354 | /* Stop here if the classes do not match */ | ||
1355 | if (!(adapter->class & driver->class)) | ||
1356 | goto exit_free; | ||
1357 | |||
1358 | /* Probe entries are done second, and are not affected by ignore | ||
1359 | entries either */ | ||
1360 | for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) { | ||
1361 | if (address_data->probe[i] == adap_id | ||
1362 | || address_data->probe[i] == ANY_I2C_BUS) { | ||
1363 | dev_dbg(&adapter->dev, "found probe parameter for " | ||
1364 | "adapter %d, addr 0x%02x\n", adap_id, | ||
1365 | address_data->probe[i + 1]); | ||
1366 | temp_client->addr = address_data->probe[i + 1]; | ||
1367 | err = i2c_detect_address(temp_client, -1, driver); | ||
1368 | if (err) | ||
1369 | goto exit_free; | ||
1370 | } | ||
1371 | } | ||
1372 | |||
1373 | /* Normal entries are done last, unless shadowed by an ignore entry */ | ||
1374 | for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) { | ||
1375 | int j, ignore; | ||
1376 | |||
1377 | ignore = 0; | ||
1378 | for (j = 0; address_data->ignore[j] != I2C_CLIENT_END; | ||
1379 | j += 2) { | ||
1380 | if ((address_data->ignore[j] == adap_id || | ||
1381 | address_data->ignore[j] == ANY_I2C_BUS) | ||
1382 | && address_data->ignore[j + 1] | ||
1383 | == address_data->normal_i2c[i]) { | ||
1384 | dev_dbg(&adapter->dev, "found ignore " | ||
1385 | "parameter for adapter %d, " | ||
1386 | "addr 0x%02x\n", adap_id, | ||
1387 | address_data->ignore[j + 1]); | ||
1388 | ignore = 1; | ||
1389 | break; | ||
1390 | } | ||
1391 | } | ||
1392 | if (ignore) | ||
1393 | continue; | ||
1394 | |||
1395 | dev_dbg(&adapter->dev, "found normal entry for adapter %d, " | ||
1396 | "addr 0x%02x\n", adap_id, | ||
1397 | address_data->normal_i2c[i]); | ||
1398 | temp_client->addr = address_data->normal_i2c[i]; | ||
1399 | err = i2c_detect_address(temp_client, -1, driver); | ||
1400 | if (err) | ||
1401 | goto exit_free; | ||
1402 | } | ||
1403 | |||
1404 | exit_free: | ||
1405 | kfree(temp_client); | ||
1406 | return err; | ||
1407 | } | ||
1408 | |||
1208 | struct i2c_client * | 1409 | struct i2c_client * |
1209 | i2c_new_probed_device(struct i2c_adapter *adap, | 1410 | i2c_new_probed_device(struct i2c_adapter *adap, |
1210 | struct i2c_board_info *info, | 1411 | struct i2c_board_info *info, |