diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/i2c-core.c | 166 |
1 files changed, 97 insertions, 69 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index c2258a51fe0c..7c469a62c3c1 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -159,107 +159,131 @@ static void i2c_device_shutdown(struct device *dev) | |||
159 | driver->shutdown(client); | 159 | driver->shutdown(client); |
160 | } | 160 | } |
161 | 161 | ||
162 | #ifdef CONFIG_SUSPEND | 162 | #ifdef CONFIG_PM_SLEEP |
163 | static int i2c_device_pm_suspend(struct device *dev) | 163 | static int i2c_legacy_suspend(struct device *dev, pm_message_t mesg) |
164 | { | 164 | { |
165 | const struct dev_pm_ops *pm; | 165 | struct i2c_client *client = i2c_verify_client(dev); |
166 | struct i2c_driver *driver; | ||
166 | 167 | ||
167 | if (!dev->driver) | 168 | if (!client || !dev->driver) |
168 | return 0; | 169 | return 0; |
169 | pm = dev->driver->pm; | 170 | driver = to_i2c_driver(dev->driver); |
170 | if (!pm || !pm->suspend) | 171 | if (!driver->suspend) |
171 | return 0; | 172 | return 0; |
172 | return pm->suspend(dev); | 173 | return driver->suspend(client, mesg); |
173 | } | 174 | } |
174 | 175 | ||
175 | static int i2c_device_pm_resume(struct device *dev) | 176 | static int i2c_legacy_resume(struct device *dev) |
176 | { | 177 | { |
177 | const struct dev_pm_ops *pm; | 178 | struct i2c_client *client = i2c_verify_client(dev); |
179 | struct i2c_driver *driver; | ||
178 | 180 | ||
179 | if (!dev->driver) | 181 | if (!client || !dev->driver) |
180 | return 0; | 182 | return 0; |
181 | pm = dev->driver->pm; | 183 | driver = to_i2c_driver(dev->driver); |
182 | if (!pm || !pm->resume) | 184 | if (!driver->resume) |
183 | return 0; | 185 | return 0; |
184 | return pm->resume(dev); | 186 | return driver->resume(client); |
185 | } | 187 | } |
186 | #else | ||
187 | #define i2c_device_pm_suspend NULL | ||
188 | #define i2c_device_pm_resume NULL | ||
189 | #endif | ||
190 | 188 | ||
191 | #ifdef CONFIG_PM_RUNTIME | 189 | static int i2c_device_pm_suspend(struct device *dev) |
192 | static int i2c_device_runtime_suspend(struct device *dev) | ||
193 | { | 190 | { |
194 | const struct dev_pm_ops *pm; | 191 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
195 | 192 | ||
196 | if (!dev->driver) | 193 | if (pm_runtime_suspended(dev)) |
197 | return 0; | ||
198 | pm = dev->driver->pm; | ||
199 | if (!pm || !pm->runtime_suspend) | ||
200 | return 0; | 194 | return 0; |
201 | return pm->runtime_suspend(dev); | ||
202 | } | ||
203 | 195 | ||
204 | static int i2c_device_runtime_resume(struct device *dev) | 196 | if (pm) |
205 | { | 197 | return pm->suspend ? pm->suspend(dev) : 0; |
206 | const struct dev_pm_ops *pm; | ||
207 | 198 | ||
208 | if (!dev->driver) | 199 | return i2c_legacy_suspend(dev, PMSG_SUSPEND); |
209 | return 0; | ||
210 | pm = dev->driver->pm; | ||
211 | if (!pm || !pm->runtime_resume) | ||
212 | return 0; | ||
213 | return pm->runtime_resume(dev); | ||
214 | } | 200 | } |
215 | 201 | ||
216 | static int i2c_device_runtime_idle(struct device *dev) | 202 | static int i2c_device_pm_resume(struct device *dev) |
217 | { | 203 | { |
218 | const struct dev_pm_ops *pm = NULL; | 204 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
219 | int ret; | 205 | int ret; |
220 | 206 | ||
221 | if (dev->driver) | 207 | if (pm) |
222 | pm = dev->driver->pm; | 208 | ret = pm->resume ? pm->resume(dev) : 0; |
223 | if (pm && pm->runtime_idle) { | 209 | else |
224 | ret = pm->runtime_idle(dev); | 210 | ret = i2c_legacy_resume(dev); |
225 | if (ret) | 211 | |
226 | return ret; | 212 | if (!ret) { |
213 | pm_runtime_disable(dev); | ||
214 | pm_runtime_set_active(dev); | ||
215 | pm_runtime_enable(dev); | ||
227 | } | 216 | } |
228 | 217 | ||
229 | return pm_runtime_suspend(dev); | 218 | return ret; |
230 | } | 219 | } |
231 | #else | ||
232 | #define i2c_device_runtime_suspend NULL | ||
233 | #define i2c_device_runtime_resume NULL | ||
234 | #define i2c_device_runtime_idle NULL | ||
235 | #endif | ||
236 | 220 | ||
237 | static int i2c_device_suspend(struct device *dev, pm_message_t mesg) | 221 | static int i2c_device_pm_freeze(struct device *dev) |
238 | { | 222 | { |
239 | struct i2c_client *client = i2c_verify_client(dev); | 223 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
240 | struct i2c_driver *driver; | ||
241 | 224 | ||
242 | if (!client || !dev->driver) | 225 | if (pm_runtime_suspended(dev)) |
243 | return 0; | 226 | return 0; |
244 | driver = to_i2c_driver(dev->driver); | 227 | |
245 | if (!driver->suspend) | 228 | if (pm) |
246 | return 0; | 229 | return pm->freeze ? pm->freeze(dev) : 0; |
247 | return driver->suspend(client, mesg); | 230 | |
231 | return i2c_legacy_suspend(dev, PMSG_FREEZE); | ||
248 | } | 232 | } |
249 | 233 | ||
250 | static int i2c_device_resume(struct device *dev) | 234 | static int i2c_device_pm_thaw(struct device *dev) |
251 | { | 235 | { |
252 | struct i2c_client *client = i2c_verify_client(dev); | 236 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; |
253 | struct i2c_driver *driver; | ||
254 | 237 | ||
255 | if (!client || !dev->driver) | 238 | if (pm_runtime_suspended(dev)) |
256 | return 0; | 239 | return 0; |
257 | driver = to_i2c_driver(dev->driver); | 240 | |
258 | if (!driver->resume) | 241 | if (pm) |
242 | return pm->thaw ? pm->thaw(dev) : 0; | ||
243 | |||
244 | return i2c_legacy_resume(dev); | ||
245 | } | ||
246 | |||
247 | static int i2c_device_pm_poweroff(struct device *dev) | ||
248 | { | ||
249 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | ||
250 | |||
251 | if (pm_runtime_suspended(dev)) | ||
259 | return 0; | 252 | return 0; |
260 | return driver->resume(client); | 253 | |
254 | if (pm) | ||
255 | return pm->poweroff ? pm->poweroff(dev) : 0; | ||
256 | |||
257 | return i2c_legacy_suspend(dev, PMSG_HIBERNATE); | ||
261 | } | 258 | } |
262 | 259 | ||
260 | static int i2c_device_pm_restore(struct device *dev) | ||
261 | { | ||
262 | const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL; | ||
263 | int ret; | ||
264 | |||
265 | if (pm) | ||
266 | ret = pm->restore ? pm->restore(dev) : 0; | ||
267 | else | ||
268 | ret = i2c_legacy_resume(dev); | ||
269 | |||
270 | if (!ret) { | ||
271 | pm_runtime_disable(dev); | ||
272 | pm_runtime_set_active(dev); | ||
273 | pm_runtime_enable(dev); | ||
274 | } | ||
275 | |||
276 | return ret; | ||
277 | } | ||
278 | #else /* !CONFIG_PM_SLEEP */ | ||
279 | #define i2c_device_pm_suspend NULL | ||
280 | #define i2c_device_pm_resume NULL | ||
281 | #define i2c_device_pm_freeze NULL | ||
282 | #define i2c_device_pm_thaw NULL | ||
283 | #define i2c_device_pm_poweroff NULL | ||
284 | #define i2c_device_pm_restore NULL | ||
285 | #endif /* !CONFIG_PM_SLEEP */ | ||
286 | |||
263 | static void i2c_client_dev_release(struct device *dev) | 287 | static void i2c_client_dev_release(struct device *dev) |
264 | { | 288 | { |
265 | kfree(to_i2c_client(dev)); | 289 | kfree(to_i2c_client(dev)); |
@@ -301,9 +325,15 @@ static const struct attribute_group *i2c_dev_attr_groups[] = { | |||
301 | static const struct dev_pm_ops i2c_device_pm_ops = { | 325 | static const struct dev_pm_ops i2c_device_pm_ops = { |
302 | .suspend = i2c_device_pm_suspend, | 326 | .suspend = i2c_device_pm_suspend, |
303 | .resume = i2c_device_pm_resume, | 327 | .resume = i2c_device_pm_resume, |
304 | .runtime_suspend = i2c_device_runtime_suspend, | 328 | .freeze = i2c_device_pm_freeze, |
305 | .runtime_resume = i2c_device_runtime_resume, | 329 | .thaw = i2c_device_pm_thaw, |
306 | .runtime_idle = i2c_device_runtime_idle, | 330 | .poweroff = i2c_device_pm_poweroff, |
331 | .restore = i2c_device_pm_restore, | ||
332 | SET_RUNTIME_PM_OPS( | ||
333 | pm_generic_runtime_suspend, | ||
334 | pm_generic_runtime_resume, | ||
335 | pm_generic_runtime_idle | ||
336 | ) | ||
307 | }; | 337 | }; |
308 | 338 | ||
309 | struct bus_type i2c_bus_type = { | 339 | struct bus_type i2c_bus_type = { |
@@ -312,8 +342,6 @@ struct bus_type i2c_bus_type = { | |||
312 | .probe = i2c_device_probe, | 342 | .probe = i2c_device_probe, |
313 | .remove = i2c_device_remove, | 343 | .remove = i2c_device_remove, |
314 | .shutdown = i2c_device_shutdown, | 344 | .shutdown = i2c_device_shutdown, |
315 | .suspend = i2c_device_suspend, | ||
316 | .resume = i2c_device_resume, | ||
317 | .pm = &i2c_device_pm_ops, | 345 | .pm = &i2c_device_pm_ops, |
318 | }; | 346 | }; |
319 | EXPORT_SYMBOL_GPL(i2c_bus_type); | 347 | EXPORT_SYMBOL_GPL(i2c_bus_type); |