diff options
Diffstat (limited to 'drivers/i2c/i2c.c')
-rw-r--r-- | drivers/i2c/i2c.c | 121 |
1 files changed, 85 insertions, 36 deletions
diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c index 12aac42794..5471519045 100644 --- a/drivers/i2c/i2c.c +++ b/drivers/i2c/i2c.c @@ -1,8 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (C) 2009 Marc Kleine-Budde <mkl@pengutronix.de> * - * This file is released under the GPLv2 - * * Derived from: * - i2c-core.c - a device driver for the iic-bus interface * Copyright (C) 1995-99 Simon G. Vogl @@ -24,6 +23,7 @@ #include <init.h> #include <of.h> #include <gpio.h> +#include <slice.h> #include <i2c/i2c.h> @@ -63,6 +63,8 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) uint64_t start; int ret, try; + slice_acquire(&adap->slice); + /* * REVISIT the fault reporting model here is weak: * @@ -97,6 +99,8 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) break; } + slice_release(&adap->slice); + return ret; } EXPORT_SYMBOL(i2c_transfer); @@ -215,7 +219,8 @@ int i2c_write_reg(struct i2c_client *client, u32 addr, const u8 *buf, u16 count) msgbuf[i++] = addr; msg->len += i; - memcpy(msg->buf + i, buf, count); + if (count) + memcpy(msg->buf + i, buf, count); status = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); dev_dbg(&client->adapter->dev, "%s: %u@%u --> %d\n", __func__, @@ -253,7 +258,7 @@ int i2c_get_sda_gpio_value(struct i2c_adapter *adap) static int i2c_get_gpios_for_recovery(struct i2c_adapter *adap) { struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; - struct device_d *dev = &adap->dev; + struct device *dev = &adap->dev; int ret = 0; ret = gpio_request_one(bri->scl_gpio, GPIOF_IN, "i2c-scl"); @@ -353,13 +358,13 @@ int i2c_generic_gpio_recovery(struct i2c_adapter *adap) int i2c_recover_bus(struct i2c_adapter *adap) { if (!adap->bus_recovery_info) - return -EOPNOTSUPP; + return -EBUSY; dev_dbg(&adap->dev, "Trying i2c bus recovery\n"); return adap->bus_recovery_info->recover_bus(adap); } -static void i2c_info(struct device_d *dev) +static void i2c_info(struct device *dev) { const struct i2c_client *client = to_i2c_client(dev); @@ -394,7 +399,7 @@ static struct i2c_client *i2c_new_device(struct i2c_adapter *adapter, client->dev.platform_data = chip->platform_data; client->dev.id = DEVICE_ID_DYNAMIC; client->dev.bus = &i2c_bus; - client->dev.device_node = chip->of_node; + client->dev.of_node = chip->of_node; client->adapter = adapter; client->addr = chip->addr; @@ -410,6 +415,9 @@ static struct i2c_client *i2c_new_device(struct i2c_adapter *adapter, if (chip->of_node) chip->of_node->dev = &client->dev; + dev_dbg(&client->dev, "registered on bus %d, chip->addr 0x%02x\n", + adapter->nr, client->addr); + return client; } @@ -418,37 +426,68 @@ static void of_i2c_register_devices(struct i2c_adapter *adap) struct device_node *n; /* Only register child devices if the adapter has a node pointer set */ - if (!IS_ENABLED(CONFIG_OFDEVICE) || !adap->dev.device_node) + if (!IS_ENABLED(CONFIG_OFDEVICE) || !adap->dev.of_node) return; - for_each_available_child_of_node(adap->dev.device_node, n) { + for_each_available_child_of_node(adap->dev.of_node, n) { struct i2c_board_info info = {}; struct i2c_client *result; const __be32 *addr; int len; + if (n->dev) { + dev_dbg(&adap->dev, "of_i2c: skipping already registered %s\n", + dev_name(n->dev)); + continue; + } + of_modalias_node(n, info.type, I2C_NAME_SIZE); info.of_node = n; addr = of_get_property(n, "reg", &len); if (!addr || (len < sizeof(int))) { - dev_err(&adap->dev, "of_i2c: invalid reg on %s\n", - n->full_name); + dev_err(&adap->dev, "of_i2c: invalid reg on %pOF\n", n); continue; } info.addr = be32_to_cpup(addr); if (info.addr > (1 << 10) - 1) { - dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n", - info.addr, n->full_name); + dev_err(&adap->dev, "of_i2c: invalid addr=%x on %pOF\n", + info.addr, n); continue; } result = i2c_new_device(adap, &info); if (!result) - dev_err(&adap->dev, "of_i2c: Failure registering %s\n", - n->full_name); + dev_err(&adap->dev, "of_i2c: Failure registering %pOF\n", + n); + } +} + +int of_i2c_register_devices_by_node(struct device_node *node) +{ + struct i2c_adapter *adap; + + adap = of_find_i2c_adapter_by_node(node); + if (!adap) + return -ENODEV; + if (IS_ERR(adap)) + return PTR_ERR(adap); + + of_i2c_register_devices(adap); + return 0; +} + +static void i2c_hw_rescan(struct device *dev) +{ + struct i2c_adapter *adap; + + list_for_each_entry(adap, &i2c_adapter_list, list) { + if (dev != adap->dev.parent) + continue; + of_i2c_register_devices(adap); + break; } } @@ -521,7 +560,6 @@ static void scan_boardinfo(struct i2c_adapter *adapter) continue; for (n = bi->n_board_info; n > 0; n--, chip++) { - debug("%s: bus_num: %d, chip->addr 0x%02x\n", __func__, bi->bus_num, chip->addr); /* * NOTE: this relies on i2c_new_device to * issue diagnostics when given bogus inputs @@ -555,10 +593,10 @@ struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) ret = of_device_ensure_probed(node); if (ret) - return ERR_PTR(ret); + return NULL; for_each_i2c_adapter(adap) - if (adap->dev.device_node == node) + if (adap->dev.of_node == node) return adap; return NULL; @@ -566,7 +604,7 @@ struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) { - struct device_d *dev = of_find_device_by_node(node); + struct device *dev = of_find_device_by_node(node); if (!dev) return NULL; @@ -577,12 +615,26 @@ struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) return to_i2c_client(dev); } -static void i2c_parse_timing(struct device_d *dev, char *prop_name, u32 *cur_val_p, - u32 def_val, bool use_def) +int of_i2c_device_enable_and_register_by_alias(const char *alias) +{ + struct device_node *np; + + np = of_find_node_by_alias(NULL, alias); + if (!np) + return -ENODEV; + + of_device_enable(np); + return of_i2c_register_devices_by_node(np->parent); +} + + +static void i2c_parse_timing(struct device *dev, char *prop_name, + u32 *cur_val_p, + u32 def_val, bool use_def) { int ret; - ret = of_property_read_u32(dev->device_node, prop_name, cur_val_p); + ret = of_property_read_u32(dev->of_node, prop_name, cur_val_p); if (ret && use_def) *cur_val_p = def_val; @@ -605,7 +657,8 @@ static void i2c_parse_timing(struct device_d *dev, char *prop_name, u32 *cur_val * to switch to this function. New drivers almost always should use the defaults. */ -void i2c_parse_fw_timings(struct device_d *dev, struct i2c_timings *t, bool use_defaults) +void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, + bool use_defaults) { bool u = use_defaults; u32 d; @@ -649,6 +702,7 @@ EXPORT_SYMBOL_GPL(i2c_parse_fw_timings); */ int i2c_add_numbered_adapter(struct i2c_adapter *adapter) { + struct device *hw_dev; int ret; if (adapter->nr < 0) { @@ -672,31 +726,26 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adapter) list_add_tail(&adapter->list, &i2c_adapter_list); + slice_init(&adapter->slice, dev_name(&adapter->dev)); + /* populate children from any i2c device tables */ scan_boardinfo(adapter); of_i2c_register_devices(adapter); + hw_dev = adapter->dev.parent; + if (hw_dev && dev_of_node(hw_dev)) { + if (!hw_dev->rescan) + hw_dev->rescan = i2c_hw_rescan; + } + return 0; } EXPORT_SYMBOL(i2c_add_numbered_adapter); -static int i2c_probe(struct device_d *dev) -{ - return dev->driver->probe(dev); -} - -static void i2c_remove(struct device_d *dev) -{ - if (dev->driver->remove) - dev->driver->remove(dev); -} - struct bus_type i2c_bus = { .name = "i2c", .match = device_match_of_modalias, - .probe = i2c_probe, - .remove = i2c_remove, }; static int i2c_bus_init(void) |