X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fi2c%2Fi2c-core.c;h=10be7b5fbe97e185d141a23881ea3efd0564a6c7;hb=82e22d77bfb2523284fdf5c484c1fa5269a5d27e;hp=80ae12048e858a4bd80bfd66deaddf7d7351ef49;hpb=a10f9e7caf8d3028d8fb1d4c3d590492cde3df3e;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 80ae120..10be7b5 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -29,21 +29,25 @@ #include #include #include -#include #include #include #include #include +#include #include #include "i2c-core.h" +/* core_lock protects i2c_adapter_idr, userspace_devices, and guarantees + that device detection, deletion of detected devices, and attach_adapter + and detach_adapter calls are serialized */ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); +static LIST_HEAD(userspace_devices); -#define is_newstyle_driver(d) ((d)->probe || (d)->remove || (d)->detect) - +static struct device_type i2c_client_type; +static int i2c_check_addr(struct i2c_adapter *adapter, int addr); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); /* ------------------------------------------------------------------------- */ @@ -61,15 +65,13 @@ static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, static int i2c_device_match(struct device *dev, struct device_driver *drv) { - struct i2c_client *client = to_i2c_client(dev); - struct i2c_driver *driver = to_i2c_driver(drv); + struct i2c_client *client = i2c_verify_client(dev); + struct i2c_driver *driver; - /* make legacy i2c drivers bypass driver model probing entirely; - * such drivers scan each i2c adapter/bus themselves. - */ - if (!is_newstyle_driver(driver)) + if (!client) return 0; + driver = to_i2c_driver(drv); /* match on an id table if there is one */ if (driver->id_table) return i2c_match_id(driver->id_table, client) != NULL; @@ -84,10 +86,6 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) { struct i2c_client *client = to_i2c_client(dev); - /* by definition, legacy drivers can't hotplug */ - if (dev->driver) - return 0; - if (add_uevent_var(env, "MODALIAS=%s%s", I2C_MODULE_PREFIX, client->name)) return -ENOMEM; @@ -101,10 +99,14 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) static int i2c_device_probe(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct i2c_driver *driver = to_i2c_driver(dev->driver); + struct i2c_client *client = i2c_verify_client(dev); + struct i2c_driver *driver; int status; + if (!client) + return 0; + + driver = to_i2c_driver(dev->driver); if (!driver->probe || !driver->id_table) return -ENODEV; client->driver = driver; @@ -121,11 +123,11 @@ static int i2c_device_probe(struct device *dev) static int i2c_device_remove(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); + struct i2c_client *client = i2c_verify_client(dev); struct i2c_driver *driver; int status; - if (!dev->driver) + if (!client || !dev->driver) return 0; driver = to_i2c_driver(dev->driver); @@ -143,43 +145,69 @@ static int i2c_device_remove(struct device *dev) static void i2c_device_shutdown(struct device *dev) { + struct i2c_client *client = i2c_verify_client(dev); struct i2c_driver *driver; - if (!dev->driver) + if (!client || !dev->driver) return; driver = to_i2c_driver(dev->driver); if (driver->shutdown) - driver->shutdown(to_i2c_client(dev)); + driver->shutdown(client); } -static int i2c_device_suspend(struct device * dev, pm_message_t mesg) +#ifdef CONFIG_SUSPEND +static int i2c_device_pm_suspend(struct device *dev) { - struct i2c_driver *driver; + const struct dev_pm_ops *pm; if (!dev->driver) return 0; - driver = to_i2c_driver(dev->driver); - if (!driver->suspend) + pm = dev->driver->pm; + if (!pm || !pm->suspend) return 0; - return driver->suspend(to_i2c_client(dev), mesg); + return pm->suspend(dev); } -static int i2c_device_resume(struct device * dev) +static int i2c_device_pm_resume(struct device *dev) { - struct i2c_driver *driver; + const struct dev_pm_ops *pm; if (!dev->driver) return 0; + pm = dev->driver->pm; + if (!pm || !pm->resume) + return 0; + return pm->resume(dev); +} +#else +#define i2c_device_pm_suspend NULL +#define i2c_device_pm_resume NULL +#endif + +static int i2c_device_suspend(struct device *dev, pm_message_t mesg) +{ + struct i2c_client *client = i2c_verify_client(dev); + struct i2c_driver *driver; + + if (!client || !dev->driver) + return 0; driver = to_i2c_driver(dev->driver); - if (!driver->resume) + if (!driver->suspend) return 0; - return driver->resume(to_i2c_client(dev)); + return driver->suspend(client, mesg); } -static void i2c_client_release(struct device *dev) +static int i2c_device_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - complete(&client->released); + struct i2c_client *client = i2c_verify_client(dev); + struct i2c_driver *driver; + + if (!client || !dev->driver) + return 0; + driver = to_i2c_driver(dev->driver); + if (!driver->resume) + return 0; + return driver->resume(client); } static void i2c_client_dev_release(struct device *dev) @@ -187,38 +215,62 @@ static void i2c_client_dev_release(struct device *dev) kfree(to_i2c_client(dev)); } -static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t +show_name(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - return sprintf(buf, "%s\n", client->name); + return sprintf(buf, "%s\n", dev->type == &i2c_client_type ? + to_i2c_client(dev)->name : to_i2c_adapter(dev)->name); } -static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t +show_modalias(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name); } -static struct device_attribute i2c_dev_attrs[] = { - __ATTR(name, S_IRUGO, show_client_name, NULL), +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); + +static struct attribute *i2c_dev_attrs[] = { + &dev_attr_name.attr, /* modalias helps coldplug: modprobe $(cat .../modalias) */ - __ATTR(modalias, S_IRUGO, show_modalias, NULL), - { }, + &dev_attr_modalias.attr, + NULL +}; + +static struct attribute_group i2c_dev_attr_group = { + .attrs = i2c_dev_attrs, +}; + +static const struct attribute_group *i2c_dev_attr_groups[] = { + &i2c_dev_attr_group, + NULL +}; + +static const struct dev_pm_ops i2c_device_pm_ops = { + .suspend = i2c_device_pm_suspend, + .resume = i2c_device_pm_resume, }; struct bus_type i2c_bus_type = { .name = "i2c", - .dev_attrs = i2c_dev_attrs, .match = i2c_device_match, - .uevent = i2c_device_uevent, .probe = i2c_device_probe, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown, .suspend = i2c_device_suspend, .resume = i2c_device_resume, + .pm = &i2c_device_pm_ops, }; EXPORT_SYMBOL_GPL(i2c_bus_type); +static struct device_type i2c_client_type = { + .groups = i2c_dev_attr_groups, + .uevent = i2c_device_uevent, + .release = i2c_client_dev_release, +}; + /** * i2c_verify_client - return parameter as i2c_client, or NULL @@ -231,7 +283,7 @@ EXPORT_SYMBOL_GPL(i2c_bus_type); */ struct i2c_client *i2c_verify_client(struct device *dev) { - return (dev->bus == &i2c_bus_type) + return (dev->type == &i2c_client_type) ? to_i2c_client(dev) : NULL; } @@ -239,15 +291,17 @@ EXPORT_SYMBOL(i2c_verify_client); /** - * i2c_new_device - instantiate an i2c device for use with a new style driver + * i2c_new_device - instantiate an i2c device * @adap: the adapter managing the device * @info: describes one I2C device; bus_num is ignored * Context: can sleep * - * Create a device to work with a new style i2c driver, where binding is - * handled through driver model probe()/remove() methods. This call is not - * appropriate for use by mainboad initialization logic, which usually runs - * during an arch_initcall() long before any i2c_adapter could exist. + * Create an i2c device. Binding is handled through driver model + * probe()/remove() methods. A driver may be bound to this device when we + * return from this function, or any later moment (e.g. maybe hotplugging will + * load the driver module). This call is not appropriate for use by mainboard + * initialization logic, which usually runs during an arch_initcall() long + * before any i2c_adapter could exist. * * This returns the new i2c client, which may be saved for later use with * i2c_unregister_device(); or NULL to indicate an error. @@ -266,23 +320,40 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->dev.platform_data = info->platform_data; + if (info->archdata) + client->dev.archdata = *info->archdata; + client->flags = info->flags; client->addr = info->addr; client->irq = info->irq; strlcpy(client->name, info->type, sizeof(client->name)); - /* a new style driver may be bound to this device when we - * return from this function, or any later moment (e.g. maybe - * hotplugging will load the driver module). and the device - * refcount model is the standard driver model one. - */ - status = i2c_attach_client(client); - if (status < 0) { - kfree(client); - client = NULL; - } + /* Check for address business */ + status = i2c_check_addr(adap, client->addr); + if (status) + goto out_err; + + client->dev.parent = &client->adapter->dev; + client->dev.bus = &i2c_bus_type; + client->dev.type = &i2c_client_type; + + dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), + client->addr); + status = device_register(&client->dev); + if (status) + goto out_err; + + dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n", + client->name, dev_name(&client->dev)); + return client; + +out_err: + dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x " + "(%d)\n", client->name, client->addr, status); + kfree(client); + return NULL; } EXPORT_SYMBOL_GPL(i2c_new_device); @@ -294,28 +365,6 @@ EXPORT_SYMBOL_GPL(i2c_new_device); */ void i2c_unregister_device(struct i2c_client *client) { - struct i2c_adapter *adapter = client->adapter; - struct i2c_driver *driver = client->driver; - - if (driver && !is_newstyle_driver(driver)) { - dev_err(&client->dev, "can't unregister devices " - "with legacy drivers\n"); - WARN_ON(1); - return; - } - - if (adapter->client_unregister) { - if (adapter->client_unregister(client)) { - dev_warn(&client->dev, - "client_unregister [%s] failed\n", - client->name); - } - } - - mutex_lock(&adapter->clist_lock); - list_del(&client->list); - mutex_unlock(&adapter->clist_lock); - device_unregister(&client->dev); } EXPORT_SYMBOL_GPL(i2c_unregister_device); @@ -362,8 +411,7 @@ static struct i2c_driver dummy_driver = { * This returns the new i2c client, which should be saved for later use with * i2c_unregister_device(); or NULL to indicate an error. */ -struct i2c_client * -i2c_new_dummy(struct i2c_adapter *adapter, u16 address) +struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address) { struct i2c_board_info info = { I2C_BOARD_INFO("dummy", address), @@ -383,45 +431,171 @@ static void i2c_adapter_dev_release(struct device *dev) complete(&adap->dev_released); } +/* + * Let users instantiate I2C devices through sysfs. This can be used when + * platform initialization code doesn't contain the proper data for + * whatever reason. Also useful for drivers that do device detection and + * detection fails, either because the device uses an unexpected address, + * or this is a compatible device with different ID register values. + * + * Parameter checking may look overzealous, but we really don't want + * the user to provide incorrect parameters. + */ +static ssize_t +i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_adapter *adap = to_i2c_adapter(dev); + struct i2c_board_info info; + struct i2c_client *client; + char *blank, end; + int res; + + dev_warn(dev, "The new_device interface is still experimental " + "and may change in a near future\n"); + memset(&info, 0, sizeof(struct i2c_board_info)); + + blank = strchr(buf, ' '); + if (!blank) { + dev_err(dev, "%s: Missing parameters\n", "new_device"); + return -EINVAL; + } + if (blank - buf > I2C_NAME_SIZE - 1) { + dev_err(dev, "%s: Invalid device name\n", "new_device"); + return -EINVAL; + } + memcpy(info.type, buf, blank - buf); + + /* Parse remaining parameters, reject extra parameters */ + res = sscanf(++blank, "%hi%c", &info.addr, &end); + if (res < 1) { + dev_err(dev, "%s: Can't parse I2C address\n", "new_device"); + return -EINVAL; + } + if (res > 1 && end != '\n') { + dev_err(dev, "%s: Extra parameters\n", "new_device"); + return -EINVAL; + } + + if (info.addr < 0x03 || info.addr > 0x77) { + dev_err(dev, "%s: Invalid I2C address 0x%hx\n", "new_device", + info.addr); + return -EINVAL; + } + + client = i2c_new_device(adap, &info); + if (!client) + return -EEXIST; + + /* Keep track of the added device */ + mutex_lock(&core_lock); + list_add_tail(&client->detected, &userspace_devices); + mutex_unlock(&core_lock); + dev_info(dev, "%s: Instantiated device %s at 0x%02hx\n", "new_device", + info.type, info.addr); + + return count; +} + +/* + * And of course let the users delete the devices they instantiated, if + * they got it wrong. This interface can only be used to delete devices + * instantiated by i2c_sysfs_new_device above. This guarantees that we + * don't delete devices to which some kernel code still has references. + * + * Parameter checking may look overzealous, but we really don't want + * the user to delete the wrong device. + */ static ssize_t -show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf) +i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_adapter *adap = to_i2c_adapter(dev); - return sprintf(buf, "%s\n", adap->name); + struct i2c_client *client, *next; + unsigned short addr; + char end; + int res; + + /* Parse parameters, reject extra parameters */ + res = sscanf(buf, "%hi%c", &addr, &end); + if (res < 1) { + dev_err(dev, "%s: Can't parse I2C address\n", "delete_device"); + return -EINVAL; + } + if (res > 1 && end != '\n') { + dev_err(dev, "%s: Extra parameters\n", "delete_device"); + return -EINVAL; + } + + /* Make sure the device was added through sysfs */ + res = -ENOENT; + mutex_lock(&core_lock); + list_for_each_entry_safe(client, next, &userspace_devices, detected) { + if (client->addr == addr && client->adapter == adap) { + dev_info(dev, "%s: Deleting device %s at 0x%02hx\n", + "delete_device", client->name, client->addr); + + list_del(&client->detected); + i2c_unregister_device(client); + res = count; + break; + } + } + mutex_unlock(&core_lock); + + if (res < 0) + dev_err(dev, "%s: Can't find device in list\n", + "delete_device"); + return res; } -static struct device_attribute i2c_adapter_attrs[] = { - __ATTR(name, S_IRUGO, show_adapter_name, NULL), - { }, +static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device); +static DEVICE_ATTR(delete_device, S_IWUSR, NULL, i2c_sysfs_delete_device); + +static struct attribute *i2c_adapter_attrs[] = { + &dev_attr_name.attr, + &dev_attr_new_device.attr, + &dev_attr_delete_device.attr, + NULL }; -static struct class i2c_adapter_class = { - .owner = THIS_MODULE, - .name = "i2c-adapter", - .dev_attrs = i2c_adapter_attrs, +static struct attribute_group i2c_adapter_attr_group = { + .attrs = i2c_adapter_attrs, }; +static const struct attribute_group *i2c_adapter_attr_groups[] = { + &i2c_adapter_attr_group, + NULL +}; + +static struct device_type i2c_adapter_type = { + .groups = i2c_adapter_attr_groups, + .release = i2c_adapter_dev_release, +}; + +#ifdef CONFIG_I2C_COMPAT +static struct class_compat *i2c_adapter_compat_class; +#endif + static void i2c_scan_static_board_info(struct i2c_adapter *adapter) { struct i2c_devinfo *devinfo; - mutex_lock(&__i2c_board_lock); + down_read(&__i2c_board_lock); list_for_each_entry(devinfo, &__i2c_board_list, list) { if (devinfo->busnum == adapter->nr && !i2c_new_device(adapter, &devinfo->board_info)) - printk(KERN_ERR "i2c-core: can't create i2c%d-%04x\n", - i2c_adapter_id(adapter), + dev_err(&adapter->dev, + "Can't create device at 0x%02x\n", devinfo->board_info.addr); } - mutex_unlock(&__i2c_board_lock); + up_read(&__i2c_board_lock); } -static int i2c_do_add_adapter(struct device_driver *d, void *data) +static int i2c_do_add_adapter(struct i2c_driver *driver, + struct i2c_adapter *adap) { - struct i2c_driver *driver = to_i2c_driver(d); - struct i2c_adapter *adap = data; - /* Detect supported devices on that bus, and instantiate them */ i2c_detect(adap, driver); @@ -433,53 +607,61 @@ static int i2c_do_add_adapter(struct device_driver *d, void *data) return 0; } +static int __process_new_adapter(struct device_driver *d, void *data) +{ + return i2c_do_add_adapter(to_i2c_driver(d), data); +} + static int i2c_register_adapter(struct i2c_adapter *adap) { int res = 0, dummy; /* Can't register until after driver model init */ - if (unlikely(WARN_ON(!i2c_bus_type.p))) - return -EAGAIN; + if (unlikely(WARN_ON(!i2c_bus_type.p))) { + res = -EAGAIN; + goto out_list; + } - mutex_init(&adap->bus_lock); - mutex_init(&adap->clist_lock); - INIT_LIST_HEAD(&adap->clients); + rt_mutex_init(&adap->bus_lock); - mutex_lock(&core_lock); + /* Set default timeout to 1 second if not already set */ + if (adap->timeout == 0) + adap->timeout = HZ; - /* Add the adapter to the driver core. - * If the parent pointer is not set up, - * we add this adapter to the host bus. - */ - if (adap->dev.parent == NULL) { - adap->dev.parent = &platform_bus; - pr_debug("I2C adapter driver [%s] forgot to specify " - "physical device\n", adap->name); - } - sprintf(adap->dev.bus_id, "i2c-%d", adap->nr); - adap->dev.release = &i2c_adapter_dev_release; - adap->dev.class = &i2c_adapter_class; + dev_set_name(&adap->dev, "i2c-%d", adap->nr); + adap->dev.bus = &i2c_bus_type; + adap->dev.type = &i2c_adapter_type; res = device_register(&adap->dev); if (res) goto out_list; dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); - /* create pre-declared device nodes for new-style drivers */ +#ifdef CONFIG_I2C_COMPAT + res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev, + adap->dev.parent); + if (res) + dev_warn(&adap->dev, + "Failed to create compatibility class link\n"); +#endif + + /* create pre-declared device nodes */ if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); /* Notify drivers */ + mutex_lock(&core_lock); dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, - i2c_do_add_adapter); - -out_unlock: + __process_new_adapter); mutex_unlock(&core_lock); - return res; + + return 0; out_list: + mutex_lock(&core_lock); idr_remove(&i2c_adapter_idr, adap->nr); - goto out_unlock; + mutex_unlock(&core_lock); + return res; } /** @@ -571,14 +753,14 @@ retry: } EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter); -static int i2c_do_del_adapter(struct device_driver *d, void *data) +static int i2c_do_del_adapter(struct i2c_driver *driver, + struct i2c_adapter *adapter) { - struct i2c_driver *driver = to_i2c_driver(d); - struct i2c_adapter *adapter = data; struct i2c_client *client, *_n; int res; - /* Remove the devices we created ourselves */ + /* Remove the devices we created ourselves as the result of hardware + * probing (using a driver's detect method) */ list_for_each_entry_safe(client, _n, &driver->clients, detected) { if (client->adapter == adapter) { dev_dbg(&adapter->dev, "Removing %s at 0x%x\n", @@ -597,6 +779,19 @@ static int i2c_do_del_adapter(struct device_driver *d, void *data) return res; } +static int __unregister_client(struct device *dev, void *dummy) +{ + struct i2c_client *client = i2c_verify_client(dev); + if (client) + i2c_unregister_device(client); + return 0; +} + +static int __process_removed_adapter(struct device_driver *d, void *data) +{ + return i2c_do_del_adapter(to_i2c_driver(d), data); +} + /** * i2c_del_adapter - unregister I2C adapter * @adap: the adapter being unregistered @@ -607,47 +802,50 @@ static int i2c_do_del_adapter(struct device_driver *d, void *data) */ int i2c_del_adapter(struct i2c_adapter *adap) { - struct i2c_client *client, *_n; int res = 0; - - mutex_lock(&core_lock); + struct i2c_adapter *found; + struct i2c_client *client, *next; /* First make sure that this adapter was ever added */ - if (idr_find(&i2c_adapter_idr, adap->nr) != adap) { + mutex_lock(&core_lock); + found = idr_find(&i2c_adapter_idr, adap->nr); + mutex_unlock(&core_lock); + if (found != adap) { pr_debug("i2c-core: attempting to delete unregistered " "adapter [%s]\n", adap->name); - res = -EINVAL; - goto out_unlock; + return -EINVAL; } /* Tell drivers about this removal */ + mutex_lock(&core_lock); res = bus_for_each_drv(&i2c_bus_type, NULL, adap, - i2c_do_del_adapter); + __process_removed_adapter); + mutex_unlock(&core_lock); if (res) - goto out_unlock; - - /* detach any active clients. This must be done first, because - * it can fail; in which case we give up. */ - list_for_each_entry_safe(client, _n, &adap->clients, list) { - struct i2c_driver *driver; - - driver = client->driver; + return res; - /* new style, follow standard driver model */ - if (!driver || is_newstyle_driver(driver)) { + /* Remove devices instantiated from sysfs */ + list_for_each_entry_safe(client, next, &userspace_devices, detected) { + if (client->adapter == adap) { + dev_dbg(&adap->dev, "Removing %s at 0x%x\n", + client->name, client->addr); + list_del(&client->detected); i2c_unregister_device(client); - continue; - } - - /* legacy drivers create and remove clients themselves */ - if ((res = driver->detach_client(client))) { - dev_err(&adap->dev, "detach_client failed for client " - "[%s] at address 0x%02x\n", client->name, - client->addr); - goto out_unlock; } } + /* Detach any active clients. This can't fail, thus we do not + checking the returned value. */ + res = device_for_each_child(&adap->dev, NULL, __unregister_client); + +#ifdef CONFIG_I2C_COMPAT + class_compat_remove_link(i2c_adapter_compat_class, &adap->dev, + adap->dev.parent); +#endif + + /* device name is gone after device_unregister */ + dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); + /* clean up the sysfs representation */ init_completion(&adap->dev_released); device_unregister(&adap->dev); @@ -656,44 +854,31 @@ int i2c_del_adapter(struct i2c_adapter *adap) wait_for_completion(&adap->dev_released); /* free bus id */ + mutex_lock(&core_lock); idr_remove(&i2c_adapter_idr, adap->nr); - - dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); + mutex_unlock(&core_lock); /* Clear the device structure in case this adapter is ever going to be added again */ memset(&adap->dev, 0, sizeof(adap->dev)); - out_unlock: - mutex_unlock(&core_lock); - return res; + return 0; } EXPORT_SYMBOL(i2c_del_adapter); /* ------------------------------------------------------------------------- */ -static int __attach_adapter(struct device *dev, void *data) +static int __process_new_driver(struct device *dev, void *data) { - struct i2c_adapter *adapter = to_i2c_adapter(dev); - struct i2c_driver *driver = data; - - i2c_detect(adapter, driver); - - /* Legacy drivers scan i2c busses directly */ - if (driver->attach_adapter) - driver->attach_adapter(adapter); - - return 0; + if (dev->type != &i2c_adapter_type) + return 0; + return i2c_do_add_adapter(data, to_i2c_adapter(dev)); } /* * 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 - * are two models for binding the driver to its device: "new style" drivers - * follow the standard Linux driver model and just respond to probe() calls - * issued if the driver core sees they match(); "legacy" drivers create device - * nodes themselves. + * i2c slave chips, on a bus instance associated with some i2c_adapter. */ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) @@ -704,84 +889,34 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) if (unlikely(WARN_ON(!i2c_bus_type.p))) return -EAGAIN; - /* new style driver methods can't mix with legacy ones */ - if (is_newstyle_driver(driver)) { - if (driver->attach_adapter || driver->detach_adapter - || driver->detach_client) { - printk(KERN_WARNING - "i2c-core: driver [%s] is confused\n", - driver->driver.name); - return -EINVAL; - } - } - /* add the driver to the list of i2c drivers in the driver core */ driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type; - /* for new style drivers, when registration returns the driver core + /* When registration returns, the driver core * will have called probe() for all matching-but-unbound devices. */ res = driver_register(&driver->driver); if (res) return res; - mutex_lock(&core_lock); - pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); INIT_LIST_HEAD(&driver->clients); /* Walk the adapters that are already present */ - class_for_each_device(&i2c_adapter_class, NULL, driver, - __attach_adapter); - + mutex_lock(&core_lock); + bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_new_driver); mutex_unlock(&core_lock); + return 0; } EXPORT_SYMBOL(i2c_register_driver); -static int __detach_adapter(struct device *dev, void *data) +static int __process_removed_driver(struct device *dev, void *data) { - struct i2c_adapter *adapter = to_i2c_adapter(dev); - struct i2c_driver *driver = data; - struct i2c_client *client, *_n; - - list_for_each_entry_safe(client, _n, &driver->clients, detected) { - dev_dbg(&adapter->dev, "Removing %s at 0x%x\n", - client->name, client->addr); - list_del(&client->detected); - i2c_unregister_device(client); - } - - if (is_newstyle_driver(driver)) + if (dev->type != &i2c_adapter_type) return 0; - - /* 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 i2c_client *client, *_n; - - list_for_each_entry_safe(client, _n, &adapter->clients, 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); - } - } - - return 0; + return i2c_do_del_adapter(data, to_i2c_adapter(dev)); } /** @@ -792,14 +927,11 @@ static int __detach_adapter(struct device *dev, void *data) void i2c_del_driver(struct i2c_driver *driver) { mutex_lock(&core_lock); - - class_for_each_device(&i2c_adapter_class, NULL, driver, - __detach_adapter); + bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_removed_driver); + mutex_unlock(&core_lock); driver_unregister(&driver->driver); pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); - - mutex_unlock(&core_lock); } EXPORT_SYMBOL(i2c_del_driver); @@ -820,86 +952,6 @@ static int i2c_check_addr(struct i2c_adapter *adapter, int addr) return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr); } -int i2c_attach_client(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - int res; - - /* Check for address business */ - res = i2c_check_addr(adapter, client->addr); - if (res) - return res; - - client->dev.parent = &client->adapter->dev; - client->dev.bus = &i2c_bus_type; - - if (client->driver) - client->dev.driver = &client->driver->driver; - - if (client->driver && !is_newstyle_driver(client->driver)) { - client->dev.release = i2c_client_release; - client->dev.uevent_suppress = 1; - } else - client->dev.release = i2c_client_dev_release; - - snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id), - "%d-%04x", i2c_adapter_id(adapter), client->addr); - res = device_register(&client->dev); - if (res) - goto out_err; - - mutex_lock(&adapter->clist_lock); - list_add_tail(&client->list, &adapter->clients); - mutex_unlock(&adapter->clist_lock); - - dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n", - client->name, client->dev.bus_id); - - if (adapter->client_register) { - if (adapter->client_register(client)) { - dev_dbg(&adapter->dev, "client_register " - "failed for client [%s] at 0x%02x\n", - client->name, client->addr); - } - } - - return 0; - -out_err: - dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " - "(%d)\n", client->name, client->addr, res); - return res; -} -EXPORT_SYMBOL(i2c_attach_client); - -int i2c_detach_client(struct i2c_client *client) -{ - struct i2c_adapter *adapter = client->adapter; - int res = 0; - - if (adapter->client_unregister) { - res = adapter->client_unregister(client); - if (res) { - dev_err(&client->dev, - "client_unregister [%s] failed, " - "client not detached\n", client->name); - goto out; - } - } - - mutex_lock(&adapter->clist_lock); - list_del(&client->list); - mutex_unlock(&adapter->clist_lock); - - init_completion(&client->released); - device_unregister(&client->dev); - wait_for_completion(&client->released); - - out: - return res; -} -EXPORT_SYMBOL(i2c_detach_client); - /** * i2c_use_client - increments the reference count of the i2c client structure * @client: the client being referenced @@ -964,17 +1016,23 @@ static int __init i2c_init(void) retval = bus_register(&i2c_bus_type); if (retval) return retval; - retval = class_register(&i2c_adapter_class); - if (retval) +#ifdef CONFIG_I2C_COMPAT + i2c_adapter_compat_class = class_compat_register("i2c-adapter"); + if (!i2c_adapter_compat_class) { + retval = -ENOMEM; goto bus_err; + } +#endif retval = i2c_add_driver(&dummy_driver); if (retval) goto class_err; return 0; class_err: - class_unregister(&i2c_adapter_class); +#ifdef CONFIG_I2C_COMPAT + class_compat_unregister(i2c_adapter_compat_class); bus_err: +#endif bus_unregister(&i2c_bus_type); return retval; } @@ -982,7 +1040,9 @@ bus_err: static void __exit i2c_exit(void) { i2c_del_driver(&dummy_driver); - class_unregister(&i2c_adapter_class); +#ifdef CONFIG_I2C_COMPAT + class_compat_unregister(i2c_adapter_compat_class); +#endif bus_unregister(&i2c_bus_type); } @@ -1009,9 +1069,10 @@ module_exit(i2c_exit); * Note that there is no requirement that each message be sent to * the same slave address, although that is the most common model. */ -int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) +int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { - int ret; + unsigned long orig_jiffies; + int ret, try; /* REVISIT the fault reporting model here is weak: * @@ -1041,16 +1102,24 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) #endif if (in_atomic() || irqs_disabled()) { - ret = mutex_trylock(&adap->bus_lock); + ret = rt_mutex_trylock(&adap->bus_lock); if (!ret) /* I2C activity is ongoing. */ return -EAGAIN; } else { - mutex_lock_nested(&adap->bus_lock, adap->level); + rt_mutex_lock(&adap->bus_lock); } - ret = adap->algo->master_xfer(adap,msgs,num); - mutex_unlock(&adap->bus_lock); + /* Retry automatically on arbitration loss */ + orig_jiffies = jiffies; + for (ret = 0, try = 0; try <= adap->retries; try++) { + ret = adap->algo->master_xfer(adap, msgs, num); + if (ret != -EAGAIN) + break; + if (time_after(jiffies, orig_jiffies + adap->timeout)) + break; + } + rt_mutex_unlock(&adap->bus_lock); return ret; } else { @@ -1120,145 +1189,8 @@ EXPORT_SYMBOL(i2c_master_recv); * Will not work for 10-bit addresses! * ---------------------------------------------------- */ -static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind, - int (*found_proc) (struct i2c_adapter *, int, int)) -{ - int err; - - /* Make sure the address is valid */ - if (addr < 0x03 || addr > 0x77) { - dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n", - addr); - return -EINVAL; - } - - /* Skip if already in use */ - if (i2c_check_addr(adapter, addr)) - return 0; - - /* Make sure there is something at this address, unless forced */ - if (kind < 0) { - if (i2c_smbus_xfer(adapter, addr, 0, 0, 0, - I2C_SMBUS_QUICK, NULL) < 0) - return 0; - - /* prevent 24RF08 corruption */ - if ((addr & ~0x0f) == 0x50) - i2c_smbus_xfer(adapter, addr, 0, 0, 0, - I2C_SMBUS_QUICK, NULL); - } - - /* Finally call the custom detection function */ - err = found_proc(adapter, addr, kind); - /* -ENODEV can be returned if there is a chip at the given address - but it isn't supported by this chip driver. We catch it here as - this isn't an error. */ - if (err == -ENODEV) - err = 0; - - if (err) - dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)\n", - addr, err); - return err; -} - -int i2c_probe(struct i2c_adapter *adapter, - const struct i2c_client_address_data *address_data, - int (*found_proc) (struct i2c_adapter *, int, int)) -{ - int i, err; - int adap_id = i2c_adapter_id(adapter); - - /* Force entries are done first, and are not affected by ignore - entries */ - if (address_data->forces) { - const unsigned short * const *forces = address_data->forces; - int kind; - - for (kind = 0; forces[kind]; kind++) { - for (i = 0; forces[kind][i] != I2C_CLIENT_END; - i += 2) { - if (forces[kind][i] == adap_id - || forces[kind][i] == ANY_I2C_BUS) { - dev_dbg(&adapter->dev, "found force " - "parameter for adapter %d, " - "addr 0x%02x, kind %d\n", - adap_id, forces[kind][i + 1], - kind); - err = i2c_probe_address(adapter, - forces[kind][i + 1], - kind, found_proc); - if (err) - return err; - } - } - } - } - - /* Stop here if we can't use SMBUS_QUICK */ - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) { - if (address_data->probe[0] == I2C_CLIENT_END - && address_data->normal_i2c[0] == I2C_CLIENT_END) - return 0; - - dev_dbg(&adapter->dev, "SMBus Quick command not supported, " - "can't probe for chips\n"); - return -EOPNOTSUPP; - } - - /* Probe entries are done second, and are not affected by ignore - entries either */ - for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) { - if (address_data->probe[i] == adap_id - || address_data->probe[i] == ANY_I2C_BUS) { - dev_dbg(&adapter->dev, "found probe parameter for " - "adapter %d, addr 0x%02x\n", adap_id, - address_data->probe[i + 1]); - err = i2c_probe_address(adapter, - address_data->probe[i + 1], - -1, found_proc); - if (err) - return err; - } - } - /* Normal entries are done last, unless shadowed by an ignore entry */ - for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) { - int j, ignore; - - ignore = 0; - for (j = 0; address_data->ignore[j] != I2C_CLIENT_END; - j += 2) { - if ((address_data->ignore[j] == adap_id || - address_data->ignore[j] == ANY_I2C_BUS) - && address_data->ignore[j + 1] - == address_data->normal_i2c[i]) { - dev_dbg(&adapter->dev, "found ignore " - "parameter for adapter %d, " - "addr 0x%02x\n", adap_id, - address_data->ignore[j + 1]); - ignore = 1; - break; - } - } - if (ignore) - continue; - - dev_dbg(&adapter->dev, "found normal entry for adapter %d, " - "addr 0x%02x\n", adap_id, - address_data->normal_i2c[i]); - err = i2c_probe_address(adapter, address_data->normal_i2c[i], - -1, found_proc); - if (err) - return err; - } - - return 0; -} -EXPORT_SYMBOL(i2c_probe); - -/* Separate detection function for new-style drivers */ -static int i2c_detect_address(struct i2c_client *temp_client, int kind, +static int i2c_detect_address(struct i2c_client *temp_client, struct i2c_driver *driver) { struct i2c_board_info info; @@ -1277,22 +1209,18 @@ static int i2c_detect_address(struct i2c_client *temp_client, int kind, if (i2c_check_addr(adapter, addr)) return 0; - /* Make sure there is something at this address, unless forced */ - if (kind < 0) { - if (i2c_smbus_xfer(adapter, addr, 0, 0, 0, - I2C_SMBUS_QUICK, NULL) < 0) - return 0; + /* Make sure there is something at this address */ + if (i2c_smbus_xfer(adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) < 0) + return 0; - /* prevent 24RF08 corruption */ - if ((addr & ~0x0f) == 0x50) - i2c_smbus_xfer(adapter, addr, 0, 0, 0, - I2C_SMBUS_QUICK, NULL); - } + /* Prevent 24RF08 corruption */ + if ((addr & ~0x0f) == 0x50) + i2c_smbus_xfer(adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL); /* Finally call the custom detection function */ memset(&info, 0, sizeof(struct i2c_board_info)); info.addr = addr; - err = driver->detect(temp_client, kind, &info); + err = driver->detect(temp_client, &info); if (err) { /* -ENODEV is returned if the detection fails. We catch it here as this isn't an error. */ @@ -1322,13 +1250,13 @@ static int i2c_detect_address(struct i2c_client *temp_client, int kind, static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) { - const struct i2c_client_address_data *address_data; + const unsigned short *address_list; struct i2c_client *temp_client; int i, err = 0; int adap_id = i2c_adapter_id(adapter); - address_data = driver->address_data; - if (!driver->detect || !address_data) + address_list = driver->address_list; + if (!driver->detect || !address_list) return 0; /* Set up a temporary client to help detect callback */ @@ -1337,40 +1265,13 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) return -ENOMEM; temp_client->adapter = adapter; - /* Force entries are done first, and are not affected by ignore - entries */ - if (address_data->forces) { - const unsigned short * const *forces = address_data->forces; - int kind; - - for (kind = 0; forces[kind]; kind++) { - for (i = 0; forces[kind][i] != I2C_CLIENT_END; - i += 2) { - if (forces[kind][i] == adap_id - || forces[kind][i] == ANY_I2C_BUS) { - dev_dbg(&adapter->dev, "found force " - "parameter for adapter %d, " - "addr 0x%02x, kind %d\n", - adap_id, forces[kind][i + 1], - kind); - temp_client->addr = forces[kind][i + 1]; - err = i2c_detect_address(temp_client, - kind, driver); - if (err) - goto exit_free; - } - } - } - } - /* Stop here if the classes do not match */ if (!(adapter->class & driver->class)) goto exit_free; /* Stop here if we can't use SMBUS_QUICK */ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) { - if (address_data->probe[0] == I2C_CLIENT_END - && address_data->normal_i2c[0] == I2C_CLIENT_END) + if (address_list[0] == I2C_CLIENT_END) goto exit_free; dev_warn(&adapter->dev, "SMBus Quick command not supported, " @@ -1379,48 +1280,11 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) goto exit_free; } - /* Probe entries are done second, and are not affected by ignore - entries either */ - for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) { - if (address_data->probe[i] == adap_id - || address_data->probe[i] == ANY_I2C_BUS) { - dev_dbg(&adapter->dev, "found probe parameter for " - "adapter %d, addr 0x%02x\n", adap_id, - address_data->probe[i + 1]); - temp_client->addr = address_data->probe[i + 1]; - err = i2c_detect_address(temp_client, -1, driver); - if (err) - goto exit_free; - } - } - - /* Normal entries are done last, unless shadowed by an ignore entry */ - for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) { - int j, ignore; - - ignore = 0; - for (j = 0; address_data->ignore[j] != I2C_CLIENT_END; - j += 2) { - if ((address_data->ignore[j] == adap_id || - address_data->ignore[j] == ANY_I2C_BUS) - && address_data->ignore[j + 1] - == address_data->normal_i2c[i]) { - dev_dbg(&adapter->dev, "found ignore " - "parameter for adapter %d, " - "addr 0x%02x\n", adap_id, - address_data->ignore[j + 1]); - ignore = 1; - break; - } - } - if (ignore) - continue; - + for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) { dev_dbg(&adapter->dev, "found normal entry for adapter %d, " - "addr 0x%02x\n", adap_id, - address_data->normal_i2c[i]); - temp_client->addr = address_data->normal_i2c[i]; - err = i2c_detect_address(temp_client, -1, driver); + "addr 0x%02x\n", adap_id, address_list[i]); + temp_client->addr = address_list[i]; + err = i2c_detect_address(temp_client, driver); if (err) goto exit_free; } @@ -1498,7 +1362,7 @@ struct i2c_adapter* i2c_get_adapter(int id) struct i2c_adapter *adapter; mutex_lock(&core_lock); - adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id); + adapter = idr_find(&i2c_adapter_idr, id); if (adapter && !try_module_get(adapter->owner)) adapter = NULL; @@ -1516,8 +1380,7 @@ EXPORT_SYMBOL(i2c_put_adapter); /* The SMBus parts */ #define POLY (0x1070U << 3) -static u8 -crc8(u16 data) +static u8 crc8(u16 data) { int i; @@ -1688,6 +1551,28 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value) EXPORT_SYMBOL(i2c_smbus_write_word_data); /** + * i2c_smbus_process_call - SMBus "process call" protocol + * @client: Handle to slave device + * @command: Byte interpreted by slave + * @value: 16-bit "word" being written + * + * This executes the SMBus "process call" protocol, returning negative errno + * else a 16-bit unsigned "word" received from the device. + */ +s32 i2c_smbus_process_call(struct i2c_client *client, u8 command, u16 value) +{ + union i2c_smbus_data data; + int status; + data.word = value; + + status = i2c_smbus_xfer(client->adapter, client->addr, client->flags, + I2C_SMBUS_WRITE, command, + I2C_SMBUS_PROC_CALL, &data); + return (status < 0) ? status : data.word; +} +EXPORT_SYMBOL(i2c_smbus_process_call); + +/** * i2c_smbus_read_block_data - SMBus "block read" protocol * @client: Handle to slave device * @command: Byte interpreted by slave @@ -1806,7 +1691,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, case I2C_SMBUS_QUICK: msg[0].len = 0; /* Special case: The read/write field is used as data */ - msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0; + msg[0].flags = flags | (read_write == I2C_SMBUS_READ ? + I2C_M_RD : 0); num = 1; break; case I2C_SMBUS_BYTE: @@ -1958,19 +1844,32 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, * This executes an SMBus protocol operation, and returns a negative * errno code else zero on success. */ -s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, +s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int protocol, - union i2c_smbus_data * data) + union i2c_smbus_data *data) { + unsigned long orig_jiffies; + int try; s32 res; flags &= I2C_M_TEN | I2C_CLIENT_PEC; if (adapter->algo->smbus_xfer) { - mutex_lock(&adapter->bus_lock); - res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, - command, protocol, data); - mutex_unlock(&adapter->bus_lock); + rt_mutex_lock(&adapter->bus_lock); + + /* Retry automatically on arbitration loss */ + orig_jiffies = jiffies; + for (res = 0, try = 0; try <= adapter->retries; try++) { + res = adapter->algo->smbus_xfer(adapter, addr, flags, + read_write, command, + protocol, data); + if (res != -EAGAIN) + break; + if (time_after(jiffies, + orig_jiffies + adapter->timeout)) + break; + } + rt_mutex_unlock(&adapter->bus_lock); } else res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, command, protocol, data);