diff options
author | Jonghwa Lee <jonghwa3.lee@samsung.com> | 2015-04-30 18:53:36 +0900 |
---|---|---|
committer | Seung-Woo Kim <sw0312.kim@samsung.com> | 2016-12-14 13:44:43 +0900 |
commit | 59e8e742fac9b21c50260f6a60df08625c5ec893 (patch) | |
tree | 7af53af067b17be1f1ca92be96d5020675f52b07 | |
parent | 81647b7c2fc47d34dbda75ac68e161bec6e4d668 (diff) |
soc: samsung: exynos_pd: Notify power domain status changing.
Add notification mechanism in exynos's power domain driver, to let
external driver which has interest in the specific power domain know
the power domain's status is changing.
Signed-off-by: Jonghwa Lee <jonghwa3.lee@samsung.com>
-rw-r--r-- | drivers/soc/samsung/pm_domains.c | 50 | ||||
-rw-r--r-- | include/linux/soc/samsung/pm_domain.h | 17 |
2 files changed, 66 insertions, 1 deletions
diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c index 623c422a636b..a97cce11cac7 100644 --- a/drivers/soc/samsung/pm_domains.c +++ b/drivers/soc/samsung/pm_domains.c @@ -16,12 +16,12 @@ #include <linux/io.h> #include <linux/err.h> #include <linux/slab.h> -#include <linux/pm_domain.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/sched.h> +#include <linux/soc/samsung/pm_domain.h> #define INT_LOCAL_PWR_EN 0xF @@ -34,6 +34,7 @@ struct exynos_pm_domain { char const *name; bool is_off; int nr_reparent_clks; + struct atomic_notifier_head nh; struct clk *oscclk; struct clk **clk; struct clk **pclk; @@ -41,6 +42,46 @@ struct exynos_pm_domain { struct clk **asb_clk; }; +int exynos_pd_notifier_register(struct generic_pm_domain *domain, + struct notifier_block *nb) +{ + struct exynos_pm_domain *pd; + + if (!domain || !nb) + return -EINVAL; + + pd = container_of(domain, struct exynos_pm_domain, pd); + return atomic_notifier_chain_register(&pd->nh, nb); +} + +void exynos_pd_notifier_unregister(struct generic_pm_domain *domain, + struct notifier_block *nb) +{ + struct exynos_pm_domain *pd; + + if (!domain || !nb) + return; + + pd = container_of(domain, struct exynos_pm_domain, pd); + atomic_notifier_chain_unregister(&pd->nh, nb); +} + +static void exynos_pd_notify_pre(struct exynos_pm_domain *pd, bool power_on) +{ + if (power_on) + atomic_notifier_call_chain(&pd->nh, EXYNOS_PD_PRE_ON, NULL); + else + atomic_notifier_call_chain(&pd->nh, EXYNOS_PD_PRE_OFF, NULL); +} + +static void exynos_pd_notify_post(struct exynos_pm_domain *pd, bool power_on) +{ + if (power_on) + atomic_notifier_call_chain(&pd->nh, EXYNOS_PD_POST_ON, NULL); + else + atomic_notifier_call_chain(&pd->nh, EXYNOS_PD_POST_OFF, NULL); +} + static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) { struct exynos_pm_domain *pd; @@ -52,6 +93,8 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) pd = container_of(domain, struct exynos_pm_domain, pd); base = pd->base; + exynos_pd_notify_pre(pd, power_on); + for (i = 0; i < pd->nr_asb_clks; i++) { if (IS_ERR(pd->asb_clk[i])) break; @@ -103,6 +146,8 @@ static int exynos_pd_power(struct generic_pm_domain *domain, bool power_on) clk_disable_unprepare(pd->asb_clk[i]); } + exynos_pd_notify_post(pd, power_on); + return 0; } @@ -138,10 +183,13 @@ static __init int exynos4_pm_init_power_domain(void) pd->pd.power_off = exynos_pd_power_off; pd->pd.power_on = exynos_pd_power_on; + ATOMIC_INIT_NOTIFIER_HEAD(&pd->nh); + nr_clks = of_count_phandle_with_args(np, "clocks","#clock-cells"); if (nr_clks > 0 && !(nr_clks % 2)) { nr_clks /= 2; + pd->oscclk = clk_get(NULL, "xxti"); if (IS_ERR(pd->oscclk)) break; diff --git a/include/linux/soc/samsung/pm_domain.h b/include/linux/soc/samsung/pm_domain.h new file mode 100644 index 000000000000..da5581f29a45 --- /dev/null +++ b/include/linux/soc/samsung/pm_domain.h @@ -0,0 +1,17 @@ +#ifndef __EXYNOS_PM_DOMAIN_H +#define __EXYNOS_PM_DOMAIN_H +#include <linux/pm_domain.h> +#include <linux/notifier.h> + +enum { + EXYNOS_PD_PRE_ON, + EXYNOS_PD_POST_ON, + EXYNOS_PD_PRE_OFF, + EXYNOS_PD_POST_OFF, +}; + +int exynos_pd_notifier_register(struct generic_pm_domain *, + struct notifier_block *); +void exynos_pd_notifier_unregister(struct generic_pm_domain *, + struct notifier_block *); +#endif /* __EXYNOS_PM_DOMAIN_H */ |