summaryrefslogtreecommitdiffstats
path: root/drivers/i2c/i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/i2c.c')
-rw-r--r--drivers/i2c/i2c.c115
1 files changed, 82 insertions, 33 deletions
diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c
index b24fd88f5b..5471519045 100644
--- a/drivers/i2c/i2c.c
+++ b/drivers/i2c/i2c.c
@@ -23,6 +23,7 @@
#include <init.h>
#include <of.h>
#include <gpio.h>
+#include <slice.h>
#include <i2c/i2c.h>
@@ -62,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:
*
@@ -96,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);
@@ -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)