Merge tag 'driver-core-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / drivers / acpi / acpi_lpss.c
index dc2ca78748a2f5c7884174dfccc3a127be2746cc..d696f165a50e6e815deef12dcc0b19d31fd22494 100644 (file)
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
 /*
  * ACPI support for Intel Lynxpoint LPSS.
  *
  * Copyright (C) 2013, Intel Corporation
  * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
  *          Rafael J. Wysocki <rafael.j.wysocki@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #include <linux/acpi.h>
@@ -1064,6 +1061,13 @@ static int acpi_lpss_suspend_noirq(struct device *dev)
        int ret;
 
        if (pdata->dev_desc->resume_from_noirq) {
+               /*
+                * The driver's ->suspend_late callback will be invoked by
+                * acpi_lpss_do_suspend_late(), with the assumption that the
+                * driver really wanted to run that code in ->suspend_noirq, but
+                * it could not run after acpi_dev_suspend() and the driver
+                * expected the latter to be called in the "late" phase.
+                */
                ret = acpi_lpss_do_suspend_late(dev);
                if (ret)
                        return ret;
@@ -1094,16 +1098,99 @@ static int acpi_lpss_resume_noirq(struct device *dev)
        struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
        int ret;
 
-       ret = acpi_subsys_resume_noirq(dev);
+       /* Follow acpi_subsys_resume_noirq(). */
+       if (dev_pm_may_skip_resume(dev))
+               return 0;
+
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               pm_runtime_set_active(dev);
+
+       ret = pm_generic_resume_noirq(dev);
        if (ret)
                return ret;
 
-       if (!dev_pm_may_skip_resume(dev) && pdata->dev_desc->resume_from_noirq)
-               ret = acpi_lpss_do_resume_early(dev);
+       if (!pdata->dev_desc->resume_from_noirq)
+               return 0;
 
-       return ret;
+       /*
+        * The driver's ->resume_early callback will be invoked by
+        * acpi_lpss_do_resume_early(), with the assumption that the driver
+        * really wanted to run that code in ->resume_noirq, but it could not
+        * run before acpi_dev_resume() and the driver expected the latter to be
+        * called in the "early" phase.
+        */
+       return acpi_lpss_do_resume_early(dev);
+}
+
+static int acpi_lpss_do_restore_early(struct device *dev)
+{
+       int ret = acpi_lpss_resume(dev);
+
+       return ret ? ret : pm_generic_restore_early(dev);
+}
+
+static int acpi_lpss_restore_early(struct device *dev)
+{
+       struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+
+       if (pdata->dev_desc->resume_from_noirq)
+               return 0;
+
+       return acpi_lpss_do_restore_early(dev);
+}
+
+static int acpi_lpss_restore_noirq(struct device *dev)
+{
+       struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+       int ret;
+
+       ret = pm_generic_restore_noirq(dev);
+       if (ret)
+               return ret;
+
+       if (!pdata->dev_desc->resume_from_noirq)
+               return 0;
+
+       /* This is analogous to what happens in acpi_lpss_resume_noirq(). */
+       return acpi_lpss_do_restore_early(dev);
+}
+
+static int acpi_lpss_do_poweroff_late(struct device *dev)
+{
+       int ret = pm_generic_poweroff_late(dev);
+
+       return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev));
 }
 
+static int acpi_lpss_poweroff_late(struct device *dev)
+{
+       struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
+
+       if (pdata->dev_desc->resume_from_noirq)
+               return 0;
+
+       return acpi_lpss_do_poweroff_late(dev);
+}
+
+static int acpi_lpss_poweroff_noirq(struct device *dev)
+{
+       struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+
+       if (dev_pm_smart_suspend_and_suspended(dev))
+               return 0;
+
+       if (pdata->dev_desc->resume_from_noirq) {
+               /* This is analogous to the acpi_lpss_suspend_noirq() case. */
+               int ret = acpi_lpss_do_poweroff_late(dev);
+               if (ret)
+                       return ret;
+       }
+
+       return pm_generic_poweroff_noirq(dev);
+}
 #endif /* CONFIG_PM_SLEEP */
 
 static int acpi_lpss_runtime_suspend(struct device *dev)
@@ -1137,14 +1224,11 @@ static struct dev_pm_domain acpi_lpss_pm_domain = {
                .resume_noirq = acpi_lpss_resume_noirq,
                .resume_early = acpi_lpss_resume_early,
                .freeze = acpi_subsys_freeze,
-               .freeze_late = acpi_subsys_freeze_late,
-               .freeze_noirq = acpi_subsys_freeze_noirq,
-               .thaw_noirq = acpi_subsys_thaw_noirq,
-               .poweroff = acpi_subsys_suspend,
-               .poweroff_late = acpi_lpss_suspend_late,
-               .poweroff_noirq = acpi_lpss_suspend_noirq,
-               .restore_noirq = acpi_lpss_resume_noirq,
-               .restore_early = acpi_lpss_resume_early,
+               .poweroff = acpi_subsys_poweroff,
+               .poweroff_late = acpi_lpss_poweroff_late,
+               .poweroff_noirq = acpi_lpss_poweroff_noirq,
+               .restore_noirq = acpi_lpss_restore_noirq,
+               .restore_early = acpi_lpss_restore_early,
 #endif
                .runtime_suspend = acpi_lpss_runtime_suspend,
                .runtime_resume = acpi_lpss_runtime_resume,