summaryrefslogtreecommitdiff
path: root/drivers/pmdomain/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pmdomain/core.c')
-rw-r--r--drivers/pmdomain/core.c80
1 files changed, 77 insertions, 3 deletions
diff --git a/drivers/pmdomain/core.c b/drivers/pmdomain/core.c
index 623d15b68707..7a61aa88c061 100644
--- a/drivers/pmdomain/core.c
+++ b/drivers/pmdomain/core.c
@@ -588,6 +588,68 @@ void dev_pm_genpd_synced_poweroff(struct device *dev)
}
EXPORT_SYMBOL_GPL(dev_pm_genpd_synced_poweroff);
+/**
+ * dev_pm_genpd_set_hwmode() - Set the HW mode for the device and its PM domain.
+ *
+ * @dev: Device for which the HW-mode should be changed.
+ * @enable: Value to set or unset the HW-mode.
+ *
+ * Some PM domains can rely on HW signals to control the power for a device. To
+ * allow a consumer driver to switch the behaviour for its device in runtime,
+ * which may be beneficial from a latency or energy point of view, this function
+ * may be called.
+ *
+ * It is assumed that the users guarantee that the genpd wouldn't be detached
+ * while this routine is getting called.
+ *
+ * Return: Returns 0 on success and negative error values on failures.
+ */
+int dev_pm_genpd_set_hwmode(struct device *dev, bool enable)
+{
+ struct generic_pm_domain *genpd;
+ int ret = 0;
+
+ genpd = dev_to_genpd_safe(dev);
+ if (!genpd)
+ return -ENODEV;
+
+ if (!genpd->set_hwmode_dev)
+ return -EOPNOTSUPP;
+
+ genpd_lock(genpd);
+
+ if (dev_gpd_data(dev)->hw_mode == enable)
+ goto out;
+
+ ret = genpd->set_hwmode_dev(genpd, dev, enable);
+ if (!ret)
+ dev_gpd_data(dev)->hw_mode = enable;
+
+out:
+ genpd_unlock(genpd);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_genpd_set_hwmode);
+
+/**
+ * dev_pm_genpd_get_hwmode() - Get the HW mode setting for the device.
+ *
+ * @dev: Device for which the current HW-mode setting should be fetched.
+ *
+ * This helper function allows consumer drivers to fetch the current HW mode
+ * setting of its the device.
+ *
+ * It is assumed that the users guarantee that the genpd wouldn't be detached
+ * while this routine is getting called.
+ *
+ * Return: Returns the HW mode setting of device from SW cached hw_mode.
+ */
+bool dev_pm_genpd_get_hwmode(struct device *dev)
+{
+ return dev_gpd_data(dev)->hw_mode;
+}
+EXPORT_SYMBOL_GPL(dev_pm_genpd_get_hwmode);
+
static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
{
unsigned int state_idx = genpd->state_idx;
@@ -1687,6 +1749,8 @@ static int genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
gpd_data->cpu = genpd_get_cpu(genpd, base_dev);
+ gpd_data->hw_mode = genpd->get_hwmode_dev ? genpd->get_hwmode_dev(genpd, dev) : false;
+
ret = genpd->attach_dev ? genpd->attach_dev(genpd, dev) : 0;
if (ret)
goto out;
@@ -2079,7 +2143,7 @@ static void genpd_free_data(struct generic_pm_domain *genpd)
static void genpd_lock_init(struct generic_pm_domain *genpd)
{
- if (genpd->flags & GENPD_FLAG_IRQ_SAFE) {
+ if (genpd_is_irq_safe(genpd)) {
spin_lock_init(&genpd->slock);
genpd->lock_ops = &genpd_spin_ops;
} else {
@@ -3120,6 +3184,15 @@ static void rtpm_status_str(struct seq_file *s, struct device *dev)
seq_printf(s, "%-25s ", p);
}
+static void mode_status_str(struct seq_file *s, struct device *dev)
+{
+ struct generic_pm_domain_data *gpd_data;
+
+ gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
+
+ seq_printf(s, "%20s", gpd_data->hw_mode ? "HW" : "SW");
+}
+
static void perf_status_str(struct seq_file *s, struct device *dev)
{
struct generic_pm_domain_data *gpd_data;
@@ -3178,6 +3251,7 @@ static int genpd_summary_one(struct seq_file *s,
seq_printf(s, "\n %-50s ", kobj_path);
rtpm_status_str(s, pm_data->dev);
perf_status_str(s, pm_data->dev);
+ mode_status_str(s, pm_data->dev);
kfree(kobj_path);
}
@@ -3194,8 +3268,8 @@ static int summary_show(struct seq_file *s, void *data)
int ret = 0;
seq_puts(s, "domain status children performance\n");
- seq_puts(s, " /device runtime status\n");
- seq_puts(s, "----------------------------------------------------------------------------------------------\n");
+ seq_puts(s, " /device runtime status managed by\n");
+ seq_puts(s, "------------------------------------------------------------------------------------------------------------\n");
ret = mutex_lock_interruptible(&gpd_list_lock);
if (ret)