summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2013-06-02 16:28:34 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2013-06-02 16:28:34 +0200
commit1f23a439245f333752d7b98b9fd5ee2e30a83cc9 (patch)
tree442b8f36703770aa45722bb368b99fa3025c011f
parent5f56c3506007eea1a284cdc55f8b3e60de67f2cc (diff)
parent711b4ae3f0f8cb005fc727139a4c60415bb73031 (diff)
downloadbarebox-1f23a439245f333752d7b98b9fd5ee2e30a83cc9.tar.gz
Merge branch 'for-next/of-i2c'
-rw-r--r--drivers/i2c/busses/i2c-imx.c10
-rw-r--r--drivers/i2c/i2c.c73
-rw-r--r--drivers/of/base.c27
-rw-r--r--include/i2c/i2c.h1
-rw-r--r--include/of.h2
5 files changed, 96 insertions, 17 deletions
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 9fcfd5c6f7..c607bcba1a 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -545,6 +545,7 @@ static int __init i2c_fsl_probe(struct device_d *pdev)
i2c_fsl->adapter.master_xfer = i2c_fsl_xfer;
i2c_fsl->adapter.nr = pdev->id;
i2c_fsl->adapter.dev.parent = pdev;
+ i2c_fsl->adapter.dev.device_node = pdev->device_node;
i2c_fsl->base = dev_request_mem_region(pdev, 0);
i2c_fsl->dfsrr = -1;
@@ -572,8 +573,17 @@ fail:
return ret;
}
+static __maybe_unused struct of_device_id imx_i2c_dt_ids[] = {
+ {
+ .compatible = "fsl,imx21-i2c",
+ }, {
+ /* sentinel */
+ }
+};
+
static struct driver_d i2c_fsl_driver = {
.probe = i2c_fsl_probe,
.name = DRIVER_NAME,
+ .of_compatible = DRV_OF_COMPAT(imx_i2c_dt_ids),
};
device_platform_driver(i2c_fsl_driver);
diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c
index 4862df3c00..b63d94604d 100644
--- a/drivers/i2c/i2c.c
+++ b/drivers/i2c/i2c.c
@@ -254,33 +254,61 @@ 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->adapter = adapter;
client->addr = chip->addr;
client->dev.parent = &adapter->dev;
status = register_device(&client->dev);
-
-#if 0
- /* drivers may modify this initial i/o setup */
- status = master->setup(client);
- if (status < 0) {
- printf("can't setup %s, status %d\n",
- client->dev.name, status);
- goto fail;
+ if (status) {
+ free(client);
+ return NULL;
}
-#endif
return client;
-
-#if 0
- fail:
- free(proxy);
- return NULL;
-#endif
}
EXPORT_SYMBOL(i2c_new_device);
+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)
+ return;
+
+ device_node_for_nach_child(adap->dev.device_node, n) {
+ struct i2c_board_info info = {};
+ struct i2c_client *result;
+ const __be32 *addr;
+ int len;
+
+ 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);
+ 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);
+ continue;
+ }
+
+ result = i2c_new_device(adap, &info);
+ if (!result)
+ dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
+ n->full_name);
+ }
+}
+
/**
* i2c_new_dummy - return a new i2c device bound to a dummy driver
* @adapter: the adapter managing the device
@@ -396,8 +424,17 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adapter)
{
int ret;
- if (i2c_get_adapter(adapter->nr))
- return -EBUSY;
+ if (adapter->nr < 0) {
+ int nr;
+
+ for (nr = 0;; nr++)
+ if (!i2c_get_adapter(nr))
+ break;
+ adapter->nr = nr;
+ } else {
+ if (i2c_get_adapter(adapter->nr))
+ return -EBUSY;
+ }
adapter->dev.id = adapter->nr;
strcpy(adapter->dev.name, "i2c");
@@ -411,6 +448,8 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adapter)
/* populate children from any i2c device tables */
scan_boardinfo(adapter);
+ of_i2c_register_devices(adapter);
+
return 0;
}
EXPORT_SYMBOL(i2c_add_numbered_adapter);
diff --git a/drivers/of/base.c b/drivers/of/base.c
index e0d7fd0f4a..4241e65b3f 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -656,6 +656,33 @@ int of_property_read_string_index(struct device_node *np, const char *propname,
}
EXPORT_SYMBOL_GPL(of_property_read_string_index);
+/**
+ * of_modalias_node - Lookup appropriate modalias for a device node
+ * @node: pointer to a device tree node
+ * @modalias: Pointer to buffer that modalias value will be copied into
+ * @len: Length of modalias value
+ *
+ * Based on the value of the compatible property, this routine will attempt
+ * to choose an appropriate modalias value for a particular device tree node.
+ * It does this by stripping the manufacturer prefix (as delimited by a ',')
+ * from the first entry in the compatible list property.
+ *
+ * This routine returns 0 on success, <0 on failure.
+ */
+int of_modalias_node(struct device_node *node, char *modalias, int len)
+{
+ const char *compatible, *p;
+ int cplen;
+
+ compatible = of_get_property(node, "compatible", &cplen);
+ if (!compatible || strlen(compatible) > cplen)
+ return -ENODEV;
+ p = strchr(compatible, ',');
+ strlcpy(modalias, p ? p + 1 : compatible, len);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_modalias_node);
+
struct device_node *of_get_root_node(void)
{
return root_node;
diff --git a/include/i2c/i2c.h b/include/i2c/i2c.h
index dab8dc59e0..46185ac921 100644
--- a/include/i2c/i2c.h
+++ b/include/i2c/i2c.h
@@ -105,6 +105,7 @@ struct i2c_board_info {
char type[I2C_NAME_SIZE]; /**< name of device */
unsigned short addr; /**< stored in i2c_client.addr */
void *platform_data; /**< platform data for device */
+ struct device_node *of_node;
};
/**
diff --git a/include/of.h b/include/of.h
index f8a45a7dd4..300b7069c0 100644
--- a/include/of.h
+++ b/include/of.h
@@ -72,6 +72,8 @@ struct fdt_header *fdt_get_tree(void);
struct fdt_header *of_get_fixed_tree(struct device_node *node);
+int of_modalias_node(struct device_node *node, char *modalias, int len);
+
#define device_node_for_nach_child(node, child) \
list_for_each_entry(child, &node->children, parent_list)