diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2010-12-25 09:32:27 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2010-12-25 09:32:27 -0500 |
commit | 3ae22e8c8ac39daf88ae32f047fb23825be7c646 (patch) | |
tree | 20e7ed1005b39e65d99ac351776e74a9c925a6aa | |
parent | 62bcb91573425975d6ad2389d7ab1d8feca88ab4 (diff) |
spi / PM: Support dev_pm_ops
Allow SPI drivers to use runtime PM and other dev_pm_ops features by
implementing dev_pm_ops for the bus. The existing bus specific suspend
and resume functions will be called if a driver does not provide dev_pm_ops
allowing for transition to the new model.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
-rw-r--r-- | drivers/spi/spi.c | 92 |
1 files changed, 84 insertions, 8 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index b02d0cbce890..34bb17f03019 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/mod_devicetable.h> | 28 | #include <linux/mod_devicetable.h> |
29 | #include <linux/spi/spi.h> | 29 | #include <linux/spi/spi.h> |
30 | #include <linux/of_spi.h> | 30 | #include <linux/of_spi.h> |
31 | #include <linux/pm_runtime.h> | ||
31 | 32 | ||
32 | static void spidev_release(struct device *dev) | 33 | static void spidev_release(struct device *dev) |
33 | { | 34 | { |
@@ -100,9 +101,8 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
100 | return 0; | 101 | return 0; |
101 | } | 102 | } |
102 | 103 | ||
103 | #ifdef CONFIG_PM | 104 | #ifdef CONFIG_PM_SLEEP |
104 | 105 | static int spi_legacy_suspend(struct device *dev, pm_message_t message) | |
105 | static int spi_suspend(struct device *dev, pm_message_t message) | ||
106 | { | 106 | { |
107 | int value = 0; | 107 | int value = 0; |
108 | struct spi_driver *drv = to_spi_driver(dev->driver); | 108 | struct spi_driver *drv = to_spi_driver(dev->driver); |
@@ -117,7 +117,7 @@ static int spi_suspend(struct device *dev, pm_message_t message) | |||
117 | return value; | 117 | return value; |
118 | } | 118 | } |
119 | 119 | ||
120 | static int spi_resume(struct device *dev) | 120 | static int spi_legacy_resume(struct device *dev) |
121 | { | 121 | { |
122 | int value = 0; | 122 | int value = 0; |
123 | struct spi_driver *drv = to_spi_driver(dev->driver); | 123 | struct spi_driver *drv = to_spi_driver(dev->driver); |
@@ -132,18 +132,94 @@ static int spi_resume(struct device *dev) | |||
132 | return value; | 132 | return value; |
133 | } | 133 | } |
134 | 134 | ||
135 | static int spi_pm_suspend(struct device *dev) | ||
136 | { | ||
137 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | ||
138 | |||
139 | if (pm) | ||
140 | return pm_generic_suspend(dev); | ||
141 | else | ||
142 | return spi_legacy_suspend(dev, PMSG_SUSPEND); | ||
143 | } | ||
144 | |||
145 | static int spi_pm_resume(struct device *dev) | ||
146 | { | ||
147 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | ||
148 | |||
149 | if (pm) | ||
150 | return pm_generic_resume(dev); | ||
151 | else | ||
152 | return spi_legacy_resume(dev); | ||
153 | } | ||
154 | |||
155 | static int spi_pm_freeze(struct device *dev) | ||
156 | { | ||
157 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | ||
158 | |||
159 | if (pm) | ||
160 | return pm_generic_freeze(dev); | ||
161 | else | ||
162 | return spi_legacy_suspend(dev, PMSG_FREEZE); | ||
163 | } | ||
164 | |||
165 | static int spi_pm_thaw(struct device *dev) | ||
166 | { | ||
167 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | ||
168 | |||
169 | if (pm) | ||
170 | return pm_generic_thaw(dev); | ||
171 | else | ||
172 | return spi_legacy_resume(dev); | ||
173 | } | ||
174 | |||
175 | static int spi_pm_poweroff(struct device *dev) | ||
176 | { | ||
177 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | ||
178 | |||
179 | if (pm) | ||
180 | return pm_generic_poweroff(dev); | ||
181 | else | ||
182 | return spi_legacy_suspend(dev, PMSG_HIBERNATE); | ||
183 | } | ||
184 | |||
185 | static int spi_pm_restore(struct device *dev) | ||
186 | { | ||
187 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | ||
188 | |||
189 | if (pm) | ||
190 | return pm_generic_restore(dev); | ||
191 | else | ||
192 | return spi_legacy_resume(dev); | ||
193 | } | ||
135 | #else | 194 | #else |
136 | #define spi_suspend NULL | 195 | #define spi_pm_suspend NULL |
137 | #define spi_resume NULL | 196 | #define spi_pm_resume NULL |
197 | #define spi_pm_freeze NULL | ||
198 | #define spi_pm_thaw NULL | ||
199 | #define spi_pm_poweroff NULL | ||
200 | #define spi_pm_restore NULL | ||
138 | #endif | 201 | #endif |
139 | 202 | ||
203 | static const struct dev_pm_ops spi_pm = { | ||
204 | .suspend = spi_pm_suspend, | ||
205 | .resume = spi_pm_resume, | ||
206 | .freeze = spi_pm_freeze, | ||
207 | .thaw = spi_pm_thaw, | ||
208 | .poweroff = spi_pm_poweroff, | ||
209 | .restore = spi_pm_restore, | ||
210 | SET_RUNTIME_PM_OPS( | ||
211 | pm_generic_runtime_suspend, | ||
212 | pm_generic_runtime_resume, | ||
213 | pm_generic_runtime_idle | ||
214 | ) | ||
215 | }; | ||
216 | |||
140 | struct bus_type spi_bus_type = { | 217 | struct bus_type spi_bus_type = { |
141 | .name = "spi", | 218 | .name = "spi", |
142 | .dev_attrs = spi_dev_attrs, | 219 | .dev_attrs = spi_dev_attrs, |
143 | .match = spi_match_device, | 220 | .match = spi_match_device, |
144 | .uevent = spi_uevent, | 221 | .uevent = spi_uevent, |
145 | .suspend = spi_suspend, | 222 | .pm = &spi_pm, |
146 | .resume = spi_resume, | ||
147 | }; | 223 | }; |
148 | EXPORT_SYMBOL_GPL(spi_bus_type); | 224 | EXPORT_SYMBOL_GPL(spi_bus_type); |
149 | 225 | ||