aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Figa <t.figa@samsung.com>2012-11-21 10:21:17 -0500
committerKukjin Kim <kgene.kim@samsung.com>2012-11-21 10:38:59 -0500
commit8a65d2365df0635da13ae30c01e217c477c9ce3e (patch)
treea87b1bc99d4f4af42de72e91e1caf2d5bf4ce271
parent7add0ec0fef19d5b7a3ae38c5deb80819a065a17 (diff)
ARM: EXYNOS: Bind devices to power domains using DT
This patch adds a way to specify bindings between devices and power domains using device tree. A device can be bound to particular power domain by adding a power-domain property containing a phandle to the domain. The device will be bound to the domain before binding a driver to it and unbound after unbinding a driver from it. Signed-off-by: Tomasz Figa <t.figa@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
-rw-r--r--Documentation/devicetree/bindings/arm/exynos/power_domain.txt13
-rw-r--r--arch/arm/mach-exynos/pm_domains.c82
2 files changed, 94 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt
index 843b54622313..5216b419016a 100644
--- a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt
+++ b/Documentation/devicetree/bindings/arm/exynos/power_domain.txt
@@ -4,14 +4,25 @@ Exynos processors include support for multiple power domains which are used
4to gate power to one or more peripherals on the processor. 4to gate power to one or more peripherals on the processor.
5 5
6Required Properties: 6Required Properties:
7- compatiable: should be one of the following. 7- compatible: should be one of the following.
8 * samsung,exynos4210-pd - for exynos4210 type power domain. 8 * samsung,exynos4210-pd - for exynos4210 type power domain.
9- reg: physical base address of the controller and length of memory mapped 9- reg: physical base address of the controller and length of memory mapped
10 region. 10 region.
11 11
12Node of a device using power domains must have a samsung,power-domain property
13defined with a phandle to respective power domain.
14
12Example: 15Example:
13 16
14 lcd0: power-domain-lcd0 { 17 lcd0: power-domain-lcd0 {
15 compatible = "samsung,exynos4210-pd"; 18 compatible = "samsung,exynos4210-pd";
16 reg = <0x10023C00 0x10>; 19 reg = <0x10023C00 0x10>;
17 }; 20 };
21
22Example of the node using power domain:
23
24 node {
25 /* ... */
26 samsung,power-domain = <&lcd0>;
27 /* ... */
28 };
diff --git a/arch/arm/mach-exynos/pm_domains.c b/arch/arm/mach-exynos/pm_domains.c
index 5b7ce7ea6c61..9f1351de52f7 100644
--- a/arch/arm/mach-exynos/pm_domains.c
+++ b/arch/arm/mach-exynos/pm_domains.c
@@ -19,6 +19,8 @@
19#include <linux/pm_domain.h> 19#include <linux/pm_domain.h>
20#include <linux/delay.h> 20#include <linux/delay.h>
21#include <linux/of_address.h> 21#include <linux/of_address.h>
22#include <linux/of_platform.h>
23#include <linux/sched.h>
22 24
23#include <mach/regs-pmu.h> 25#include <mach/regs-pmu.h>
24#include <plat/devs.h> 26#include <plat/devs.h>
@@ -83,14 +85,89 @@ static struct exynos_pm_domain PD = { \
83} 85}
84 86
85#ifdef CONFIG_OF 87#ifdef CONFIG_OF
88static void exynos_add_device_to_domain(struct exynos_pm_domain *pd,
89 struct device *dev)
90{
91 int ret;
92
93 dev_dbg(dev, "adding to power domain %s\n", pd->pd.name);
94
95 while (1) {
96 ret = pm_genpd_add_device(&pd->pd, dev);
97 if (ret != -EAGAIN)
98 break;
99 cond_resched();
100 }
101
102 pm_genpd_dev_need_restore(dev, true);
103}
104
105static void exynos_remove_device_from_domain(struct device *dev)
106{
107 struct generic_pm_domain *genpd = dev_to_genpd(dev);
108 int ret;
109
110 dev_dbg(dev, "removing from power domain %s\n", genpd->name);
111
112 while (1) {
113 ret = pm_genpd_remove_device(genpd, dev);
114 if (ret != -EAGAIN)
115 break;
116 cond_resched();
117 }
118}
119
120static void exynos_read_domain_from_dt(struct device *dev)
121{
122 struct platform_device *pd_pdev;
123 struct exynos_pm_domain *pd;
124 struct device_node *node;
125
126 node = of_parse_phandle(dev->of_node, "samsung,power-domain", 0);
127 if (!node)
128 return;
129 pd_pdev = of_find_device_by_node(node);
130 if (!pd_pdev)
131 return;
132 pd = platform_get_drvdata(pd_pdev);
133 exynos_add_device_to_domain(pd, dev);
134}
135
136static int exynos_pm_notifier_call(struct notifier_block *nb,
137 unsigned long event, void *data)
138{
139 struct device *dev = data;
140
141 switch (event) {
142 case BUS_NOTIFY_BIND_DRIVER:
143 if (dev->of_node)
144 exynos_read_domain_from_dt(dev);
145
146 break;
147
148 case BUS_NOTIFY_UNBOUND_DRIVER:
149 exynos_remove_device_from_domain(dev);
150
151 break;
152 }
153 return NOTIFY_DONE;
154}
155
156static struct notifier_block platform_nb = {
157 .notifier_call = exynos_pm_notifier_call,
158};
159
86static __init int exynos_pm_dt_parse_domains(void) 160static __init int exynos_pm_dt_parse_domains(void)
87{ 161{
162 struct platform_device *pdev;
88 struct device_node *np; 163 struct device_node *np;
89 164
90 for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") { 165 for_each_compatible_node(np, NULL, "samsung,exynos4210-pd") {
91 struct exynos_pm_domain *pd; 166 struct exynos_pm_domain *pd;
92 int on; 167 int on;
93 168
169 pdev = of_find_device_by_node(np);
170
94 pd = kzalloc(sizeof(*pd), GFP_KERNEL); 171 pd = kzalloc(sizeof(*pd), GFP_KERNEL);
95 if (!pd) { 172 if (!pd) {
96 pr_err("%s: failed to allocate memory for domain\n", 173 pr_err("%s: failed to allocate memory for domain\n",
@@ -105,10 +182,15 @@ static __init int exynos_pm_dt_parse_domains(void)
105 pd->pd.power_on = exynos_pd_power_on; 182 pd->pd.power_on = exynos_pd_power_on;
106 pd->pd.of_node = np; 183 pd->pd.of_node = np;
107 184
185 platform_set_drvdata(pdev, pd);
186
108 on = __raw_readl(pd->base + 0x4) & S5P_INT_LOCAL_PWR_EN; 187 on = __raw_readl(pd->base + 0x4) & S5P_INT_LOCAL_PWR_EN;
109 188
110 pm_genpd_init(&pd->pd, NULL, !on); 189 pm_genpd_init(&pd->pd, NULL, !on);
111 } 190 }
191
192 bus_register_notifier(&platform_bus_type, &platform_nb);
193
112 return 0; 194 return 0;
113} 195}
114#else 196#else