|
@@ -42,6 +42,7 @@
|
|
|
#include <linux/reset.h>
|
|
|
#include <linux/sched.h>
|
|
|
#include <linux/slab.h>
|
|
|
+#include <linux/suspend.h>
|
|
|
|
|
|
#include "i2c-designware-core.h"
|
|
|
|
|
@@ -372,7 +373,10 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
|
|
|
ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
|
|
|
adap->dev.of_node = pdev->dev.of_node;
|
|
|
|
|
|
- dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_SMART_PREPARE);
|
|
|
+ dev_pm_set_driver_flags(&pdev->dev,
|
|
|
+ DPM_FLAG_SMART_PREPARE |
|
|
|
+ DPM_FLAG_SMART_SUSPEND |
|
|
|
+ DPM_FLAG_LEAVE_SUSPENDED);
|
|
|
|
|
|
/* The code below assumes runtime PM to be disabled. */
|
|
|
WARN_ON(pm_runtime_enabled(&pdev->dev));
|
|
@@ -448,7 +452,13 @@ static int dw_i2c_plat_prepare(struct device *dev)
|
|
|
|
|
|
static void dw_i2c_plat_complete(struct device *dev)
|
|
|
{
|
|
|
- if (dev->power.direct_complete)
|
|
|
+ /*
|
|
|
+ * The device can only be in runtime suspend at this point if it has not
|
|
|
+ * been resumed throughout the ending system suspend/resume cycle, so if
|
|
|
+ * the platform firmware might mess up with it, request the runtime PM
|
|
|
+ * framework to resume it.
|
|
|
+ */
|
|
|
+ if (pm_runtime_suspended(dev) && pm_resume_via_firmware())
|
|
|
pm_request_resume(dev);
|
|
|
}
|
|
|
#else
|
|
@@ -461,16 +471,9 @@ static int dw_i2c_plat_suspend(struct device *dev)
|
|
|
{
|
|
|
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
|
|
|
|
|
|
- if (i_dev->suspended) {
|
|
|
- i_dev->skip_resume = true;
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
i_dev->disable(i_dev);
|
|
|
i2c_dw_plat_prepare_clk(i_dev, false);
|
|
|
|
|
|
- i_dev->suspended = true;
|
|
|
-
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -478,19 +481,9 @@ static int dw_i2c_plat_resume(struct device *dev)
|
|
|
{
|
|
|
struct dw_i2c_dev *i_dev = dev_get_drvdata(dev);
|
|
|
|
|
|
- if (!i_dev->suspended)
|
|
|
- return 0;
|
|
|
-
|
|
|
- if (i_dev->skip_resume) {
|
|
|
- i_dev->skip_resume = false;
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
i2c_dw_plat_prepare_clk(i_dev, true);
|
|
|
i_dev->init(i_dev);
|
|
|
|
|
|
- i_dev->suspended = false;
|
|
|
-
|
|
|
return 0;
|
|
|
}
|
|
|
|