arm: tegra: add usb ehci and xhci to mc domain
[linux-3.10.git] / arch / arm / mach-tegra / pm_domains.c
1 /*
2  * arch/arm/mach-tegra/pm_domains.c
3  *
4  * Copyright (c) 2012-2013 NVIDIA Corporation.
5  *
6  *
7  * This software is licensed under the terms of the GNU General Public
8  * License version 2, as published by the Free Software Foundation, and
9  * may be copied, distributed, and modified under those terms.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  */
17
18 #include <linux/module.h>
19 #include <linux/pm.h>
20 #include <linux/pm_runtime.h>
21 #include <linux/pm_domain.h>
22
23 #include <mach/pm_domains.h>
24
25 #ifdef CONFIG_TEGRA_MC_DOMAINS
26 #define TEGRA_PD_DEV_CALLBACK(callback, dev)                    \
27 ({                                                              \
28         int (*__routine)(struct device *__d);                   \
29         int __ret = 0;                                          \
30                                                                 \
31         if (dev->type && dev->type->pm)                         \
32                 __routine = dev->type->pm->callback;            \
33         else if (dev->class && dev->class->pm)                  \
34                 __routine = dev->class->pm->callback;           \
35         else if (dev->bus && dev->bus->pm)                      \
36                 __routine = dev->bus->pm->callback;             \
37         else                                                    \
38                 __routine = NULL;                               \
39                                                                 \
40         if (!__routine && dev->driver && dev->driver->pm)       \
41                 __routine = dev->driver->pm->callback;          \
42                                                                 \
43         if (__routine)                                          \
44                 __ret = __routine(dev);                         \
45         __ret;                                                  \
46 })
47
48 struct domain_client {
49         const char *name;
50         struct generic_pm_domain *domain;
51 };
52
53 #ifdef CONFIG_PM_SLEEP
54
55 static int tegra_pd_suspend_dev(struct device *dev)
56 {
57         return TEGRA_PD_DEV_CALLBACK(suspend, dev);
58 }
59
60 static int tegra_pd_suspend_late(struct device *dev)
61 {
62         return TEGRA_PD_DEV_CALLBACK(suspend_late, dev);
63 }
64
65 static int tegra_pd_resume_early(struct device *dev)
66 {
67         return TEGRA_PD_DEV_CALLBACK(resume_early, dev);
68 }
69
70 static int tegra_pd_resume_dev(struct device *dev)
71 {
72         return TEGRA_PD_DEV_CALLBACK(resume, dev);
73 }
74
75 static int tegra_pd_freeze_dev(struct device *dev)
76 {
77         return TEGRA_PD_DEV_CALLBACK(freeze, dev);
78 }
79
80 static int tegra_pd_freeze_late(struct device *dev)
81 {
82         return TEGRA_PD_DEV_CALLBACK(freeze_late, dev);
83 }
84
85 static int tegra_pd_thaw_early(struct device *dev)
86 {
87         return TEGRA_PD_DEV_CALLBACK(thaw_early, dev);
88 }
89
90 static int tegra_pd_thaw_dev(struct device *dev)
91 {
92         return TEGRA_PD_DEV_CALLBACK(thaw, dev);
93 }
94 #else /* !CONFIG_PM_SLEEP */
95
96 #define tegra_pd_suspend_dev    NULL
97 #define tegra_pd_suspend_late   NULL
98 #define tegra_pd_resume_early   NULL
99 #define tegra_pd_resume_dev     NULL
100 #define tegra_pd_freeze_dev     NULL
101 #define tegra_pd_freeze_late    NULL
102 #define tegra_pd_thaw_early     NULL
103 #define tegra_pd_thaw_dev       NULL
104
105 #endif /* !CONFIG_PM_SLEEP */
106
107 static bool tegra_pd_active_wakeup(struct device *dev)
108 {
109         return false;
110 }
111
112 static int tegra_pd_save_dev(struct device *dev)
113 {
114         return 0;
115 }
116
117 static int tegra_pd_restore_dev(struct device *dev)
118 {
119         return 0;
120 }
121
122 static int tegra_pd_stop_dev(struct device *dev)
123 {
124         return TEGRA_PD_DEV_CALLBACK(runtime_suspend, dev);
125 }
126
127 static int tegra_pd_start_dev(struct device *dev)
128 {
129         return TEGRA_PD_DEV_CALLBACK(runtime_resume, dev);
130 }
131
132 struct gpd_dev_ops tegra_pd_ops = {
133         .active_wakeup = tegra_pd_active_wakeup,
134         .save_state = tegra_pd_save_dev,
135         .restore_state = tegra_pd_restore_dev,
136         .stop = tegra_pd_stop_dev,
137         .start = tegra_pd_start_dev,
138         .suspend = tegra_pd_suspend_dev,
139         .suspend_late = tegra_pd_suspend_late,
140         .resume_early = tegra_pd_resume_early,
141         .resume = tegra_pd_resume_dev,
142         .freeze = tegra_pd_freeze_dev,
143         .freeze_late = tegra_pd_freeze_late,
144         .thaw_early = tegra_pd_thaw_early,
145         .thaw = tegra_pd_thaw_dev,
146 };
147
148 static int tegra_mc_clk_power_off(struct generic_pm_domain *genpd)
149 {
150         struct tegra_pm_domain *pd = to_tegra_pd(genpd);
151
152         if (!pd)
153                 return -EINVAL;
154
155         if (IS_ERR_OR_NULL(pd->clk))
156                 return 0;
157
158         clk_disable_unprepare(pd->clk);
159
160         return 0;
161 }
162
163 static int tegra_mc_clk_power_on(struct generic_pm_domain *genpd)
164 {
165         struct tegra_pm_domain *pd = to_tegra_pd(genpd);
166
167         if (!pd)
168                 return -EINVAL;
169
170         if (IS_ERR_OR_NULL(pd->clk))
171                 return 0;
172
173         clk_prepare_enable(pd->clk);
174
175         return 0;
176 }
177
178 static struct tegra_pm_domain tegra_mc_clk = {
179         .gpd.name = "tegra_mc_clk",
180         .gpd.power_off = tegra_mc_clk_power_off,
181         .gpd.power_on = tegra_mc_clk_power_on,
182 };
183
184 #ifdef CONFIG_ARCH_TEGRA_14x_SOC
185 static struct tegra_pm_domain tegra_mc_chain_a = {
186         .gpd.name = "tegra_mc_chain_a",
187         .gpd.power_off = tegra_mc_clk_power_off,
188         .gpd.power_on = tegra_mc_clk_power_on,
189 };
190
191 static struct tegra_pm_domain tegra_mc_chain_b = {
192         .gpd.name = "tegra_mc_chain_b",
193         .gpd.power_off = tegra_mc_clk_power_off,
194         .gpd.power_on = tegra_mc_clk_power_on,
195 };
196 #endif
197
198 static struct domain_client client_list[] = {
199 #ifdef CONFIG_ARCH_TEGRA_14x_SOC
200         { .name = "tegra_mc_chain_a", .domain = &tegra_mc_clk.gpd },
201         { .name = "tegra_mc_chain_b", .domain = &tegra_mc_clk.gpd },
202         { .name = "gr2d", .domain = &tegra_mc_chain_a.gpd },
203         { .name = "gr3d", .domain = &tegra_mc_chain_a.gpd },
204         { .name = "msenc", .domain = &tegra_mc_chain_a.gpd },
205         { .name = "isp", .domain = &tegra_mc_chain_a.gpd },
206         { .name = "tegradc", .domain = &tegra_mc_chain_a.gpd },
207         { .name = "vi", .domain = &tegra_mc_chain_a.gpd },
208         { .name = "tegra30-hda", .domain = &tegra_mc_chain_a.gpd },
209         { .name = "tegra-apbdma", .domain = &tegra_mc_chain_b.gpd },
210         { .name = "tegra-otg", .domain = &tegra_mc_chain_b.gpd },
211         { .name = "tegra-ehci", .domain = &tegra_mc_chain_b.gpd },
212         { .name = "tegra-xhci", .domain = &tegra_mc_chain_b.gpd },
213         { .name = "host1x", .domain = &tegra_mc_chain_b.gpd },
214         { .name = "tsec", .domain = &tegra_mc_chain_b.gpd },
215         { .name = "nvavp", .domain = &tegra_mc_chain_b.gpd },
216         { .name = "sdhci-tegra", .domain = &tegra_mc_chain_b.gpd },
217         { .name = "tegra11-se", .domain = &tegra_mc_chain_b.gpd },
218         { .name = "tegra_bb", .domain = &tegra_mc_clk.gpd },
219 #endif
220 #ifdef CONFIG_ARCH_TEGRA_11x_SOC
221         { .name = "gr2d", .domain = &tegra_mc_clk.gpd },
222         { .name = "gr3d", .domain = &tegra_mc_clk.gpd },
223         { .name = "msenc", .domain = &tegra_mc_clk.gpd },
224         { .name = "isp", .domain = &tegra_mc_clk.gpd },
225         { .name = "tegradc", .domain = &tegra_mc_clk.gpd },
226         { .name = "vi", .domain = &tegra_mc_clk.gpd },
227         { .name = "tegra30-hda", .domain = &tegra_mc_clk.gpd },
228         { .name = "tegra-apbdma", .domain = &tegra_mc_clk.gpd },
229         { .name = "tegra-otg", .domain = &tegra_mc_clk.gpd },
230         { .name = "tegra-ehci", .domain = &tegra_mc_clk.gpd },
231         { .name = "tegra-xhci", .domain = &tegra_mc_clk.gpd },
232         { .name = "host1x", .domain = &tegra_mc_clk.gpd },
233         { .name = "tsec", .domain = &tegra_mc_clk.gpd },
234         { .name = "nvavp", .domain = &tegra_mc_clk.gpd },
235         { .name = "sdhci-tegra", .domain = &tegra_mc_clk.gpd },
236         { .name = "tegra11-se", .domain = &tegra_mc_clk.gpd },
237 #endif
238         {},
239 };
240
241 static int __init tegra_init_pm_domain(void)
242 {
243         pm_genpd_init(&tegra_mc_clk.gpd, &simple_qos_governor, false);
244
245 #ifdef CONFIG_ARCH_TEGRA_14x_SOC
246         pm_genpd_init(&tegra_mc_chain_a.gpd, &simple_qos_governor, false);
247         tegra_pd_add_sd(&tegra_mc_chain_a.gpd);
248
249         pm_genpd_init(&tegra_mc_chain_b.gpd, &simple_qos_governor, false);
250         tegra_pd_add_sd(&tegra_mc_chain_b.gpd);
251 #endif
252         return 0;
253 }
254 core_initcall(tegra_init_pm_domain);
255
256 static struct generic_pm_domain *tegra_pd_get_domain(const char *client)
257 {
258         const char *s;
259         struct domain_client *clients = client_list;
260
261         while ((s = clients->name) != NULL) {
262                 if (!strncmp(s, client, strlen(s)))
263                         return clients->domain;
264
265                 clients++;
266         }
267         return NULL;
268 }
269
270 void tegra_pd_add_device(struct device *dev)
271 {
272         struct generic_pm_domain *master = tegra_pd_get_domain(dev_name(dev));
273
274         if (!master)
275                 return;
276
277         device_set_wakeup_capable(dev, 1);
278         pm_genpd_add_device(master, dev);
279         pm_genpd_add_callbacks(dev, &tegra_pd_ops, NULL);
280 }
281 EXPORT_SYMBOL(tegra_pd_add_device);
282
283 void tegra_pd_add_sd(struct generic_pm_domain *sd)
284 {
285         struct generic_pm_domain *master = tegra_pd_get_domain(sd->name);
286
287         if (!master)
288                 return;
289
290         pm_genpd_add_subdomain(master, sd);
291 }
292 EXPORT_SYMBOL(tegra_pd_add_sd);
293 #else
294 struct tegra_pm_domain tegra_mc_clk;
295 EXPORT_SYMBOL(tegra_mc_clk);
296 struct tegra_pm_domain tegra_mc_chain_a;
297 EXPORT_SYMBOL(tegra_mc_chain_a);
298 struct tegra_pm_domain tegra_mc_chain_b;
299 EXPORT_SYMBOL(tegra_mc_chain_b);
300 #endif