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