ARM: tegra12: set CPU rate to 2.2GHz for sku 0x87
[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-2014, NVIDIA CORPORATION. All rights reserved.
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 device_may_wakeup(dev);
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_nvavp = {
179         .gpd.name = "tegra_nvavp",
180 };
181
182 static struct tegra_pm_domain tegra_mc_clk = {
183         .gpd.name = "tegra_mc_clk",
184         .gpd.power_off = tegra_mc_clk_power_off,
185         .gpd.power_on = tegra_mc_clk_power_on,
186 };
187
188 static struct domain_client client_list[] = {
189         { .name = "tegradc", .domain = &tegra_mc_clk.gpd },
190         { .name = "tegra30-hda", .domain = &tegra_mc_clk.gpd },
191         { .name = "tegra-apbdma", .domain = &tegra_mc_clk.gpd },
192         { .name = "tegra-otg", .domain = &tegra_mc_clk.gpd },
193         { .name = "tegra-ehci", .domain = &tegra_mc_clk.gpd },
194         { .name = "tegra-xhci", .domain = &tegra_mc_clk.gpd },
195         { .name = "tegra-host1x", .domain = &tegra_mc_clk.gpd },
196         { .name = "tegra_nvavp", .domain = &tegra_mc_clk.gpd },
197         { .name = "nvavp", .domain = &tegra_nvavp.gpd },
198         { .name = "sdhci-tegra", .domain = &tegra_mc_clk.gpd },
199         { .name = "tegra11-se", .domain = &tegra_mc_clk.gpd },
200         { .name = "tegra12-se", .domain = &tegra_mc_clk.gpd },
201         { .name = "tegra-pcie", .domain = &tegra_mc_clk.gpd },
202         {},
203 };
204
205 static int __init tegra_init_pm_domain(void)
206 {
207         pm_genpd_init(&tegra_mc_clk.gpd, &simple_qos_governor, false);
208
209         pm_genpd_init(&tegra_nvavp.gpd, &simple_qos_governor, false);
210         tegra_pd_add_sd(&tegra_nvavp.gpd);
211
212         return 0;
213 }
214 core_initcall(tegra_init_pm_domain);
215
216 static struct generic_pm_domain *tegra_pd_get_domain(const char *client)
217 {
218         const char *s;
219         struct domain_client *clients = client_list;
220
221         while ((s = clients->name) != NULL) {
222                 if (!strncmp(s, client, strlen(s)))
223                         return clients->domain;
224
225                 clients++;
226         }
227         return NULL;
228 }
229
230 void tegra_pd_add_device(struct device *dev)
231 {
232         struct generic_pm_domain *master = tegra_pd_get_domain(dev_name(dev));
233
234         if (!master)
235                 return;
236
237         device_set_wakeup_capable(dev, 1);
238         pm_genpd_add_device(master, dev);
239         pm_genpd_dev_need_save(dev, false);
240         pm_genpd_add_callbacks(dev, &tegra_pd_ops, NULL);
241 }
242 EXPORT_SYMBOL(tegra_pd_add_device);
243
244 void tegra_pd_remove_device(struct device *dev)
245 {
246         struct generic_pm_domain *genpd = dev_to_genpd(dev);
247
248         if (!IS_ERR_OR_NULL(genpd))
249                 pm_genpd_remove_device(genpd, dev);
250 }
251 EXPORT_SYMBOL(tegra_pd_remove_device);
252
253 void tegra_pd_add_sd(struct generic_pm_domain *sd)
254 {
255         struct generic_pm_domain *master = tegra_pd_get_domain(sd->name);
256
257         if (!master)
258                 return;
259
260         pm_genpd_add_subdomain(master, sd);
261 }
262 EXPORT_SYMBOL(tegra_pd_add_sd);
263 #else
264 struct tegra_pm_domain tegra_mc_clk;
265 EXPORT_SYMBOL(tegra_mc_clk);
266 struct tegra_pm_domain tegra_mc_chain_a;
267 EXPORT_SYMBOL(tegra_mc_chain_a);
268 struct tegra_pm_domain tegra_mc_chain_b;
269 EXPORT_SYMBOL(tegra_mc_chain_b);
270 #endif