summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonghwa Lee <jonghwa3.lee@samsung.com>2015-04-30 18:53:36 +0900
committerSeung-Woo Kim <sw0312.kim@samsung.com>2016-12-14 13:44:43 +0900
commit59e8e742fac9b21c50260f6a60df08625c5ec893 (patch)
tree7af53af067b17be1f1ca92be96d5020675f52b07
parent81647b7c2fc47d34dbda75ac68e161bec6e4d668 (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.c50
-rw-r--r--include/linux/soc/samsung/pm_domain.h17
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 */