[PATCH 1/5] call i2c_probe from i2c core

From: Nathan Lutchansky
Date: Mon Aug 15 2005 - 12:53:20 EST


Add the address_data and detect_client fields to the i2c_driver
structure. If these are set, i2c core will call i2c_probe directly when
attach_adapter would have been called. If the i2c_driver class field is
also set, probing will only be done on adapters with an intersecting
class field.

The attach_adapter callback will still be called if it is present, but
this makes it unnecessary for almost all in-tree i2c drivers.

Signed-off-by: Nathan Lutchansky <lutchann@xxxxxxxxxx>

Documentation/i2c/writing-clients | 58 ++++++++++++++++++++++++--------------
drivers/i2c/i2c-core.c | 21 +++++++++++--
include/linux/i2c.h | 11 +++++++
3 files changed, 65 insertions(+), 25 deletions(-)

Index: linux-2.6.13-rc6+gregkh/include/linux/i2c.h
===================================================================
--- linux-2.6.13-rc6+gregkh.orig/include/linux/i2c.h
+++ linux-2.6.13-rc6+gregkh/include/linux/i2c.h
@@ -48,6 +48,7 @@ struct i2c_algorithm;
struct i2c_adapter;
struct i2c_client;
struct i2c_driver;
+struct i2c_client_address_data;
union i2c_smbus_data;

/*
@@ -113,6 +114,7 @@ struct i2c_driver {
int id;
unsigned int class;
unsigned int flags; /* div., see below */
+ struct i2c_client_address_data *address_data;

/* 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
@@ -123,6 +125,15 @@ struct i2c_driver {
int (*attach_adapter)(struct i2c_adapter *);
int (*detach_adapter)(struct i2c_adapter *);

+ /* Requests that the driver validate an address on a bus and attach a
+ * new client. If this routine is supplied, it will be called for
+ * each device on new buses that appear, provided the bus class
+ * matches the class field and devices exist at the addresses listed
+ * in the address_data field. For most drivers, this mechanism can
+ * be used instead of an attach_adapter routine.
+ */
+ int (*detect_client)(struct i2c_adapter *, int addr, int kind);
+
/* tells the driver that a client is about to be deleted & gives it
* the chance to remove its private data. Also, if the client struct
* has been dynamically allocated by the driver in the function above,
Index: linux-2.6.13-rc6+gregkh/drivers/i2c/i2c-core.c
===================================================================
--- linux-2.6.13-rc6+gregkh.orig/drivers/i2c/i2c-core.c
+++ linux-2.6.13-rc6+gregkh/drivers/i2c/i2c-core.c
@@ -193,9 +193,16 @@ int i2c_add_adapter(struct i2c_adapter *
/* inform drivers of new adapters */
list_for_each(item,&drivers) {
driver = list_entry(item, struct i2c_driver, list);
- if (driver->flags & I2C_DF_NOTIFY)
- /* We ignore the return code; if it fails, too bad */
- driver->attach_adapter(adap);
+ if (driver->flags & I2C_DF_NOTIFY) {
+ /* We ignore the return codes; if it fails, too bad */
+ if (driver->attach_adapter)
+ driver->attach_adapter(adap);
+ if (driver->detect_client && driver->address_data &&
+ ((driver->class & adap->class) ||
+ driver->class == 0))
+ i2c_probe(adap, driver->address_data,
+ driver->detect_client);
+ }
}

out_unlock:
@@ -307,7 +314,13 @@ int i2c_add_driver(struct i2c_driver *dr
if (driver->flags & I2C_DF_NOTIFY) {
list_for_each(item,&adapters) {
adapter = list_entry(item, struct i2c_adapter, list);
- driver->attach_adapter(adapter);
+ if (driver->attach_adapter)
+ driver->attach_adapter(adapter);
+ if (driver->detect_client && driver->address_data &&
+ ((driver->class & adapter->class) ||
+ driver->class == 0))
+ i2c_probe(adapter, driver->address_data,
+ driver->detect_client);
}
}

Index: linux-2.6.13-rc6+gregkh/Documentation/i2c/writing-clients
===================================================================
--- linux-2.6.13-rc6+gregkh.orig/Documentation/i2c/writing-clients
+++ linux-2.6.13-rc6+gregkh/Documentation/i2c/writing-clients
@@ -27,8 +27,10 @@ address.
static struct i2c_driver foo_driver = {
.owner = THIS_MODULE,
.name = "Foo version 2.3 driver",
+ .class = I2C_CLASS_HWMON,
.flags = I2C_DF_NOTIFY,
- .attach_adapter = &foo_attach_adapter,
+ .address_data = &addr_data,
+ .detect_client = &foo_detect_client,
.detach_client = &foo_detach_client,
.command = &foo_command /* may be NULL */
}
@@ -147,8 +149,8 @@ are defined to help determine what addre
are defined in i2c.h to help you support them, as well as a generic
detection algorithm.

-You do not have to use this parameter interface; but don't try to use
-function i2c_probe() if you don't.
+You do not have to use this parameter interface; but then the i2c core won't
+be able to probe for devices for you.

NOTE: If you want to write a `sensors' driver, the interface is slightly
different! See below.
@@ -207,35 +209,49 @@ Attaching to an adapter
-----------------------

Whenever a new adapter is inserted, or for all adapters if the driver is
-being registered, the callback attach_adapter() is called. Now is the
-time to determine what devices are present on the adapter, and to register
-a client for each of them.
-
-The attach_adapter callback is really easy: we just call the generic
-detection function. This function will scan the bus for us, using the
-information as defined in the lists explained above. If a device is
-detected at a specific address, another callback is called.
+being registered, your driver may be notified through one of two
+callbacks, depending on the degree of control you need to exercise over
+the probing process. This is the time to determine what devices are
+present on the adapter and to register a client for each device your
+driver supports.
+
+The easiest way to handle the probing process is to simply set the `class',
+`address_data', and `detect_client' fields in the i2c_driver structure.
+The `class' field is a bitmask of all the adapter classes which should be
+probed for devices supported by this driver. Typically you would just set
+this to I2C_CLASS_HWMON, which is appropriate for `sensors' drivers. The
+`address_data' field should be set to `&addr_data', which is defined by the
+macros explained above, so you do not have to define it yourself. When a
+new adapter is attached, the bus is scanned for the addresses defined in
+the lists above, and the detect_client callback gets called when a device
+is detected at a specific address.
+
+If you prefer, you can omit the `class', `address_data', and
+`detect_client' fields from your i2c_driver structure, and instead set
+`attach_adapter'. The `attach_adapter' callback gets called every time a
+new adapter is attached and the bus needs to be scanned, so if you need to
+perform any special checks or configuration before you scan a bus for
+devices, you should use attach_adapter. If the bus is suitable, you can
+then call the generic i2c_probe function to scan for the addresses in the
+lists explained above, and the callback passed in the third parameter will
+get called for each device detected.

int foo_attach_adapter(struct i2c_adapter *adapter)
{
return i2c_probe(adapter,&addr_data,&foo_detect_client);
}

-Remember, structure `addr_data' is defined by the macros explained above,
-so you do not have to define it yourself.
-
-The i2c_probe function will call the foo_detect_client
-function only for those i2c addresses that actually have a device on
-them (unless a `force' parameter was used). In addition, addresses that
-are already in use (by some other registered client) are skipped.
+With either mechanism, addresses that are already in use (by some other
+registered client) are skipped.


The detect client function
--------------------------

-The detect client function is called by i2c_probe. The `kind' parameter
-contains -1 for a probed detection, 0 for a forced detection, or a positive
-number for a forced detection with a chip type forced.
+The detect client function is called by the address probing mechanism.
+The `kind' parameter contains -1 for a probed detection, 0 for a forced
+detection, or a positive number for a forced detection with a chip type
+forced.

Below, some things are only needed if this is a `sensors' driver. Those
parts are between /* SENSORS ONLY START */ and /* SENSORS ONLY END */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/