556 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Driver for voltage controller regulators4 *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 21struct vctrl_voltage_range {22 int min_uV;23 int max_uV;24};25 26struct vctrl_voltage_ranges {27 struct vctrl_voltage_range ctrl;28 struct vctrl_voltage_range out;29};30 31struct vctrl_voltage_table {32 int ctrl;33 int out;34 int ovp_min_sel;35};36 37struct 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 48static 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 59static 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 81static 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->supply->rdev);90 91 return vctrl_calc_output_voltage(vctrl, ctrl_uV);92}93 94static 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->supply->rdev);107 uV = vctrl_calc_output_voltage(vctrl, 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->supply->rdev,112 vctrl_calc_ctrl_voltage(vctrl, req_min_uV),113 vctrl_calc_ctrl_voltage(vctrl, 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, next_uV);128 129 ret = regulator_set_voltage_rdev(rdev->supply->rdev,130 next_ctrl_uV,131 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(delay, delay + DIV_ROUND_UP(delay, 10));138 139 uV = next_uV;140 }141 142 return 0;143 144err:145 /* Try to go back to original voltage */146 regulator_set_voltage_rdev(rdev->supply->rdev, orig_ctrl_uV, orig_ctrl_uV,147 PM_SUSPEND_ON);148 149 return ret;150}151 152static 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 159static 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->supply->rdev,175 vctrl->vtable[selector].ctrl,176 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->supply->rdev,191 vctrl->vtable[next_sel].ctrl,192 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(delay, delay + DIV_ROUND_UP(delay, 10));206 }207 208 return 0;209 210err:211 if (vctrl->sel != orig_sel) {212 /* Try to go back to original voltage */213 if (!regulator_set_voltage_rdev(rdev->supply->rdev,214 vctrl->vtable[orig_sel].ctrl,215 vctrl->vtable[orig_sel].ctrl,216 PM_SUSPEND_ON))217 vctrl->sel = orig_sel;218 else219 dev_warn(&rdev->dev,220 "failed to restore original voltage\n");221 }222 223 return ret;224}225 226static 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 237static 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, "ovp-threshold-percent", &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, "min-slew-down-rate", &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, "regulator-min-microvolt", &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, "regulator-max-microvolt", &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, "ctrl-voltage-range", vrange_ctrl,295 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 314static 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 322static 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(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(ctrl_reg, 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(&pdev->dev, rdesc->n_voltages,351 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(ctrl_reg, 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(vctrl->vtable, rdesc->n_voltages,372 sizeof(struct vctrl_voltage_table), 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 399static 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 408static 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 417static 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 424static 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 432static 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 442static 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(&pdev->dev, sizeof(struct vctrl_data),455 GFP_KERNEL);456 if (!vctrl)457 return -ENOMEM;458 459 platform_set_drvdata(pdev, vctrl);460 461 ret = vctrl_parse_dt(pdev, vctrl);462 if (ret)463 return ret;464 465 ctrl_reg = devm_regulator_get(&pdev->dev, "ctrl");466 if (IS_ERR(ctrl_reg))467 return PTR_ERR(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(ctrl_reg) == 1) ||478 (regulator_count_voltages(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(&pdev->dev, np, 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(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(ctrl_reg);525 526 vctrl->rdev = devm_regulator_register(&pdev->dev, rdesc, &cfg);527 if (IS_ERR(vctrl->rdev)) {528 ret = PTR_ERR(vctrl->rdev);529 dev_err(&pdev->dev, "failed to register regulator: %d\n", ret);530 return ret;531 }532 533 return 0;534}535 536static const struct of_device_id vctrl_of_match[] = {537 { .compatible = "vctrl-regulator", },538 {},539};540MODULE_DEVICE_TABLE(of, vctrl_of_match);541 542static 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 551module_platform_driver(vctrl_driver);552 553MODULE_DESCRIPTION("Voltage Controlled Regulator Driver");554MODULE_AUTHOR("Matthias Kaehlcke <mka@chromium.org>");555MODULE_LICENSE("GPL v2");556