aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/i2c-core.c166
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
163static int i2c_device_pm_suspend(struct device *dev) 163static 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
175static int i2c_device_pm_resume(struct device *dev) 176static 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 189static int i2c_device_pm_suspend(struct device *dev)
192static 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
204static 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
216static int i2c_device_runtime_idle(struct device *dev) 202static 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
237static int i2c_device_suspend(struct device *dev, pm_message_t mesg) 221static 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
250static int i2c_device_resume(struct device *dev) 234static 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
247static 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
260static 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
263static void i2c_client_dev_release(struct device *dev) 287static 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[] = {
301static const struct dev_pm_ops i2c_device_pm_ops = { 325static 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
309struct bus_type i2c_bus_type = { 339struct 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};
319EXPORT_SYMBOL_GPL(i2c_bus_type); 347EXPORT_SYMBOL_GPL(i2c_bus_type);