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 <[EMAIL PROTECTED]> --- 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 <[EMAIL PROTECTED]>. +/* With some changes from Kyösti MÀlkki <[EMAIL PROTECTED]>. All SMBus-related things are written by Frodo Looijaard <[EMAIL PROTECTED]> SMBus 2.0 support by Mark Studebaker <[EMAIL PROTECTED]> and Jean Delvare <[EMAIL PROTECTED]> */ @@ -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 [EMAIL PROTECTED] _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev