diff options
Diffstat (limited to 'drivers')
| -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); |
