diff options
Diffstat (limited to 'drivers/i2c/i2c-core.c')
-rw-r--r-- | drivers/i2c/i2c-core.c | 180 |
1 files changed, 49 insertions, 131 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 8d80fceca6a..4f34823e86b 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -558,11 +558,9 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter) 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); @@ -574,6 +572,11 @@ 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; @@ -584,7 +587,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) goto out_list; } - mutex_init(&adap->bus_lock); + rt_mutex_init(&adap->bus_lock); /* Set default timeout to 1 second if not already set */ if (adap->timeout == 0) @@ -614,7 +617,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) /* Notify drivers */ mutex_lock(&core_lock); dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap, - i2c_do_add_adapter); + __process_new_adapter); mutex_unlock(&core_lock); return 0; @@ -715,10 +718,9 @@ 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; @@ -750,6 +752,11 @@ static int __unregister_client(struct device *dev, void *dummy) 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 @@ -762,6 +769,7 @@ int i2c_del_adapter(struct i2c_adapter *adap) { int res = 0; struct i2c_adapter *found; + struct i2c_client *client, *next; /* First make sure that this adapter was ever added */ mutex_lock(&core_lock); @@ -776,11 +784,21 @@ int i2c_del_adapter(struct i2c_adapter *adap) /* 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) return res; + /* 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); + } + } + /* 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); @@ -815,22 +833,11 @@ 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; - struct i2c_driver *driver = data; - if (dev->type != &i2c_adapter_type) return 0; - adapter = to_i2c_adapter(dev); - - i2c_detect(adapter, driver); - - /* Legacy drivers scan i2c busses directly */ - if (driver->attach_adapter) - driver->attach_adapter(adapter); - - return 0; + return i2c_do_add_adapter(data, to_i2c_adapter(dev)); } /* @@ -862,40 +869,18 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) INIT_LIST_HEAD(&driver->clients); /* Walk the adapters that are already present */ mutex_lock(&core_lock); - bus_for_each_dev(&i2c_bus_type, NULL, driver, __attach_adapter); + 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; - struct i2c_driver *driver = data; - struct i2c_client *client, *_n; - if (dev->type != &i2c_adapter_type) return 0; - adapter = to_i2c_adapter(dev); - - /* 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) { - dev_dbg(&adapter->dev, "Removing %s at 0x%x\n", - client->name, client->addr); - list_del(&client->detected); - i2c_unregister_device(client); - } - - if (driver->detach_adapter) { - if (driver->detach_adapter(adapter)) - dev_err(&adapter->dev, - "detach_adapter failed for driver [%s]\n", - driver->driver.name); - } - - return 0; + return i2c_do_del_adapter(data, to_i2c_adapter(dev)); } /** @@ -906,7 +891,7 @@ static int __detach_adapter(struct device *dev, void *data) void i2c_del_driver(struct i2c_driver *driver) { mutex_lock(&core_lock); - bus_for_each_dev(&i2c_bus_type, NULL, driver, __detach_adapter); + bus_for_each_dev(&i2c_bus_type, NULL, driver, __process_removed_driver); mutex_unlock(&core_lock); driver_unregister(&driver->driver); @@ -1081,12 +1066,12 @@ 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); } /* Retry automatically on arbitration loss */ @@ -1098,7 +1083,7 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (time_after(jiffies, orig_jiffies + adap->timeout)) break; } - mutex_unlock(&adap->bus_lock); + rt_mutex_unlock(&adap->bus_lock); return ret; } else { @@ -1169,7 +1154,7 @@ EXPORT_SYMBOL(i2c_master_recv); * ---------------------------------------------------- */ -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; @@ -1188,22 +1173,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, -1, &info); if (err) { /* -ENODEV is returned if the detection fails. We catch it here as this isn't an error. */ @@ -1248,40 +1229,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_data->normal_i2c[0] == I2C_CLIENT_END) goto exit_free; dev_warn(&adapter->dev, "SMBus Quick command not supported, " @@ -1290,48 +1244,12 @@ 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; - 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); + err = i2c_detect_address(temp_client, driver); if (err) goto exit_free; } @@ -1902,7 +1820,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, flags &= I2C_M_TEN | I2C_CLIENT_PEC; if (adapter->algo->smbus_xfer) { - mutex_lock(&adapter->bus_lock); + rt_mutex_lock(&adapter->bus_lock); /* Retry automatically on arbitration loss */ orig_jiffies = jiffies; @@ -1916,7 +1834,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, orig_jiffies + adapter->timeout)) break; } - mutex_unlock(&adapter->bus_lock); + rt_mutex_unlock(&adapter->bus_lock); } else res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, command, protocol, data); |