1
2
3
4
5
6
7
8
9
10#define pr_fmt(fmt) "tegra voltage-coupler: " fmt
11
12#include <linux/init.h>
13#include <linux/kernel.h>
14#include <linux/of.h>
15#include <linux/reboot.h>
16#include <linux/regulator/coupler.h>
17#include <linux/regulator/driver.h>
18#include <linux/regulator/machine.h>
19
20#include <soc/tegra/pmc.h>
21
22struct tegra_regulator_coupler {
23 struct regulator_coupler coupler;
24 struct regulator_dev *core_rdev;
25 struct regulator_dev *cpu_rdev;
26 struct regulator_dev *rtc_rdev;
27 struct notifier_block reboot_notifier;
28 int core_min_uV, cpu_min_uV;
29 bool sys_reboot_mode_req;
30 bool sys_reboot_mode;
31};
32
33static inline struct tegra_regulator_coupler *
34to_tegra_coupler(struct regulator_coupler *coupler)
35{
36 return container_of(coupler, struct tegra_regulator_coupler, coupler);
37}
38
39static int tegra20_core_limit(struct tegra_regulator_coupler *tegra,
40 struct regulator_dev *core_rdev)
41{
42 int core_min_uV = 0;
43 int core_max_uV;
44 int core_cur_uV;
45 int err;
46
47
48
49
50
51
52
53
54
55
56
57 if (tegra_pmc_core_domain_state_synced() && !tegra->sys_reboot_mode) {
58 pr_info_once("voltage state synced\n");
59 return 0;
60 }
61
62 if (tegra->core_min_uV > 0)
63 return tegra->core_min_uV;
64
65 core_cur_uV = regulator_get_voltage_rdev(core_rdev);
66 if (core_cur_uV < 0)
67 return core_cur_uV;
68
69 core_max_uV = max(core_cur_uV, 1200000);
70
71 err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV);
72 if (err)
73 return err;
74
75
76
77
78
79
80 tegra->core_min_uV = core_max_uV;
81
82 pr_info("core voltage initialized to %duV\n", tegra->core_min_uV);
83
84 return tegra->core_min_uV;
85}
86
87static int tegra20_core_rtc_max_spread(struct regulator_dev *core_rdev,
88 struct regulator_dev *rtc_rdev)
89{
90 struct coupling_desc *c_desc = &core_rdev->coupling_desc;
91 struct regulator_dev *rdev;
92 int max_spread;
93 unsigned int i;
94
95 for (i = 1; i < c_desc->n_coupled; i++) {
96 max_spread = core_rdev->constraints->max_spread[i - 1];
97 rdev = c_desc->coupled_rdevs[i];
98
99 if (rdev == rtc_rdev && max_spread)
100 return max_spread;
101 }
102
103 pr_err_once("rtc-core max-spread is undefined in device-tree\n");
104
105 return 150000;
106}
107
108static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra,
109 struct regulator_dev *core_rdev,
110 struct regulator_dev *rtc_rdev,
111 int cpu_uV, int cpu_min_uV)
112{
113 int core_min_uV, core_max_uV = INT_MAX;
114 int rtc_min_uV, rtc_max_uV = INT_MAX;
115 int core_target_uV;
116 int rtc_target_uV;
117 int max_spread;
118 int core_uV;
119 int rtc_uV;
120 int err;
121
122
123
124
125
126
127 max_spread = tegra20_core_rtc_max_spread(core_rdev, rtc_rdev);
128
129
130
131
132
133
134 core_min_uV = tegra20_core_limit(tegra, core_rdev);
135 if (core_min_uV < 0)
136 return core_min_uV;
137
138 err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV);
139 if (err)
140 return err;
141
142 err = regulator_check_consumers(core_rdev, &core_min_uV, &core_max_uV,
143 PM_SUSPEND_ON);
144 if (err)
145 return err;
146
147 core_uV = regulator_get_voltage_rdev(core_rdev);
148 if (core_uV < 0)
149 return core_uV;
150
151 core_min_uV = max(cpu_min_uV + 125000, core_min_uV);
152 if (core_min_uV > core_max_uV)
153 return -EINVAL;
154
155 if (cpu_uV + 120000 > core_uV)
156 pr_err("core-cpu voltage constraint violated: %d %d\n",
157 core_uV, cpu_uV + 120000);
158
159 rtc_uV = regulator_get_voltage_rdev(rtc_rdev);
160 if (rtc_uV < 0)
161 return rtc_uV;
162
163 if (cpu_uV + 120000 > rtc_uV)
164 pr_err("rtc-cpu voltage constraint violated: %d %d\n",
165 rtc_uV, cpu_uV + 120000);
166
167 if (abs(core_uV - rtc_uV) > 170000)
168 pr_err("core-rtc voltage constraint violated: %d %d\n",
169 core_uV, rtc_uV);
170
171 rtc_min_uV = max(cpu_min_uV + 125000, core_min_uV - max_spread);
172
173 err = regulator_check_voltage(rtc_rdev, &rtc_min_uV, &rtc_max_uV);
174 if (err)
175 return err;
176
177 while (core_uV != core_min_uV || rtc_uV != rtc_min_uV) {
178 if (core_uV < core_min_uV) {
179 core_target_uV = min(core_uV + max_spread, core_min_uV);
180 core_target_uV = min(rtc_uV + max_spread, core_target_uV);
181 } else {
182 core_target_uV = max(core_uV - max_spread, core_min_uV);
183 core_target_uV = max(rtc_uV - max_spread, core_target_uV);
184 }
185
186 if (core_uV == core_target_uV)
187 goto update_rtc;
188
189 err = regulator_set_voltage_rdev(core_rdev,
190 core_target_uV,
191 core_max_uV,
192 PM_SUSPEND_ON);
193 if (err)
194 return err;
195
196 core_uV = core_target_uV;
197update_rtc:
198 if (rtc_uV < rtc_min_uV) {
199 rtc_target_uV = min(rtc_uV + max_spread, rtc_min_uV);
200 rtc_target_uV = min(core_uV + max_spread, rtc_target_uV);
201 } else {
202 rtc_target_uV = max(rtc_uV - max_spread, rtc_min_uV);
203 rtc_target_uV = max(core_uV - max_spread, rtc_target_uV);
204 }
205
206 if (rtc_uV == rtc_target_uV)
207 continue;
208
209 err = regulator_set_voltage_rdev(rtc_rdev,
210 rtc_target_uV,
211 rtc_max_uV,
212 PM_SUSPEND_ON);
213 if (err)
214 return err;
215
216 rtc_uV = rtc_target_uV;
217 }
218
219 return 0;
220}
221
222static int tegra20_core_voltage_update(struct tegra_regulator_coupler *tegra,
223 struct regulator_dev *cpu_rdev,
224 struct regulator_dev *core_rdev,
225 struct regulator_dev *rtc_rdev)
226{
227 int cpu_uV;
228
229 cpu_uV = regulator_get_voltage_rdev(cpu_rdev);
230 if (cpu_uV < 0)
231 return cpu_uV;
232
233 return tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
234 cpu_uV, cpu_uV);
235}
236
237static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra,
238 struct regulator_dev *cpu_rdev,
239 struct regulator_dev *core_rdev,
240 struct regulator_dev *rtc_rdev)
241{
242 int cpu_min_uV_consumers = 0;
243 int cpu_max_uV = INT_MAX;
244 int cpu_min_uV = 0;
245 int cpu_uV;
246 int err;
247
248 err = regulator_check_voltage(cpu_rdev, &cpu_min_uV, &cpu_max_uV);
249 if (err)
250 return err;
251
252 err = regulator_check_consumers(cpu_rdev, &cpu_min_uV, &cpu_max_uV,
253 PM_SUSPEND_ON);
254 if (err)
255 return err;
256
257 err = regulator_check_consumers(cpu_rdev, &cpu_min_uV_consumers,
258 &cpu_max_uV, PM_SUSPEND_ON);
259 if (err)
260 return err;
261
262 cpu_uV = regulator_get_voltage_rdev(cpu_rdev);
263 if (cpu_uV < 0)
264 return cpu_uV;
265
266
267 if (!tegra->cpu_min_uV)
268 tegra->cpu_min_uV = cpu_uV;
269
270
271
272
273
274
275 if (!cpu_min_uV_consumers)
276 cpu_min_uV = cpu_uV;
277
278
279 if (tegra->sys_reboot_mode)
280 cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV);
281
282 if (cpu_min_uV > cpu_uV) {
283 err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
284 cpu_uV, cpu_min_uV);
285 if (err)
286 return err;
287
288 err = regulator_set_voltage_rdev(cpu_rdev, cpu_min_uV,
289 cpu_max_uV, PM_SUSPEND_ON);
290 if (err)
291 return err;
292 } else if (cpu_min_uV < cpu_uV) {
293 err = regulator_set_voltage_rdev(cpu_rdev, cpu_min_uV,
294 cpu_max_uV, PM_SUSPEND_ON);
295 if (err)
296 return err;
297
298 err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
299 cpu_uV, cpu_min_uV);
300 if (err)
301 return err;
302 }
303
304 return 0;
305}
306
307static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler,
308 struct regulator_dev *rdev,
309 suspend_state_t state)
310{
311 struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
312 struct regulator_dev *core_rdev = tegra->core_rdev;
313 struct regulator_dev *cpu_rdev = tegra->cpu_rdev;
314 struct regulator_dev *rtc_rdev = tegra->rtc_rdev;
315
316 if ((core_rdev != rdev && cpu_rdev != rdev && rtc_rdev != rdev) ||
317 state != PM_SUSPEND_ON) {
318 pr_err("regulators are not coupled properly\n");
319 return -EINVAL;
320 }
321
322 tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req);
323
324 if (rdev == cpu_rdev)
325 return tegra20_cpu_voltage_update(tegra, cpu_rdev,
326 core_rdev, rtc_rdev);
327
328 if (rdev == core_rdev)
329 return tegra20_core_voltage_update(tegra, cpu_rdev,
330 core_rdev, rtc_rdev);
331
332 pr_err("changing %s voltage not permitted\n", rdev_get_name(rtc_rdev));
333
334 return -EPERM;
335}
336
337static int tegra20_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra,
338 bool sys_reboot_mode)
339{
340 int err;
341
342 if (!tegra->core_rdev || !tegra->rtc_rdev || !tegra->cpu_rdev)
343 return 0;
344
345 WRITE_ONCE(tegra->sys_reboot_mode_req, true);
346
347
348
349
350
351
352 err = regulator_sync_voltage_rdev(tegra->cpu_rdev);
353 if (err)
354 return err;
355
356 err = regulator_sync_voltage_rdev(tegra->core_rdev);
357 if (err)
358 return err;
359
360 WRITE_ONCE(tegra->sys_reboot_mode_req, sys_reboot_mode);
361
362 return 0;
363}
364
365static int tegra20_regulator_reboot(struct notifier_block *notifier,
366 unsigned long event, void *cmd)
367{
368 struct tegra_regulator_coupler *tegra;
369 int ret;
370
371 if (event != SYS_RESTART)
372 return NOTIFY_DONE;
373
374 tegra = container_of(notifier, struct tegra_regulator_coupler,
375 reboot_notifier);
376
377 ret = tegra20_regulator_prepare_reboot(tegra, true);
378
379 return notifier_from_errno(ret);
380}
381
382static int tegra20_regulator_attach(struct regulator_coupler *coupler,
383 struct regulator_dev *rdev)
384{
385 struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
386 struct device_node *np = rdev->dev.of_node;
387
388 if (of_property_read_bool(np, "nvidia,tegra-core-regulator") &&
389 !tegra->core_rdev) {
390 tegra->core_rdev = rdev;
391 return 0;
392 }
393
394 if (of_property_read_bool(np, "nvidia,tegra-rtc-regulator") &&
395 !tegra->rtc_rdev) {
396 tegra->rtc_rdev = rdev;
397 return 0;
398 }
399
400 if (of_property_read_bool(np, "nvidia,tegra-cpu-regulator") &&
401 !tegra->cpu_rdev) {
402 tegra->cpu_rdev = rdev;
403 return 0;
404 }
405
406 return -EINVAL;
407}
408
409static int tegra20_regulator_detach(struct regulator_coupler *coupler,
410 struct regulator_dev *rdev)
411{
412 struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
413
414
415
416
417
418
419 if (WARN_ON_ONCE(system_state > SYSTEM_RUNNING))
420 return -EPERM;
421
422 if (tegra->core_rdev == rdev) {
423 tegra->core_rdev = NULL;
424 return 0;
425 }
426
427 if (tegra->rtc_rdev == rdev) {
428 tegra->rtc_rdev = NULL;
429 return 0;
430 }
431
432 if (tegra->cpu_rdev == rdev) {
433 tegra->cpu_rdev = NULL;
434 return 0;
435 }
436
437 return -EINVAL;
438}
439
440static struct tegra_regulator_coupler tegra20_coupler = {
441 .coupler = {
442 .attach_regulator = tegra20_regulator_attach,
443 .detach_regulator = tegra20_regulator_detach,
444 .balance_voltage = tegra20_regulator_balance_voltage,
445 },
446 .reboot_notifier.notifier_call = tegra20_regulator_reboot,
447};
448
449static int __init tegra_regulator_coupler_init(void)
450{
451 int err;
452
453 if (!of_machine_is_compatible("nvidia,tegra20"))
454 return 0;
455
456 err = register_reboot_notifier(&tegra20_coupler.reboot_notifier);
457 WARN_ON(err);
458
459 return regulator_coupler_register(&tegra20_coupler.coupler);
460}
461arch_initcall(tegra_regulator_coupler_init);
462