From 59e8e742fac9b21c50260f6a60df08625c5ec893 Mon Sep 17 00:00:00 2001 From: Jonghwa Lee Date: Thu, 30 Apr 2015 18:53:36 +0900 Subject: [PATCH] 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 --- drivers/soc/samsung/pm_domains.c | 50 ++++++++++++++++++++++++++++++++++- include/linux/soc/samsung/pm_domain.h | 17 ++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 include/linux/soc/samsung/pm_domain.h diff --git a/drivers/soc/samsung/pm_domains.c b/drivers/soc/samsung/pm_domains.c index 623c422..a97cce1 100644 --- a/drivers/soc/samsung/pm_domains.c +++ b/drivers/soc/samsung/pm_domains.c @@ -16,12 +16,12 @@ #include #include #include -#include #include #include #include #include #include +#include #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 0000000..da5581f --- /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 +#include + +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 */ -- 2.7.4