[i2c] [PATCH] Allow alias names for i2c drivers using MODULE_DEVICE_TABLE()

Jon Smirl jonsmirl at gmail.com
Mon Nov 26 01:13:13 CET 2007


This patch allows new style i2c chip drivers to have alias names using
the official kernel aliasing system and MODULE_DEVICE_TABLE(). I've
tested it on PowerPC and x86. This change is required for PowerPC
device tree support.

i2c names used in PowerPC device trees are set by an outside entity
and do no match the driver names being used by Linux. Aliases map
these names onto the correct module. For example "ricoh,rv5c387a" onto
rtc-rs5c372.

Discussion of what to do with i2c_client.name and
i2c_client.driver_name is needed. Now that the modules support
official aliases one of these fields is not needed anymore.

struct i2c_client {
	char name[I2C_NAME_SIZE];
	char driver_name[KOBJ_NAME_LEN];
};

These drivers need to be fixed to be used with this patch. I've
already fixed ds1307, ds1374, and rs5c372. If this patch is accepted
I'll fix the rest, it only takes about 20 minutes per driver.

drivers/i2c/chips/ds1682.c
drivers/i2c/chips/tsl2550.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1374.c
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-rs5c372.c

From: Jon Smirl <jonsmirl at gmail.com>
---

 drivers/i2c/i2c-core.c          |   34 +++++++++++++++++++++++++++-------
 include/linux/i2c.h             |    5 ++---
 include/linux/mod_devicetable.h |    9 +++++++++
 3 files changed, 38 insertions(+), 10 deletions(-)


diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index b5e13e4..76f48be 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -47,10 +47,26 @@ static DEFINE_IDR(i2c_adapter_idr);

 /* ------------------------------------------------------------------------- */

-static int i2c_device_match(struct device *dev, struct device_driver *drv)
+static const struct i2c_device_id * i2c_device_match(const struct
i2c_device_id *id, struct i2c_client *client)
+{
+	/* new style drivers use the same kind of driver matching policy
+	 * as platform devices or SPI:  compare device and driver IDs.
+	 */
+	if (id) {
+    	while (id->name[0]) {
+        	if (strcmp(client->driver_name, id->name) == 0)
+            	return id;
+            id++;
+        }
+    }
+    return NULL;
+}
+
+static int i2c_bus_match(struct device *dev, struct device_driver *drv)
 {
 	struct i2c_client	*client = to_i2c_client(dev);
 	struct i2c_driver	*driver = to_i2c_driver(drv);
+	const struct i2c_device_id *found_id;

 	/* make legacy i2c drivers bypass driver model probing entirely;
 	 * such drivers scan each i2c adapter/bus themselves.
@@ -58,10 +74,11 @@ static int i2c_device_match(struct device *dev,
struct device_driver *drv)
 	if (!is_newstyle_driver(driver))
 		return 0;

-	/* new style drivers use the same kind of driver matching policy
-	 * as platform devices or SPI:  compare device and driver IDs.
-	 */
-	return strcmp(client->driver_name, drv->name) == 0;
+    found_id = i2c_device_match(driver->id_table, client);
+    if (found_id)
+            return 1;
+
+    return 0;
 }

 #ifdef	CONFIG_HOTPLUG
@@ -89,12 +106,15 @@ static int i2c_device_probe(struct device *dev)
 {
 	struct i2c_client	*client = to_i2c_client(dev);
 	struct i2c_driver	*driver = to_i2c_driver(dev->driver);
+	const struct i2c_device_id *id;

 	if (!driver->probe)
 		return -ENODEV;
 	client->driver = driver;
 	dev_dbg(dev, "probe\n");
-	return driver->probe(client);
+	
+    id = i2c_device_match(driver->id_table, client);
+	return driver->probe(client, id);
 }

 static int i2c_device_remove(struct device *dev)
@@ -189,7 +209,7 @@ static struct device_attribute i2c_dev_attrs[] = {
 static struct bus_type i2c_bus_type = {
 	.name		= "i2c",
 	.dev_attrs	= i2c_dev_attrs,
-	.match		= i2c_device_match,
+	.match		= i2c_bus_match,
 	.uevent		= i2c_device_uevent,
 	.probe		= i2c_device_probe,
 	.remove		= i2c_device_remove,
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index a100c9f..56d2dca 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -126,7 +126,7 @@ struct i2c_driver {
 	 * With the driver model, device enumeration is NEVER done by drivers;
 	 * it's done by infrastructure.  (NEW STYLE DRIVERS ONLY)
 	 */
-	int (*probe)(struct i2c_client *);
+	int (*probe)(struct i2c_client *, const struct i2c_device_id *id);
 	int (*remove)(struct i2c_client *);

 	/* driver model interfaces that don't relate to enumeration  */
@@ -141,11 +141,10 @@ struct i2c_driver {

 	struct device_driver driver;
 	struct list_head list;
+	struct i2c_device_id *id_table;
 };
 #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)

-#define I2C_NAME_SIZE	20
-
 /**
  * struct i2c_client - represent an I2C slave device
  * @flags: I2C_CLIENT_TEN indicates the device uses a ten bit chip address;
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index e9fddb4..688fad6 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -367,4 +367,13 @@ struct virtio_device_id {
 };
 #define VIRTIO_DEV_ANY_ID	0xffffffff

+/* i2c */
+
+#define I2C_NAME_SIZE	40
+struct i2c_device_id {
+	char name[I2C_NAME_SIZE];
+	kernel_ulong_t driver_data;	/* Data private to the driver */
+};
+
+
 #endif /* LINUX_MOD_DEVICETABLE_H */

--------------------------------------------------------------------------------------------------------
Example change to a chip driver

diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 6b67b50..de0d458 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -62,13 +62,26 @@


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

+static struct i2c_device_id rs5c372_id[] = {
+	{"rtc-rs5c372", rtc_rs5c372a},
+	{"rs5c372a", rtc_rs5c372a},
+	{"rs5c372b", rtc_rs5c372b},
+	{"rv5c386", rtc_rv5c386},
+	{"rv5c387a", rtc_rv5c387a},
+	{"ricoh,rs5c372a", rtc_rs5c372a},
+	{"ricoh,rs5c372b", rtc_rs5c372b},
+	{"ricoh,rv5c386", rtc_rv5c386},
+	{"ricoh,rv5c387a", rtc_rv5c387a},
+	{},
+};
+MODULE_DEVICE_TABLE(i2c, rs5c372_id);
+
 /* REVISIT:  this assumes that:
  *  - we're in the 21st century, so it's safe to ignore the century
  *    bit for rv5c38[67] (REG_MONTH bit 7);
@@ -494,7 +507,7 @@ static void rs5c_sysfs_unregister(struct device *dev)

 static struct i2c_driver rs5c372_driver;

-static int rs5c372_probe(struct i2c_client *client)
+static int rs5c372_probe(struct i2c_client *client, const struct
i2c_device_id *id)
 {
 	int err = 0;
 	struct rs5c372 *rs5c372;
@@ -522,18 +535,7 @@ static int rs5c372_probe(struct i2c_client *client)
 	if (err < 0)
 		goto exit_kfree;

-	if (strcmp(client->name, "rs5c372a") == 0)
-		rs5c372->type = rtc_rs5c372a;
-	else if (strcmp(client->name, "rs5c372b") == 0)
-		rs5c372->type = rtc_rs5c372b;
-	else if (strcmp(client->name, "rv5c386") == 0)
-		rs5c372->type = rtc_rv5c386;
-	else if (strcmp(client->name, "rv5c387a") == 0)
-		rs5c372->type = rtc_rv5c387a;
-	else {
-		rs5c372->type = rtc_rs5c372b;
-		dev_warn(&client->dev, "assuming rs5c372b\n");
-	}
+	rs5c372->type = id->driver_data;

 	/* clock may be set for am/pm or 24 hr time */
 	switch (rs5c372->type) {
@@ -651,6 +653,7 @@ static struct i2c_driver rs5c372_driver = {
 	},
 	.probe		= rs5c372_probe,
 	.remove		= rs5c372_remove,
+	.id_table	= rs5c372_id,
 };

 static __init int rs5c372_init(void)


-- 
Jon Smirl
jonsmirl at gmail.com



More information about the i2c mailing list