* [PATCH 1/4] i2c: Add detection capability to new-style drivers
[not found] ` <20080606145212.76f95d52-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
@ 2008-06-06 13:02 ` Jean Delvare
2008-06-06 14:09 ` [PATCH 2/4] i2c: Convert the lm90 driver to a new-style i2c driver Jean Delvare
` (3 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Jean Delvare @ 2008-06-06 13:02 UTC (permalink / raw)
To: Linux I2C; +Cc: David Brownell
Add a mechanism to let new-style i2c drivers auto-detect devices they
would support and ask i2c-core to instantiate them. This is a
replacement for legacy drivers, much cleaner.
Signed-off-by: Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org>
---
This patch depends on:
http://khali.linux-fr.org/devel/linux-2.6/jdelvare-i2c/i2c-use-class_for_each_device.patch
http://khali.linux-fr.org/devel/linux-2.6/jdelvare-i2c/i2c-simplify-i2c_del_driver.patch
Implementation note: i2c_detect and i2c_detect_address are basically
clones of i2c_probe and i2c_probe_address but operating on a callback
with a slightly different prototype. This duplicated code accounts
for a large part of the patch, but once legacy drivers are gone,
i2c_probe and i2c_probe_address will be removed, so this is no
long-term duplication.
drivers/i2c/i2c-core.c | 207 +++++++++++++++++++++++++++++++++++++++++++++---
include/linux/i2c.h | 14 +++
2 files changed, 210 insertions(+), 11 deletions(-)
--- linux-2.6.26-rc5.orig/include/linux/i2c.h 2008-06-05 21:04:35.000000000 +0200
+++ linux-2.6.26-rc5/include/linux/i2c.h 2008-06-05 21:54:49.000000000 +0200
@@ -43,6 +43,7 @@ struct i2c_adapter;
struct i2c_client;
struct i2c_driver;
union i2c_smbus_data;
+struct i2c_board_info;
/*
* The master routines are the ones normally used to transmit data to devices
@@ -99,6 +100,11 @@ extern s32 i2c_smbus_write_i2c_block_dat
*
* The driver.owner field should be set to the module owner of this driver.
* The driver.name field should be set to the name of this driver.
+ *
+ * @class: What kind of i2c device we may instantiate
+ * @detect: Callback for device detection
+ * @address_data: The I2C addresses to probe, ignore or force
+ * @clients: List of detected clients we created
*/
struct i2c_driver {
@@ -140,6 +146,12 @@ struct i2c_driver {
struct device_driver driver;
const struct i2c_device_id *id_table;
+
+ /* Device detection callback for automatic device creation */
+ int (*detect)(struct i2c_adapter *, int address, int kind,
+ struct i2c_board_info *);
+ const struct i2c_client_address_data *address_data;
+ struct list_head clients;
};
#define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
@@ -155,6 +167,7 @@ struct i2c_driver {
* @dev: Driver model device node for the slave.
* @irq: indicates the IRQ generated by this device (if any)
* @list: list of active/busy clients (DEPRECATED)
+ * @detected: member of a i2c_driver.clients list
* @released: used to synchronize client releases & detaches and references
*
* An i2c_client identifies a single device (i.e. chip) connected to an
@@ -172,6 +185,7 @@ struct i2c_client {
struct device dev; /* the device structure */
int irq; /* irq issued by device (or -1) */
struct list_head list; /* DEPRECATED */
+ struct list_head detected;
struct completion released;
};
#define to_i2c_client(d) container_of(d, struct i2c_client, dev)
--- linux-2.6.26-rc5.orig/drivers/i2c/i2c-core.c 2008-06-05 21:04:35.000000000 +0200
+++ linux-2.6.26-rc5/drivers/i2c/i2c-core.c 2008-06-06 14:04:40.000000000 +0200
@@ -42,7 +42,9 @@
static DEFINE_MUTEX(core_lock);
static DEFINE_IDR(i2c_adapter_idr);
-#define is_newstyle_driver(d) ((d)->probe || (d)->remove)
+#define is_newstyle_driver(d) ((d)->probe || (d)->remove || (d)->detect)
+
+static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
/* ------------------------------------------------------------------------- */
@@ -409,6 +411,10 @@ static int i2c_do_add_adapter(struct dev
struct i2c_driver *driver = to_i2c_driver(d);
struct i2c_adapter *adap = data;
+ /* Detect supported devices on that bus, and instantiate them */
+ i2c_detect(adap, driver);
+
+ /* Let legacy drivers scan this bus for matching devices */
if (driver->attach_adapter) {
/* We ignore the return code; if it fails, too bad */
driver->attach_adapter(adap);
@@ -448,7 +454,7 @@ static int i2c_register_adapter(struct i
if (adap->nr < __i2c_first_dynamic_bus_num)
i2c_scan_static_board_info(adap);
- /* let legacy drivers scan this bus for matching devices */
+ /* Notify drivers */
dummy = bus_for_each_drv(&i2c_bus_type, NULL, adap,
i2c_do_add_adapter);
@@ -554,14 +560,26 @@ static int i2c_do_del_adapter(struct dev
{
struct i2c_driver *driver = to_i2c_driver(d);
struct i2c_adapter *adapter = data;
+ struct i2c_client *client, *_n;
int res;
+ /* Remove the devices we created ourselves */
+ list_for_each_entry_safe(client, _n, &driver->clients, detected) {
+ if (client->adapter == adapter) {
+ dev_dbg(&adapter->dev, "Removing %s at 0x%x\n",
+ client->name, client->addr);
+ list_del(&client->detected);
+ i2c_unregister_device(client);
+ }
+ }
+
if (!driver->detach_adapter)
return 0;
res = driver->detach_adapter(adapter);
if (res)
dev_err(&adapter->dev, "detach_adapter failed (%d) "
"for driver [%s]\n", res, driver->driver.name);
+
return res;
}
@@ -642,7 +660,10 @@ static int __attach_adapter(struct devic
struct i2c_adapter *adapter = to_i2c_adapter(dev);
struct i2c_driver *driver = data;
- driver->attach_adapter(adapter);
+ i2c_detect(adapter, driver);
+
+ if (driver->attach_adapter)
+ driver->attach_adapter(adapter);
return 0;
}
@@ -686,10 +707,10 @@ int i2c_register_driver(struct module *o
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
- /* legacy drivers scan i2c busses directly */
- if (driver->attach_adapter)
- class_for_each_device(&i2c_adapter_class, driver,
- __attach_adapter);
+ INIT_LIST_HEAD(&driver->clients);
+ /* Walk the adapters that are already present */
+ class_for_each_device(&i2c_adapter_class, driver,
+ __attach_adapter);
mutex_unlock(&core_lock);
return 0;
@@ -700,6 +721,17 @@ static int __detach_adapter(struct devic
{
struct i2c_adapter *adapter = to_i2c_adapter(dev);
struct i2c_driver *driver = data;
+ struct i2c_client *client, *_n;
+
+ list_for_each_entry_safe(client, _n, &driver->clients, detected) {
+ dev_dbg(&adapter->dev, "Removing %s at 0x%x\n",
+ client->name, client->addr);
+ list_del(&client->detected);
+ i2c_unregister_device(client);
+ }
+
+ if (is_newstyle_driver(driver))
+ return 0;
/* Have a look at each adapter, if clients of this driver are still
* attached. If so, detach them to be able to kill the driver
@@ -738,10 +770,7 @@ void i2c_del_driver(struct i2c_driver *d
{
mutex_lock(&core_lock);
- /* legacy driver? */
- if (!is_newstyle_driver(driver))
- class_for_each_device(&i2c_adapter_class, driver,
- __detach_adapter);
+ class_for_each_device(&i2c_adapter_class, driver, __detach_adapter);
driver_unregister(&driver->driver);
pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name);
@@ -1196,6 +1225,162 @@ int i2c_probe(struct i2c_adapter *adapte
}
EXPORT_SYMBOL(i2c_probe);
+/* Separate detection function for new-style drivers */
+static int i2c_detect_address(struct i2c_adapter *adapter,
+ int addr, int kind, struct i2c_driver *driver)
+{
+ struct i2c_board_info info;
+ struct i2c_client *client;
+ int err;
+
+ /* Make sure the address is valid */
+ if (addr < 0x03 || addr > 0x77) {
+ dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
+ addr);
+ return -EINVAL;
+ }
+
+ /* Skip if already in use */
+ if (i2c_check_addr(adapter, addr))
+ return 0;
+
+ /* Make sure there is something at this address, unless forced */
+ if (kind < 0) {
+ if (i2c_smbus_xfer(adapter, addr, 0, 0, 0,
+ I2C_SMBUS_QUICK, NULL) < 0)
+ return 0;
+
+ /* prevent 24RF08 corruption */
+ if ((addr & ~0x0f) == 0x50)
+ i2c_smbus_xfer(adapter, addr, 0, 0, 0,
+ I2C_SMBUS_QUICK, NULL);
+ }
+
+ /* Finally call the custom detection function */
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ err = driver->detect(adapter, addr, kind, &info);
+ if (err) {
+ /* -ENODEV can be returned if there is a chip at the given address
+ but it isn't supported by this chip driver. We catch it here as
+ this isn't an error. */
+ return err == -ENODEV ? 0 : err;
+ }
+
+ /* Consistency check */
+ if (info.type[0] == '\0' || info.addr != addr) {
+ dev_err(&adapter->dev, "Detection function returned "
+ "inconsistent data for 0x%x\n", addr);
+ } else {
+ /* Detection succeeded, instantiate the device */
+ dev_dbg(&adapter->dev, "Creating %s at 0x%x\n",
+ info.type, info.addr);
+ client = i2c_new_device(adapter, &info);
+ list_add_tail(&client->detected, &driver->clients);
+ }
+ return 0;
+}
+
+static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver)
+{
+ const struct i2c_client_address_data *address_data;
+ int i, err;
+ int adap_id = i2c_adapter_id(adapter);
+
+ if (!driver->detect)
+ return 0;
+ address_data = driver->address_data;
+
+ /* Force entries are done first, and are not affected by ignore
+ entries */
+ if (address_data->forces) {
+ const unsigned short * const *forces = address_data->forces;
+ int kind;
+
+ for (kind = 0; forces[kind]; kind++) {
+ for (i = 0; forces[kind][i] != I2C_CLIENT_END;
+ i += 2) {
+ if (forces[kind][i] == adap_id
+ || forces[kind][i] == ANY_I2C_BUS) {
+ dev_dbg(&adapter->dev, "found force "
+ "parameter for adapter %d, "
+ "addr 0x%02x, kind %d\n",
+ adap_id, forces[kind][i + 1],
+ kind);
+ err = i2c_detect_address(adapter,
+ forces[kind][i + 1],
+ kind, driver);
+ if (err)
+ return err;
+ }
+ }
+ }
+ }
+
+ /* Stop here if we can't use SMBUS_QUICK */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) {
+ if (address_data->probe[0] == I2C_CLIENT_END
+ && address_data->normal_i2c[0] == I2C_CLIENT_END)
+ return 0;
+
+ dev_warn(&adapter->dev, "SMBus Quick command not supported, "
+ "can't probe for chips\n");
+ return -EOPNOTSUPP;
+ }
+
+ /* Probe entries are done second, and are not affected by ignore
+ entries either */
+ for (i = 0; address_data->probe[i] != I2C_CLIENT_END; i += 2) {
+ if (address_data->probe[i] == adap_id
+ || address_data->probe[i] == ANY_I2C_BUS) {
+ dev_dbg(&adapter->dev, "found probe parameter for "
+ "adapter %d, addr 0x%02x\n", adap_id,
+ address_data->probe[i + 1]);
+ err = i2c_detect_address(adapter,
+ address_data->probe[i + 1],
+ -1, driver);
+ if (err)
+ return err;
+ }
+ }
+
+ /* Stop here if the classes do not match */
+ if (!(adapter->class & driver->class))
+ return 0;
+
+ /* Normal entries are done last, unless shadowed by an ignore entry */
+ for (i = 0; address_data->normal_i2c[i] != I2C_CLIENT_END; i += 1) {
+ int j, ignore;
+
+ ignore = 0;
+ for (j = 0; address_data->ignore[j] != I2C_CLIENT_END;
+ j += 2) {
+ if ((address_data->ignore[j] == adap_id ||
+ address_data->ignore[j] == ANY_I2C_BUS)
+ && address_data->ignore[j + 1]
+ == address_data->normal_i2c[i]) {
+ dev_dbg(&adapter->dev, "found ignore "
+ "parameter for adapter %d, "
+ "addr 0x%02x\n", adap_id,
+ address_data->ignore[j + 1]);
+ ignore = 1;
+ break;
+ }
+ }
+ if (ignore)
+ continue;
+
+ dev_dbg(&adapter->dev, "found normal entry for adapter %d, "
+ "addr 0x%02x\n", adap_id,
+ address_data->normal_i2c[i]);
+ err = i2c_detect_address(adapter, address_data->normal_i2c[i],
+ -1, driver);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
struct i2c_client *
i2c_new_probed_device(struct i2c_adapter *adap,
struct i2c_board_info *info,
--
Jean Delvare
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 2/4] i2c: Convert the lm90 driver to a new-style i2c driver
[not found] ` <20080606145212.76f95d52-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-06-06 13:02 ` [PATCH 1/4] " Jean Delvare
@ 2008-06-06 14:09 ` Jean Delvare
2008-06-06 14:09 ` [PATCH 3/4] i2c: Drop legacy f75375s driver Jean Delvare
` (2 subsequent siblings)
4 siblings, 0 replies; 10+ messages in thread
From: Jean Delvare @ 2008-06-06 14:09 UTC (permalink / raw)
To: Linux I2C; +Cc: David Brownell
The new-style lm90 driver implements the optional detect() callback
to cover the use cases of the legacy driver.
Signed-off-by: Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org>
---
drivers/hwmon/lm90.c | 103 +++++++++++++++++++++++++++++---------------------
1 file changed, 60 insertions(+), 43 deletions(-)
--- linux-2.6.26-rc5.orig/drivers/hwmon/lm90.c 2008-06-05 21:04:34.000000000 +0200
+++ linux-2.6.26-rc5/drivers/hwmon/lm90.c 2008-06-05 22:11:23.000000000 +0200
@@ -187,23 +187,40 @@ I2C_CLIENT_INSMOD_7(lm90, adm1032, lm99,
* Functions declaration
*/
-static int lm90_attach_adapter(struct i2c_adapter *adapter);
static int lm90_detect(struct i2c_adapter *adapter, int address,
- int kind);
+ int kind, struct i2c_board_info *info);
+static int lm90_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
static void lm90_init_client(struct i2c_client *client);
-static int lm90_detach_client(struct i2c_client *client);
+static int lm90_remove(struct i2c_client *client);
static struct lm90_data *lm90_update_device(struct device *dev);
/*
* Driver data (common to all clients)
*/
+static struct i2c_device_id lm90_id[] = {
+ { "lm90", lm90 },
+ { "adm1032", adm1032 },
+ { "lm99", lm99 },
+ { "lm86", lm86 },
+ { "max6657", max6657 },
+ { "adt7461", adt7461 },
+ { "max6680", max6680 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, lm90_id);
+
static struct i2c_driver lm90_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "lm90",
},
- .attach_adapter = lm90_attach_adapter,
- .detach_client = lm90_detach_client,
+ .probe = lm90_probe,
+ .remove = lm90_remove,
+ .id_table = lm90_id,
+ .detect = lm90_detect,
+ .address_data = &addr_data,
};
/*
@@ -211,7 +228,6 @@ static struct i2c_driver lm90_driver = {
*/
struct lm90_data {
- struct i2c_client client;
struct device *hwmon_dev;
struct mutex update_lock;
char valid; /* zero until following fields are valid */
@@ -477,40 +493,26 @@ static int lm90_read_reg(struct i2c_clie
return 0;
}
-static int lm90_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, lm90_detect);
-}
-
-/*
- * The following function does more than just detection. If detection
- * succeeds, it also registers the new chip.
- */
-static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
+/* Returns -ENODEV if no supported device is detected */
+static int lm90_detect(struct i2c_adapter *adapter, int address, int kind,
+ struct i2c_board_info *info)
{
struct i2c_client *new_client;
- struct lm90_data *data;
- int err = 0;
+ int err = -ENODEV;
const char *name = "";
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
goto exit;
- if (!(data = kzalloc(sizeof(struct lm90_data), GFP_KERNEL))) {
+ new_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (!new_client) {
err = -ENOMEM;
goto exit;
}
- /* The common I2C client data is placed right before the
- LM90-specific data. */
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
+ /* Enough to use smbus calls */
new_client->addr = address;
new_client->adapter = adapter;
- new_client->driver = &lm90_driver;
- new_client->flags = 0;
/*
* Now we do the remaining detection. A negative kind means that
@@ -613,7 +615,10 @@ static int lm90_detect(struct i2c_adapte
goto exit_free;
}
}
+ err = 0; /* detection OK */
+ /* Fill the i2c board info */
+ info->addr = address;
if (kind == lm90) {
name = "lm90";
} else if (kind == adm1032) {
@@ -621,7 +626,7 @@ static int lm90_detect(struct i2c_adapte
/* The ADM1032 supports PEC, but only if combined
transactions are not used. */
if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
- new_client->flags |= I2C_CLIENT_PEC;
+ info->flags |= I2C_CLIENT_PEC;
} else if (kind == lm99) {
name = "lm99";
} else if (kind == lm86) {
@@ -633,23 +638,41 @@ static int lm90_detect(struct i2c_adapte
} else if (kind == adt7461) {
name = "adt7461";
}
+ strlcpy(info->type, name, I2C_NAME_SIZE);
+
+exit_free:
+ kfree(new_client);
+exit:
+ return err;
+}
- /* We can fill in the remaining client fields */
- strlcpy(new_client->name, name, I2C_NAME_SIZE);
- data->valid = 0;
- data->kind = kind;
+static int lm90_probe(struct i2c_client *new_client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(new_client->dev.parent);
+ struct lm90_data *data;
+ int err;
+
+ if (!(data = kzalloc(sizeof(struct lm90_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+ i2c_set_clientdata(new_client, data);
mutex_init(&data->update_lock);
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto exit_free;
+ /* Set the device type */
+ data->kind = id->driver_data;
+ if (data->kind == adm1032) {
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
+ new_client->flags &= ~I2C_CLIENT_PEC;
+ }
/* Initialize the LM90 chip */
lm90_init_client(new_client);
/* Register sysfs hooks */
if ((err = sysfs_create_group(&new_client->dev.kobj, &lm90_group)))
- goto exit_detach;
+ goto exit_free;
if (new_client->flags & I2C_CLIENT_PEC) {
if ((err = device_create_file(&new_client->dev,
&dev_attr_pec)))
@@ -672,8 +695,6 @@ static int lm90_detect(struct i2c_adapte
exit_remove_files:
sysfs_remove_group(&new_client->dev.kobj, &lm90_group);
device_remove_file(&new_client->dev, &dev_attr_pec);
-exit_detach:
- i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -710,10 +731,9 @@ static void lm90_init_client(struct i2c_
i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
}
-static int lm90_detach_client(struct i2c_client *client)
+static int lm90_remove(struct i2c_client *client)
{
struct lm90_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm90_group);
@@ -722,9 +742,6 @@ static int lm90_detach_client(struct i2c
device_remove_file(&client->dev,
&sensor_dev_attr_temp2_offset.dev_attr);
- if ((err = i2c_detach_client(client)))
- return err;
-
kfree(data);
return 0;
}
--
Jean Delvare
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 3/4] i2c: Drop legacy f75375s driver
[not found] ` <20080606145212.76f95d52-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-06-06 13:02 ` [PATCH 1/4] " Jean Delvare
2008-06-06 14:09 ` [PATCH 2/4] i2c: Convert the lm90 driver to a new-style i2c driver Jean Delvare
@ 2008-06-06 14:09 ` Jean Delvare
[not found] ` <20080606160957.2ea712bb-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2008-06-06 14:11 ` [PATCH 4/4] i2c: Drop legacy lm75 driver Jean Delvare
2008-06-06 23:17 ` [PATCH 0/4] i2c: Add detection capability to new-style drivers Trent Piepho
4 siblings, 1 reply; 10+ messages in thread
From: Jean Delvare @ 2008-06-06 14:09 UTC (permalink / raw)
To: Linux I2C; +Cc: David Brownell
Drop the legacy f75375s driver, and add a detect callback to the
new-style driver to achieve the same functionality.
Signed-off-by: Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org>
---
drivers/hwmon/f75375s.c | 74 +++++++----------------------------------------
1 file changed, 12 insertions(+), 62 deletions(-)
--- linux-2.6.26-rc5.orig/drivers/hwmon/f75375s.c 2008-06-05 21:04:26.000000000 +0200
+++ linux-2.6.26-rc5/drivers/hwmon/f75375s.c 2008-06-05 22:14:00.000000000 +0200
@@ -114,21 +114,12 @@ struct f75375_data {
s8 temp_max_hyst[2];
};
-static int f75375_attach_adapter(struct i2c_adapter *adapter);
-static int f75375_detect(struct i2c_adapter *adapter, int address, int kind);
-static int f75375_detach_client(struct i2c_client *client);
+static int f75375_detect(struct i2c_adapter *adapter, int address, int kind,
+ struct i2c_board_info *info);
static int f75375_probe(struct i2c_client *client,
const struct i2c_device_id *id);
static int f75375_remove(struct i2c_client *client);
-static struct i2c_driver f75375_legacy_driver = {
- .driver = {
- .name = "f75375_legacy",
- },
- .attach_adapter = f75375_attach_adapter,
- .detach_client = f75375_detach_client,
-};
-
static const struct i2c_device_id f75375_id[] = {
{ "f75373", f75373 },
{ "f75375", f75375 },
@@ -137,12 +128,15 @@ static const struct i2c_device_id f75375
MODULE_DEVICE_TABLE(i2c, f75375_id);
static struct i2c_driver f75375_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "f75375",
},
.probe = f75375_probe,
.remove = f75375_remove,
.id_table = f75375_id,
+ .detect = f75375_detect,
+ .address_data = &addr_data,
};
static inline int f75375_read8(struct i2c_client *client, u8 reg)
@@ -607,22 +601,6 @@ static const struct attribute_group f753
.attrs = f75375_attributes,
};
-static int f75375_detach_client(struct i2c_client *client)
-{
- int err;
-
- f75375_remove(client);
- err = i2c_detach_client(client);
- if (err) {
- dev_err(&client->dev,
- "Client deregistration failed, "
- "client not detached.\n");
- return err;
- }
- kfree(client);
- return 0;
-}
-
static void f75375_init(struct i2c_client *client, struct f75375_data *data,
struct f75375s_platform_data *f75375s_pdata)
{
@@ -700,21 +678,14 @@ static int f75375_remove(struct i2c_clie
return 0;
}
-static int f75375_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, f75375_detect);
-}
-
/* This function is called by i2c_probe */
-static int f75375_detect(struct i2c_adapter *adapter, int address, int kind)
+static int f75375_detect(struct i2c_adapter *adapter, int address, int kind,
+ struct i2c_board_info *info)
{
struct i2c_client *client;
u8 version = 0;
- int err = 0;
+ int err = -ENODEV;
const char *name = "";
- struct i2c_device_id id;
if (!(client = kzalloc(sizeof(*client), GFP_KERNEL))) {
err = -ENOMEM;
@@ -722,7 +693,6 @@ static int f75375_detect(struct i2c_adap
}
client->addr = address;
client->adapter = adapter;
- client->driver = &f75375_legacy_driver;
if (kind < 0) {
u16 vendid = f75375_read16(client, F75375_REG_VENDOR);
@@ -739,6 +709,7 @@ static int f75375_detect(struct i2c_adap
goto exit_free;
}
}
+ err = 0; /* detection OK */
if (kind == f75375) {
name = "f75375";
@@ -746,20 +717,9 @@ static int f75375_detect(struct i2c_adap
name = "f75373";
}
dev_info(&adapter->dev, "found %s version: %02X\n", name, version);
- strlcpy(client->name, name, I2C_NAME_SIZE);
+ strlcpy(info->type, name, I2C_NAME_SIZE);
+ info->addr = address;
- if ((err = i2c_attach_client(client)))
- goto exit_free;
-
- strlcpy(id.name, name, I2C_NAME_SIZE);
- id.driver_data = kind;
- if ((err = f75375_probe(client, &id)) < 0)
- goto exit_detach;
-
- return 0;
-
-exit_detach:
- i2c_detach_client(client);
exit_free:
kfree(client);
exit:
@@ -768,21 +728,11 @@ exit:
static int __init sensors_f75375_init(void)
{
- int status;
- status = i2c_add_driver(&f75375_driver);
- if (status)
- return status;
-
- status = i2c_add_driver(&f75375_legacy_driver);
- if (status)
- i2c_del_driver(&f75375_driver);
-
- return status;
+ return i2c_add_driver(&f75375_driver);
}
static void __exit sensors_f75375_exit(void)
{
- i2c_del_driver(&f75375_legacy_driver);
i2c_del_driver(&f75375_driver);
}
--
Jean Delvare
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 4/4] i2c: Drop legacy lm75 driver
[not found] ` <20080606145212.76f95d52-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
` (2 preceding siblings ...)
2008-06-06 14:09 ` [PATCH 3/4] i2c: Drop legacy f75375s driver Jean Delvare
@ 2008-06-06 14:11 ` Jean Delvare
2008-06-06 23:17 ` [PATCH 0/4] i2c: Add detection capability to new-style drivers Trent Piepho
4 siblings, 0 replies; 10+ messages in thread
From: Jean Delvare @ 2008-06-06 14:11 UTC (permalink / raw)
To: Linux I2C; +Cc: David Brownell
Drop the legacy lm75 driver, and add a detect callback to the
new-style driver to achieve the same functionality.
Signed-off-by: Jean Delvare <khali-PUYAD+kWke1g9hUCZPvPmw@public.gmane.org>
---
This goes on top of David Brownell's patches:
http://lists.lm-sensors.org/pipermail/lm-sensors/2008-April/022931.html
http://lists.lm-sensors.org/pipermail/lm-sensors/2008-May/023040.html
http://lists.lm-sensors.org/pipermail/lm-sensors/2008-May/023041.html
Also available from:
http://jdelvare.pck.nerim.net/sensors/lm75/
drivers/hwmon/lm75.c | 120 ++++++++++++++------------------------------------
1 file changed, 35 insertions(+), 85 deletions(-)
--- linux-2.6.26-rc5.orig/drivers/hwmon/lm75.c 2008-06-05 21:04:26.000000000 +0200
+++ linux-2.6.26-rc5/drivers/hwmon/lm75.c 2008-06-05 22:19:23.000000000 +0200
@@ -54,11 +54,11 @@ enum lm75_type { /* keep sorted in alph
tmp75,
};
-/* Addresses scanned by legacy style driver binding */
+/* Addresses scanned */
static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 0x4c,
0x4d, 0x4e, 0x4f, I2C_CLIENT_END };
-/* Insmod parameters (only for legacy style driver binding) */
+/* Insmod parameters */
I2C_CLIENT_INSMOD_1(lm75);
@@ -217,46 +217,12 @@ static int lm75_remove(struct i2c_client
return 0;
}
-static const struct i2c_device_id lm75_ids[] = {
- { "ds1775", ds1775, },
- { "ds75", ds75, },
- { "lm75", lm75, },
- { "lm75a", lm75a, },
- { "max6625", max6625, },
- { "max6626", max6626, },
- { "mcp980x", mcp980x, },
- { "stds75", stds75, },
- { "tcn75", tcn75, },
- { "tmp100", tmp100, },
- { "tmp101", tmp101, },
- { "tmp175", tmp175, },
- { "tmp275", tmp275, },
- { "tmp75", tmp75, },
- { /* LIST END */ }
-};
-MODULE_DEVICE_TABLE(i2c, lm75_ids);
-
-static struct i2c_driver lm75_driver = {
- .driver = {
- .name = "lm75",
- },
- .probe = lm75_probe,
- .remove = lm75_remove,
- .id_table = lm75_ids,
-};
-
-/*-----------------------------------------------------------------------*/
-
-/* "Legacy" I2C driver binding */
-
-static struct i2c_driver lm75_legacy_driver;
-
-/* This function is called by i2c_probe */
-static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
+static int lm75_detect(struct i2c_adapter *adapter, int address, int kind,
+ struct i2c_board_info *info)
{
int i;
struct i2c_client *new_client;
- int err = 0;
+ int err = -ENODEV;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_WORD_DATA))
@@ -273,8 +239,6 @@ static int lm75_detect(struct i2c_adapte
new_client->addr = address;
new_client->adapter = adapter;
- new_client->driver = &lm75_legacy_driver;
- new_client->flags = 0;
/* Now, we do the remaining detection. There is no identification-
dedicated register so we have to rely on several tricks:
@@ -313,52 +277,49 @@ static int lm75_detect(struct i2c_adapte
|| i2c_smbus_read_word_data(new_client, i + 3) != os)
goto exit_free;
}
+ err = 0; /* detection OK */
/* NOTE: we treat "force=..." and "force_lm75=..." the same.
* Only new-style driver binding distinguishes chip types.
*/
- strlcpy(new_client->name, "lm75", I2C_NAME_SIZE);
-
- /* Tell the I2C layer a new client has arrived */
- err = i2c_attach_client(new_client);
- if (err)
- goto exit_free;
-
- err = lm75_probe(new_client, NULL);
- if (err < 0)
- goto exit_detach;
+ strlcpy(info->type, "lm75", I2C_NAME_SIZE);
+ info->addr = address;
- return 0;
-
-exit_detach:
- i2c_detach_client(new_client);
exit_free:
kfree(new_client);
exit:
return err;
}
-static int lm75_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON))
- return 0;
- return i2c_probe(adapter, &addr_data, lm75_detect);
-}
-
-static int lm75_detach_client(struct i2c_client *client)
-{
- lm75_remove(client);
- i2c_detach_client(client);
- kfree(client);
- return 0;
-}
+static const struct i2c_device_id lm75_ids[] = {
+ { "ds1775", ds1775, },
+ { "ds75", ds75, },
+ { "lm75", lm75, },
+ { "lm75a", lm75a, },
+ { "max6625", max6625, },
+ { "max6626", max6626, },
+ { "mcp980x", mcp980x, },
+ { "stds75", stds75, },
+ { "tcn75", tcn75, },
+ { "tmp100", tmp100, },
+ { "tmp101", tmp101, },
+ { "tmp175", tmp175, },
+ { "tmp275", tmp275, },
+ { "tmp75", tmp75, },
+ { /* LIST END */ }
+};
+MODULE_DEVICE_TABLE(i2c, lm75_ids);
-static struct i2c_driver lm75_legacy_driver = {
+static struct i2c_driver lm75_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
- .name = "lm75_legacy",
+ .name = "lm75",
},
- .attach_adapter = lm75_attach_adapter,
- .detach_client = lm75_detach_client,
+ .probe = lm75_probe,
+ .remove = lm75_remove,
+ .id_table = lm75_ids,
+ .detect = lm75_detect,
+ .address_data = &addr_data,
};
/*-----------------------------------------------------------------------*/
@@ -424,22 +385,11 @@ static struct lm75_data *lm75_update_dev
static int __init sensors_lm75_init(void)
{
- int status;
-
- status = i2c_add_driver(&lm75_driver);
- if (status < 0)
- return status;
-
- status = i2c_add_driver(&lm75_legacy_driver);
- if (status < 0)
- i2c_del_driver(&lm75_driver);
-
- return status;
+ return i2c_add_driver(&lm75_driver);
}
static void __exit sensors_lm75_exit(void)
{
- i2c_del_driver(&lm75_legacy_driver);
i2c_del_driver(&lm75_driver);
}
--
Jean Delvare
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH 0/4] i2c: Add detection capability to new-style drivers
[not found] ` <20080606145212.76f95d52-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
` (3 preceding siblings ...)
2008-06-06 14:11 ` [PATCH 4/4] i2c: Drop legacy lm75 driver Jean Delvare
@ 2008-06-06 23:17 ` Trent Piepho
[not found] ` <Pine.LNX.4.58.0806061550510.10290-13q4cmjDBaTP3RPoUHIrnuTW4wlIGRCZ@public.gmane.org>
4 siblings, 1 reply; 10+ messages in thread
From: Trent Piepho @ 2008-06-06 23:17 UTC (permalink / raw)
To: Jean Delvare; +Cc: David Brownell, Linux I2C
On Fri, 6 Jun 2008, Jean Delvare wrote:
> The mechanism behind the device detection callback is as follows:
> * When a new-style i2c_driver is added, for each existing i2c_adapter,
> address_data (those format is the same as what i2c_probe() is already
> using for legacy drivers) is processed by i2c-core. For each relevant
> address, the detect callback will be called, with a pointer to an
> empty struct i2c_board_info address as the last parameter. The detect
> callback will attempt to identify a supported device at the given
> address, and if successful, it will fill the struct i2c_board_info
> with the parameters required to instantiate a new-style i2c device.
Isn't the detect callback going to be the same for almost every driver?
It seems like you could have the i2c core do the detection. Take the "to
be probed" addresses listed by the driver, do a standard i2c probe on them,
and pass a device to the driver's probe function if something is detected.
The probe function is of course free to return ENODEV if it has some
additional way to check for device presence. If an address is on the force
list, then the device is created and passed to the driver's probe without
the core doing any kind of i2c probe. The driver can do a non-standard
probe if it has one and return ENODEV if nothing is there.
> * When a new i2c_adapter is added, for each existing new-style
> i2c_driver, the same happens.
It would nice if there was a no-probe option when creating an i2c_adapter.
Some hardware doesn't support probing of any kind, usually because there is
no way to detect a NAK. In some cases the creator of the i2c_adapter knows
exactly what's on the bus it's creating and doesn't want whatever random
i2c drivers happen to be loaded to probe it. For instance, the ivtv TV
card driver knows what tuners are on the i2c bus, while the bttv driver
doesn't. The ivtv driver could use this to prevent an i2c driver used by
bttv from probing ivtv's i2c bus.
> * When it gets a filled struct i2c_board_info from a detect callback,
> i2c-core will instantiate it. If a new-style driver exists for the
> device, it will be able to bind with the device.
> * We keep track of the devices created that way, in a per-driver list.
> * When a new-style i2c_driver is removed, all devices that originate
> from it are destroyed.
Is it necessary to remove the devices? They are still there after all.
It's perfectly normal to have devices with no drivers loaded for them on
other busses.
> * When an i2c_adapter is removed, all devices on it that were created
> as the result of calling a detect callback, are destroyed.
Shouldn't all devices on it, no matter how they were created, be removed?
Or is that the case?
_______________________________________________
i2c mailing list
i2c-GZX6beZjE8VD60Wz+7aTrA@public.gmane.org
http://lists.lm-sensors.org/mailman/listinfo/i2c
^ permalink raw reply [flat|nested] 10+ messages in thread