diff options
Diffstat (limited to 'drivers/i2c/i2c.c')
-rw-r--r-- | drivers/i2c/i2c.c | 205 |
1 files changed, 135 insertions, 70 deletions
diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c index 9df5ee70c7..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; @@ -407,6 +412,12 @@ static struct i2c_client *i2c_new_device(struct i2c_adapter *adapter, } client->dev.info = i2c_info; + 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; } @@ -415,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; } } @@ -518,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 @@ -548,14 +589,58 @@ struct i2c_adapter *i2c_get_adapter(int busnum) struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) { struct i2c_adapter *adap; + int ret; + + ret = of_device_ensure_probed(node); + if (ret) + return NULL; for_each_i2c_adapter(adap) - if (adap->dev.device_node == node) + if (adap->dev.of_node == node) return adap; return NULL; } +struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) +{ + struct device *dev = of_find_device_by_node(node); + + if (!dev) + return NULL; + + if (dev->bus != &i2c_bus) + return NULL; + + return to_i2c_client(dev); +} + +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->of_node, prop_name, cur_val_p); + if (ret && use_def) + *cur_val_p = def_val; + + dev_dbg(dev, "%s: %u\n", prop_name, *cur_val_p); +} + /** * i2c_parse_fw_timings - get I2C related timing parameters from firmware * @dev: The device to scan for I2C timing properties @@ -572,47 +657,31 @@ struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) * 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) { - int ret; - - memset(t, 0, sizeof(*t)); - - ret = of_property_read_u32(dev->device_node, "clock-frequency", - &t->bus_freq_hz); - if (ret && use_defaults) - t->bus_freq_hz = 100000; - - ret = of_property_read_u32(dev->device_node, "i2c-scl-rising-time-ns", - &t->scl_rise_ns); - if (ret && use_defaults) { - if (t->bus_freq_hz <= 100000) - t->scl_rise_ns = 1000; - else if (t->bus_freq_hz <= 400000) - t->scl_rise_ns = 300; - else - t->scl_rise_ns = 120; - } - - ret = of_property_read_u32(dev->device_node, "i2c-scl-falling-time-ns", - &t->scl_fall_ns); - if (ret && use_defaults) { - if (t->bus_freq_hz <= 400000) - t->scl_fall_ns = 300; - else - t->scl_fall_ns = 120; - } - - of_property_read_u32(dev->device_node, "i2c-scl-internal-delay-ns", - &t->scl_int_delay_ns); - - ret = of_property_read_u32(dev->device_node, "i2c-sda-falling-time-ns", - &t->sda_fall_ns); - if (ret && use_defaults) - t->sda_fall_ns = t->scl_fall_ns; - - of_property_read_u32(dev->device_node, "i2c-sda-hold-time-ns", - &t->sda_hold_ns); + bool u = use_defaults; + u32 d; + + i2c_parse_timing(dev, "clock-frequency", &t->bus_freq_hz, + I2C_MAX_STANDARD_MODE_FREQ, u); + + d = t->bus_freq_hz <= I2C_MAX_STANDARD_MODE_FREQ ? 1000 : + t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ ? 300 : 120; + i2c_parse_timing(dev, "i2c-scl-rising-time-ns", &t->scl_rise_ns, d, u); + + d = t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ ? 300 : 120; + i2c_parse_timing(dev, "i2c-scl-falling-time-ns", &t->scl_fall_ns, d, u); + + i2c_parse_timing(dev, "i2c-scl-internal-delay-ns", + &t->scl_int_delay_ns, 0, u); + i2c_parse_timing(dev, "i2c-sda-falling-time-ns", &t->sda_fall_ns, + t->scl_fall_ns, u); + i2c_parse_timing(dev, "i2c-sda-hold-time-ns", &t->sda_hold_ns, 0, u); + i2c_parse_timing(dev, "i2c-digital-filter-width-ns", + &t->digital_filter_width_ns, 0, u); + i2c_parse_timing(dev, "i2c-analog-filter-cutoff-frequency", + &t->analog_filter_cutoff_freq_hz, 0, u); } EXPORT_SYMBOL_GPL(i2c_parse_fw_timings); @@ -633,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) { @@ -656,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) |