diff options
| author | Jochen Friedrich <jochen@scram.de> | 2008-04-12 05:22:35 +1000 | 
|---|---|---|
| committer | Paul Mackerras <paulus@samba.org> | 2008-04-17 07:46:11 +1000 | 
| commit | 612212a3f2f053ea68ce9cd16d3deeca7754e8c9 (patch) | |
| tree | 90956837077b037215d4447e670e9a7e8426dedf | |
| parent | b7ce341585a51a6d65c7a77b6918132a3b360b81 (diff) | |
| download | olio-linux-3.10-612212a3f2f053ea68ce9cd16d3deeca7754e8c9.tar.xz olio-linux-3.10-612212a3f2f053ea68ce9cd16d3deeca7754e8c9.zip  | |
[POWERPC] i2c: OF helpers for the i2c API
This implements various helpers to support OF bindings for the i2c
API.
Signed-off-by: Jochen Friedrich <jochen@scram.de>
Acked-by: David S. Miller <davem@davemloft.net>
Acked-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
| -rw-r--r-- | drivers/of/Kconfig | 6 | ||||
| -rw-r--r-- | drivers/of/Makefile | 1 | ||||
| -rw-r--r-- | drivers/of/i2c.c | 115 | ||||
| -rw-r--r-- | include/linux/of_i2c.h | 24 | 
4 files changed, 146 insertions, 0 deletions
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 3354ad766a4..7c305317f37 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig @@ -7,3 +7,9 @@ config OF_GPIO  	depends on OF && PPC_OF && HAVE_GPIO_LIB  	help  	  OpenFirmware GPIO accessors + +config OF_I2C +	def_bool y +	depends on OF && I2C +	help +	  OpenFirmware I2C accessors diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 5a61f70b402..a07b95362c5 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile @@ -1,3 +1,4 @@  obj-y = base.o  obj-$(CONFIG_OF_DEVICE) += device.o platform.o  obj-$(CONFIG_OF_GPIO)   += gpio.o +obj-$(CONFIG_OF_I2C)	+= i2c.o diff --git a/drivers/of/i2c.c b/drivers/of/i2c.c new file mode 100644 index 00000000000..63168917115 --- /dev/null +++ b/drivers/of/i2c.c @@ -0,0 +1,115 @@ +/* + * OF helpers for the I2C API + * + * Copyright (c) 2008 Jochen Friedrich <jochen@scram.de> + * + * Based on a previous patch from Jon Smirl <jonsmirl@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/i2c.h> +#include <linux/of.h> + +struct i2c_driver_device { +	char    *of_device; +	char    *i2c_type; +}; + +static struct i2c_driver_device i2c_devices[] = { +	{ "dallas,ds1374", "rtc-ds1374" }, +}; + +static int of_find_i2c_driver(struct device_node *node, +			      struct i2c_board_info *info) +{ +	int i, cplen; +	const char *compatible; +	const char *p; + +	/* 1. search for exception list entry */ +	for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) { +		if (!of_device_is_compatible(node, i2c_devices[i].of_device)) +			continue; +		if (strlcpy(info->type, i2c_devices[i].i2c_type, +			    I2C_NAME_SIZE) >= I2C_NAME_SIZE) +			return -ENOMEM; + +		return 0; +	} + +	compatible = of_get_property(node, "compatible", &cplen); +	if (!compatible) +		return -ENODEV; + +	/* 2. search for linux,<i2c-type> entry */ +	p = compatible; +	while (cplen > 0) { +		if (!strncmp(p, "linux,", 6)) { +			p += 6; +			if (strlcpy(info->type, p, +				    I2C_NAME_SIZE) >= I2C_NAME_SIZE) +				return -ENOMEM; +			return 0; +		} + +		i = strlen(p) + 1; +		p += i; +		cplen -= i; +	} + +	/* 3. take fist compatible entry and strip manufacturer */ +	p = strchr(compatible, ','); +	if (!p) +		return -ENODEV; +	p++; +	if (strlcpy(info->type, p, I2C_NAME_SIZE) >= I2C_NAME_SIZE) +		return -ENOMEM; +	return 0; +} + +void of_register_i2c_devices(struct i2c_adapter *adap, +			     struct device_node *adap_node) +{ +	void *result; +	struct device_node *node; + +	for_each_child_of_node(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 > (1 << 10) - 1) { +			printk(KERN_ERR +			       "of-i2c: invalid i2c device entry\n"); +			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) { +			irq_dispose_mapping(info.irq); +			continue; +		} + +		info.addr = *addr; + +		request_module(info.type); + +		result = i2c_new_device(adap, &info); +		if (result == NULL) { +			printk(KERN_ERR +			       "of-i2c: Failed to load driver for %s\n", +			       info.type); +			irq_dispose_mapping(info.irq); +			continue; +		} +	} +} +EXPORT_SYMBOL(of_register_i2c_devices); diff --git a/include/linux/of_i2c.h b/include/linux/of_i2c.h new file mode 100644 index 00000000000..2e5a9673204 --- /dev/null +++ b/include/linux/of_i2c.h @@ -0,0 +1,24 @@ +/* + * Generic I2C API implementation for PowerPC. + * + * Copyright (c) 2008 Jochen Friedrich <jochen@scram.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __LINUX_OF_I2C_H +#define __LINUX_OF_I2C_H + +#include <linux/i2c.h> + +#ifdef CONFIG_OF_I2C + +void of_register_i2c_devices(struct i2c_adapter *adap, +			     struct device_node *adap_node); + +#endif /* CONFIG_OF_I2C */ + +#endif /* __LINUX_OF_I2C_H */  |