diff options
author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2012-07-05 04:24:46 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2012-07-06 14:33:57 -0400 |
commit | 8f45b112fc66ef6869ccca4c3966976982f496a9 (patch) | |
tree | dcef2c88be3b824344b6505a2712ba1dcb3d7eb5 | |
parent | 64e9de2f854fb5d08d255b24568c60b090f2603a (diff) |
ARM: shmobile: soc-core: add R-mobile PM domain common APIs
This patch adds Renesas R-mobile series common PM domain APIs.
R-mobile CPU can use/switch this API
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Acked-by: Magnus Damm <damm@opensource.se>
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
-rw-r--r-- | arch/arm/mach-shmobile/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/pm-rmobile.h | 44 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/pm-rmobile.c | 167 |
3 files changed, 212 insertions, 0 deletions
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 8aa1962c22a2..3ffe4126922f 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile | |||
@@ -39,6 +39,7 @@ obj-$(CONFIG_ARCH_R8A7740) += entry-intc.o | |||
39 | # PM objects | 39 | # PM objects |
40 | obj-$(CONFIG_SUSPEND) += suspend.o | 40 | obj-$(CONFIG_SUSPEND) += suspend.o |
41 | obj-$(CONFIG_CPU_IDLE) += cpuidle.o | 41 | obj-$(CONFIG_CPU_IDLE) += cpuidle.o |
42 | obj-$(CONFIG_ARCH_SHMOBILE) += pm-rmobile.o | ||
42 | obj-$(CONFIG_ARCH_SH7372) += pm-sh7372.o sleep-sh7372.o | 43 | obj-$(CONFIG_ARCH_SH7372) += pm-sh7372.o sleep-sh7372.o |
43 | obj-$(CONFIG_ARCH_R8A7779) += pm-r8a7779.o | 44 | obj-$(CONFIG_ARCH_R8A7779) += pm-r8a7779.o |
44 | 45 | ||
diff --git a/arch/arm/mach-shmobile/include/mach/pm-rmobile.h b/arch/arm/mach-shmobile/include/mach/pm-rmobile.h new file mode 100644 index 000000000000..5a402840fe28 --- /dev/null +++ b/arch/arm/mach-shmobile/include/mach/pm-rmobile.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Renesas Solutions Corp. | ||
3 | * | ||
4 | * Kuninori Morimoto <morimoto.kuninori@renesas.com> | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #ifndef PM_RMOBILE_H | ||
11 | #define PM_RMOBILE_H | ||
12 | |||
13 | #include <linux/pm_domain.h> | ||
14 | |||
15 | struct platform_device; | ||
16 | |||
17 | struct rmobile_pm_domain { | ||
18 | struct generic_pm_domain genpd; | ||
19 | struct dev_power_governor *gov; | ||
20 | int (*suspend)(void); | ||
21 | void (*resume)(void); | ||
22 | unsigned int bit_shift; | ||
23 | bool no_debug; | ||
24 | }; | ||
25 | |||
26 | static inline | ||
27 | struct rmobile_pm_domain *to_rmobile_pd(struct generic_pm_domain *d) | ||
28 | { | ||
29 | return container_of(d, struct rmobile_pm_domain, genpd); | ||
30 | } | ||
31 | |||
32 | #ifdef CONFIG_PM | ||
33 | extern void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd); | ||
34 | extern void rmobile_add_device_to_domain(struct rmobile_pm_domain *rmobile_pd, | ||
35 | struct platform_device *pdev); | ||
36 | extern void rmobile_pm_add_subdomain(struct rmobile_pm_domain *rmobile_pd, | ||
37 | struct rmobile_pm_domain *rmobile_sd); | ||
38 | #else | ||
39 | #define rmobile_init_pm_domain(pd) do { } while (0) | ||
40 | #define rmobile_add_device_to_domain(pd, pdev) do { } while (0) | ||
41 | #define rmobile_pm_add_subdomain(pd, sd) do { } while (0) | ||
42 | #endif /* CONFIG_PM */ | ||
43 | |||
44 | #endif /* PM_RMOBILE_H */ | ||
diff --git a/arch/arm/mach-shmobile/pm-rmobile.c b/arch/arm/mach-shmobile/pm-rmobile.c new file mode 100644 index 000000000000..a8562540f1d6 --- /dev/null +++ b/arch/arm/mach-shmobile/pm-rmobile.c | |||
@@ -0,0 +1,167 @@ | |||
1 | /* | ||
2 | * rmobile power management support | ||
3 | * | ||
4 | * Copyright (C) 2012 Renesas Solutions Corp. | ||
5 | * Copyright (C) 2012 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
6 | * | ||
7 | * based on pm-sh7372.c | ||
8 | * Copyright (C) 2011 Magnus Damm | ||
9 | * | ||
10 | * This file is subject to the terms and conditions of the GNU General Public | ||
11 | * License. See the file "COPYING" in the main directory of this archive | ||
12 | * for more details. | ||
13 | */ | ||
14 | #include <linux/console.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/pm.h> | ||
18 | #include <linux/pm_clock.h> | ||
19 | #include <asm/io.h> | ||
20 | #include <mach/pm-rmobile.h> | ||
21 | |||
22 | /* SYSC */ | ||
23 | #define SPDCR 0xe6180008 | ||
24 | #define SWUCR 0xe6180014 | ||
25 | #define PSTR 0xe6180080 | ||
26 | |||
27 | #define PSTR_RETRIES 100 | ||
28 | #define PSTR_DELAY_US 10 | ||
29 | |||
30 | #ifdef CONFIG_PM | ||
31 | static int rmobile_pd_power_down(struct generic_pm_domain *genpd) | ||
32 | { | ||
33 | struct rmobile_pm_domain *rmobile_pd = to_rmobile_pd(genpd); | ||
34 | unsigned int mask = 1 << rmobile_pd->bit_shift; | ||
35 | |||
36 | if (rmobile_pd->suspend) { | ||
37 | int ret = rmobile_pd->suspend(); | ||
38 | |||
39 | if (ret) | ||
40 | return ret; | ||
41 | } | ||
42 | |||
43 | if (__raw_readl(PSTR) & mask) { | ||
44 | unsigned int retry_count; | ||
45 | __raw_writel(mask, SPDCR); | ||
46 | |||
47 | for (retry_count = PSTR_RETRIES; retry_count; retry_count--) { | ||
48 | if (!(__raw_readl(SPDCR) & mask)) | ||
49 | break; | ||
50 | cpu_relax(); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | if (!rmobile_pd->no_debug) | ||
55 | pr_debug("%s: Power off, 0x%08x -> PSTR = 0x%08x\n", | ||
56 | genpd->name, mask, __raw_readl(PSTR)); | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static int __rmobile_pd_power_up(struct rmobile_pm_domain *rmobile_pd, | ||
62 | bool do_resume) | ||
63 | { | ||
64 | unsigned int mask = 1 << rmobile_pd->bit_shift; | ||
65 | unsigned int retry_count; | ||
66 | int ret = 0; | ||
67 | |||
68 | if (__raw_readl(PSTR) & mask) | ||
69 | goto out; | ||
70 | |||
71 | __raw_writel(mask, SWUCR); | ||
72 | |||
73 | for (retry_count = 2 * PSTR_RETRIES; retry_count; retry_count--) { | ||
74 | if (!(__raw_readl(SWUCR) & mask)) | ||
75 | break; | ||
76 | if (retry_count > PSTR_RETRIES) | ||
77 | udelay(PSTR_DELAY_US); | ||
78 | else | ||
79 | cpu_relax(); | ||
80 | } | ||
81 | if (!retry_count) | ||
82 | ret = -EIO; | ||
83 | |||
84 | if (!rmobile_pd->no_debug) | ||
85 | pr_debug("%s: Power on, 0x%08x -> PSTR = 0x%08x\n", | ||
86 | rmobile_pd->genpd.name, mask, __raw_readl(PSTR)); | ||
87 | |||
88 | out: | ||
89 | if (ret == 0 && rmobile_pd->resume && do_resume) | ||
90 | rmobile_pd->resume(); | ||
91 | |||
92 | return ret; | ||
93 | } | ||
94 | |||
95 | static int rmobile_pd_power_up(struct generic_pm_domain *genpd) | ||
96 | { | ||
97 | return __rmobile_pd_power_up(to_rmobile_pd(genpd), true); | ||
98 | } | ||
99 | |||
100 | static bool rmobile_pd_active_wakeup(struct device *dev) | ||
101 | { | ||
102 | bool (*active_wakeup)(struct device *dev); | ||
103 | |||
104 | active_wakeup = dev_gpd_data(dev)->ops.active_wakeup; | ||
105 | return active_wakeup ? active_wakeup(dev) : true; | ||
106 | } | ||
107 | |||
108 | static int rmobile_pd_stop_dev(struct device *dev) | ||
109 | { | ||
110 | int (*stop)(struct device *dev); | ||
111 | |||
112 | stop = dev_gpd_data(dev)->ops.stop; | ||
113 | if (stop) { | ||
114 | int ret = stop(dev); | ||
115 | if (ret) | ||
116 | return ret; | ||
117 | } | ||
118 | return pm_clk_suspend(dev); | ||
119 | } | ||
120 | |||
121 | static int rmobile_pd_start_dev(struct device *dev) | ||
122 | { | ||
123 | int (*start)(struct device *dev); | ||
124 | int ret; | ||
125 | |||
126 | ret = pm_clk_resume(dev); | ||
127 | if (ret) | ||
128 | return ret; | ||
129 | |||
130 | start = dev_gpd_data(dev)->ops.start; | ||
131 | if (start) | ||
132 | ret = start(dev); | ||
133 | |||
134 | return ret; | ||
135 | } | ||
136 | |||
137 | void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd) | ||
138 | { | ||
139 | struct generic_pm_domain *genpd = &rmobile_pd->genpd; | ||
140 | struct dev_power_governor *gov = rmobile_pd->gov; | ||
141 | |||
142 | pm_genpd_init(genpd, gov ? : &simple_qos_governor, false); | ||
143 | genpd->dev_ops.stop = rmobile_pd_stop_dev; | ||
144 | genpd->dev_ops.start = rmobile_pd_start_dev; | ||
145 | genpd->dev_ops.active_wakeup = rmobile_pd_active_wakeup; | ||
146 | genpd->dev_irq_safe = true; | ||
147 | genpd->power_off = rmobile_pd_power_down; | ||
148 | genpd->power_on = rmobile_pd_power_up; | ||
149 | __rmobile_pd_power_up(rmobile_pd, false); | ||
150 | } | ||
151 | |||
152 | void rmobile_add_device_to_domain(struct rmobile_pm_domain *rmobile_pd, | ||
153 | struct platform_device *pdev) | ||
154 | { | ||
155 | struct device *dev = &pdev->dev; | ||
156 | |||
157 | pm_genpd_add_device(&rmobile_pd->genpd, dev); | ||
158 | if (pm_clk_no_clocks(dev)) | ||
159 | pm_clk_add(dev, NULL); | ||
160 | } | ||
161 | |||
162 | void rmobile_pm_add_subdomain(struct rmobile_pm_domain *rmobile_pd, | ||
163 | struct rmobile_pm_domain *rmobile_sd) | ||
164 | { | ||
165 | pm_genpd_add_subdomain(&rmobile_pd->genpd, &rmobile_sd->genpd); | ||
166 | } | ||
167 | #endif /* CONFIG_PM */ | ||