1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Driver for voltage controller regulators |
4 | * |
5 | * Copyright (C) 2017 Google, Inc. |
6 | */ |
7 | |
8 | #include <linux/delay.h> |
9 | #include <linux/err.h> |
10 | #include <linux/init.h> |
11 | #include <linux/module.h> |
12 | #include <linux/of.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/regulator/coupler.h> |
15 | #include <linux/regulator/driver.h> |
16 | #include <linux/regulator/of_regulator.h> |
17 | #include <linux/sort.h> |
18 | |
19 | #include "internal.h" |
20 | |
21 | struct vctrl_voltage_range { |
22 | int min_uV; |
23 | int max_uV; |
24 | }; |
25 | |
26 | struct vctrl_voltage_ranges { |
27 | struct vctrl_voltage_range ctrl; |
28 | struct vctrl_voltage_range out; |
29 | }; |
30 | |
31 | struct vctrl_voltage_table { |
32 | int ctrl; |
33 | int out; |
34 | int ovp_min_sel; |
35 | }; |
36 | |
37 | struct vctrl_data { |
38 | struct regulator_dev *rdev; |
39 | struct regulator_desc desc; |
40 | bool enabled; |
41 | unsigned int min_slew_down_rate; |
42 | unsigned int ovp_threshold; |
43 | struct vctrl_voltage_ranges vrange; |
44 | struct vctrl_voltage_table *vtable; |
45 | unsigned int sel; |
46 | }; |
47 | |
48 | static int vctrl_calc_ctrl_voltage(struct vctrl_data *vctrl, int out_uV) |
49 | { |
50 | struct vctrl_voltage_range *ctrl = &vctrl->vrange.ctrl; |
51 | struct vctrl_voltage_range *out = &vctrl->vrange.out; |
52 | |
53 | return ctrl->min_uV + |
54 | DIV_ROUND_CLOSEST_ULL((s64)(out_uV - out->min_uV) * |
55 | (ctrl->max_uV - ctrl->min_uV), |
56 | out->max_uV - out->min_uV); |
57 | } |
58 | |
59 | static int vctrl_calc_output_voltage(struct vctrl_data *vctrl, int ctrl_uV) |
60 | { |
61 | struct vctrl_voltage_range *ctrl = &vctrl->vrange.ctrl; |
62 | struct vctrl_voltage_range *out = &vctrl->vrange.out; |
63 | |
64 | if (ctrl_uV < 0) { |
65 | pr_err("vctrl: failed to get control voltage\n" ); |
66 | return ctrl_uV; |
67 | } |
68 | |
69 | if (ctrl_uV < ctrl->min_uV) |
70 | return out->min_uV; |
71 | |
72 | if (ctrl_uV > ctrl->max_uV) |
73 | return out->max_uV; |
74 | |
75 | return out->min_uV + |
76 | DIV_ROUND_CLOSEST_ULL((s64)(ctrl_uV - ctrl->min_uV) * |
77 | (out->max_uV - out->min_uV), |
78 | ctrl->max_uV - ctrl->min_uV); |
79 | } |
80 | |
81 | static int vctrl_get_voltage(struct regulator_dev *rdev) |
82 | { |
83 | struct vctrl_data *vctrl = rdev_get_drvdata(rdev); |
84 | int ctrl_uV; |
85 | |
86 | if (!rdev->supply) |
87 | return -EPROBE_DEFER; |
88 | |
89 | ctrl_uV = regulator_get_voltage_rdev(rdev: rdev->supply->rdev); |
90 | |
91 | return vctrl_calc_output_voltage(vctrl, ctrl_uV); |
92 | } |
93 | |
94 | static int vctrl_set_voltage(struct regulator_dev *rdev, |
95 | int req_min_uV, int req_max_uV, |
96 | unsigned int *selector) |
97 | { |
98 | struct vctrl_data *vctrl = rdev_get_drvdata(rdev); |
99 | int orig_ctrl_uV; |
100 | int uV; |
101 | int ret; |
102 | |
103 | if (!rdev->supply) |
104 | return -EPROBE_DEFER; |
105 | |
106 | orig_ctrl_uV = regulator_get_voltage_rdev(rdev: rdev->supply->rdev); |
107 | uV = vctrl_calc_output_voltage(vctrl, ctrl_uV: orig_ctrl_uV); |
108 | |
109 | if (req_min_uV >= uV || !vctrl->ovp_threshold) |
110 | /* voltage rising or no OVP */ |
111 | return regulator_set_voltage_rdev(rdev: rdev->supply->rdev, |
112 | min_uV: vctrl_calc_ctrl_voltage(vctrl, out_uV: req_min_uV), |
113 | max_uV: vctrl_calc_ctrl_voltage(vctrl, out_uV: req_max_uV), |
114 | PM_SUSPEND_ON); |
115 | |
116 | while (uV > req_min_uV) { |
117 | int max_drop_uV = (uV * vctrl->ovp_threshold) / 100; |
118 | int next_uV; |
119 | int next_ctrl_uV; |
120 | int delay; |
121 | |
122 | /* Make sure no infinite loop even in crazy cases */ |
123 | if (max_drop_uV == 0) |
124 | max_drop_uV = 1; |
125 | |
126 | next_uV = max_t(int, req_min_uV, uV - max_drop_uV); |
127 | next_ctrl_uV = vctrl_calc_ctrl_voltage(vctrl, out_uV: next_uV); |
128 | |
129 | ret = regulator_set_voltage_rdev(rdev: rdev->supply->rdev, |
130 | min_uV: next_ctrl_uV, |
131 | max_uV: next_ctrl_uV, |
132 | PM_SUSPEND_ON); |
133 | if (ret) |
134 | goto err; |
135 | |
136 | delay = DIV_ROUND_UP(uV - next_uV, vctrl->min_slew_down_rate); |
137 | usleep_range(min: delay, max: delay + DIV_ROUND_UP(delay, 10)); |
138 | |
139 | uV = next_uV; |
140 | } |
141 | |
142 | return 0; |
143 | |
144 | err: |
145 | /* Try to go back to original voltage */ |
146 | regulator_set_voltage_rdev(rdev: rdev->supply->rdev, min_uV: orig_ctrl_uV, max_uV: orig_ctrl_uV, |
147 | PM_SUSPEND_ON); |
148 | |
149 | return ret; |
150 | } |
151 | |
152 | static int vctrl_get_voltage_sel(struct regulator_dev *rdev) |
153 | { |
154 | struct vctrl_data *vctrl = rdev_get_drvdata(rdev); |
155 | |
156 | return vctrl->sel; |
157 | } |
158 | |
159 | static int vctrl_set_voltage_sel(struct regulator_dev *rdev, |
160 | unsigned int selector) |
161 | { |
162 | struct vctrl_data *vctrl = rdev_get_drvdata(rdev); |
163 | unsigned int orig_sel = vctrl->sel; |
164 | int ret; |
165 | |
166 | if (!rdev->supply) |
167 | return -EPROBE_DEFER; |
168 | |
169 | if (selector >= rdev->desc->n_voltages) |
170 | return -EINVAL; |
171 | |
172 | if (selector >= vctrl->sel || !vctrl->ovp_threshold) { |
173 | /* voltage rising or no OVP */ |
174 | ret = regulator_set_voltage_rdev(rdev: rdev->supply->rdev, |
175 | min_uV: vctrl->vtable[selector].ctrl, |
176 | max_uV: vctrl->vtable[selector].ctrl, |
177 | PM_SUSPEND_ON); |
178 | if (!ret) |
179 | vctrl->sel = selector; |
180 | |
181 | return ret; |
182 | } |
183 | |
184 | while (vctrl->sel != selector) { |
185 | unsigned int next_sel; |
186 | int delay; |
187 | |
188 | next_sel = max_t(unsigned int, selector, vctrl->vtable[vctrl->sel].ovp_min_sel); |
189 | |
190 | ret = regulator_set_voltage_rdev(rdev: rdev->supply->rdev, |
191 | min_uV: vctrl->vtable[next_sel].ctrl, |
192 | max_uV: vctrl->vtable[next_sel].ctrl, |
193 | PM_SUSPEND_ON); |
194 | if (ret) { |
195 | dev_err(&rdev->dev, |
196 | "failed to set control voltage to %duV\n" , |
197 | vctrl->vtable[next_sel].ctrl); |
198 | goto err; |
199 | } |
200 | vctrl->sel = next_sel; |
201 | |
202 | delay = DIV_ROUND_UP(vctrl->vtable[vctrl->sel].out - |
203 | vctrl->vtable[next_sel].out, |
204 | vctrl->min_slew_down_rate); |
205 | usleep_range(min: delay, max: delay + DIV_ROUND_UP(delay, 10)); |
206 | } |
207 | |
208 | return 0; |
209 | |
210 | err: |
211 | if (vctrl->sel != orig_sel) { |
212 | /* Try to go back to original voltage */ |
213 | if (!regulator_set_voltage_rdev(rdev: rdev->supply->rdev, |
214 | min_uV: vctrl->vtable[orig_sel].ctrl, |
215 | max_uV: vctrl->vtable[orig_sel].ctrl, |
216 | PM_SUSPEND_ON)) |
217 | vctrl->sel = orig_sel; |
218 | else |
219 | dev_warn(&rdev->dev, |
220 | "failed to restore original voltage\n" ); |
221 | } |
222 | |
223 | return ret; |
224 | } |
225 | |
226 | static int vctrl_list_voltage(struct regulator_dev *rdev, |
227 | unsigned int selector) |
228 | { |
229 | struct vctrl_data *vctrl = rdev_get_drvdata(rdev); |
230 | |
231 | if (selector >= rdev->desc->n_voltages) |
232 | return -EINVAL; |
233 | |
234 | return vctrl->vtable[selector].out; |
235 | } |
236 | |
237 | static int vctrl_parse_dt(struct platform_device *pdev, |
238 | struct vctrl_data *vctrl) |
239 | { |
240 | int ret; |
241 | struct device_node *np = pdev->dev.of_node; |
242 | u32 pval; |
243 | u32 vrange_ctrl[2]; |
244 | |
245 | ret = of_property_read_u32(np, propname: "ovp-threshold-percent" , out_value: &pval); |
246 | if (!ret) { |
247 | vctrl->ovp_threshold = pval; |
248 | if (vctrl->ovp_threshold > 100) { |
249 | dev_err(&pdev->dev, |
250 | "ovp-threshold-percent (%u) > 100\n" , |
251 | vctrl->ovp_threshold); |
252 | return -EINVAL; |
253 | } |
254 | } |
255 | |
256 | ret = of_property_read_u32(np, propname: "min-slew-down-rate" , out_value: &pval); |
257 | if (!ret) { |
258 | vctrl->min_slew_down_rate = pval; |
259 | |
260 | /* We use the value as int and as divider; sanity check */ |
261 | if (vctrl->min_slew_down_rate == 0) { |
262 | dev_err(&pdev->dev, |
263 | "min-slew-down-rate must not be 0\n" ); |
264 | return -EINVAL; |
265 | } else if (vctrl->min_slew_down_rate > INT_MAX) { |
266 | dev_err(&pdev->dev, "min-slew-down-rate (%u) too big\n" , |
267 | vctrl->min_slew_down_rate); |
268 | return -EINVAL; |
269 | } |
270 | } |
271 | |
272 | if (vctrl->ovp_threshold && !vctrl->min_slew_down_rate) { |
273 | dev_err(&pdev->dev, |
274 | "ovp-threshold-percent requires min-slew-down-rate\n" ); |
275 | return -EINVAL; |
276 | } |
277 | |
278 | ret = of_property_read_u32(np, propname: "regulator-min-microvolt" , out_value: &pval); |
279 | if (ret) { |
280 | dev_err(&pdev->dev, |
281 | "failed to read regulator-min-microvolt: %d\n" , ret); |
282 | return ret; |
283 | } |
284 | vctrl->vrange.out.min_uV = pval; |
285 | |
286 | ret = of_property_read_u32(np, propname: "regulator-max-microvolt" , out_value: &pval); |
287 | if (ret) { |
288 | dev_err(&pdev->dev, |
289 | "failed to read regulator-max-microvolt: %d\n" , ret); |
290 | return ret; |
291 | } |
292 | vctrl->vrange.out.max_uV = pval; |
293 | |
294 | ret = of_property_read_u32_array(np, propname: "ctrl-voltage-range" , out_values: vrange_ctrl, |
295 | sz: 2); |
296 | if (ret) { |
297 | dev_err(&pdev->dev, "failed to read ctrl-voltage-range: %d\n" , |
298 | ret); |
299 | return ret; |
300 | } |
301 | |
302 | if (vrange_ctrl[0] >= vrange_ctrl[1]) { |
303 | dev_err(&pdev->dev, "ctrl-voltage-range is invalid: %d-%d\n" , |
304 | vrange_ctrl[0], vrange_ctrl[1]); |
305 | return -EINVAL; |
306 | } |
307 | |
308 | vctrl->vrange.ctrl.min_uV = vrange_ctrl[0]; |
309 | vctrl->vrange.ctrl.max_uV = vrange_ctrl[1]; |
310 | |
311 | return 0; |
312 | } |
313 | |
314 | static int vctrl_cmp_ctrl_uV(const void *a, const void *b) |
315 | { |
316 | const struct vctrl_voltage_table *at = a; |
317 | const struct vctrl_voltage_table *bt = b; |
318 | |
319 | return at->ctrl - bt->ctrl; |
320 | } |
321 | |
322 | static int vctrl_init_vtable(struct platform_device *pdev, |
323 | struct regulator *ctrl_reg) |
324 | { |
325 | struct vctrl_data *vctrl = platform_get_drvdata(pdev); |
326 | struct regulator_desc *rdesc = &vctrl->desc; |
327 | struct vctrl_voltage_range *vrange_ctrl = &vctrl->vrange.ctrl; |
328 | int n_voltages; |
329 | int ctrl_uV; |
330 | int i, idx_vt; |
331 | |
332 | n_voltages = regulator_count_voltages(regulator: ctrl_reg); |
333 | |
334 | rdesc->n_voltages = n_voltages; |
335 | |
336 | /* determine number of steps within the range of the vctrl regulator */ |
337 | for (i = 0; i < n_voltages; i++) { |
338 | ctrl_uV = regulator_list_voltage(regulator: ctrl_reg, selector: i); |
339 | |
340 | if (ctrl_uV < vrange_ctrl->min_uV || |
341 | ctrl_uV > vrange_ctrl->max_uV) |
342 | rdesc->n_voltages--; |
343 | } |
344 | |
345 | if (rdesc->n_voltages == 0) { |
346 | dev_err(&pdev->dev, "invalid configuration\n" ); |
347 | return -EINVAL; |
348 | } |
349 | |
350 | vctrl->vtable = devm_kcalloc(dev: &pdev->dev, n: rdesc->n_voltages, |
351 | size: sizeof(struct vctrl_voltage_table), |
352 | GFP_KERNEL); |
353 | if (!vctrl->vtable) |
354 | return -ENOMEM; |
355 | |
356 | /* create mapping control <=> output voltage */ |
357 | for (i = 0, idx_vt = 0; i < n_voltages; i++) { |
358 | ctrl_uV = regulator_list_voltage(regulator: ctrl_reg, selector: i); |
359 | |
360 | if (ctrl_uV < vrange_ctrl->min_uV || |
361 | ctrl_uV > vrange_ctrl->max_uV) |
362 | continue; |
363 | |
364 | vctrl->vtable[idx_vt].ctrl = ctrl_uV; |
365 | vctrl->vtable[idx_vt].out = |
366 | vctrl_calc_output_voltage(vctrl, ctrl_uV); |
367 | idx_vt++; |
368 | } |
369 | |
370 | /* we rely on the table to be ordered by ascending voltage */ |
371 | sort(base: vctrl->vtable, num: rdesc->n_voltages, |
372 | size: sizeof(struct vctrl_voltage_table), cmp_func: vctrl_cmp_ctrl_uV, |
373 | NULL); |
374 | |
375 | /* pre-calculate OVP-safe downward transitions */ |
376 | for (i = rdesc->n_voltages - 1; i > 0; i--) { |
377 | int j; |
378 | int ovp_min_uV = (vctrl->vtable[i].out * |
379 | (100 - vctrl->ovp_threshold)) / 100; |
380 | |
381 | for (j = 0; j < i; j++) { |
382 | if (vctrl->vtable[j].out >= ovp_min_uV) { |
383 | vctrl->vtable[i].ovp_min_sel = j; |
384 | break; |
385 | } |
386 | } |
387 | |
388 | if (j == i) { |
389 | dev_warn(&pdev->dev, "switching down from %duV may cause OVP shutdown\n" , |
390 | vctrl->vtable[i].out); |
391 | /* use next lowest voltage */ |
392 | vctrl->vtable[i].ovp_min_sel = i - 1; |
393 | } |
394 | } |
395 | |
396 | return 0; |
397 | } |
398 | |
399 | static int vctrl_enable(struct regulator_dev *rdev) |
400 | { |
401 | struct vctrl_data *vctrl = rdev_get_drvdata(rdev); |
402 | |
403 | vctrl->enabled = true; |
404 | |
405 | return 0; |
406 | } |
407 | |
408 | static int vctrl_disable(struct regulator_dev *rdev) |
409 | { |
410 | struct vctrl_data *vctrl = rdev_get_drvdata(rdev); |
411 | |
412 | vctrl->enabled = false; |
413 | |
414 | return 0; |
415 | } |
416 | |
417 | static int vctrl_is_enabled(struct regulator_dev *rdev) |
418 | { |
419 | struct vctrl_data *vctrl = rdev_get_drvdata(rdev); |
420 | |
421 | return vctrl->enabled; |
422 | } |
423 | |
424 | static const struct regulator_ops vctrl_ops_cont = { |
425 | .enable = vctrl_enable, |
426 | .disable = vctrl_disable, |
427 | .is_enabled = vctrl_is_enabled, |
428 | .get_voltage = vctrl_get_voltage, |
429 | .set_voltage = vctrl_set_voltage, |
430 | }; |
431 | |
432 | static const struct regulator_ops vctrl_ops_non_cont = { |
433 | .enable = vctrl_enable, |
434 | .disable = vctrl_disable, |
435 | .is_enabled = vctrl_is_enabled, |
436 | .set_voltage_sel = vctrl_set_voltage_sel, |
437 | .get_voltage_sel = vctrl_get_voltage_sel, |
438 | .list_voltage = vctrl_list_voltage, |
439 | .map_voltage = regulator_map_voltage_iterate, |
440 | }; |
441 | |
442 | static int vctrl_probe(struct platform_device *pdev) |
443 | { |
444 | struct device_node *np = pdev->dev.of_node; |
445 | struct vctrl_data *vctrl; |
446 | const struct regulator_init_data *init_data; |
447 | struct regulator_desc *rdesc; |
448 | struct regulator_config cfg = { }; |
449 | struct vctrl_voltage_range *vrange_ctrl; |
450 | struct regulator *ctrl_reg; |
451 | int ctrl_uV; |
452 | int ret; |
453 | |
454 | vctrl = devm_kzalloc(dev: &pdev->dev, size: sizeof(struct vctrl_data), |
455 | GFP_KERNEL); |
456 | if (!vctrl) |
457 | return -ENOMEM; |
458 | |
459 | platform_set_drvdata(pdev, data: vctrl); |
460 | |
461 | ret = vctrl_parse_dt(pdev, vctrl); |
462 | if (ret) |
463 | return ret; |
464 | |
465 | ctrl_reg = devm_regulator_get(dev: &pdev->dev, id: "ctrl" ); |
466 | if (IS_ERR(ptr: ctrl_reg)) |
467 | return PTR_ERR(ptr: ctrl_reg); |
468 | |
469 | vrange_ctrl = &vctrl->vrange.ctrl; |
470 | |
471 | rdesc = &vctrl->desc; |
472 | rdesc->name = "vctrl" ; |
473 | rdesc->type = REGULATOR_VOLTAGE; |
474 | rdesc->owner = THIS_MODULE; |
475 | rdesc->supply_name = "ctrl" ; |
476 | |
477 | if ((regulator_get_linear_step(regulator: ctrl_reg) == 1) || |
478 | (regulator_count_voltages(regulator: ctrl_reg) == -EINVAL)) { |
479 | rdesc->continuous_voltage_range = true; |
480 | rdesc->ops = &vctrl_ops_cont; |
481 | } else { |
482 | rdesc->ops = &vctrl_ops_non_cont; |
483 | } |
484 | |
485 | init_data = of_get_regulator_init_data(dev: &pdev->dev, node: np, desc: rdesc); |
486 | if (!init_data) |
487 | return -ENOMEM; |
488 | |
489 | cfg.of_node = np; |
490 | cfg.dev = &pdev->dev; |
491 | cfg.driver_data = vctrl; |
492 | cfg.init_data = init_data; |
493 | |
494 | if (!rdesc->continuous_voltage_range) { |
495 | ret = vctrl_init_vtable(pdev, ctrl_reg); |
496 | if (ret) |
497 | return ret; |
498 | |
499 | /* Use locked consumer API when not in regulator framework */ |
500 | ctrl_uV = regulator_get_voltage(regulator: ctrl_reg); |
501 | if (ctrl_uV < 0) { |
502 | dev_err(&pdev->dev, "failed to get control voltage\n" ); |
503 | return ctrl_uV; |
504 | } |
505 | |
506 | /* determine current voltage selector from control voltage */ |
507 | if (ctrl_uV < vrange_ctrl->min_uV) { |
508 | vctrl->sel = 0; |
509 | } else if (ctrl_uV > vrange_ctrl->max_uV) { |
510 | vctrl->sel = rdesc->n_voltages - 1; |
511 | } else { |
512 | int i; |
513 | |
514 | for (i = 0; i < rdesc->n_voltages; i++) { |
515 | if (ctrl_uV == vctrl->vtable[i].ctrl) { |
516 | vctrl->sel = i; |
517 | break; |
518 | } |
519 | } |
520 | } |
521 | } |
522 | |
523 | /* Drop ctrl-supply here in favor of regulator core managed supply */ |
524 | devm_regulator_put(regulator: ctrl_reg); |
525 | |
526 | vctrl->rdev = devm_regulator_register(dev: &pdev->dev, regulator_desc: rdesc, config: &cfg); |
527 | if (IS_ERR(ptr: vctrl->rdev)) { |
528 | ret = PTR_ERR(ptr: vctrl->rdev); |
529 | dev_err(&pdev->dev, "failed to register regulator: %d\n" , ret); |
530 | return ret; |
531 | } |
532 | |
533 | return 0; |
534 | } |
535 | |
536 | static const struct of_device_id vctrl_of_match[] = { |
537 | { .compatible = "vctrl-regulator" , }, |
538 | {}, |
539 | }; |
540 | MODULE_DEVICE_TABLE(of, vctrl_of_match); |
541 | |
542 | static struct platform_driver vctrl_driver = { |
543 | .probe = vctrl_probe, |
544 | .driver = { |
545 | .name = "vctrl-regulator" , |
546 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
547 | .of_match_table = of_match_ptr(vctrl_of_match), |
548 | }, |
549 | }; |
550 | |
551 | module_platform_driver(vctrl_driver); |
552 | |
553 | MODULE_DESCRIPTION("Voltage Controlled Regulator Driver" ); |
554 | MODULE_AUTHOR("Matthias Kaehlcke <mka@chromium.org>" ); |
555 | MODULE_LICENSE("GPL v2" ); |
556 | |