[prev in list] [next in list] [prev in thread] [next in thread]
List: linux-i2c
Subject: [i2c] [patch 2.6.19-rc5] i2c driver model updates:
From: david-b () pacbell ! net (David Brownell)
Date: 2006-11-17 20:57:03
Message-ID: 200611171257.03947.david-b () pacbell ! net
[Download RAW message or body]
Some driver model updates for the I2C core:
- Add new suspend(), resume(), and shutdown() methods. Use them in the
standard driver model style; document them.
- Minor doc updates to highlight zero-initialized fields in drivers, and
the driver model accessors for "clientdata".
If any i2c drivers were previously using the old suspend/resume calls
in "struct driver", they were getting warning messages ... and will
now no longer work. Other than that, this patch changes no behaviors;
and it lets I2C drivers use conventional PM and shutdown support.
Signed-off-by: David Brownell <dbrownell at users.sourceforge.net>
Index: o26/Documentation/i2c/writing-clients
===================================================================
--- o26.orig/Documentation/i2c/writing-clients 2006-11-17 12:28:45.000000000 -0800
+++ o26/Documentation/i2c/writing-clients 2006-11-17 12:40:07.000000000 -0800
@@ -21,20 +21,26 @@ The driver structure
Usually, you will implement a single driver structure, and instantiate
all clients from it. Remember, a driver structure contains general access
-routines, a client structure specific information like the actual I2C
-address.
+routines, and should be zero-initialized except for fields with data you
+provide. A client structure holds device-specific information like the
+driver model device node, and its I2C address.
static struct i2c_driver foo_driver = {
.driver = {
.name = "foo",
},
- .attach_adapter = &foo_attach_adapter,
- .detach_client = &foo_detach_client,
- .command = &foo_command /* may be NULL */
+ .attach_adapter = foo_attach_adapter,
+ .detach_client = foo_detach_client,
+ .shutdown = foo_shutdown, /* optional */
+ .suspend = foo_suspend, /* optional */
+ .resume = foo_resume, /* optional */
+ .command = foo_command, /* optional */
}
-The name field must match the driver name, including the case. It must not
-contain spaces, and may be up to 31 characters long.
+The name field is the driver name, and must not contain spaces. It
+should match the module name (if the driver can be compiled as a module),
+although you can use MODULE_ALIAS (passing "foo" in this example) to add
+another name for the module.
All other fields are for call-back functions which will be explained
below.
@@ -43,11 +49,18 @@ below.
Extra client data
=================
-The client structure has a special `data' field that can point to any
-structure at all. You can use this to keep client-specific data. You
+Each client structure has a special `data' field that can point to any
+structure at all. You should use this to keep device-specific data,
+especially in drivers that handle multiple I2C or SMBUS devices. You
do not always need this, but especially for `sensors' drivers, it can
be very useful.
+ /* store the value */
+ void i2c_set_clientdata(struct i2c_client *client, void *data);
+
+ /* retrieve the value */
+ void *i2c_get_clientdata(struct i2c_client *client);
+
An example structure is below.
struct foo_data {
@@ -493,6 +506,33 @@ by `__init_data'. Hose functions and st
kernel booting (or module loading) is completed.
+Power Management
+================
+
+If your I2C device needs special handling when entering a system low
+power state -- like putting a transceiver into a low power mode, or
+activating a system wakeup mechanism -- do that in the suspend() method.
+The resume() method should reverse what the suspend() method does.
+
+These are standard driver model calls, and they work just like they
+would for any other driver stack. The calls can sleep, and can use
+I2C messaging to the device being suspended or resumed (since their
+parent I2C adapter is active when these calls are issued, and IRQs
+are still enabled).
+
+
+System Shutdown
+===============
+
+If your I2C device needs special handling when the system shuts down
+or reboots (including kexec) -- like turning something off -- use a
+shutdown() method.
+
+Again, this is a standard driver model call, working just like it
+would for any other driver stack: the calls can sleep, and can use
+I2C messaging.
+
+
Command function
================
Index: o26/Documentation/i2c/porting-clients
===================================================================
--- o26.orig/Documentation/i2c/porting-clients 2006-11-17 12:28:45.000000000 -0800
+++ o26/Documentation/i2c/porting-clients 2006-11-17 12:30:35.000000000 -0800
@@ -129,9 +129,16 @@ Technical changes:
structure, those name member should be initialized to a driver name
string. i2c_driver itself has no name member anymore.
+* [Driver model] Instead of shutdown or reboot notifiers, provide a
+ shutdown() method in your driver.
+
+* [Power management] Use the driver model suspend() and resume()
+ callbacks instead of the obsolete pm_register() calls.
+
Coding policy:
-* [Copyright] Use (C), not (c), for copyright.
+* [Copyright] Use (C), not (c), for copyright. Provide dates and names:
+ "Copyright (C) 2006 you", "Copyright (C) 1998,2004-2006 company", etc
* [Debug/log] Get rid of #ifdef DEBUG/#endif constructs whenever you
can. Calls to printk for debugging purposes are replaced by calls to
Index: o26/include/linux/i2c.h
===================================================================
--- o26.orig/include/linux/i2c.h 2006-11-17 12:28:45.000000000 -0800
+++ o26/include/linux/i2c.h 2006-11-17 12:41:13.000000000 -0800
@@ -125,7 +125,12 @@ struct i2c_driver {
* it must be freed here.
*/
int (*detach_client)(struct i2c_client *);
-
+
+ /* driver model interfaces that don't relate to enumeration */
+ void (*shutdown)(struct i2c_client *);
+ int (*suspend)(struct i2c_client *, pm_message_t mesg);
+ int (*resume)(struct i2c_client *);
+
/* a ioctl like command that can be used to perform specific functions
* with the device.
*/
Index: o26/drivers/i2c/i2c-core.c
===================================================================
--- o26.orig/drivers/i2c/i2c-core.c 2006-11-17 12:28:45.000000000 -0800
+++ o26/drivers/i2c/i2c-core.c 2006-11-17 12:37:54.000000000 -0800
@@ -40,28 +40,33 @@ static LIST_HEAD(drivers);
static DEFINE_MUTEX(core_lists);
static DEFINE_IDR(i2c_adapter_idr);
-/* match always succeeds, as we want the probe() to tell if we really accept this match */
+
+/* ------------------------------------------------------------------------- */
+
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
- return 1;
+ /* (for now) bypass driver model probing entirely; drivers
+ * scan each i2c adapter/bus themselves.
+ */
+ return 0;
}
-static int i2c_bus_suspend(struct device * dev, pm_message_t state)
+static int i2c_device_suspend(struct device * dev, pm_message_t mesg)
{
- int rc = 0;
+ struct i2c_driver *driver = to_i2c_driver(dev->driver);
- if (dev->driver && dev->driver->suspend)
- rc = dev->driver->suspend(dev, state);
- return rc;
+ if (!dev->driver || !driver->suspend)
+ return 0;
+ return driver->suspend(to_i2c_client(dev), mesg);
}
-static int i2c_bus_resume(struct device * dev)
+static int i2c_device_resume(struct device * dev)
{
- int rc = 0;
-
- if (dev->driver && dev->driver->resume)
- rc = dev->driver->resume(dev);
- return rc;
+ struct i2c_driver *driver = to_i2c_driver(dev->driver);
+
+ if (!dev->driver || !driver->resume)
+ return 0;
+ return driver->resume(to_i2c_client(dev));
}
static int i2c_device_probe(struct device *dev)
@@ -74,15 +79,29 @@ static int i2c_device_remove(struct devi
return 0;
}
+static void i2c_device_shutdown(struct device *dev)
+{
+ struct i2c_driver *driver = to_i2c_driver(dev->driver);
+
+ if (!dev->driver || !driver->shutdown)
+ return;
+ driver->shutdown(to_i2c_client(dev));
+}
+
struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
.probe = i2c_device_probe,
.remove = i2c_device_remove,
- .suspend = i2c_bus_suspend,
- .resume = i2c_bus_resume,
+ .shutdown = i2c_device_shutdown,
+ .suspend = i2c_device_suspend,
+ .resume = i2c_device_resume,
};
+/* ------------------------------------------------------------------------- */
+
+/* I2C bus adapters -- one roots each I2C or SMBUS segment */
+
void i2c_adapter_dev_release(struct device *dev)
{
struct i2c_adapter *adap = dev_to_i2c_adapter(dev);
@@ -114,6 +133,8 @@ static ssize_t show_adapter_name(struct
}
static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL);
+/* ------------------------------------------------------------------------- */
+
static void i2c_client_release(struct device *dev)
{
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic