Commit 99cd8e25875a109455b709b5a41d4891b8d8e58e
1 parent
35fc37f818
Exists in
master
and in
7 other branches
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 <khali@linux-fr.org> Cc: David Brownell <dbrownell@users.sourceforge.net>
Showing 3 changed files with 168 additions and 2 deletions Side-by-side Diff
Documentation/i2c/instantiating-devices
... | ... | @@ -165,4 +165,48 @@ |
165 | 165 | Once again, method 3 should be avoided wherever possible. Explicit device |
166 | 166 | instantiation (methods 1 and 2) is much preferred for it is safer and |
167 | 167 | faster. |
168 | + | |
169 | + | |
170 | +Method 4: Instantiate from user-space | |
171 | +------------------------------------- | |
172 | + | |
173 | +In general, the kernel should know which I2C devices are connected and | |
174 | +what addresses they live at. However, in certain cases, it does not, so a | |
175 | +sysfs interface was added to let the user provide the information. This | |
176 | +interface is made of 2 attribute files which are created in every I2C bus | |
177 | +directory: new_device and delete_device. Both files are write only and you | |
178 | +must write the right parameters to them in order to properly instantiate, | |
179 | +respectively delete, an I2C device. | |
180 | + | |
181 | +File new_device takes 2 parameters: the name of the I2C device (a string) | |
182 | +and the address of the I2C device (a number, typically expressed in | |
183 | +hexadecimal starting with 0x, but can also be expressed in decimal.) | |
184 | + | |
185 | +File delete_device takes a single parameter: the address of the I2C | |
186 | +device. As no two devices can live at the same address on a given I2C | |
187 | +segment, the address is sufficient to uniquely identify the device to be | |
188 | +deleted. | |
189 | + | |
190 | +Example: | |
191 | +# echo eeprom 0x50 > /sys/class/i2c-adapter/i2c-3/new_device | |
192 | + | |
193 | +While this interface should only be used when in-kernel device declaration | |
194 | +can't be done, there is a variety of cases where it can be helpful: | |
195 | +* The I2C driver usually detects devices (method 3 above) but the bus | |
196 | + segment your device lives on doesn't have the proper class bit set and | |
197 | + thus detection doesn't trigger. | |
198 | +* The I2C driver usually detects devices, but your device lives at an | |
199 | + unexpected address. | |
200 | +* The I2C driver usually detects devices, but your device is not detected, | |
201 | + either because the detection routine is too strict, or because your | |
202 | + device is not officially supported yet but you know it is compatible. | |
203 | +* You are developing a driver on a test board, where you soldered the I2C | |
204 | + device yourself. | |
205 | + | |
206 | +This interface is a replacement for the force_* module parameters some I2C | |
207 | +drivers implement. Being implemented in i2c-core rather than in each | |
208 | +device driver individually, it is much more efficient, and also has the | |
209 | +advantage that you do not have to reload the driver to change a setting. | |
210 | +You can also instantiate the device before the driver is loaded or even | |
211 | +available, and you don't need to know what driver the device needs. |
drivers/i2c/i2c-core.c
... | ... | @@ -38,11 +38,12 @@ |
38 | 38 | #include "i2c-core.h" |
39 | 39 | |
40 | 40 | |
41 | -/* core_lock protects i2c_adapter_idr, and guarantees | |
41 | +/* core_lock protects i2c_adapter_idr, userspace_devices, and guarantees | |
42 | 42 | that device detection, deletion of detected devices, and attach_adapter |
43 | 43 | and detach_adapter calls are serialized */ |
44 | 44 | static DEFINE_MUTEX(core_lock); |
45 | 45 | static DEFINE_IDR(i2c_adapter_idr); |
46 | +static LIST_HEAD(userspace_devices); | |
46 | 47 | |
47 | 48 | static int i2c_check_addr(struct i2c_adapter *adapter, int addr); |
48 | 49 | static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); |
49 | 50 | |
... | ... | @@ -373,8 +374,128 @@ |
373 | 374 | return sprintf(buf, "%s\n", adap->name); |
374 | 375 | } |
375 | 376 | |
377 | +/* | |
378 | + * Let users instantiate I2C devices through sysfs. This can be used when | |
379 | + * platform initialization code doesn't contain the proper data for | |
380 | + * whatever reason. Also useful for drivers that do device detection and | |
381 | + * detection fails, either because the device uses an unexpected address, | |
382 | + * or this is a compatible device with different ID register values. | |
383 | + * | |
384 | + * Parameter checking may look overzealous, but we really don't want | |
385 | + * the user to provide incorrect parameters. | |
386 | + */ | |
387 | +static ssize_t | |
388 | +i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, | |
389 | + const char *buf, size_t count) | |
390 | +{ | |
391 | + struct i2c_adapter *adap = to_i2c_adapter(dev); | |
392 | + struct i2c_board_info info; | |
393 | + struct i2c_client *client; | |
394 | + char *blank, end; | |
395 | + int res; | |
396 | + | |
397 | + dev_warn(dev, "The new_device interface is still experimental " | |
398 | + "and may change in a near future\n"); | |
399 | + memset(&info, 0, sizeof(struct i2c_board_info)); | |
400 | + | |
401 | + blank = strchr(buf, ' '); | |
402 | + if (!blank) { | |
403 | + dev_err(dev, "%s: Missing parameters\n", "new_device"); | |
404 | + return -EINVAL; | |
405 | + } | |
406 | + if (blank - buf > I2C_NAME_SIZE - 1) { | |
407 | + dev_err(dev, "%s: Invalid device name\n", "new_device"); | |
408 | + return -EINVAL; | |
409 | + } | |
410 | + memcpy(info.type, buf, blank - buf); | |
411 | + | |
412 | + /* Parse remaining parameters, reject extra parameters */ | |
413 | + res = sscanf(++blank, "%hi%c", &info.addr, &end); | |
414 | + if (res < 1) { | |
415 | + dev_err(dev, "%s: Can't parse I2C address\n", "new_device"); | |
416 | + return -EINVAL; | |
417 | + } | |
418 | + if (res > 1 && end != '\n') { | |
419 | + dev_err(dev, "%s: Extra parameters\n", "new_device"); | |
420 | + return -EINVAL; | |
421 | + } | |
422 | + | |
423 | + if (info.addr < 0x03 || info.addr > 0x77) { | |
424 | + dev_err(dev, "%s: Invalid I2C address 0x%hx\n", "new_device", | |
425 | + info.addr); | |
426 | + return -EINVAL; | |
427 | + } | |
428 | + | |
429 | + client = i2c_new_device(adap, &info); | |
430 | + if (!client) | |
431 | + return -EEXIST; | |
432 | + | |
433 | + /* Keep track of the added device */ | |
434 | + mutex_lock(&core_lock); | |
435 | + list_add_tail(&client->detected, &userspace_devices); | |
436 | + mutex_unlock(&core_lock); | |
437 | + dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", | |
438 | + info.type, info.addr); | |
439 | + | |
440 | + return count; | |
441 | +} | |
442 | + | |
443 | +/* | |
444 | + * And of course let the users delete the devices they instantiated, if | |
445 | + * they got it wrong. This interface can only be used to delete devices | |
446 | + * instantiated by i2c_sysfs_new_device above. This guarantees that we | |
447 | + * don't delete devices to which some kernel code still has references. | |
448 | + * | |
449 | + * Parameter checking may look overzealous, but we really don't want | |
450 | + * the user to delete the wrong device. | |
451 | + */ | |
452 | +static ssize_t | |
453 | +i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, | |
454 | + const char *buf, size_t count) | |
455 | +{ | |
456 | + struct i2c_adapter *adap = to_i2c_adapter(dev); | |
457 | + struct i2c_client *client, *next; | |
458 | + unsigned short addr; | |
459 | + char end; | |
460 | + int res; | |
461 | + | |
462 | + /* Parse parameters, reject extra parameters */ | |
463 | + res = sscanf(buf, "%hi%c", &addr, &end); | |
464 | + if (res < 1) { | |
465 | + dev_err(dev, "%s: Can't parse I2C address\n", "delete_device"); | |
466 | + return -EINVAL; | |
467 | + } | |
468 | + if (res > 1 && end != '\n') { | |
469 | + dev_err(dev, "%s: Extra parameters\n", "delete_device"); | |
470 | + return -EINVAL; | |
471 | + } | |
472 | + | |
473 | + /* Make sure the device was added through sysfs */ | |
474 | + res = -ENOENT; | |
475 | + mutex_lock(&core_lock); | |
476 | + list_for_each_entry_safe(client, next, &userspace_devices, detected) { | |
477 | + if (client->addr == addr && client->adapter == adap) { | |
478 | + dev_info(dev, "%s: Deleting device %s at 0x%02hx\n", | |
479 | + "delete_device", client->name, client->addr); | |
480 | + | |
481 | + list_del(&client->detected); | |
482 | + i2c_unregister_device(client); | |
483 | + res = count; | |
484 | + break; | |
485 | + } | |
486 | + } | |
487 | + mutex_unlock(&core_lock); | |
488 | + | |
489 | + if (res < 0) | |
490 | + dev_err(dev, "%s: Can't find device in list\n", | |
491 | + "delete_device"); | |
492 | + return res; | |
493 | +} | |
494 | + | |
376 | 495 | static struct device_attribute i2c_adapter_attrs[] = { |
377 | 496 | __ATTR(name, S_IRUGO, show_adapter_name, NULL), |
497 | + __ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device), | |
498 | + __ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device), | |
378 | 499 | { }, |
379 | 500 | }; |
380 | 501 |
include/linux/i2c.h
... | ... | @@ -178,7 +178,8 @@ |
178 | 178 | * @driver: device's driver, hence pointer to access routines |
179 | 179 | * @dev: Driver model device node for the slave. |
180 | 180 | * @irq: indicates the IRQ generated by this device (if any) |
181 | - * @detected: member of an i2c_driver.clients list | |
181 | + * @detected: member of an i2c_driver.clients list or i2c-core's | |
182 | + * userspace_devices list | |
182 | 183 | * |
183 | 184 | * An i2c_client identifies a single device (i.e. chip) connected to an |
184 | 185 | * i2c bus. The behaviour exposed to Linux is defined by the driver |