[RFC] Rework of i2c-mpc.c - Freescale i2c driver

Jon Smirl jonsmirl at gmail.com
Wed Nov 7 06:02:12 EST 2007


Second pass at extending i2c core to accept strings of aliases for the
module. This version eliminate the need for separate name and type
fields when selecting a driver. PowerPC has to have a mapping from
device tree names to the i2c drivers, it makes sense to keep this
mapping inside the i2c driver.

Extend i2c-core to support lists of device tree compatible names when
matching drivers

From: Jon Smirl <jonsmirl at gmail.com>


---

 drivers/i2c/busses/i2c-mpc.c |   37 +++++++------------------------------
 drivers/i2c/i2c-core.c       |   35 ++++++++++++++++++-----------------
 drivers/rtc/rtc-pcf8563.c    |    1 +
 drivers/rtc/rtc-rs5c372.c    |    3 ++-
 include/linux/i2c.h          |   13 +++++++++----
 5 files changed, 37 insertions(+), 52 deletions(-)


diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 4ddebe4..30420ad 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -312,34 +312,6 @@ static struct i2c_adapter mpc_ops = {
 	.retries = 1
 };

-struct i2c_driver_device {
-	char	*of_device;
-	char	*i2c_driver;
-	char	*i2c_type;
-};
-
-static struct i2c_driver_device i2c_devices[] = {
-	{"ricoh,rs5c372a", "rtc-rs5c372", "rs5c372a",},
-	{"ricoh,rs5c372b", "rtc-rs5c372", "rs5c372b",},
-	{"ricoh,rv5c386",  "rtc-rs5c372", "rv5c386",},
-	{"ricoh,rv5c387a", "rtc-rs5c372", "rv5c387a",},
-	{"epson,pcf8564", "rtc-pcf8563", "pcf8564",},
-};
-
-static int 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 of_register_i2c_devices(struct i2c_adapter *adap, struct
device_node *adap_node)
 {
 	struct device_node *node = NULL;
@@ -347,11 +319,12 @@ static void of_register_i2c_devices(struct
i2c_adapter *adap, struct device_node
 	while ((node = of_get_next_child(adap_node, node))) {
 		struct i2c_board_info info;
 		const u32 *addr;
+		const char *compatible;
 		int len;

 		addr = of_get_property(node, "reg", &len);
 		if (!addr || len < sizeof(int) || *addr > (1 << 10) - 1) {
-			printk(KERN_WARNING "i2c-mpc.c: invalid i2c device entry\n");
+			printk(KERN_WARNING "i2c-mpc.c: invalid entry, missing reg attribute\n");
 			continue;
 		}

@@ -359,8 +332,12 @@ static void of_register_i2c_devices(struct
i2c_adapter *adap, struct device_node
 		if (info.irq == NO_IRQ)
 			info.irq = -1;

-		if (of_find_i2c_driver(node, &info) < 0)
+		compatible = of_get_property(node, "compatible", &len);
+		if (!compatible) {
+			printk(KERN_WARNING "i2c-mpc.c: invalid entry, missing compatible
attribute\n");
 			continue;
+		}
+		strncpy(info.name, compatible, sizeof(info.name));

 		info.platform_data = NULL;
 		info.addr = *addr;
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index d663e69..d9a70c2 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -17,7 +17,7 @@
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
 /* ------------------------------------------------------------------------- */

-/* With some changes from Kyösti Mälkki <kmalkki at cc.hut.fi>.
+/* With some changes from Kyösti MÀlkki <kmalkki at cc.hut.fi>.
    All SMBus-related things are written by Frodo Looijaard <frodol at dds.nl>
    SMBus 2.0 support by Mark Studebaker <mdsxyz123 at yahoo.com> and
    Jean Delvare <khali at linux-fr.org> */
@@ -51,6 +51,7 @@ static int i2c_device_match(struct device *dev,
struct device_driver *drv)
 {
 	struct i2c_client	*client = to_i2c_client(dev);
 	struct i2c_driver	*driver = to_i2c_driver(drv);
+	char const **alias;

 	/* make legacy i2c drivers bypass driver model probing entirely;
 	 * such drivers scan each i2c adapter/bus themselves.
@@ -60,8 +61,18 @@ static int i2c_device_match(struct device *dev,
struct device_driver *drv)

 	/* new style drivers use the same kind of driver matching policy
 	 * as platform devices or SPI:  compare device and driver IDs.
+	 * Match against arrary of alias device tree names. When a match
+	 * is found change the reference to point at the copy inside the
+	 * chip driver allowing the caller's string to be freed.
 	 */
-	return strcmp(client->driver_name, drv->name) == 0;
+	alias = driver->aliases;
+	while (*alias) {
+		if (strcmp(client->name, *alias) == 0) {
+			return true;
+		}
+		alias++;
+	}
+	return 0;
 }

 #ifdef	CONFIG_HOTPLUG
@@ -74,11 +85,11 @@ static int i2c_device_uevent(struct device *dev,
char **envp, int num_envp,
 	int			i = 0, length = 0;

 	/* by definition, legacy drivers can't hotplug */
-	if (dev->driver || !client->driver_name)
+	if (dev->driver || !client->name)
 		return 0;

 	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-			"MODALIAS=%s", client->driver_name))
+			"MODALIAS=%s", client->name))
 		return -ENOMEM;
 	envp[i] = NULL;
 	dev_dbg(dev, "uevent\n");
@@ -169,22 +180,15 @@ static void i2c_client_dev_release(struct device *dev)
 	kfree(to_i2c_client(dev));
 }

-static ssize_t show_client_name(struct device *dev, struct
device_attribute *attr, char *buf)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-	return sprintf(buf, "%s\n", client->name);
-}
-
 static ssize_t show_modalias(struct device *dev, struct
device_attribute *attr, char *buf)
 {
 	struct i2c_client *client = to_i2c_client(dev);
-	return client->driver_name
-		? sprintf(buf, "%s\n", client->driver_name)
+	return client->name
+		? sprintf(buf, "%s\n", client->name)
 		: 0;
 }

 static struct device_attribute i2c_dev_attrs[] = {
-	__ATTR(name, S_IRUGO, show_client_name, NULL),
 	/* modalias helps coldplug:  modprobe $(cat .../modalias) */
 	__ATTR(modalias, S_IRUGO, show_modalias, NULL),
 	{ },
@@ -233,10 +237,7 @@ i2c_new_device(struct i2c_adapter *adap, struct
i2c_board_info const *info)
 	client->flags = info->flags;
 	client->addr = info->addr;
 	client->irq = info->irq;
-
-	strlcpy(client->driver_name, info->driver_name,
-		sizeof(client->driver_name));
-	strlcpy(client->name, info->type, sizeof(client->name));
+	strlcpy(client->name, info->name, sizeof(info->name));

 	/* a new style driver may be bound to this device when we
 	 * return from this function, or any later moment (e.g. maybe
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index b778d35..8162f77 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -266,6 +266,7 @@ static struct i2c_driver pcf8563_driver = {
 	.driver		= {
 		.name	= "rtc-pcf8563",
 	},
+	.aliases = (char const *[]){"philips,pcf8563", "epson,rtc8564", 0},
 	.id		= I2C_DRIVERID_PCF8563,
 	.probe = &pcf8563_probe,
 	.remove = &pcf8563_remove,
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 6b67b50..b2da981 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -62,11 +62,11 @@


 enum rtc_type {
-	rtc_undef = 0,
 	rtc_rs5c372a,
 	rtc_rs5c372b,
 	rtc_rv5c386,
 	rtc_rv5c387a,
+	rtc_undef,
 };

 /* REVISIT:  this assumes that:
@@ -649,6 +649,7 @@ static struct i2c_driver rs5c372_driver = {
 	.driver		= {
 		.name	= "rtc-rs5c372",
 	},
+	.aliases	= (char const
*[]){"ricoh,rs5c372a","ricoh,rs5c372b","ricoh,rv5c386","ricoh,rv5c387a",	0},
 	.probe		= rs5c372_probe,
 	.remove		= rs5c372_remove,
 };
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 2a32f2f..4384cc1 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -107,6 +107,13 @@ extern s32 i2c_smbus_write_i2c_block_data(struct
i2c_client * client,
 struct i2c_driver {
 	int id;
 	unsigned int class;
+	
+	/* Alias names for the driver. Used to support device trees on
+	 * the PowerPC architecture. Device tree names take the form of
+	 * vendor,chip. For example "epson,rtc8564". Alias is a list of
+	 * strings terminated by a zero entry.
+	 */
+	char const **aliases;

 	/* Notifies the driver that a new bus has appeared. This routine
 	 * can be used by the driver to test if the bus meets its conditions
@@ -146,7 +153,7 @@ struct i2c_driver {
 };
 #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)

-#define I2C_NAME_SIZE	20
+#define I2C_NAME_SIZE	40

 /**
  * struct i2c_client - represent an I2C slave device
@@ -181,7 +188,6 @@ struct i2c_client {
 					/* to the client		*/
 	struct device dev;		/* the device structure		*/
 	int irq;			/* irq issued by device (or -1) */
-	char driver_name[KOBJ_NAME_LEN];
 	struct list_head list;
 	struct completion released;
 };
@@ -225,8 +231,7 @@ static inline void i2c_set_clientdata (struct
i2c_client *dev, void *data)
  * with the adapter already known.
  */
 struct i2c_board_info {
-	char		driver_name[KOBJ_NAME_LEN];
-	char		type[I2C_NAME_SIZE];
+	char 		name[I2C_NAME_SIZE];
 	unsigned short	flags;
 	unsigned short	addr;
 	void		*platform_data;

-- 
Jon Smirl
jonsmirl at gmail.com



More information about the Linuxppc-dev mailing list