diff options
author | David Brownell <david-b@pacbell.net> | 2007-02-13 16:09:00 -0500 |
---|---|---|
committer | Jean Delvare <khali@arrakis.delvare> | 2007-02-13 16:09:00 -0500 |
commit | f37dd80ac2a67e4e4e921f99d34a1ceeb2488abb (patch) | |
tree | c845e39b24feac331a9a67d49e0b8061f52131b3 | |
parent | b8d6f45b32f6fe72bf7304183275e99332544ce1 (diff) |
i2c: Add driver suspend/resume/shutdown support
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@users.sourceforge.net>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
-rw-r--r-- | Documentation/i2c/porting-clients | 6 | ||||
-rw-r--r-- | Documentation/i2c/writing-clients | 58 | ||||
-rw-r--r-- | drivers/i2c/i2c-core.c | 65 | ||||
-rw-r--r-- | include/linux/i2c.h | 7 |
4 files changed, 105 insertions, 31 deletions
diff --git a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients index f03c2a02f806..ca272b263a92 100644 --- a/Documentation/i2c/porting-clients +++ b/Documentation/i2c/porting-clients | |||
@@ -129,6 +129,12 @@ Technical changes: | |||
129 | structure, those name member should be initialized to a driver name | 129 | structure, those name member should be initialized to a driver name |
130 | string. i2c_driver itself has no name member anymore. | 130 | string. i2c_driver itself has no name member anymore. |
131 | 131 | ||
132 | * [Driver model] Instead of shutdown or reboot notifiers, provide a | ||
133 | shutdown() method in your driver. | ||
134 | |||
135 | * [Power management] Use the driver model suspend() and resume() | ||
136 | callbacks instead of the obsolete pm_register() calls. | ||
137 | |||
132 | Coding policy: | 138 | Coding policy: |
133 | 139 | ||
134 | * [Copyright] Use (C), not (c), for copyright. | 140 | * [Copyright] Use (C), not (c), for copyright. |
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index 3a057c8e5507..fbcff96f4ca1 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients | |||
@@ -21,20 +21,26 @@ The driver structure | |||
21 | 21 | ||
22 | Usually, you will implement a single driver structure, and instantiate | 22 | Usually, you will implement a single driver structure, and instantiate |
23 | all clients from it. Remember, a driver structure contains general access | 23 | all clients from it. Remember, a driver structure contains general access |
24 | routines, a client structure specific information like the actual I2C | 24 | routines, and should be zero-initialized except for fields with data you |
25 | address. | 25 | provide. A client structure holds device-specific information like the |
26 | driver model device node, and its I2C address. | ||
26 | 27 | ||
27 | static struct i2c_driver foo_driver = { | 28 | static struct i2c_driver foo_driver = { |
28 | .driver = { | 29 | .driver = { |
29 | .name = "foo", | 30 | .name = "foo", |
30 | }, | 31 | }, |
31 | .attach_adapter = &foo_attach_adapter, | 32 | .attach_adapter = foo_attach_adapter, |
32 | .detach_client = &foo_detach_client, | 33 | .detach_client = foo_detach_client, |
33 | .command = &foo_command /* may be NULL */ | 34 | .shutdown = foo_shutdown, /* optional */ |
35 | .suspend = foo_suspend, /* optional */ | ||
36 | .resume = foo_resume, /* optional */ | ||
37 | .command = foo_command, /* optional */ | ||
34 | } | 38 | } |
35 | 39 | ||
36 | The name field must match the driver name, including the case. It must not | 40 | The name field is the driver name, and must not contain spaces. It |
37 | contain spaces, and may be up to 31 characters long. | 41 | should match the module name (if the driver can be compiled as a module), |
42 | although you can use MODULE_ALIAS (passing "foo" in this example) to add | ||
43 | another name for the module. | ||
38 | 44 | ||
39 | All other fields are for call-back functions which will be explained | 45 | All other fields are for call-back functions which will be explained |
40 | below. | 46 | below. |
@@ -43,11 +49,18 @@ below. | |||
43 | Extra client data | 49 | Extra client data |
44 | ================= | 50 | ================= |
45 | 51 | ||
46 | The client structure has a special `data' field that can point to any | 52 | Each client structure has a special `data' field that can point to any |
47 | structure at all. You can use this to keep client-specific data. You | 53 | structure at all. You should use this to keep device-specific data, |
54 | especially in drivers that handle multiple I2C or SMBUS devices. You | ||
48 | do not always need this, but especially for `sensors' drivers, it can | 55 | do not always need this, but especially for `sensors' drivers, it can |
49 | be very useful. | 56 | be very useful. |
50 | 57 | ||
58 | /* store the value */ | ||
59 | void i2c_set_clientdata(struct i2c_client *client, void *data); | ||
60 | |||
61 | /* retrieve the value */ | ||
62 | void *i2c_get_clientdata(struct i2c_client *client); | ||
63 | |||
51 | An example structure is below. | 64 | An example structure is below. |
52 | 65 | ||
53 | struct foo_data { | 66 | struct foo_data { |
@@ -493,6 +506,33 @@ by `__init_data'. Hose functions and structures can be removed after | |||
493 | kernel booting (or module loading) is completed. | 506 | kernel booting (or module loading) is completed. |
494 | 507 | ||
495 | 508 | ||
509 | Power Management | ||
510 | ================ | ||
511 | |||
512 | If your I2C device needs special handling when entering a system low | ||
513 | power state -- like putting a transceiver into a low power mode, or | ||
514 | activating a system wakeup mechanism -- do that in the suspend() method. | ||
515 | The resume() method should reverse what the suspend() method does. | ||
516 | |||
517 | These are standard driver model calls, and they work just like they | ||
518 | would for any other driver stack. The calls can sleep, and can use | ||
519 | I2C messaging to the device being suspended or resumed (since their | ||
520 | parent I2C adapter is active when these calls are issued, and IRQs | ||
521 | are still enabled). | ||
522 | |||
523 | |||
524 | System Shutdown | ||
525 | =============== | ||
526 | |||
527 | If your I2C device needs special handling when the system shuts down | ||
528 | or reboots (including kexec) -- like turning something off -- use a | ||
529 | shutdown() method. | ||
530 | |||
531 | Again, this is a standard driver model call, working just like it | ||
532 | would for any other driver stack: the calls can sleep, and can use | ||
533 | I2C messaging. | ||
534 | |||
535 | |||
496 | Command function | 536 | Command function |
497 | ================ | 537 | ================ |
498 | 538 | ||
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 60f6eb194046..9653f7f81561 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -41,49 +41,72 @@ static LIST_HEAD(drivers); | |||
41 | static DEFINE_MUTEX(core_lists); | 41 | static DEFINE_MUTEX(core_lists); |
42 | static DEFINE_IDR(i2c_adapter_idr); | 42 | static DEFINE_IDR(i2c_adapter_idr); |
43 | 43 | ||
44 | |||
45 | /* ------------------------------------------------------------------------- */ | ||
46 | |||
44 | /* match always succeeds, as we want the probe() to tell if we really accept this match */ | 47 | /* match always succeeds, as we want the probe() to tell if we really accept this match */ |
45 | static int i2c_device_match(struct device *dev, struct device_driver *drv) | 48 | static int i2c_device_match(struct device *dev, struct device_driver *drv) |
46 | { | 49 | { |
47 | return 1; | 50 | return 1; |
48 | } | 51 | } |
49 | 52 | ||
50 | static int i2c_bus_suspend(struct device * dev, pm_message_t state) | 53 | static int i2c_device_probe(struct device *dev) |
51 | { | 54 | { |
52 | int rc = 0; | 55 | return -ENODEV; |
56 | } | ||
53 | 57 | ||
54 | if (dev->driver && dev->driver->suspend) | 58 | static int i2c_device_remove(struct device *dev) |
55 | rc = dev->driver->suspend(dev, state); | 59 | { |
56 | return rc; | 60 | return 0; |
57 | } | 61 | } |
58 | 62 | ||
59 | static int i2c_bus_resume(struct device * dev) | 63 | static void i2c_device_shutdown(struct device *dev) |
60 | { | 64 | { |
61 | int rc = 0; | 65 | struct i2c_driver *driver; |
62 | 66 | ||
63 | if (dev->driver && dev->driver->resume) | 67 | if (!dev->driver) |
64 | rc = dev->driver->resume(dev); | 68 | return; |
65 | return rc; | 69 | driver = to_i2c_driver(dev->driver); |
70 | if (driver->shutdown) | ||
71 | driver->shutdown(to_i2c_client(dev)); | ||
66 | } | 72 | } |
67 | 73 | ||
68 | static int i2c_device_probe(struct device *dev) | 74 | static int i2c_device_suspend(struct device * dev, pm_message_t mesg) |
69 | { | 75 | { |
70 | return -ENODEV; | 76 | struct i2c_driver *driver; |
77 | |||
78 | if (!dev->driver) | ||
79 | return 0; | ||
80 | driver = to_i2c_driver(dev->driver); | ||
81 | if (!driver->suspend) | ||
82 | return 0; | ||
83 | return driver->suspend(to_i2c_client(dev), mesg); | ||
71 | } | 84 | } |
72 | 85 | ||
73 | static int i2c_device_remove(struct device *dev) | 86 | static int i2c_device_resume(struct device * dev) |
74 | { | 87 | { |
75 | return 0; | 88 | struct i2c_driver *driver; |
89 | |||
90 | if (!dev->driver) | ||
91 | return 0; | ||
92 | driver = to_i2c_driver(dev->driver); | ||
93 | if (!driver->resume) | ||
94 | return 0; | ||
95 | return driver->resume(to_i2c_client(dev)); | ||
76 | } | 96 | } |
77 | 97 | ||
78 | struct bus_type i2c_bus_type = { | 98 | struct bus_type i2c_bus_type = { |
79 | .name = "i2c", | 99 | .name = "i2c", |
80 | .match = i2c_device_match, | 100 | .match = i2c_device_match, |
81 | .probe = i2c_device_probe, | 101 | .probe = i2c_device_probe, |
82 | .remove = i2c_device_remove, | 102 | .remove = i2c_device_remove, |
83 | .suspend = i2c_bus_suspend, | 103 | .shutdown = i2c_device_shutdown, |
84 | .resume = i2c_bus_resume, | 104 | .suspend = i2c_device_suspend, |
105 | .resume = i2c_device_resume, | ||
85 | }; | 106 | }; |
86 | 107 | ||
108 | /* ------------------------------------------------------------------------- */ | ||
109 | |||
87 | void i2c_adapter_dev_release(struct device *dev) | 110 | void i2c_adapter_dev_release(struct device *dev) |
88 | { | 111 | { |
89 | struct i2c_adapter *adap = dev_to_i2c_adapter(dev); | 112 | struct i2c_adapter *adap = dev_to_i2c_adapter(dev); |
diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 71e50d3e492f..9428092017e3 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h | |||
@@ -125,7 +125,12 @@ struct i2c_driver { | |||
125 | * it must be freed here. | 125 | * it must be freed here. |
126 | */ | 126 | */ |
127 | int (*detach_client)(struct i2c_client *); | 127 | int (*detach_client)(struct i2c_client *); |
128 | 128 | ||
129 | /* driver model interfaces that don't relate to enumeration */ | ||
130 | void (*shutdown)(struct i2c_client *); | ||
131 | int (*suspend)(struct i2c_client *, pm_message_t mesg); | ||
132 | int (*resume)(struct i2c_client *); | ||
133 | |||
129 | /* a ioctl like command that can be used to perform specific functions | 134 | /* a ioctl like command that can be used to perform specific functions |
130 | * with the device. | 135 | * with the device. |
131 | */ | 136 | */ |