19dee7a72SMatthias Kaehlcke /* 29dee7a72SMatthias Kaehlcke * Driver for voltage controller regulators 39dee7a72SMatthias Kaehlcke * 49dee7a72SMatthias Kaehlcke * Copyright (C) 2017 Google, Inc. 59dee7a72SMatthias Kaehlcke * 69dee7a72SMatthias Kaehlcke * This software is licensed under the terms of the GNU General Public 79dee7a72SMatthias Kaehlcke * License version 2, as published by the Free Software Foundation, and 89dee7a72SMatthias Kaehlcke * may be copied, distributed, and modified under those terms. 99dee7a72SMatthias Kaehlcke * 109dee7a72SMatthias Kaehlcke * This program is distributed in the hope that it will be useful, 119dee7a72SMatthias Kaehlcke * but WITHOUT ANY WARRANTY; without even the implied warranty of 129dee7a72SMatthias Kaehlcke * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 139dee7a72SMatthias Kaehlcke * GNU General Public License for more details. 149dee7a72SMatthias Kaehlcke */ 159dee7a72SMatthias Kaehlcke 169dee7a72SMatthias Kaehlcke #include <linux/delay.h> 179dee7a72SMatthias Kaehlcke #include <linux/err.h> 189dee7a72SMatthias Kaehlcke #include <linux/init.h> 199dee7a72SMatthias Kaehlcke #include <linux/module.h> 209dee7a72SMatthias Kaehlcke #include <linux/of.h> 219dee7a72SMatthias Kaehlcke #include <linux/of_device.h> 229dee7a72SMatthias Kaehlcke #include <linux/regulator/driver.h> 239dee7a72SMatthias Kaehlcke #include <linux/regulator/of_regulator.h> 249dee7a72SMatthias Kaehlcke #include <linux/sort.h> 259dee7a72SMatthias Kaehlcke 269dee7a72SMatthias Kaehlcke struct vctrl_voltage_range { 279dee7a72SMatthias Kaehlcke int min_uV; 289dee7a72SMatthias Kaehlcke int max_uV; 299dee7a72SMatthias Kaehlcke }; 309dee7a72SMatthias Kaehlcke 319dee7a72SMatthias Kaehlcke struct vctrl_voltage_ranges { 329dee7a72SMatthias Kaehlcke struct vctrl_voltage_range ctrl; 339dee7a72SMatthias Kaehlcke struct vctrl_voltage_range out; 349dee7a72SMatthias Kaehlcke }; 359dee7a72SMatthias Kaehlcke 369dee7a72SMatthias Kaehlcke struct vctrl_voltage_table { 379dee7a72SMatthias Kaehlcke int ctrl; 389dee7a72SMatthias Kaehlcke int out; 399dee7a72SMatthias Kaehlcke int ovp_min_sel; 409dee7a72SMatthias Kaehlcke }; 419dee7a72SMatthias Kaehlcke 429dee7a72SMatthias Kaehlcke struct vctrl_data { 439dee7a72SMatthias Kaehlcke struct regulator_dev *rdev; 449dee7a72SMatthias Kaehlcke struct regulator_desc desc; 459dee7a72SMatthias Kaehlcke struct regulator *ctrl_reg; 469dee7a72SMatthias Kaehlcke bool enabled; 479dee7a72SMatthias Kaehlcke unsigned int min_slew_down_rate; 489dee7a72SMatthias Kaehlcke unsigned int ovp_threshold; 499dee7a72SMatthias Kaehlcke struct vctrl_voltage_ranges vrange; 509dee7a72SMatthias Kaehlcke struct vctrl_voltage_table *vtable; 519dee7a72SMatthias Kaehlcke unsigned int sel; 529dee7a72SMatthias Kaehlcke }; 539dee7a72SMatthias Kaehlcke 549dee7a72SMatthias Kaehlcke static int vctrl_calc_ctrl_voltage(struct vctrl_data *vctrl, int out_uV) 559dee7a72SMatthias Kaehlcke { 569dee7a72SMatthias Kaehlcke struct vctrl_voltage_range *ctrl = &vctrl->vrange.ctrl; 579dee7a72SMatthias Kaehlcke struct vctrl_voltage_range *out = &vctrl->vrange.out; 589dee7a72SMatthias Kaehlcke 599dee7a72SMatthias Kaehlcke return ctrl->min_uV + 609dee7a72SMatthias Kaehlcke DIV_ROUND_CLOSEST_ULL((s64)(out_uV - out->min_uV) * 619dee7a72SMatthias Kaehlcke (ctrl->max_uV - ctrl->min_uV), 629dee7a72SMatthias Kaehlcke out->max_uV - out->min_uV); 639dee7a72SMatthias Kaehlcke } 649dee7a72SMatthias Kaehlcke 659dee7a72SMatthias Kaehlcke static int vctrl_calc_output_voltage(struct vctrl_data *vctrl, int ctrl_uV) 669dee7a72SMatthias Kaehlcke { 679dee7a72SMatthias Kaehlcke struct vctrl_voltage_range *ctrl = &vctrl->vrange.ctrl; 689dee7a72SMatthias Kaehlcke struct vctrl_voltage_range *out = &vctrl->vrange.out; 699dee7a72SMatthias Kaehlcke 709dee7a72SMatthias Kaehlcke if (ctrl_uV < 0) { 719dee7a72SMatthias Kaehlcke pr_err("vctrl: failed to get control voltage\n"); 729dee7a72SMatthias Kaehlcke return ctrl_uV; 739dee7a72SMatthias Kaehlcke } 749dee7a72SMatthias Kaehlcke 759dee7a72SMatthias Kaehlcke if (ctrl_uV < ctrl->min_uV) 769dee7a72SMatthias Kaehlcke return out->min_uV; 779dee7a72SMatthias Kaehlcke 789dee7a72SMatthias Kaehlcke if (ctrl_uV > ctrl->max_uV) 799dee7a72SMatthias Kaehlcke return out->max_uV; 809dee7a72SMatthias Kaehlcke 819dee7a72SMatthias Kaehlcke return out->min_uV + 829dee7a72SMatthias Kaehlcke DIV_ROUND_CLOSEST_ULL((s64)(ctrl_uV - ctrl->min_uV) * 839dee7a72SMatthias Kaehlcke (out->max_uV - out->min_uV), 849dee7a72SMatthias Kaehlcke ctrl->max_uV - ctrl->min_uV); 859dee7a72SMatthias Kaehlcke } 869dee7a72SMatthias Kaehlcke 879dee7a72SMatthias Kaehlcke static int vctrl_get_voltage(struct regulator_dev *rdev) 889dee7a72SMatthias Kaehlcke { 899dee7a72SMatthias Kaehlcke struct vctrl_data *vctrl = rdev_get_drvdata(rdev); 909dee7a72SMatthias Kaehlcke int ctrl_uV = regulator_get_voltage(vctrl->ctrl_reg); 919dee7a72SMatthias Kaehlcke 929dee7a72SMatthias Kaehlcke return vctrl_calc_output_voltage(vctrl, ctrl_uV); 939dee7a72SMatthias Kaehlcke } 949dee7a72SMatthias Kaehlcke 959dee7a72SMatthias Kaehlcke static int vctrl_set_voltage(struct regulator_dev *rdev, 969dee7a72SMatthias Kaehlcke int req_min_uV, int req_max_uV, 979dee7a72SMatthias Kaehlcke unsigned int *selector) 989dee7a72SMatthias Kaehlcke { 999dee7a72SMatthias Kaehlcke struct vctrl_data *vctrl = rdev_get_drvdata(rdev); 1009dee7a72SMatthias Kaehlcke struct regulator *ctrl_reg = vctrl->ctrl_reg; 1019dee7a72SMatthias Kaehlcke int orig_ctrl_uV = regulator_get_voltage(ctrl_reg); 1029dee7a72SMatthias Kaehlcke int uV = vctrl_calc_output_voltage(vctrl, orig_ctrl_uV); 1039dee7a72SMatthias Kaehlcke int ret; 1049dee7a72SMatthias Kaehlcke 1059dee7a72SMatthias Kaehlcke if (req_min_uV >= uV || !vctrl->ovp_threshold) 1069dee7a72SMatthias Kaehlcke /* voltage rising or no OVP */ 1079dee7a72SMatthias Kaehlcke return regulator_set_voltage( 1089dee7a72SMatthias Kaehlcke ctrl_reg, 1099dee7a72SMatthias Kaehlcke vctrl_calc_ctrl_voltage(vctrl, req_min_uV), 1109dee7a72SMatthias Kaehlcke vctrl_calc_ctrl_voltage(vctrl, req_max_uV)); 1119dee7a72SMatthias Kaehlcke 1129dee7a72SMatthias Kaehlcke while (uV > req_min_uV) { 1139dee7a72SMatthias Kaehlcke int max_drop_uV = (uV * vctrl->ovp_threshold) / 100; 1149dee7a72SMatthias Kaehlcke int next_uV; 1159dee7a72SMatthias Kaehlcke int next_ctrl_uV; 1169dee7a72SMatthias Kaehlcke int delay; 1179dee7a72SMatthias Kaehlcke 1189dee7a72SMatthias Kaehlcke /* Make sure no infinite loop even in crazy cases */ 1199dee7a72SMatthias Kaehlcke if (max_drop_uV == 0) 1209dee7a72SMatthias Kaehlcke max_drop_uV = 1; 1219dee7a72SMatthias Kaehlcke 1229dee7a72SMatthias Kaehlcke next_uV = max_t(int, req_min_uV, uV - max_drop_uV); 1239dee7a72SMatthias Kaehlcke next_ctrl_uV = vctrl_calc_ctrl_voltage(vctrl, next_uV); 1249dee7a72SMatthias Kaehlcke 1259dee7a72SMatthias Kaehlcke ret = regulator_set_voltage(ctrl_reg, 1269dee7a72SMatthias Kaehlcke next_ctrl_uV, 1279dee7a72SMatthias Kaehlcke next_ctrl_uV); 1289dee7a72SMatthias Kaehlcke if (ret) 1299dee7a72SMatthias Kaehlcke goto err; 1309dee7a72SMatthias Kaehlcke 1319dee7a72SMatthias Kaehlcke delay = DIV_ROUND_UP(uV - next_uV, vctrl->min_slew_down_rate); 1329dee7a72SMatthias Kaehlcke usleep_range(delay, delay + DIV_ROUND_UP(delay, 10)); 1339dee7a72SMatthias Kaehlcke 1349dee7a72SMatthias Kaehlcke uV = next_uV; 1359dee7a72SMatthias Kaehlcke } 1369dee7a72SMatthias Kaehlcke 1379dee7a72SMatthias Kaehlcke return 0; 1389dee7a72SMatthias Kaehlcke 1399dee7a72SMatthias Kaehlcke err: 1409dee7a72SMatthias Kaehlcke /* Try to go back to original voltage */ 1419dee7a72SMatthias Kaehlcke regulator_set_voltage(ctrl_reg, orig_ctrl_uV, orig_ctrl_uV); 1429dee7a72SMatthias Kaehlcke 1439dee7a72SMatthias Kaehlcke return ret; 1449dee7a72SMatthias Kaehlcke } 1459dee7a72SMatthias Kaehlcke 1469dee7a72SMatthias Kaehlcke static int vctrl_get_voltage_sel(struct regulator_dev *rdev) 1479dee7a72SMatthias Kaehlcke { 1489dee7a72SMatthias Kaehlcke struct vctrl_data *vctrl = rdev_get_drvdata(rdev); 1499dee7a72SMatthias Kaehlcke 1509dee7a72SMatthias Kaehlcke return vctrl->sel; 1519dee7a72SMatthias Kaehlcke } 1529dee7a72SMatthias Kaehlcke 1539dee7a72SMatthias Kaehlcke static int vctrl_set_voltage_sel(struct regulator_dev *rdev, 1549dee7a72SMatthias Kaehlcke unsigned int selector) 1559dee7a72SMatthias Kaehlcke { 1569dee7a72SMatthias Kaehlcke struct vctrl_data *vctrl = rdev_get_drvdata(rdev); 1579dee7a72SMatthias Kaehlcke struct regulator *ctrl_reg = vctrl->ctrl_reg; 1589dee7a72SMatthias Kaehlcke unsigned int orig_sel = vctrl->sel; 1599dee7a72SMatthias Kaehlcke int ret; 1609dee7a72SMatthias Kaehlcke 1619dee7a72SMatthias Kaehlcke if (selector >= rdev->desc->n_voltages) 1629dee7a72SMatthias Kaehlcke return -EINVAL; 1639dee7a72SMatthias Kaehlcke 1649dee7a72SMatthias Kaehlcke if (selector >= vctrl->sel || !vctrl->ovp_threshold) { 1659dee7a72SMatthias Kaehlcke /* voltage rising or no OVP */ 1669dee7a72SMatthias Kaehlcke ret = regulator_set_voltage(ctrl_reg, 1679dee7a72SMatthias Kaehlcke vctrl->vtable[selector].ctrl, 1689dee7a72SMatthias Kaehlcke vctrl->vtable[selector].ctrl); 1699dee7a72SMatthias Kaehlcke if (!ret) 1709dee7a72SMatthias Kaehlcke vctrl->sel = selector; 1719dee7a72SMatthias Kaehlcke 1729dee7a72SMatthias Kaehlcke return ret; 1739dee7a72SMatthias Kaehlcke } 1749dee7a72SMatthias Kaehlcke 1759dee7a72SMatthias Kaehlcke while (vctrl->sel != selector) { 1769dee7a72SMatthias Kaehlcke unsigned int next_sel; 1779dee7a72SMatthias Kaehlcke int delay; 1789dee7a72SMatthias Kaehlcke 1799dee7a72SMatthias Kaehlcke if (selector >= vctrl->vtable[vctrl->sel].ovp_min_sel) 1809dee7a72SMatthias Kaehlcke next_sel = selector; 1819dee7a72SMatthias Kaehlcke else 1829dee7a72SMatthias Kaehlcke next_sel = vctrl->vtable[vctrl->sel].ovp_min_sel; 1839dee7a72SMatthias Kaehlcke 1849dee7a72SMatthias Kaehlcke ret = regulator_set_voltage(ctrl_reg, 1859dee7a72SMatthias Kaehlcke vctrl->vtable[next_sel].ctrl, 1869dee7a72SMatthias Kaehlcke vctrl->vtable[next_sel].ctrl); 1879dee7a72SMatthias Kaehlcke if (ret) { 1889dee7a72SMatthias Kaehlcke dev_err(&rdev->dev, 1899dee7a72SMatthias Kaehlcke "failed to set control voltage to %duV\n", 1909dee7a72SMatthias Kaehlcke vctrl->vtable[next_sel].ctrl); 1919dee7a72SMatthias Kaehlcke goto err; 1929dee7a72SMatthias Kaehlcke } 1939dee7a72SMatthias Kaehlcke vctrl->sel = next_sel; 1949dee7a72SMatthias Kaehlcke 1959dee7a72SMatthias Kaehlcke delay = DIV_ROUND_UP(vctrl->vtable[vctrl->sel].out - 1969dee7a72SMatthias Kaehlcke vctrl->vtable[next_sel].out, 1979dee7a72SMatthias Kaehlcke vctrl->min_slew_down_rate); 1989dee7a72SMatthias Kaehlcke usleep_range(delay, delay + DIV_ROUND_UP(delay, 10)); 1999dee7a72SMatthias Kaehlcke } 2009dee7a72SMatthias Kaehlcke 2019dee7a72SMatthias Kaehlcke return 0; 2029dee7a72SMatthias Kaehlcke 2039dee7a72SMatthias Kaehlcke err: 2049dee7a72SMatthias Kaehlcke if (vctrl->sel != orig_sel) { 2059dee7a72SMatthias Kaehlcke /* Try to go back to original voltage */ 2069dee7a72SMatthias Kaehlcke if (!regulator_set_voltage(ctrl_reg, 2079dee7a72SMatthias Kaehlcke vctrl->vtable[orig_sel].ctrl, 2089dee7a72SMatthias Kaehlcke vctrl->vtable[orig_sel].ctrl)) 2099dee7a72SMatthias Kaehlcke vctrl->sel = orig_sel; 2109dee7a72SMatthias Kaehlcke else 2119dee7a72SMatthias Kaehlcke dev_warn(&rdev->dev, 2129dee7a72SMatthias Kaehlcke "failed to restore original voltage\n"); 2139dee7a72SMatthias Kaehlcke } 2149dee7a72SMatthias Kaehlcke 2159dee7a72SMatthias Kaehlcke return ret; 2169dee7a72SMatthias Kaehlcke } 2179dee7a72SMatthias Kaehlcke 2189dee7a72SMatthias Kaehlcke static int vctrl_list_voltage(struct regulator_dev *rdev, 2199dee7a72SMatthias Kaehlcke unsigned int selector) 2209dee7a72SMatthias Kaehlcke { 2219dee7a72SMatthias Kaehlcke struct vctrl_data *vctrl = rdev_get_drvdata(rdev); 2229dee7a72SMatthias Kaehlcke 2239dee7a72SMatthias Kaehlcke if (selector >= rdev->desc->n_voltages) 2249dee7a72SMatthias Kaehlcke return -EINVAL; 2259dee7a72SMatthias Kaehlcke 2269dee7a72SMatthias Kaehlcke return vctrl->vtable[selector].out; 2279dee7a72SMatthias Kaehlcke } 2289dee7a72SMatthias Kaehlcke 2299dee7a72SMatthias Kaehlcke static int vctrl_parse_dt(struct platform_device *pdev, 2309dee7a72SMatthias Kaehlcke struct vctrl_data *vctrl) 2319dee7a72SMatthias Kaehlcke { 2329dee7a72SMatthias Kaehlcke int ret; 2339dee7a72SMatthias Kaehlcke struct device_node *np = pdev->dev.of_node; 2349dee7a72SMatthias Kaehlcke u32 pval; 2359dee7a72SMatthias Kaehlcke u32 vrange_ctrl[2]; 2369dee7a72SMatthias Kaehlcke 2379dee7a72SMatthias Kaehlcke vctrl->ctrl_reg = devm_regulator_get(&pdev->dev, "ctrl"); 2389dee7a72SMatthias Kaehlcke if (IS_ERR(vctrl->ctrl_reg)) 2399dee7a72SMatthias Kaehlcke return PTR_ERR(vctrl->ctrl_reg); 2409dee7a72SMatthias Kaehlcke 2419dee7a72SMatthias Kaehlcke ret = of_property_read_u32(np, "ovp-threshold-percent", &pval); 2429dee7a72SMatthias Kaehlcke if (!ret) { 2439dee7a72SMatthias Kaehlcke vctrl->ovp_threshold = pval; 2449dee7a72SMatthias Kaehlcke if (vctrl->ovp_threshold > 100) { 2459dee7a72SMatthias Kaehlcke dev_err(&pdev->dev, 2469dee7a72SMatthias Kaehlcke "ovp-threshold-percent (%u) > 100\n", 2479dee7a72SMatthias Kaehlcke vctrl->ovp_threshold); 2489dee7a72SMatthias Kaehlcke return -EINVAL; 2499dee7a72SMatthias Kaehlcke } 2509dee7a72SMatthias Kaehlcke } 2519dee7a72SMatthias Kaehlcke 2529dee7a72SMatthias Kaehlcke ret = of_property_read_u32(np, "min-slew-down-rate", &pval); 2539dee7a72SMatthias Kaehlcke if (!ret) { 2549dee7a72SMatthias Kaehlcke vctrl->min_slew_down_rate = pval; 2559dee7a72SMatthias Kaehlcke 2569dee7a72SMatthias Kaehlcke /* We use the value as int and as divider; sanity check */ 2579dee7a72SMatthias Kaehlcke if (vctrl->min_slew_down_rate == 0) { 2589dee7a72SMatthias Kaehlcke dev_err(&pdev->dev, 2599dee7a72SMatthias Kaehlcke "min-slew-down-rate must not be 0\n"); 2609dee7a72SMatthias Kaehlcke return -EINVAL; 2619dee7a72SMatthias Kaehlcke } else if (vctrl->min_slew_down_rate > INT_MAX) { 2629dee7a72SMatthias Kaehlcke dev_err(&pdev->dev, "min-slew-down-rate (%u) too big\n", 2639dee7a72SMatthias Kaehlcke vctrl->min_slew_down_rate); 2649dee7a72SMatthias Kaehlcke return -EINVAL; 2659dee7a72SMatthias Kaehlcke } 2669dee7a72SMatthias Kaehlcke } 2679dee7a72SMatthias Kaehlcke 2689dee7a72SMatthias Kaehlcke if (vctrl->ovp_threshold && !vctrl->min_slew_down_rate) { 2699dee7a72SMatthias Kaehlcke dev_err(&pdev->dev, 2709dee7a72SMatthias Kaehlcke "ovp-threshold-percent requires min-slew-down-rate\n"); 2719dee7a72SMatthias Kaehlcke return -EINVAL; 2729dee7a72SMatthias Kaehlcke } 2739dee7a72SMatthias Kaehlcke 2749dee7a72SMatthias Kaehlcke ret = of_property_read_u32(np, "regulator-min-microvolt", &pval); 2759dee7a72SMatthias Kaehlcke if (ret) { 2769dee7a72SMatthias Kaehlcke dev_err(&pdev->dev, 2779dee7a72SMatthias Kaehlcke "failed to read regulator-min-microvolt: %d\n", ret); 2789dee7a72SMatthias Kaehlcke return ret; 2799dee7a72SMatthias Kaehlcke } 2809dee7a72SMatthias Kaehlcke vctrl->vrange.out.min_uV = pval; 2819dee7a72SMatthias Kaehlcke 2829dee7a72SMatthias Kaehlcke ret = of_property_read_u32(np, "regulator-max-microvolt", &pval); 2839dee7a72SMatthias Kaehlcke if (ret) { 2849dee7a72SMatthias Kaehlcke dev_err(&pdev->dev, 2859dee7a72SMatthias Kaehlcke "failed to read regulator-max-microvolt: %d\n", ret); 2869dee7a72SMatthias Kaehlcke return ret; 2879dee7a72SMatthias Kaehlcke } 2889dee7a72SMatthias Kaehlcke vctrl->vrange.out.max_uV = pval; 2899dee7a72SMatthias Kaehlcke 2909dee7a72SMatthias Kaehlcke ret = of_property_read_u32_array(np, "ctrl-voltage-range", vrange_ctrl, 2919dee7a72SMatthias Kaehlcke 2); 2929dee7a72SMatthias Kaehlcke if (ret) { 2939dee7a72SMatthias Kaehlcke dev_err(&pdev->dev, "failed to read ctrl-voltage-range: %d\n", 2949dee7a72SMatthias Kaehlcke ret); 2959dee7a72SMatthias Kaehlcke return ret; 2969dee7a72SMatthias Kaehlcke } 2979dee7a72SMatthias Kaehlcke 2989dee7a72SMatthias Kaehlcke if (vrange_ctrl[0] >= vrange_ctrl[1]) { 2999dee7a72SMatthias Kaehlcke dev_err(&pdev->dev, "ctrl-voltage-range is invalid: %d-%d\n", 3009dee7a72SMatthias Kaehlcke vrange_ctrl[0], vrange_ctrl[1]); 3019dee7a72SMatthias Kaehlcke return -EINVAL; 3029dee7a72SMatthias Kaehlcke } 3039dee7a72SMatthias Kaehlcke 3049dee7a72SMatthias Kaehlcke vctrl->vrange.ctrl.min_uV = vrange_ctrl[0]; 3059dee7a72SMatthias Kaehlcke vctrl->vrange.ctrl.max_uV = vrange_ctrl[1]; 3069dee7a72SMatthias Kaehlcke 3079dee7a72SMatthias Kaehlcke return 0; 3089dee7a72SMatthias Kaehlcke } 3099dee7a72SMatthias Kaehlcke 3109dee7a72SMatthias Kaehlcke static int vctrl_cmp_ctrl_uV(const void *a, const void *b) 3119dee7a72SMatthias Kaehlcke { 3129dee7a72SMatthias Kaehlcke const struct vctrl_voltage_table *at = a; 3139dee7a72SMatthias Kaehlcke const struct vctrl_voltage_table *bt = b; 3149dee7a72SMatthias Kaehlcke 3159dee7a72SMatthias Kaehlcke return at->ctrl - bt->ctrl; 3169dee7a72SMatthias Kaehlcke } 3179dee7a72SMatthias Kaehlcke 3189dee7a72SMatthias Kaehlcke static int vctrl_init_vtable(struct platform_device *pdev) 3199dee7a72SMatthias Kaehlcke { 3209dee7a72SMatthias Kaehlcke struct vctrl_data *vctrl = platform_get_drvdata(pdev); 3219dee7a72SMatthias Kaehlcke struct regulator_desc *rdesc = &vctrl->desc; 3229dee7a72SMatthias Kaehlcke struct regulator *ctrl_reg = vctrl->ctrl_reg; 3239dee7a72SMatthias Kaehlcke struct vctrl_voltage_range *vrange_ctrl = &vctrl->vrange.ctrl; 3249dee7a72SMatthias Kaehlcke int n_voltages; 3259dee7a72SMatthias Kaehlcke int ctrl_uV; 3269dee7a72SMatthias Kaehlcke int i, idx_vt; 3279dee7a72SMatthias Kaehlcke 3289dee7a72SMatthias Kaehlcke n_voltages = regulator_count_voltages(ctrl_reg); 3299dee7a72SMatthias Kaehlcke 3309dee7a72SMatthias Kaehlcke rdesc->n_voltages = n_voltages; 3319dee7a72SMatthias Kaehlcke 3329dee7a72SMatthias Kaehlcke /* determine number of steps within the range of the vctrl regulator */ 3339dee7a72SMatthias Kaehlcke for (i = 0; i < n_voltages; i++) { 3349dee7a72SMatthias Kaehlcke ctrl_uV = regulator_list_voltage(ctrl_reg, i); 3359dee7a72SMatthias Kaehlcke 3369dee7a72SMatthias Kaehlcke if (ctrl_uV < vrange_ctrl->min_uV || 3379dee7a72SMatthias Kaehlcke ctrl_uV > vrange_ctrl->max_uV) { 3389dee7a72SMatthias Kaehlcke rdesc->n_voltages--; 3399dee7a72SMatthias Kaehlcke continue; 3409dee7a72SMatthias Kaehlcke } 3419dee7a72SMatthias Kaehlcke } 3429dee7a72SMatthias Kaehlcke 3439dee7a72SMatthias Kaehlcke if (rdesc->n_voltages == 0) { 3449dee7a72SMatthias Kaehlcke dev_err(&pdev->dev, "invalid configuration\n"); 3459dee7a72SMatthias Kaehlcke return -EINVAL; 3469dee7a72SMatthias Kaehlcke } 3479dee7a72SMatthias Kaehlcke 348*a9bbb453SAxel Lin vctrl->vtable = devm_kcalloc(&pdev->dev, rdesc->n_voltages, 349*a9bbb453SAxel Lin sizeof(struct vctrl_voltage_table), 350*a9bbb453SAxel Lin GFP_KERNEL); 3519dee7a72SMatthias Kaehlcke if (!vctrl->vtable) 3529dee7a72SMatthias Kaehlcke return -ENOMEM; 3539dee7a72SMatthias Kaehlcke 3549dee7a72SMatthias Kaehlcke /* create mapping control <=> output voltage */ 3559dee7a72SMatthias Kaehlcke for (i = 0, idx_vt = 0; i < n_voltages; i++) { 3569dee7a72SMatthias Kaehlcke ctrl_uV = regulator_list_voltage(ctrl_reg, i); 3579dee7a72SMatthias Kaehlcke 3589dee7a72SMatthias Kaehlcke if (ctrl_uV < vrange_ctrl->min_uV || 3599dee7a72SMatthias Kaehlcke ctrl_uV > vrange_ctrl->max_uV) 3609dee7a72SMatthias Kaehlcke continue; 3619dee7a72SMatthias Kaehlcke 3629dee7a72SMatthias Kaehlcke vctrl->vtable[idx_vt].ctrl = ctrl_uV; 3639dee7a72SMatthias Kaehlcke vctrl->vtable[idx_vt].out = 3649dee7a72SMatthias Kaehlcke vctrl_calc_output_voltage(vctrl, ctrl_uV); 3659dee7a72SMatthias Kaehlcke idx_vt++; 3669dee7a72SMatthias Kaehlcke } 3679dee7a72SMatthias Kaehlcke 3689dee7a72SMatthias Kaehlcke /* we rely on the table to be ordered by ascending voltage */ 3699dee7a72SMatthias Kaehlcke sort(vctrl->vtable, rdesc->n_voltages, 3709dee7a72SMatthias Kaehlcke sizeof(struct vctrl_voltage_table), vctrl_cmp_ctrl_uV, 3719dee7a72SMatthias Kaehlcke NULL); 3729dee7a72SMatthias Kaehlcke 3739dee7a72SMatthias Kaehlcke /* pre-calculate OVP-safe downward transitions */ 374*a9bbb453SAxel Lin for (i = rdesc->n_voltages - 1; i > 0; i--) { 3759dee7a72SMatthias Kaehlcke int j; 3769dee7a72SMatthias Kaehlcke int ovp_min_uV = (vctrl->vtable[i].out * 3779dee7a72SMatthias Kaehlcke (100 - vctrl->ovp_threshold)) / 100; 3789dee7a72SMatthias Kaehlcke 3799dee7a72SMatthias Kaehlcke for (j = 0; j < i; j++) { 3809dee7a72SMatthias Kaehlcke if (vctrl->vtable[j].out >= ovp_min_uV) { 3819dee7a72SMatthias Kaehlcke vctrl->vtable[i].ovp_min_sel = j; 3829dee7a72SMatthias Kaehlcke break; 3839dee7a72SMatthias Kaehlcke } 3849dee7a72SMatthias Kaehlcke } 3859dee7a72SMatthias Kaehlcke 3869dee7a72SMatthias Kaehlcke if (j == i) { 3879dee7a72SMatthias Kaehlcke dev_warn(&pdev->dev, "switching down from %duV may cause OVP shutdown\n", 3889dee7a72SMatthias Kaehlcke vctrl->vtable[i].out); 3899dee7a72SMatthias Kaehlcke /* use next lowest voltage */ 3909dee7a72SMatthias Kaehlcke vctrl->vtable[i].ovp_min_sel = i - 1; 3919dee7a72SMatthias Kaehlcke } 3929dee7a72SMatthias Kaehlcke } 3939dee7a72SMatthias Kaehlcke 3949dee7a72SMatthias Kaehlcke return 0; 3959dee7a72SMatthias Kaehlcke } 3969dee7a72SMatthias Kaehlcke 3979dee7a72SMatthias Kaehlcke static int vctrl_enable(struct regulator_dev *rdev) 3989dee7a72SMatthias Kaehlcke { 3999dee7a72SMatthias Kaehlcke struct vctrl_data *vctrl = rdev_get_drvdata(rdev); 4009dee7a72SMatthias Kaehlcke int ret = regulator_enable(vctrl->ctrl_reg); 4019dee7a72SMatthias Kaehlcke 4029dee7a72SMatthias Kaehlcke if (!ret) 4039dee7a72SMatthias Kaehlcke vctrl->enabled = true; 4049dee7a72SMatthias Kaehlcke 4059dee7a72SMatthias Kaehlcke return ret; 4069dee7a72SMatthias Kaehlcke } 4079dee7a72SMatthias Kaehlcke 4089dee7a72SMatthias Kaehlcke static int vctrl_disable(struct regulator_dev *rdev) 4099dee7a72SMatthias Kaehlcke { 4109dee7a72SMatthias Kaehlcke struct vctrl_data *vctrl = rdev_get_drvdata(rdev); 4119dee7a72SMatthias Kaehlcke int ret = regulator_disable(vctrl->ctrl_reg); 4129dee7a72SMatthias Kaehlcke 4139dee7a72SMatthias Kaehlcke if (!ret) 4149dee7a72SMatthias Kaehlcke vctrl->enabled = false; 4159dee7a72SMatthias Kaehlcke 4169dee7a72SMatthias Kaehlcke return ret; 4179dee7a72SMatthias Kaehlcke } 4189dee7a72SMatthias Kaehlcke 4199dee7a72SMatthias Kaehlcke static int vctrl_is_enabled(struct regulator_dev *rdev) 4209dee7a72SMatthias Kaehlcke { 4219dee7a72SMatthias Kaehlcke struct vctrl_data *vctrl = rdev_get_drvdata(rdev); 4229dee7a72SMatthias Kaehlcke 4239dee7a72SMatthias Kaehlcke return vctrl->enabled; 4249dee7a72SMatthias Kaehlcke } 4259dee7a72SMatthias Kaehlcke 4269dee7a72SMatthias Kaehlcke static const struct regulator_ops vctrl_ops_cont = { 4279dee7a72SMatthias Kaehlcke .enable = vctrl_enable, 4289dee7a72SMatthias Kaehlcke .disable = vctrl_disable, 4299dee7a72SMatthias Kaehlcke .is_enabled = vctrl_is_enabled, 4309dee7a72SMatthias Kaehlcke .get_voltage = vctrl_get_voltage, 4319dee7a72SMatthias Kaehlcke .set_voltage = vctrl_set_voltage, 4329dee7a72SMatthias Kaehlcke }; 4339dee7a72SMatthias Kaehlcke 4349dee7a72SMatthias Kaehlcke static const struct regulator_ops vctrl_ops_non_cont = { 4359dee7a72SMatthias Kaehlcke .enable = vctrl_enable, 4369dee7a72SMatthias Kaehlcke .disable = vctrl_disable, 4379dee7a72SMatthias Kaehlcke .is_enabled = vctrl_is_enabled, 4389dee7a72SMatthias Kaehlcke .set_voltage_sel = vctrl_set_voltage_sel, 4399dee7a72SMatthias Kaehlcke .get_voltage_sel = vctrl_get_voltage_sel, 4409dee7a72SMatthias Kaehlcke .list_voltage = vctrl_list_voltage, 4419dee7a72SMatthias Kaehlcke .map_voltage = regulator_map_voltage_iterate, 4429dee7a72SMatthias Kaehlcke }; 4439dee7a72SMatthias Kaehlcke 4449dee7a72SMatthias Kaehlcke static int vctrl_probe(struct platform_device *pdev) 4459dee7a72SMatthias Kaehlcke { 4469dee7a72SMatthias Kaehlcke struct device_node *np = pdev->dev.of_node; 4479dee7a72SMatthias Kaehlcke struct vctrl_data *vctrl; 4489dee7a72SMatthias Kaehlcke const struct regulator_init_data *init_data; 4499dee7a72SMatthias Kaehlcke struct regulator_desc *rdesc; 4509dee7a72SMatthias Kaehlcke struct regulator_config cfg = { }; 4519dee7a72SMatthias Kaehlcke struct vctrl_voltage_range *vrange_ctrl; 4529dee7a72SMatthias Kaehlcke int ctrl_uV; 4539dee7a72SMatthias Kaehlcke int ret; 4549dee7a72SMatthias Kaehlcke 4559dee7a72SMatthias Kaehlcke vctrl = devm_kzalloc(&pdev->dev, sizeof(struct vctrl_data), 4569dee7a72SMatthias Kaehlcke GFP_KERNEL); 4579dee7a72SMatthias Kaehlcke if (!vctrl) 4589dee7a72SMatthias Kaehlcke return -ENOMEM; 4599dee7a72SMatthias Kaehlcke 4609dee7a72SMatthias Kaehlcke platform_set_drvdata(pdev, vctrl); 4619dee7a72SMatthias Kaehlcke 4629dee7a72SMatthias Kaehlcke ret = vctrl_parse_dt(pdev, vctrl); 4639dee7a72SMatthias Kaehlcke if (ret) 4649dee7a72SMatthias Kaehlcke return ret; 4659dee7a72SMatthias Kaehlcke 4669dee7a72SMatthias Kaehlcke vrange_ctrl = &vctrl->vrange.ctrl; 4679dee7a72SMatthias Kaehlcke 4689dee7a72SMatthias Kaehlcke rdesc = &vctrl->desc; 4699dee7a72SMatthias Kaehlcke rdesc->name = "vctrl"; 4709dee7a72SMatthias Kaehlcke rdesc->type = REGULATOR_VOLTAGE; 4719dee7a72SMatthias Kaehlcke rdesc->owner = THIS_MODULE; 4729dee7a72SMatthias Kaehlcke 4739dee7a72SMatthias Kaehlcke if ((regulator_get_linear_step(vctrl->ctrl_reg) == 1) || 4749dee7a72SMatthias Kaehlcke (regulator_count_voltages(vctrl->ctrl_reg) == -EINVAL)) { 4759dee7a72SMatthias Kaehlcke rdesc->continuous_voltage_range = true; 4769dee7a72SMatthias Kaehlcke rdesc->ops = &vctrl_ops_cont; 4779dee7a72SMatthias Kaehlcke } else { 4789dee7a72SMatthias Kaehlcke rdesc->ops = &vctrl_ops_non_cont; 4799dee7a72SMatthias Kaehlcke } 4809dee7a72SMatthias Kaehlcke 4819dee7a72SMatthias Kaehlcke init_data = of_get_regulator_init_data(&pdev->dev, np, rdesc); 4829dee7a72SMatthias Kaehlcke if (!init_data) 4839dee7a72SMatthias Kaehlcke return -ENOMEM; 4849dee7a72SMatthias Kaehlcke 4859dee7a72SMatthias Kaehlcke cfg.of_node = np; 4869dee7a72SMatthias Kaehlcke cfg.dev = &pdev->dev; 4879dee7a72SMatthias Kaehlcke cfg.driver_data = vctrl; 4889dee7a72SMatthias Kaehlcke cfg.init_data = init_data; 4899dee7a72SMatthias Kaehlcke 4909dee7a72SMatthias Kaehlcke if (!rdesc->continuous_voltage_range) { 4919dee7a72SMatthias Kaehlcke ret = vctrl_init_vtable(pdev); 4929dee7a72SMatthias Kaehlcke if (ret) 4939dee7a72SMatthias Kaehlcke return ret; 4949dee7a72SMatthias Kaehlcke 4959dee7a72SMatthias Kaehlcke ctrl_uV = regulator_get_voltage(vctrl->ctrl_reg); 4969dee7a72SMatthias Kaehlcke if (ctrl_uV < 0) { 4979dee7a72SMatthias Kaehlcke dev_err(&pdev->dev, "failed to get control voltage\n"); 4989dee7a72SMatthias Kaehlcke return ctrl_uV; 4999dee7a72SMatthias Kaehlcke } 5009dee7a72SMatthias Kaehlcke 5019dee7a72SMatthias Kaehlcke /* determine current voltage selector from control voltage */ 5029dee7a72SMatthias Kaehlcke if (ctrl_uV < vrange_ctrl->min_uV) { 5039dee7a72SMatthias Kaehlcke vctrl->sel = 0; 5049dee7a72SMatthias Kaehlcke } else if (ctrl_uV > vrange_ctrl->max_uV) { 5059dee7a72SMatthias Kaehlcke vctrl->sel = rdesc->n_voltages - 1; 5069dee7a72SMatthias Kaehlcke } else { 5079dee7a72SMatthias Kaehlcke int i; 5089dee7a72SMatthias Kaehlcke 5099dee7a72SMatthias Kaehlcke for (i = 0; i < rdesc->n_voltages; i++) { 5109dee7a72SMatthias Kaehlcke if (ctrl_uV == vctrl->vtable[i].ctrl) { 5119dee7a72SMatthias Kaehlcke vctrl->sel = i; 5129dee7a72SMatthias Kaehlcke break; 5139dee7a72SMatthias Kaehlcke } 5149dee7a72SMatthias Kaehlcke } 5159dee7a72SMatthias Kaehlcke } 5169dee7a72SMatthias Kaehlcke } 5179dee7a72SMatthias Kaehlcke 5189dee7a72SMatthias Kaehlcke vctrl->rdev = devm_regulator_register(&pdev->dev, rdesc, &cfg); 5199dee7a72SMatthias Kaehlcke if (IS_ERR(vctrl->rdev)) { 5209dee7a72SMatthias Kaehlcke ret = PTR_ERR(vctrl->rdev); 5219dee7a72SMatthias Kaehlcke dev_err(&pdev->dev, "failed to register regulator: %d\n", ret); 5229dee7a72SMatthias Kaehlcke return ret; 5239dee7a72SMatthias Kaehlcke } 5249dee7a72SMatthias Kaehlcke 5259dee7a72SMatthias Kaehlcke return 0; 5269dee7a72SMatthias Kaehlcke } 5279dee7a72SMatthias Kaehlcke 5289dee7a72SMatthias Kaehlcke static const struct of_device_id vctrl_of_match[] = { 5299dee7a72SMatthias Kaehlcke { .compatible = "vctrl-regulator", }, 5309dee7a72SMatthias Kaehlcke {}, 5319dee7a72SMatthias Kaehlcke }; 5329dee7a72SMatthias Kaehlcke MODULE_DEVICE_TABLE(of, vctrl_of_match); 5339dee7a72SMatthias Kaehlcke 5349dee7a72SMatthias Kaehlcke static struct platform_driver vctrl_driver = { 5359dee7a72SMatthias Kaehlcke .probe = vctrl_probe, 5369dee7a72SMatthias Kaehlcke .driver = { 5379dee7a72SMatthias Kaehlcke .name = "vctrl-regulator", 5389dee7a72SMatthias Kaehlcke .of_match_table = of_match_ptr(vctrl_of_match), 5399dee7a72SMatthias Kaehlcke }, 5409dee7a72SMatthias Kaehlcke }; 5419dee7a72SMatthias Kaehlcke 5429dee7a72SMatthias Kaehlcke module_platform_driver(vctrl_driver); 5439dee7a72SMatthias Kaehlcke 5449dee7a72SMatthias Kaehlcke MODULE_DESCRIPTION("Voltage Controlled Regulator Driver"); 5459dee7a72SMatthias Kaehlcke MODULE_AUTHOR("Matthias Kaehlcke <mka@chromium.org>"); 5469dee7a72SMatthias Kaehlcke MODULE_LICENSE("GPL v2"); 547