[PATCH 04/19] pmdomain: associate devices with their power domain

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



In Linux, there is no public consumer API to enable or disable
a struct generic_pm_domain. Operations are instead performed on regular
struct device, each of which has a reference to a single attached
power domain.

Power domain consumer API in barebox was so far limited to automatically
attaching a single power domain and powering it on prior to function probe,
which is never detached and thus no further consumer API is needed.

To support more complex power domain setups, we adopt here the kernel API
of attaching power domains to devices to enable using struct device
as handles for additional power domain operations.

Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx>
---
 drivers/base/power.c | 26 +++++++++++++++++++++++++-
 include/driver.h     |  3 +++
 include/pm_domain.h  |  4 ++++
 3 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/base/power.c b/drivers/base/power.c
index e927d0f83ff0..4ff7b055c825 100644
--- a/drivers/base/power.c
+++ b/drivers/base/power.c
@@ -10,6 +10,14 @@
 
 static LIST_HEAD(gpd_list);
 
+static inline struct generic_pm_domain *dev_to_genpd(struct device *dev)
+{
+	if (IS_ERR_OR_NULL(dev->pm_domain))
+		return ERR_PTR(-EINVAL);
+
+	return dev->pm_domain;
+}
+
 /**
  * pm_genpd_init - Initialize a generic I/O PM domain object.
  * @genpd: PM domain object to initialize.
@@ -280,6 +288,17 @@ static int genpd_power_on(struct generic_pm_domain *genpd)
 	return 0;
 }
 
+static void genpd_add_device(struct generic_pm_domain *genpd, struct device *dev)
+{
+	dev->pm_domain = genpd;
+}
+
+static void genpd_remove_device(struct generic_pm_domain *genpd,
+			       struct device *dev)
+{
+	dev->pm_domain = NULL;
+}
+
 static int __genpd_dev_pm_attach(struct device *dev, struct device_node *np,
 				 unsigned int index, bool power_on)
 {
@@ -306,8 +325,13 @@ static int __genpd_dev_pm_attach(struct device *dev, struct device_node *np,
 
 	dev_dbg(dev, "adding to PM domain %s\n", pd ? pd->name : "dummy");
 
-	if (power_on)
+	genpd_add_device(pd, dev);
+
+	if (power_on) {
 		ret = genpd_power_on(pd);
+		if (ret < 0)
+			genpd_remove_device(pd, dev);
+	}
 
 	return ret ?: 1;
 }
diff --git a/include/driver.h b/include/driver.h
index 43d002f66dbe..7dfa565b8960 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -19,6 +19,7 @@
 
 struct filep;
 struct bus_type;
+struct generic_pm_domain;
 
 struct platform_device_id {
 	const char *name;
@@ -75,6 +76,8 @@ struct device {
 
 	struct device *parent;   /* our parent, NULL if not present */
 
+	struct generic_pm_domain *pm_domain;	/* attached power domain */
+
 	struct bus_type *bus;
 
 	/*! The parameters for this device. This is used to carry information
diff --git a/include/pm_domain.h b/include/pm_domain.h
index bf122460d0fe..59932ffee0b9 100644
--- a/include/pm_domain.h
+++ b/include/pm_domain.h
@@ -4,6 +4,7 @@
 #define _PM_DOMAIN_H
 
 #include <linux/list.h>
+#include <driver.h>
 #include <of.h>
 
 enum gpd_status {
@@ -93,6 +94,9 @@ of_genpd_add_provider_simple(struct device_node *np,
  */
 static inline int dev_pm_domain_attach(struct device *dev, bool power_on)
 {
+	if (dev->pm_domain)
+		return 0;
+
 	return genpd_dev_pm_attach(dev);
 }
 
-- 
2.39.2





[Index of Archives]     [Linux Embedded]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux