Re: [PATCH] powerpc: Add of_register_i2c_devices()
From: Guennadi Liakhovetski <hidden>
Date: 2007-07-19 22:08:06
Subsystem:
linux for powerpc (32-bit and 64-bit), the rest · Maintainers:
Madhavan Srinivasan, Michael Ellerman, Linus Torvalds
On Thu, 19 Jul 2007, Segher Boessenkool wrote:
quoted
quoted
Your device is an rs5c372b. So, that's what you put in your device tree. Simple so far, right? Now some OF I2C code goes looking for IIC devices in the device tree. It finds this thing, and from a table or something it derives that it has to tell the kernel I2C layer this is an "rtc-rs5c372". [It would be nicer if it could just instantiate the correct driver directly, but if that's how the Linux I2C layer works, so be it]. No change in the I2C "core" needed, just an OF "compatible" matching thing like is needed *everywhere else* too.How about the patch below?Looks good. It should later be moved to a more generic I2C OF matching layer, but fine for now. Thanks! You might want to put vendor names in the "compatible" entries, dunno though, maybe these are "cross-vendor" ICs?
You mean like compatible = "ricoh,rs5c372a" etc? With this change, plus __init(data) attributes for functions and the array, attached below is version 2 of the patch. Corresponding modifications to the kurobox*.dts will follow separately. Thanks Guennadi --- Guennadi Liakhovetski Scan the device tree for i2c devices, check their "compatible" property against a hard-coded table, and, if found, register with i2c boardinfo. Signed-off-by: G. Liakhovetski <redacted>
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 3289fab..e07d031 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c@@ -305,6 +305,62 @@ err: arch_initcall(gfar_of_init); +#ifdef CONFIG_I2C_BOARDINFO +#include <linux/i2c.h> +struct i2c_driver_device { + char *of_device; + char *i2c_driver; + char *i2c_type; +}; + +static struct i2c_driver_device i2c_devices[] __initdata = { + {"ricoh,rs5c372a", "rtc-rs5c372", "rs5c372a",}, + {"ricoh,rs5c372b", "rtc-rs5c372", "rs5c372b",}, + {"ricoh,rv5c386", "rtc-rs5c372", "rv5c386",}, + {"ricoh,rv5c387a", "rtc-rs5c372", "rv5c387a",}, +}; + +static int __init of_find_i2c_driver(struct device_node *node, struct i2c_board_info *info) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) { + if (!of_device_is_compatible(node, i2c_devices[i].of_device)) + continue; + strncpy(info->driver_name, i2c_devices[i].i2c_driver, KOBJ_NAME_LEN); + strncpy(info->type, i2c_devices[i].i2c_type, I2C_NAME_SIZE); + return 0; + } + return -ENODEV; +} + +static void __init of_register_i2c_devices(struct device_node *adap_node, int bus_num) +{ + struct device_node *node = NULL; + + while ((node = of_get_next_child(adap_node, node))) { + struct i2c_board_info info; + const u32 *addr; + int len; + + addr = of_get_property(node, "reg", &len); + if (!addr || len < sizeof(int) || *addr > 0xffff) + continue; + + info.irq = irq_of_parse_and_map(node, 0); + if (info.irq == NO_IRQ) + info.irq = -1; + + if (of_find_i2c_driver(node, &info) < 0) + continue; + + info.platform_data = NULL; + info.addr = *addr; + + i2c_register_board_info(bus_num, &info, 1); + } +} + static int __init fsl_i2c_of_init(void) { struct device_node *np;
@@ -349,6 +405,8 @@ static int __init fsl_i2c_of_init(void) fsl_i2c_platform_data)); if (ret) goto unreg; + + of_register_i2c_devices(np, i); } return 0;
@@ -360,6 +418,7 @@ err: } arch_initcall(fsl_i2c_of_init); +#endif #ifdef CONFIG_PPC_83xx static int __init mpc83xx_wdt_init(void)