diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-03-02 06:23:46 -0500 |
---|---|---|
committer | Jean Delvare <khali@linux-fr.org> | 2010-03-02 06:23:46 -0500 |
commit | 6de468ae2df0ee6fbee668d946811638b57361f6 (patch) | |
tree | c0b43c2d3bb8c89c012cbfeb185ff03ad3d86326 | |
parent | 927ab2f80745ec26f1e83e6ca15a5b29e134c8e5 (diff) |
i2c: Hook up runtime PM support
Allow I2C drivers to make use of the runtime PM framework by adding
bus implementations of the runtime PM operations. These simply
immediately suspend when the device is idle. The runtime PM framework
provides drivers with off the shelf refcounts for enables and sysfs
control for managing runtime suspend from userspace so is useful even
without meaningful input from the bus.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
-rw-r--r-- | drivers/i2c/i2c-core.c | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 10be7b5fbe97..4131698008b9 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/hardirq.h> | 34 | #include <linux/hardirq.h> |
35 | #include <linux/irqflags.h> | 35 | #include <linux/irqflags.h> |
36 | #include <linux/rwsem.h> | 36 | #include <linux/rwsem.h> |
37 | #include <linux/pm_runtime.h> | ||
37 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
38 | 39 | ||
39 | #include "i2c-core.h" | 40 | #include "i2c-core.h" |
@@ -184,6 +185,52 @@ static int i2c_device_pm_resume(struct device *dev) | |||
184 | #define i2c_device_pm_resume NULL | 185 | #define i2c_device_pm_resume NULL |
185 | #endif | 186 | #endif |
186 | 187 | ||
188 | #ifdef CONFIG_PM_RUNTIME | ||
189 | static int i2c_device_runtime_suspend(struct device *dev) | ||
190 | { | ||
191 | const struct dev_pm_ops *pm; | ||
192 | |||
193 | if (!dev->driver) | ||
194 | return 0; | ||
195 | pm = dev->driver->pm; | ||
196 | if (!pm || !pm->runtime_suspend) | ||
197 | return 0; | ||
198 | return pm->runtime_suspend(dev); | ||
199 | } | ||
200 | |||
201 | static int i2c_device_runtime_resume(struct device *dev) | ||
202 | { | ||
203 | const struct dev_pm_ops *pm; | ||
204 | |||
205 | if (!dev->driver) | ||
206 | return 0; | ||
207 | pm = dev->driver->pm; | ||
208 | if (!pm || !pm->runtime_resume) | ||
209 | return 0; | ||
210 | return pm->runtime_resume(dev); | ||
211 | } | ||
212 | |||
213 | static int i2c_device_runtime_idle(struct device *dev) | ||
214 | { | ||
215 | const struct dev_pm_ops *pm = NULL; | ||
216 | int ret; | ||
217 | |||
218 | if (dev->driver) | ||
219 | pm = dev->driver->pm; | ||
220 | if (pm && pm->runtime_idle) { | ||
221 | ret = pm->runtime_idle(dev); | ||
222 | if (ret) | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | return pm_runtime_suspend(dev); | ||
227 | } | ||
228 | #else | ||
229 | #define i2c_device_runtime_suspend NULL | ||
230 | #define i2c_device_runtime_resume NULL | ||
231 | #define i2c_device_runtime_idle NULL | ||
232 | #endif | ||
233 | |||
187 | static int i2c_device_suspend(struct device *dev, pm_message_t mesg) | 234 | static int i2c_device_suspend(struct device *dev, pm_message_t mesg) |
188 | { | 235 | { |
189 | struct i2c_client *client = i2c_verify_client(dev); | 236 | struct i2c_client *client = i2c_verify_client(dev); |
@@ -251,6 +298,9 @@ static const struct attribute_group *i2c_dev_attr_groups[] = { | |||
251 | static const struct dev_pm_ops i2c_device_pm_ops = { | 298 | static const struct dev_pm_ops i2c_device_pm_ops = { |
252 | .suspend = i2c_device_pm_suspend, | 299 | .suspend = i2c_device_pm_suspend, |
253 | .resume = i2c_device_pm_resume, | 300 | .resume = i2c_device_pm_resume, |
301 | .runtime_suspend = i2c_device_runtime_suspend, | ||
302 | .runtime_resume = i2c_device_runtime_resume, | ||
303 | .runtime_idle = i2c_device_runtime_idle, | ||
254 | }; | 304 | }; |
255 | 305 | ||
256 | struct bus_type i2c_bus_type = { | 306 | struct bus_type i2c_bus_type = { |