From 05753b98c078b59be4cb59006c9352cd88d5c662 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 20 May 2013 21:55:43 +0200 Subject: [PATCH 1/6] i2c: Add missing result check Signed-off-by: Sascha Hauer --- drivers/i2c/i2c.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c index 4862df3c0..488b636b2 100644 --- a/drivers/i2c/i2c.c +++ b/drivers/i2c/i2c.c @@ -260,6 +260,10 @@ struct i2c_client *i2c_new_device(struct i2c_adapter *adapter, client->dev.parent = &adapter->dev; status = register_device(&client->dev); + if (status) { + free(client); + return NULL; + } #if 0 /* drivers may modify this initial i/o setup */ From 5cee215f3eabdef1648773e34eed2f2d1c8f5088 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 20 May 2013 20:57:25 +0200 Subject: [PATCH 2/6] i2c: remove dead code Signed-off-by: Sascha Hauer --- drivers/i2c/i2c.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c index 488b636b2..53a11fe44 100644 --- a/drivers/i2c/i2c.c +++ b/drivers/i2c/i2c.c @@ -265,23 +265,7 @@ struct i2c_client *i2c_new_device(struct i2c_adapter *adapter, return NULL; } -#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; - } -#endif - return client; - -#if 0 - fail: - free(proxy); - return NULL; -#endif } EXPORT_SYMBOL(i2c_new_device); From 5b79ceee575e5b51bda945fb37aff667470ce106 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 20 May 2013 20:34:14 +0200 Subject: [PATCH 3/6] i2c: Add support for dynamic i2c bus numbers Signed-off-by: Sascha Hauer --- drivers/i2c/i2c.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c index 53a11fe44..ddf00826b 100644 --- a/drivers/i2c/i2c.c +++ b/drivers/i2c/i2c.c @@ -384,8 +384,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"); From 75ea5f1c0f6b93eae17470dfc62b40d254bb171b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 31 May 2013 15:47:14 +0200 Subject: [PATCH 4/6] of: Add of_modalias_node function Directly from the Kernel. Signed-off-by: Sascha Hauer --- drivers/of/base.c | 27 +++++++++++++++++++++++++++ include/of.h | 2 ++ 2 files changed, 29 insertions(+) diff --git a/drivers/of/base.c b/drivers/of/base.c index 838354982..2aae31721 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -625,6 +625,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/of.h b/include/of.h index 4dcf37e14..89f60d484 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) From b1a4a659c68bb0c37c5265a354c6a32b321c3446 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 20 May 2013 21:54:52 +0200 Subject: [PATCH 5/6] i2c: Add devicetree support Signed-off-by: Sascha Hauer --- drivers/i2c/i2c.c | 42 ++++++++++++++++++++++++++++++++++++++++++ include/i2c/i2c.h | 1 + 2 files changed, 43 insertions(+) diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c index ddf00826b..b63d94604 100644 --- a/drivers/i2c/i2c.c +++ b/drivers/i2c/i2c.c @@ -254,6 +254,7 @@ 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; @@ -269,6 +270,45 @@ struct i2c_client *i2c_new_device(struct i2c_adapter *adapter, } 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 @@ -408,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/include/i2c/i2c.h b/include/i2c/i2c.h index 7b59a5102..3b4be45ad 100644 --- a/include/i2c/i2c.h +++ b/include/i2c/i2c.h @@ -102,6 +102,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; }; /** From 711b4ae3f0f8cb005fc727139a4c60415bb73031 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 20 May 2013 20:34:55 +0200 Subject: [PATCH 6/6] i2c: fsl: Add devicetree probe support Signed-off-by: Sascha Hauer --- drivers/i2c/busses/i2c-imx.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 9fcfd5c6f..c607bcba1 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);