|
@@ -561,6 +561,46 @@ static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
|
|
|
return GENPD_DEV_CALLBACK(genpd, bool, active_wakeup, dev);
|
|
|
}
|
|
|
|
|
|
+static int genpd_suspend_dev(struct generic_pm_domain *genpd, struct device *dev)
|
|
|
+{
|
|
|
+ return GENPD_DEV_CALLBACK(genpd, int, suspend, dev);
|
|
|
+}
|
|
|
+
|
|
|
+static int genpd_suspend_late(struct generic_pm_domain *genpd, struct device *dev)
|
|
|
+{
|
|
|
+ return GENPD_DEV_CALLBACK(genpd, int, suspend_late, dev);
|
|
|
+}
|
|
|
+
|
|
|
+static int genpd_resume_early(struct generic_pm_domain *genpd, struct device *dev)
|
|
|
+{
|
|
|
+ return GENPD_DEV_CALLBACK(genpd, int, resume_early, dev);
|
|
|
+}
|
|
|
+
|
|
|
+static int genpd_resume_dev(struct generic_pm_domain *genpd, struct device *dev)
|
|
|
+{
|
|
|
+ return GENPD_DEV_CALLBACK(genpd, int, resume, dev);
|
|
|
+}
|
|
|
+
|
|
|
+static int genpd_freeze_dev(struct generic_pm_domain *genpd, struct device *dev)
|
|
|
+{
|
|
|
+ return GENPD_DEV_CALLBACK(genpd, int, freeze, dev);
|
|
|
+}
|
|
|
+
|
|
|
+static int genpd_freeze_late(struct generic_pm_domain *genpd, struct device *dev)
|
|
|
+{
|
|
|
+ return GENPD_DEV_CALLBACK(genpd, int, freeze_late, dev);
|
|
|
+}
|
|
|
+
|
|
|
+static int genpd_thaw_early(struct generic_pm_domain *genpd, struct device *dev)
|
|
|
+{
|
|
|
+ return GENPD_DEV_CALLBACK(genpd, int, thaw_early, dev);
|
|
|
+}
|
|
|
+
|
|
|
+static int genpd_thaw_dev(struct generic_pm_domain *genpd, struct device *dev)
|
|
|
+{
|
|
|
+ return GENPD_DEV_CALLBACK(genpd, int, thaw, dev);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* pm_genpd_sync_poweroff - Synchronously power off a PM domain and its masters.
|
|
|
* @genpd: PM domain to power off, if possible.
|
|
@@ -712,7 +752,7 @@ static int pm_genpd_suspend(struct device *dev)
|
|
|
if (IS_ERR(genpd))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- return genpd->suspend_power_off ? 0 : pm_generic_suspend(dev);
|
|
|
+ return genpd->suspend_power_off ? 0 : genpd_suspend_dev(genpd, dev);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -737,7 +777,7 @@ static int pm_genpd_suspend_noirq(struct device *dev)
|
|
|
if (genpd->suspend_power_off)
|
|
|
return 0;
|
|
|
|
|
|
- ret = pm_generic_suspend_noirq(dev);
|
|
|
+ ret = genpd_suspend_late(genpd, dev);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
@@ -788,7 +828,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
|
|
|
genpd->suspended_count--;
|
|
|
genpd_start_dev(genpd, dev);
|
|
|
|
|
|
- return pm_generic_resume_noirq(dev);
|
|
|
+ return genpd_resume_early(genpd, dev);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -809,7 +849,7 @@ static int pm_genpd_resume(struct device *dev)
|
|
|
if (IS_ERR(genpd))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- return genpd->suspend_power_off ? 0 : pm_generic_resume(dev);
|
|
|
+ return genpd->suspend_power_off ? 0 : genpd_resume_dev(genpd, dev);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -830,7 +870,7 @@ static int pm_genpd_freeze(struct device *dev)
|
|
|
if (IS_ERR(genpd))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- return genpd->suspend_power_off ? 0 : pm_generic_freeze(dev);
|
|
|
+ return genpd->suspend_power_off ? 0 : genpd_freeze_dev(genpd, dev);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -856,7 +896,7 @@ static int pm_genpd_freeze_noirq(struct device *dev)
|
|
|
if (genpd->suspend_power_off)
|
|
|
return 0;
|
|
|
|
|
|
- ret = pm_generic_freeze_noirq(dev);
|
|
|
+ ret = genpd_freeze_late(genpd, dev);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
@@ -889,7 +929,7 @@ static int pm_genpd_thaw_noirq(struct device *dev)
|
|
|
|
|
|
genpd_start_dev(genpd, dev);
|
|
|
|
|
|
- return pm_generic_thaw_noirq(dev);
|
|
|
+ return genpd_thaw_early(genpd, dev);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -910,70 +950,7 @@ static int pm_genpd_thaw(struct device *dev)
|
|
|
if (IS_ERR(genpd))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- return genpd->suspend_power_off ? 0 : pm_generic_thaw(dev);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * pm_genpd_dev_poweroff - Power off a device belonging to an I/O PM domain.
|
|
|
- * @dev: Device to suspend.
|
|
|
- *
|
|
|
- * Power off a device under the assumption that its pm_domain field points to
|
|
|
- * the domain member of an object of type struct generic_pm_domain representing
|
|
|
- * a PM domain consisting of I/O devices.
|
|
|
- */
|
|
|
-static int pm_genpd_dev_poweroff(struct device *dev)
|
|
|
-{
|
|
|
- struct generic_pm_domain *genpd;
|
|
|
-
|
|
|
- dev_dbg(dev, "%s()\n", __func__);
|
|
|
-
|
|
|
- genpd = dev_to_genpd(dev);
|
|
|
- if (IS_ERR(genpd))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- return genpd->suspend_power_off ? 0 : pm_generic_poweroff(dev);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * pm_genpd_dev_poweroff_noirq - Late power off of a device from a PM domain.
|
|
|
- * @dev: Device to suspend.
|
|
|
- *
|
|
|
- * Carry out a late powering off of a device under the assumption that its
|
|
|
- * pm_domain field points to the domain member of an object of type
|
|
|
- * struct generic_pm_domain representing a PM domain consisting of I/O devices.
|
|
|
- */
|
|
|
-static int pm_genpd_dev_poweroff_noirq(struct device *dev)
|
|
|
-{
|
|
|
- struct generic_pm_domain *genpd;
|
|
|
- int ret;
|
|
|
-
|
|
|
- dev_dbg(dev, "%s()\n", __func__);
|
|
|
-
|
|
|
- genpd = dev_to_genpd(dev);
|
|
|
- if (IS_ERR(genpd))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- if (genpd->suspend_power_off)
|
|
|
- return 0;
|
|
|
-
|
|
|
- ret = pm_generic_poweroff_noirq(dev);
|
|
|
- if (ret)
|
|
|
- return ret;
|
|
|
-
|
|
|
- if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
|
|
|
- return 0;
|
|
|
-
|
|
|
- genpd_stop_dev(genpd, dev);
|
|
|
-
|
|
|
- /*
|
|
|
- * Since all of the "noirq" callbacks are executed sequentially, it is
|
|
|
- * guaranteed that this function will never run twice in parallel for
|
|
|
- * the same PM domain, so it is not necessary to use locking here.
|
|
|
- */
|
|
|
- genpd->suspended_count++;
|
|
|
- pm_genpd_sync_poweroff(genpd);
|
|
|
-
|
|
|
- return 0;
|
|
|
+ return genpd->suspend_power_off ? 0 : genpd_thaw_dev(genpd, dev);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1015,28 +992,7 @@ static int pm_genpd_restore_noirq(struct device *dev)
|
|
|
genpd->suspended_count--;
|
|
|
genpd_start_dev(genpd, dev);
|
|
|
|
|
|
- return pm_generic_restore_noirq(dev);
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * pm_genpd_restore - Restore a device belonging to an I/O power domain.
|
|
|
- * @dev: Device to resume.
|
|
|
- *
|
|
|
- * Restore a device under the assumption that its pm_domain field points to the
|
|
|
- * domain member of an object of type struct generic_pm_domain representing
|
|
|
- * a power domain consisting of I/O devices.
|
|
|
- */
|
|
|
-static int pm_genpd_restore(struct device *dev)
|
|
|
-{
|
|
|
- struct generic_pm_domain *genpd;
|
|
|
-
|
|
|
- dev_dbg(dev, "%s()\n", __func__);
|
|
|
-
|
|
|
- genpd = dev_to_genpd(dev);
|
|
|
- if (IS_ERR(genpd))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- return genpd->suspend_power_off ? 0 : pm_generic_restore(dev);
|
|
|
+ return genpd_resume_early(genpd, dev);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1086,10 +1042,7 @@ static void pm_genpd_complete(struct device *dev)
|
|
|
#define pm_genpd_freeze_noirq NULL
|
|
|
#define pm_genpd_thaw_noirq NULL
|
|
|
#define pm_genpd_thaw NULL
|
|
|
-#define pm_genpd_dev_poweroff_noirq NULL
|
|
|
-#define pm_genpd_dev_poweroff NULL
|
|
|
#define pm_genpd_restore_noirq NULL
|
|
|
-#define pm_genpd_restore NULL
|
|
|
#define pm_genpd_complete NULL
|
|
|
|
|
|
#endif /* CONFIG_PM_SLEEP */
|
|
@@ -1361,6 +1314,8 @@ int pm_genpd_remove_callbacks(struct device *dev)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(pm_genpd_remove_callbacks);
|
|
|
|
|
|
+/* Default device callbacks for generic PM domains. */
|
|
|
+
|
|
|
/**
|
|
|
* pm_genpd_default_save_state - Default "save device state" for PM domians.
|
|
|
* @dev: Device to handle.
|
|
@@ -1399,6 +1354,94 @@ static int pm_genpd_default_restore_state(struct device *dev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * pm_genpd_default_suspend - Default "device suspend" for PM domians.
|
|
|
+ * @dev: Device to handle.
|
|
|
+ */
|
|
|
+static int pm_genpd_default_suspend(struct device *dev)
|
|
|
+{
|
|
|
+ int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze;
|
|
|
+
|
|
|
+ return cb ? cb(dev) : pm_generic_suspend(dev);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * pm_genpd_default_suspend_late - Default "late device suspend" for PM domians.
|
|
|
+ * @dev: Device to handle.
|
|
|
+ */
|
|
|
+static int pm_genpd_default_suspend_late(struct device *dev)
|
|
|
+{
|
|
|
+ int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late;
|
|
|
+
|
|
|
+ return cb ? cb(dev) : pm_generic_suspend_noirq(dev);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * pm_genpd_default_resume_early - Default "early device resume" for PM domians.
|
|
|
+ * @dev: Device to handle.
|
|
|
+ */
|
|
|
+static int pm_genpd_default_resume_early(struct device *dev)
|
|
|
+{
|
|
|
+ int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early;
|
|
|
+
|
|
|
+ return cb ? cb(dev) : pm_generic_resume_noirq(dev);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * pm_genpd_default_resume - Default "device resume" for PM domians.
|
|
|
+ * @dev: Device to handle.
|
|
|
+ */
|
|
|
+static int pm_genpd_default_resume(struct device *dev)
|
|
|
+{
|
|
|
+ int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw;
|
|
|
+
|
|
|
+ return cb ? cb(dev) : pm_generic_resume(dev);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * pm_genpd_default_freeze - Default "device freeze" for PM domians.
|
|
|
+ * @dev: Device to handle.
|
|
|
+ */
|
|
|
+static int pm_genpd_default_freeze(struct device *dev)
|
|
|
+{
|
|
|
+ int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze;
|
|
|
+
|
|
|
+ return cb ? cb(dev) : pm_generic_freeze(dev);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * pm_genpd_default_freeze_late - Default "late device freeze" for PM domians.
|
|
|
+ * @dev: Device to handle.
|
|
|
+ */
|
|
|
+static int pm_genpd_default_freeze_late(struct device *dev)
|
|
|
+{
|
|
|
+ int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.freeze_late;
|
|
|
+
|
|
|
+ return cb ? cb(dev) : pm_generic_freeze_noirq(dev);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * pm_genpd_default_thaw_early - Default "early device thaw" for PM domians.
|
|
|
+ * @dev: Device to handle.
|
|
|
+ */
|
|
|
+static int pm_genpd_default_thaw_early(struct device *dev)
|
|
|
+{
|
|
|
+ int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw_early;
|
|
|
+
|
|
|
+ return cb ? cb(dev) : pm_generic_thaw_noirq(dev);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * pm_genpd_default_thaw - Default "device thaw" for PM domians.
|
|
|
+ * @dev: Device to handle.
|
|
|
+ */
|
|
|
+static int pm_genpd_default_thaw(struct device *dev)
|
|
|
+{
|
|
|
+ int (*cb)(struct device *__dev) = dev_gpd_data(dev)->ops.thaw;
|
|
|
+
|
|
|
+ return cb ? cb(dev) : pm_generic_thaw(dev);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* pm_genpd_init - Initialize a generic I/O PM domain object.
|
|
|
* @genpd: PM domain object to initialize.
|
|
@@ -1437,13 +1480,21 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
|
|
|
genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq;
|
|
|
genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq;
|
|
|
genpd->domain.ops.thaw = pm_genpd_thaw;
|
|
|
- genpd->domain.ops.poweroff = pm_genpd_dev_poweroff;
|
|
|
- genpd->domain.ops.poweroff_noirq = pm_genpd_dev_poweroff_noirq;
|
|
|
+ genpd->domain.ops.poweroff = pm_genpd_suspend;
|
|
|
+ genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq;
|
|
|
genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq;
|
|
|
- genpd->domain.ops.restore = pm_genpd_restore;
|
|
|
+ genpd->domain.ops.restore = pm_genpd_resume;
|
|
|
genpd->domain.ops.complete = pm_genpd_complete;
|
|
|
genpd->dev_ops.save_state = pm_genpd_default_save_state;
|
|
|
genpd->dev_ops.restore_state = pm_genpd_default_restore_state;
|
|
|
+ genpd->dev_ops.freeze = pm_genpd_default_suspend;
|
|
|
+ genpd->dev_ops.freeze_late = pm_genpd_default_suspend_late;
|
|
|
+ genpd->dev_ops.thaw_early = pm_genpd_default_resume_early;
|
|
|
+ genpd->dev_ops.thaw = pm_genpd_default_resume;
|
|
|
+ genpd->dev_ops.freeze = pm_genpd_default_freeze;
|
|
|
+ genpd->dev_ops.freeze_late = pm_genpd_default_freeze_late;
|
|
|
+ genpd->dev_ops.thaw_early = pm_genpd_default_thaw_early;
|
|
|
+ genpd->dev_ops.thaw = pm_genpd_default_thaw;
|
|
|
mutex_lock(&gpd_list_lock);
|
|
|
list_add(&genpd->gpd_list_node, &gpd_list);
|
|
|
mutex_unlock(&gpd_list_lock);
|