X-Git-Url: http://git.cascardo.info/?a=blobdiff_plain;f=drivers%2Fi2c%2Fi2c-core.c;h=da3a02ef4a3187e2c97e1a8bcb795c318544c4d1;hb=fb79e09a74faf39fbeee975e0ead442b7b7f6aac;hp=e584d88ee337f66e158644076f7b9a2b0018177e;hpb=8c57a5e7b2820f349c95b8c8393fec1e0f4070d2;p=cascardo%2Flinux.git diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index e584d88ee337..56e50ca905ba 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -27,6 +27,8 @@ I2C slave support (c) 2014 by Wolfram Sang */ +#define pr_fmt(fmt) "i2c-core: " fmt + #include #include #include @@ -107,12 +109,11 @@ struct acpi_i2c_lookup { acpi_handle device_handle; }; -static int acpi_i2c_find_address(struct acpi_resource *ares, void *data) +static int acpi_i2c_fill_info(struct acpi_resource *ares, void *data) { struct acpi_i2c_lookup *lookup = data; struct i2c_board_info *info = lookup->info; struct acpi_resource_i2c_serialbus *sb; - acpi_handle adapter_handle; acpi_status status; if (info->addr || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) @@ -122,80 +123,102 @@ static int acpi_i2c_find_address(struct acpi_resource *ares, void *data) if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) return 1; - /* - * Extract the ResourceSource and make sure that the handle matches - * with the I2C adapter handle. - */ status = acpi_get_handle(lookup->device_handle, sb->resource_source.string_ptr, - &adapter_handle); - if (ACPI_SUCCESS(status) && adapter_handle == lookup->adapter_handle) { - info->addr = sb->slave_address; - if (sb->access_mode == ACPI_I2C_10BIT_MODE) - info->flags |= I2C_CLIENT_TEN; - } + &lookup->adapter_handle); + if (!ACPI_SUCCESS(status)) + return 1; + + info->addr = sb->slave_address; + if (sb->access_mode == ACPI_I2C_10BIT_MODE) + info->flags |= I2C_CLIENT_TEN; return 1; } -static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, - void *data, void **return_value) +static int acpi_i2c_get_info(struct acpi_device *adev, + struct i2c_board_info *info, + acpi_handle *adapter_handle) { - struct i2c_adapter *adapter = data; struct list_head resource_list; - struct acpi_i2c_lookup lookup; struct resource_entry *entry; - struct i2c_board_info info; - struct acpi_device *adev; + struct acpi_i2c_lookup lookup; int ret; - if (acpi_bus_get_device(handle, &adev)) - return AE_OK; - if (acpi_bus_get_status(adev) || !adev->status.present) - return AE_OK; + if (acpi_bus_get_status(adev) || !adev->status.present || + acpi_device_enumerated(adev)) + return -EINVAL; - memset(&info, 0, sizeof(info)); - info.fwnode = acpi_fwnode_handle(adev); + memset(info, 0, sizeof(*info)); + info->fwnode = acpi_fwnode_handle(adev); memset(&lookup, 0, sizeof(lookup)); - lookup.adapter_handle = ACPI_HANDLE(&adapter->dev); - lookup.device_handle = handle; - lookup.info = &info; + lookup.device_handle = acpi_device_handle(adev); + lookup.info = info; - /* - * Look up for I2cSerialBus resource with ResourceSource that - * matches with this adapter. - */ + /* Look up for I2cSerialBus resource */ INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, - acpi_i2c_find_address, &lookup); + acpi_i2c_fill_info, &lookup); acpi_dev_free_resource_list(&resource_list); - if (ret < 0 || !info.addr) - return AE_OK; + if (ret < 0 || !info->addr) + return -EINVAL; + + *adapter_handle = lookup.adapter_handle; /* Then fill IRQ number if any */ ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); if (ret < 0) - return AE_OK; + return -EINVAL; resource_list_for_each_entry(entry, &resource_list) { if (resource_type(entry->res) == IORESOURCE_IRQ) { - info.irq = entry->res->start; + info->irq = entry->res->start; break; } } acpi_dev_free_resource_list(&resource_list); + strlcpy(info->type, dev_name(&adev->dev), sizeof(info->type)); + + return 0; +} + +static void acpi_i2c_register_device(struct i2c_adapter *adapter, + struct acpi_device *adev, + struct i2c_board_info *info) +{ adev->power.flags.ignore_parent = true; - strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type)); - if (!i2c_new_device(adapter, &info)) { + acpi_device_set_enumerated(adev); + + if (!i2c_new_device(adapter, info)) { adev->power.flags.ignore_parent = false; dev_err(&adapter->dev, "failed to add I2C device %s from ACPI\n", dev_name(&adev->dev)); } +} + +static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, + void *data, void **return_value) +{ + struct i2c_adapter *adapter = data; + struct acpi_device *adev; + acpi_handle adapter_handle; + struct i2c_board_info info; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + + if (acpi_i2c_get_info(adev, &info, &adapter_handle)) + return AE_OK; + + if (adapter_handle != ACPI_HANDLE(&adapter->dev)) + return AE_OK; + + acpi_i2c_register_device(adapter, adev, &info); return AE_OK; } @@ -225,8 +248,80 @@ static void acpi_i2c_register_devices(struct i2c_adapter *adap) dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); } +static int acpi_i2c_match_adapter(struct device *dev, void *data) +{ + struct i2c_adapter *adapter = i2c_verify_adapter(dev); + + if (!adapter) + return 0; + + return ACPI_HANDLE(dev) == (acpi_handle)data; +} + +static int acpi_i2c_match_device(struct device *dev, void *data) +{ + return ACPI_COMPANION(dev) == data; +} + +static struct i2c_adapter *acpi_i2c_find_adapter_by_handle(acpi_handle handle) +{ + struct device *dev; + + dev = bus_find_device(&i2c_bus_type, NULL, handle, + acpi_i2c_match_adapter); + return dev ? i2c_verify_adapter(dev) : NULL; +} + +static struct i2c_client *acpi_i2c_find_client_by_adev(struct acpi_device *adev) +{ + struct device *dev; + + dev = bus_find_device(&i2c_bus_type, NULL, adev, acpi_i2c_match_device); + return dev ? i2c_verify_client(dev) : NULL; +} + +static int acpi_i2c_notify(struct notifier_block *nb, unsigned long value, + void *arg) +{ + struct acpi_device *adev = arg; + struct i2c_board_info info; + acpi_handle adapter_handle; + struct i2c_adapter *adapter; + struct i2c_client *client; + + switch (value) { + case ACPI_RECONFIG_DEVICE_ADD: + if (acpi_i2c_get_info(adev, &info, &adapter_handle)) + break; + + adapter = acpi_i2c_find_adapter_by_handle(adapter_handle); + if (!adapter) + break; + + acpi_i2c_register_device(adapter, adev, &info); + break; + case ACPI_RECONFIG_DEVICE_REMOVE: + if (!acpi_device_enumerated(adev)) + break; + + client = acpi_i2c_find_client_by_adev(adev); + if (!client) + break; + + i2c_unregister_device(client); + put_device(&client->dev); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block i2c_acpi_notifier = { + .notifier_call = acpi_i2c_notify, +}; #else /* CONFIG_ACPI */ static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { } +extern struct notifier_block i2c_acpi_notifier; #endif /* CONFIG_ACPI */ #ifdef CONFIG_ACPI_I2C_OPREGION @@ -400,7 +495,8 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command, break; default: - pr_info("protocol(0x%02x) is not supported.\n", accessor_type); + dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", + accessor_type, client->addr); ret = AE_BAD_PARAMETER; goto err; } @@ -666,6 +762,47 @@ int i2c_recover_bus(struct i2c_adapter *adap) } EXPORT_SYMBOL_GPL(i2c_recover_bus); +static void i2c_init_recovery(struct i2c_adapter *adap) +{ + struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; + char *err_str; + + if (!bri) + return; + + if (!bri->recover_bus) { + err_str = "no recover_bus() found"; + goto err; + } + + /* Generic GPIO recovery */ + if (bri->recover_bus == i2c_generic_gpio_recovery) { + if (!gpio_is_valid(bri->scl_gpio)) { + err_str = "invalid SCL gpio"; + goto err; + } + + if (gpio_is_valid(bri->sda_gpio)) + bri->get_sda = get_sda_gpio_value; + else + bri->get_sda = NULL; + + bri->get_scl = get_scl_gpio_value; + bri->set_scl = set_scl_gpio_value; + } else if (bri->recover_bus == i2c_generic_scl_recovery) { + /* Generic SCL recovery */ + if (!bri->set_scl || !bri->get_scl) { + err_str = "no {get|set}_scl() found"; + goto err; + } + } + + return; + err: + dev_err(&adap->dev, "Not using recovery: %s\n", err_str); + adap->bus_recovery_info = NULL; +} + static int i2c_device_probe(struct device *dev) { struct i2c_client *client = i2c_verify_client(dev); @@ -954,48 +1091,40 @@ static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr) } /** - * i2c_lock_adapter - Get exclusive access to an I2C bus segment + * i2c_adapter_lock_bus - Get exclusive access to an I2C bus segment * @adapter: Target I2C bus segment + * @flags: I2C_LOCK_ROOT_ADAPTER locks the root i2c adapter, I2C_LOCK_SEGMENT + * locks only this branch in the adapter tree */ -void i2c_lock_adapter(struct i2c_adapter *adapter) +static void i2c_adapter_lock_bus(struct i2c_adapter *adapter, + unsigned int flags) { - struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); - - if (parent) - i2c_lock_adapter(parent); - else - rt_mutex_lock(&adapter->bus_lock); + rt_mutex_lock(&adapter->bus_lock); } -EXPORT_SYMBOL_GPL(i2c_lock_adapter); /** - * i2c_trylock_adapter - Try to get exclusive access to an I2C bus segment + * i2c_adapter_trylock_bus - Try to get exclusive access to an I2C bus segment * @adapter: Target I2C bus segment + * @flags: I2C_LOCK_ROOT_ADAPTER trylocks the root i2c adapter, I2C_LOCK_SEGMENT + * trylocks only this branch in the adapter tree */ -static int i2c_trylock_adapter(struct i2c_adapter *adapter) +static int i2c_adapter_trylock_bus(struct i2c_adapter *adapter, + unsigned int flags) { - struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); - - if (parent) - return i2c_trylock_adapter(parent); - else - return rt_mutex_trylock(&adapter->bus_lock); + return rt_mutex_trylock(&adapter->bus_lock); } /** - * i2c_unlock_adapter - Release exclusive access to an I2C bus segment + * i2c_adapter_unlock_bus - Release exclusive access to an I2C bus segment * @adapter: Target I2C bus segment + * @flags: I2C_LOCK_ROOT_ADAPTER unlocks the root i2c adapter, I2C_LOCK_SEGMENT + * unlocks only this branch in the adapter tree */ -void i2c_unlock_adapter(struct i2c_adapter *adapter) +static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter, + unsigned int flags) { - struct i2c_adapter *parent = i2c_parent_is_i2c_adapter(adapter); - - if (parent) - i2c_unlock_adapter(parent); - else - rt_mutex_unlock(&adapter->bus_lock); + rt_mutex_unlock(&adapter->bus_lock); } -EXPORT_SYMBOL_GPL(i2c_unlock_adapter); static void i2c_dev_set_name(struct i2c_adapter *adap, struct i2c_client *client) @@ -1097,6 +1226,8 @@ void i2c_unregister_device(struct i2c_client *client) { if (client->dev.of_node) of_node_clear_flag(client->dev.of_node, OF_POPULATED); + if (ACPI_COMPANION(&client->dev)) + acpi_device_clear_enumerated(ACPI_COMPANION(&client->dev)); device_unregister(&client->dev); } EXPORT_SYMBOL_GPL(i2c_unregister_device); @@ -1153,6 +1284,47 @@ struct i2c_client *i2c_new_dummy(struct i2c_adapter *adapter, u16 address) } EXPORT_SYMBOL_GPL(i2c_new_dummy); +/** + * i2c_new_secondary_device - Helper to get the instantiated secondary address + * and create the associated device + * @client: Handle to the primary client + * @name: Handle to specify which secondary address to get + * @default_addr: Used as a fallback if no secondary address was specified + * Context: can sleep + * + * I2C clients can be composed of multiple I2C slaves bound together in a single + * component. The I2C client driver then binds to the master I2C slave and needs + * to create I2C dummy clients to communicate with all the other slaves. + * + * This function creates and returns an I2C dummy client whose I2C address is + * retrieved from the platform firmware based on the given slave name. If no + * address is specified by the firmware default_addr is used. + * + * On DT-based platforms the address is retrieved from the "reg" property entry + * cell whose "reg-names" value matches the slave name. + * + * 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_secondary_device(struct i2c_client *client, + const char *name, + u16 default_addr) +{ + struct device_node *np = client->dev.of_node; + u32 addr = default_addr; + int i; + + if (np) { + i = of_property_match_string(np, "reg-names", name); + if (i >= 0) + of_property_read_u32_index(np, "reg", i, &addr); + } + + dev_dbg(&client->adapter->dev, "Address for %s : 0x%x\n", name, addr); + return i2c_new_dummy(client->adapter, addr); +} +EXPORT_SYMBOL_GPL(i2c_new_secondary_device); + /* ------------------------------------------------------------------------- */ /* I2C bus adapters -- one roots each I2C or SMBUS segment */ @@ -1521,7 +1693,7 @@ static int __process_new_adapter(struct device_driver *d, void *data) static int i2c_register_adapter(struct i2c_adapter *adap) { - int res = 0; + int res = -EINVAL; /* Can't register until after driver model init */ if (WARN_ON(!is_registered)) { @@ -1530,18 +1702,22 @@ static int i2c_register_adapter(struct i2c_adapter *adap) } /* Sanity checks */ - if (unlikely(adap->name[0] == '\0')) { - pr_err("i2c-core: Attempt to register an adapter with " - "no name!\n"); - return -EINVAL; + if (WARN(!adap->name[0], "i2c adapter has no name")) + goto out_list; + + if (!adap->algo) { + pr_err("adapter '%s': no algo supplied!\n", adap->name); + goto out_list; } - if (unlikely(!adap->algo)) { - pr_err("i2c-core: Attempt to register adapter '%s' with " - "no algo!\n", adap->name); - return -EINVAL; + + if (!adap->lock_bus) { + adap->lock_bus = i2c_adapter_lock_bus; + adap->trylock_bus = i2c_adapter_trylock_bus; + adap->unlock_bus = i2c_adapter_unlock_bus; } rt_mutex_init(&adap->bus_lock); + rt_mutex_init(&adap->mux_lock); mutex_init(&adap->userspace_clients_lock); INIT_LIST_HEAD(&adap->userspace_clients); @@ -1553,12 +1729,15 @@ static int i2c_register_adapter(struct i2c_adapter *adap) adap->dev.bus = &i2c_bus_type; adap->dev.type = &i2c_adapter_type; res = device_register(&adap->dev); - if (res) + if (res) { + pr_err("adapter '%s': can't register device (%d)\n", adap->name, res); goto out_list; + } dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); pm_runtime_no_callbacks(&adap->dev); + pm_suspend_ignore_children(&adap->dev, true); pm_runtime_enable(&adap->dev); #ifdef CONFIG_I2C_COMPAT @@ -1569,39 +1748,8 @@ static int i2c_register_adapter(struct i2c_adapter *adap) "Failed to create compatibility class link\n"); #endif - /* bus recovery specific initialization */ - if (adap->bus_recovery_info) { - struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; + i2c_init_recovery(adap); - if (!bri->recover_bus) { - dev_err(&adap->dev, "No recover_bus() found, not using recovery\n"); - adap->bus_recovery_info = NULL; - goto exit_recovery; - } - - /* Generic GPIO recovery */ - if (bri->recover_bus == i2c_generic_gpio_recovery) { - if (!gpio_is_valid(bri->scl_gpio)) { - dev_err(&adap->dev, "Invalid SCL gpio, not using recovery\n"); - adap->bus_recovery_info = NULL; - goto exit_recovery; - } - - if (gpio_is_valid(bri->sda_gpio)) - bri->get_sda = get_sda_gpio_value; - else - bri->get_sda = NULL; - - bri->get_scl = get_scl_gpio_value; - bri->set_scl = set_scl_gpio_value; - } else if (!bri->set_scl || !bri->get_scl) { - /* Generic SCL recovery */ - dev_err(&adap->dev, "No {get|set}_gpio() found, not using recovery\n"); - adap->bus_recovery_info = NULL; - } - } - -exit_recovery: /* create pre-declared device nodes */ of_i2c_register_devices(adap); acpi_i2c_register_devices(adap); @@ -1633,13 +1781,12 @@ out_list: */ static int __i2c_add_numbered_adapter(struct i2c_adapter *adap) { - int id; + int id; mutex_lock(&core_lock); - id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1, - GFP_KERNEL); + id = idr_alloc(&i2c_adapter_idr, adap, adap->nr, adap->nr + 1, GFP_KERNEL); mutex_unlock(&core_lock); - if (id < 0) + if (WARN(id < 0, "couldn't get idr")) return id == -ENOSPC ? -EBUSY : id; return i2c_register_adapter(adap); @@ -1676,7 +1823,7 @@ int i2c_add_adapter(struct i2c_adapter *adapter) id = idr_alloc(&i2c_adapter_idr, adapter, __i2c_first_dynamic_bus_num, 0, GFP_KERNEL); mutex_unlock(&core_lock); - if (id < 0) + if (WARN(id < 0, "couldn't get idr")) return id; adapter->nr = id; @@ -1774,8 +1921,7 @@ void i2c_del_adapter(struct i2c_adapter *adap) 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); + pr_debug("attempting to delete unregistered adapter [%s]\n", adap->name); return; } @@ -1935,7 +2081,7 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) if (res) return res; - pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); + pr_debug("driver [%s] registered\n", driver->driver.name); INIT_LIST_HEAD(&driver->clients); /* Walk the adapters that are already present */ @@ -1962,7 +2108,7 @@ void i2c_del_driver(struct i2c_driver *driver) i2c_for_each_dev(driver, __process_removed_driver); driver_unregister(&driver->driver); - pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); + pr_debug("driver [%s] unregistered\n", driver->driver.name); } EXPORT_SYMBOL(i2c_del_driver); @@ -2053,8 +2199,8 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action, put_device(&adap->dev); if (IS_ERR(client)) { - pr_err("%s: failed to create for '%s'\n", - __func__, rd->dn->full_name); + dev_err(&adap->dev, "failed to create client for '%s'\n", + rd->dn->full_name); return notifier_from_errno(PTR_ERR(client)); } break; @@ -2115,6 +2261,8 @@ static int __init i2c_init(void) if (IS_ENABLED(CONFIG_OF_DYNAMIC)) WARN_ON(of_reconfig_notifier_register(&i2c_of_notifier)); + if (IS_ENABLED(CONFIG_ACPI)) + WARN_ON(acpi_reconfig_notifier_register(&i2c_acpi_notifier)); return 0; @@ -2130,6 +2278,8 @@ bus_err: static void __exit i2c_exit(void) { + if (IS_ENABLED(CONFIG_ACPI)) + WARN_ON(acpi_reconfig_notifier_unregister(&i2c_acpi_notifier)); if (IS_ENABLED(CONFIG_OF_DYNAMIC)) WARN_ON(of_reconfig_notifier_unregister(&i2c_of_notifier)); i2c_del_driver(&dummy_driver); @@ -2309,16 +2459,16 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) #endif if (in_atomic() || irqs_disabled()) { - ret = i2c_trylock_adapter(adap); + ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT); if (!ret) /* I2C activity is ongoing. */ return -EAGAIN; } else { - i2c_lock_adapter(adap); + i2c_lock_bus(adap, I2C_LOCK_SEGMENT); } ret = __i2c_transfer(adap, msgs, num); - i2c_unlock_adapter(adap); + i2c_unlock_bus(adap, I2C_LOCK_SEGMENT); return ret; } else { @@ -2646,7 +2796,7 @@ static u8 i2c_smbus_pec(u8 crc, u8 *p, size_t count) static u8 i2c_smbus_msg_pec(u8 pec, struct i2c_msg *msg) { /* The address will be sent first */ - u8 addr = (msg->addr << 1) | !!(msg->flags & I2C_M_RD); + u8 addr = i2c_8bit_addr_from_msg(msg); pec = i2c_smbus_pec(pec, &addr, 1); /* The data buffer follows */ @@ -2671,7 +2821,7 @@ static int i2c_smbus_check_pec(u8 cpec, struct i2c_msg *msg) cpec = i2c_smbus_msg_pec(cpec, msg); if (rpec != cpec) { - pr_debug("i2c-core: Bad PEC 0x%02x vs. 0x%02x\n", + pr_debug("Bad PEC 0x%02x vs. 0x%02x\n", rpec, cpec); return -EBADMSG; } @@ -3093,7 +3243,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB; if (adapter->algo->smbus_xfer) { - i2c_lock_adapter(adapter); + i2c_lock_bus(adapter, I2C_LOCK_SEGMENT); /* Retry automatically on arbitration loss */ orig_jiffies = jiffies; @@ -3107,7 +3257,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, orig_jiffies + adapter->timeout)) break; } - i2c_unlock_adapter(adapter); + i2c_unlock_bus(adapter, I2C_LOCK_SEGMENT); if (res != -EOPNOTSUPP || !adapter->algo->master_xfer) goto trace;