|
@@ -159,107 +159,131 @@ static void i2c_device_shutdown(struct device *dev)
|
|
driver->shutdown(client);
|
|
driver->shutdown(client);
|
|
}
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_SUSPEND
|
|
|
|
-static int i2c_device_pm_suspend(struct device *dev)
|
|
|
|
|
|
+#ifdef CONFIG_PM_SLEEP
|
|
|
|
+static int i2c_legacy_suspend(struct device *dev, pm_message_t mesg)
|
|
{
|
|
{
|
|
- const struct dev_pm_ops *pm;
|
|
|
|
|
|
+ struct i2c_client *client = i2c_verify_client(dev);
|
|
|
|
+ struct i2c_driver *driver;
|
|
|
|
|
|
- if (!dev->driver)
|
|
|
|
|
|
+ if (!client || !dev->driver)
|
|
return 0;
|
|
return 0;
|
|
- pm = dev->driver->pm;
|
|
|
|
- if (!pm || !pm->suspend)
|
|
|
|
|
|
+ driver = to_i2c_driver(dev->driver);
|
|
|
|
+ if (!driver->suspend)
|
|
return 0;
|
|
return 0;
|
|
- return pm->suspend(dev);
|
|
|
|
|
|
+ return driver->suspend(client, mesg);
|
|
}
|
|
}
|
|
|
|
|
|
-static int i2c_device_pm_resume(struct device *dev)
|
|
|
|
|
|
+static int i2c_legacy_resume(struct device *dev)
|
|
{
|
|
{
|
|
- const struct dev_pm_ops *pm;
|
|
|
|
|
|
+ struct i2c_client *client = i2c_verify_client(dev);
|
|
|
|
+ struct i2c_driver *driver;
|
|
|
|
|
|
- if (!dev->driver)
|
|
|
|
|
|
+ if (!client || !dev->driver)
|
|
return 0;
|
|
return 0;
|
|
- pm = dev->driver->pm;
|
|
|
|
- if (!pm || !pm->resume)
|
|
|
|
|
|
+ driver = to_i2c_driver(dev->driver);
|
|
|
|
+ if (!driver->resume)
|
|
return 0;
|
|
return 0;
|
|
- return pm->resume(dev);
|
|
|
|
|
|
+ return driver->resume(client);
|
|
}
|
|
}
|
|
-#else
|
|
|
|
-#define i2c_device_pm_suspend NULL
|
|
|
|
-#define i2c_device_pm_resume NULL
|
|
|
|
-#endif
|
|
|
|
|
|
|
|
-#ifdef CONFIG_PM_RUNTIME
|
|
|
|
-static int i2c_device_runtime_suspend(struct device *dev)
|
|
|
|
|
|
+static int i2c_device_pm_suspend(struct device *dev)
|
|
{
|
|
{
|
|
- const struct dev_pm_ops *pm;
|
|
|
|
|
|
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
|
|
|
|
|
- if (!dev->driver)
|
|
|
|
- return 0;
|
|
|
|
- pm = dev->driver->pm;
|
|
|
|
- if (!pm || !pm->runtime_suspend)
|
|
|
|
|
|
+ if (pm_runtime_suspended(dev))
|
|
return 0;
|
|
return 0;
|
|
- return pm->runtime_suspend(dev);
|
|
|
|
-}
|
|
|
|
|
|
|
|
-static int i2c_device_runtime_resume(struct device *dev)
|
|
|
|
-{
|
|
|
|
- const struct dev_pm_ops *pm;
|
|
|
|
|
|
+ if (pm)
|
|
|
|
+ return pm->suspend ? pm->suspend(dev) : 0;
|
|
|
|
|
|
- if (!dev->driver)
|
|
|
|
- return 0;
|
|
|
|
- pm = dev->driver->pm;
|
|
|
|
- if (!pm || !pm->runtime_resume)
|
|
|
|
- return 0;
|
|
|
|
- return pm->runtime_resume(dev);
|
|
|
|
|
|
+ return i2c_legacy_suspend(dev, PMSG_SUSPEND);
|
|
}
|
|
}
|
|
|
|
|
|
-static int i2c_device_runtime_idle(struct device *dev)
|
|
|
|
|
|
+static int i2c_device_pm_resume(struct device *dev)
|
|
{
|
|
{
|
|
- const struct dev_pm_ops *pm = NULL;
|
|
|
|
|
|
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
- if (dev->driver)
|
|
|
|
- pm = dev->driver->pm;
|
|
|
|
- if (pm && pm->runtime_idle) {
|
|
|
|
- ret = pm->runtime_idle(dev);
|
|
|
|
- if (ret)
|
|
|
|
- return ret;
|
|
|
|
|
|
+ if (pm)
|
|
|
|
+ ret = pm->resume ? pm->resume(dev) : 0;
|
|
|
|
+ else
|
|
|
|
+ ret = i2c_legacy_resume(dev);
|
|
|
|
+
|
|
|
|
+ if (!ret) {
|
|
|
|
+ pm_runtime_disable(dev);
|
|
|
|
+ pm_runtime_set_active(dev);
|
|
|
|
+ pm_runtime_enable(dev);
|
|
}
|
|
}
|
|
|
|
|
|
- return pm_runtime_suspend(dev);
|
|
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
-#else
|
|
|
|
-#define i2c_device_runtime_suspend NULL
|
|
|
|
-#define i2c_device_runtime_resume NULL
|
|
|
|
-#define i2c_device_runtime_idle NULL
|
|
|
|
-#endif
|
|
|
|
|
|
|
|
-static int i2c_device_suspend(struct device *dev, pm_message_t mesg)
|
|
|
|
|
|
+static int i2c_device_pm_freeze(struct device *dev)
|
|
{
|
|
{
|
|
- struct i2c_client *client = i2c_verify_client(dev);
|
|
|
|
- struct i2c_driver *driver;
|
|
|
|
|
|
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
|
|
|
|
|
- if (!client || !dev->driver)
|
|
|
|
|
|
+ if (pm_runtime_suspended(dev))
|
|
return 0;
|
|
return 0;
|
|
- driver = to_i2c_driver(dev->driver);
|
|
|
|
- if (!driver->suspend)
|
|
|
|
- return 0;
|
|
|
|
- return driver->suspend(client, mesg);
|
|
|
|
|
|
+
|
|
|
|
+ if (pm)
|
|
|
|
+ return pm->freeze ? pm->freeze(dev) : 0;
|
|
|
|
+
|
|
|
|
+ return i2c_legacy_suspend(dev, PMSG_FREEZE);
|
|
}
|
|
}
|
|
|
|
|
|
-static int i2c_device_resume(struct device *dev)
|
|
|
|
|
|
+static int i2c_device_pm_thaw(struct device *dev)
|
|
{
|
|
{
|
|
- struct i2c_client *client = i2c_verify_client(dev);
|
|
|
|
- struct i2c_driver *driver;
|
|
|
|
|
|
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
|
|
|
|
|
- if (!client || !dev->driver)
|
|
|
|
|
|
+ if (pm_runtime_suspended(dev))
|
|
return 0;
|
|
return 0;
|
|
- driver = to_i2c_driver(dev->driver);
|
|
|
|
- if (!driver->resume)
|
|
|
|
|
|
+
|
|
|
|
+ if (pm)
|
|
|
|
+ return pm->thaw ? pm->thaw(dev) : 0;
|
|
|
|
+
|
|
|
|
+ return i2c_legacy_resume(dev);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int i2c_device_pm_poweroff(struct device *dev)
|
|
|
|
+{
|
|
|
|
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
|
|
|
+
|
|
|
|
+ if (pm_runtime_suspended(dev))
|
|
return 0;
|
|
return 0;
|
|
- return driver->resume(client);
|
|
|
|
|
|
+
|
|
|
|
+ if (pm)
|
|
|
|
+ return pm->poweroff ? pm->poweroff(dev) : 0;
|
|
|
|
+
|
|
|
|
+ return i2c_legacy_suspend(dev, PMSG_HIBERNATE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int i2c_device_pm_restore(struct device *dev)
|
|
|
|
+{
|
|
|
|
+ const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ if (pm)
|
|
|
|
+ ret = pm->restore ? pm->restore(dev) : 0;
|
|
|
|
+ else
|
|
|
|
+ ret = i2c_legacy_resume(dev);
|
|
|
|
+
|
|
|
|
+ if (!ret) {
|
|
|
|
+ pm_runtime_disable(dev);
|
|
|
|
+ pm_runtime_set_active(dev);
|
|
|
|
+ pm_runtime_enable(dev);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+#else /* !CONFIG_PM_SLEEP */
|
|
|
|
+#define i2c_device_pm_suspend NULL
|
|
|
|
+#define i2c_device_pm_resume NULL
|
|
|
|
+#define i2c_device_pm_freeze NULL
|
|
|
|
+#define i2c_device_pm_thaw NULL
|
|
|
|
+#define i2c_device_pm_poweroff NULL
|
|
|
|
+#define i2c_device_pm_restore NULL
|
|
|
|
+#endif /* !CONFIG_PM_SLEEP */
|
|
|
|
+
|
|
static void i2c_client_dev_release(struct device *dev)
|
|
static void i2c_client_dev_release(struct device *dev)
|
|
{
|
|
{
|
|
kfree(to_i2c_client(dev));
|
|
kfree(to_i2c_client(dev));
|
|
@@ -301,9 +325,15 @@ static const struct attribute_group *i2c_dev_attr_groups[] = {
|
|
static const struct dev_pm_ops i2c_device_pm_ops = {
|
|
static const struct dev_pm_ops i2c_device_pm_ops = {
|
|
.suspend = i2c_device_pm_suspend,
|
|
.suspend = i2c_device_pm_suspend,
|
|
.resume = i2c_device_pm_resume,
|
|
.resume = i2c_device_pm_resume,
|
|
- .runtime_suspend = i2c_device_runtime_suspend,
|
|
|
|
- .runtime_resume = i2c_device_runtime_resume,
|
|
|
|
- .runtime_idle = i2c_device_runtime_idle,
|
|
|
|
|
|
+ .freeze = i2c_device_pm_freeze,
|
|
|
|
+ .thaw = i2c_device_pm_thaw,
|
|
|
|
+ .poweroff = i2c_device_pm_poweroff,
|
|
|
|
+ .restore = i2c_device_pm_restore,
|
|
|
|
+ SET_RUNTIME_PM_OPS(
|
|
|
|
+ pm_generic_runtime_suspend,
|
|
|
|
+ pm_generic_runtime_resume,
|
|
|
|
+ pm_generic_runtime_idle
|
|
|
|
+ )
|
|
};
|
|
};
|
|
|
|
|
|
struct bus_type i2c_bus_type = {
|
|
struct bus_type i2c_bus_type = {
|
|
@@ -312,8 +342,6 @@ struct bus_type i2c_bus_type = {
|
|
.probe = i2c_device_probe,
|
|
.probe = i2c_device_probe,
|
|
.remove = i2c_device_remove,
|
|
.remove = i2c_device_remove,
|
|
.shutdown = i2c_device_shutdown,
|
|
.shutdown = i2c_device_shutdown,
|
|
- .suspend = i2c_device_suspend,
|
|
|
|
- .resume = i2c_device_resume,
|
|
|
|
.pm = &i2c_device_pm_ops,
|
|
.pm = &i2c_device_pm_ops,
|
|
};
|
|
};
|
|
EXPORT_SYMBOL_GPL(i2c_bus_type);
|
|
EXPORT_SYMBOL_GPL(i2c_bus_type);
|