445 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Regulator driver for PWM Regulators4 *5 * Copyright (C) 2014 - STMicroelectronics Inc.6 *7 * Author: Lee Jones <lee.jones@linaro.org>8 */9 10#include <linux/module.h>11#include <linux/init.h>12#include <linux/err.h>13#include <linux/platform_device.h>14#include <linux/regulator/driver.h>15#include <linux/regulator/machine.h>16#include <linux/regulator/of_regulator.h>17#include <linux/of.h>18#include <linux/pwm.h>19#include <linux/gpio/consumer.h>20 21struct pwm_continuous_reg_data {22 unsigned int min_uV_dutycycle;23 unsigned int max_uV_dutycycle;24 unsigned int dutycycle_unit;25};26 27struct pwm_regulator_data {28 /* Shared */29 struct pwm_device *pwm;30 31 /* Voltage table */32 struct pwm_voltages *duty_cycle_table;33 34 /* Continuous mode info */35 struct pwm_continuous_reg_data continuous;36 37 /* regulator descriptor */38 struct regulator_desc desc;39 40 int state;41 42 /* Enable GPIO */43 struct gpio_desc *enb_gpio;44};45 46struct pwm_voltages {47 unsigned int uV;48 unsigned int dutycycle;49};50 51/*52 * Voltage table call-backs53 */54static void pwm_regulator_init_state(struct regulator_dev *rdev)55{56 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);57 struct pwm_state pwm_state;58 unsigned int dutycycle;59 int i;60 61 pwm_get_state(drvdata->pwm, &pwm_state);62 dutycycle = pwm_get_relative_duty_cycle(&pwm_state, 100);63 64 for (i = 0; i < rdev->desc->n_voltages; i++) {65 if (dutycycle == drvdata->duty_cycle_table[i].dutycycle) {66 drvdata->state = i;67 return;68 }69 }70}71 72static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev)73{74 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);75 76 if (drvdata->state < 0)77 pwm_regulator_init_state(rdev);78 79 return drvdata->state;80}81 82static int pwm_regulator_set_voltage_sel(struct regulator_dev *rdev,83 unsigned selector)84{85 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);86 struct pwm_state pstate;87 int ret;88 89 pwm_init_state(drvdata->pwm, &pstate);90 pwm_set_relative_duty_cycle(&pstate,91 drvdata->duty_cycle_table[selector].dutycycle, 100);92 93 ret = pwm_apply_might_sleep(drvdata->pwm, &pstate);94 if (ret) {95 dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);96 return ret;97 }98 99 drvdata->state = selector;100 101 return 0;102}103 104static int pwm_regulator_list_voltage(struct regulator_dev *rdev,105 unsigned selector)106{107 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);108 109 if (selector >= rdev->desc->n_voltages)110 return -EINVAL;111 112 return drvdata->duty_cycle_table[selector].uV;113}114 115static int pwm_regulator_enable(struct regulator_dev *dev)116{117 struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);118 119 gpiod_set_value_cansleep(drvdata->enb_gpio, 1);120 121 return pwm_enable(drvdata->pwm);122}123 124static int pwm_regulator_disable(struct regulator_dev *dev)125{126 struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);127 128 pwm_disable(drvdata->pwm);129 130 gpiod_set_value_cansleep(drvdata->enb_gpio, 0);131 132 return 0;133}134 135static int pwm_regulator_is_enabled(struct regulator_dev *dev)136{137 struct pwm_regulator_data *drvdata = rdev_get_drvdata(dev);138 139 if (drvdata->enb_gpio && !gpiod_get_value_cansleep(drvdata->enb_gpio))140 return false;141 142 return pwm_is_enabled(drvdata->pwm);143}144 145static int pwm_regulator_get_voltage(struct regulator_dev *rdev)146{147 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);148 unsigned int min_uV_duty = drvdata->continuous.min_uV_dutycycle;149 unsigned int max_uV_duty = drvdata->continuous.max_uV_dutycycle;150 unsigned int duty_unit = drvdata->continuous.dutycycle_unit;151 int min_uV = rdev->constraints->min_uV;152 int max_uV = rdev->constraints->max_uV;153 int diff_uV = max_uV - min_uV;154 struct pwm_state pstate;155 unsigned int diff_duty;156 unsigned int voltage;157 158 pwm_get_state(drvdata->pwm, &pstate);159 160 if (!pstate.enabled) {161 if (pstate.polarity == PWM_POLARITY_INVERSED)162 pstate.duty_cycle = pstate.period;163 else164 pstate.duty_cycle = 0;165 }166 167 voltage = pwm_get_relative_duty_cycle(&pstate, duty_unit);168 if (voltage < min(max_uV_duty, min_uV_duty) ||169 voltage > max(max_uV_duty, min_uV_duty))170 return -ENOTRECOVERABLE;171 172 /*173 * The dutycycle for min_uV might be greater than the one for max_uV.174 * This is happening when the user needs an inversed polarity, but the175 * PWM device does not support inversing it in hardware.176 */177 if (max_uV_duty < min_uV_duty) {178 voltage = min_uV_duty - voltage;179 diff_duty = min_uV_duty - max_uV_duty;180 } else {181 voltage = voltage - min_uV_duty;182 diff_duty = max_uV_duty - min_uV_duty;183 }184 185 voltage = DIV_ROUND_CLOSEST_ULL((u64)voltage * diff_uV, diff_duty);186 187 return voltage + min_uV;188}189 190static int pwm_regulator_set_voltage(struct regulator_dev *rdev,191 int req_min_uV, int req_max_uV,192 unsigned int *selector)193{194 struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev);195 unsigned int min_uV_duty = drvdata->continuous.min_uV_dutycycle;196 unsigned int max_uV_duty = drvdata->continuous.max_uV_dutycycle;197 unsigned int duty_unit = drvdata->continuous.dutycycle_unit;198 int min_uV = rdev->constraints->min_uV;199 int max_uV = rdev->constraints->max_uV;200 int diff_uV = max_uV - min_uV;201 struct pwm_state pstate;202 unsigned int diff_duty;203 unsigned int dutycycle;204 int ret;205 206 pwm_init_state(drvdata->pwm, &pstate);207 208 /*209 * The dutycycle for min_uV might be greater than the one for max_uV.210 * This is happening when the user needs an inversed polarity, but the211 * PWM device does not support inversing it in hardware.212 */213 if (max_uV_duty < min_uV_duty)214 diff_duty = min_uV_duty - max_uV_duty;215 else216 diff_duty = max_uV_duty - min_uV_duty;217 218 dutycycle = DIV_ROUND_CLOSEST_ULL((u64)(req_min_uV - min_uV) *219 diff_duty,220 diff_uV);221 222 if (max_uV_duty < min_uV_duty)223 dutycycle = min_uV_duty - dutycycle;224 else225 dutycycle = min_uV_duty + dutycycle;226 227 pwm_set_relative_duty_cycle(&pstate, dutycycle, duty_unit);228 229 ret = pwm_apply_might_sleep(drvdata->pwm, &pstate);230 if (ret) {231 dev_err(&rdev->dev, "Failed to configure PWM: %d\n", ret);232 return ret;233 }234 235 return 0;236}237 238static const struct regulator_ops pwm_regulator_voltage_table_ops = {239 .set_voltage_sel = pwm_regulator_set_voltage_sel,240 .get_voltage_sel = pwm_regulator_get_voltage_sel,241 .list_voltage = pwm_regulator_list_voltage,242 .map_voltage = regulator_map_voltage_iterate,243 .enable = pwm_regulator_enable,244 .disable = pwm_regulator_disable,245 .is_enabled = pwm_regulator_is_enabled,246};247 248static const struct regulator_ops pwm_regulator_voltage_continuous_ops = {249 .get_voltage = pwm_regulator_get_voltage,250 .set_voltage = pwm_regulator_set_voltage,251 .enable = pwm_regulator_enable,252 .disable = pwm_regulator_disable,253 .is_enabled = pwm_regulator_is_enabled,254};255 256static const struct regulator_desc pwm_regulator_desc = {257 .name = "pwm-regulator",258 .type = REGULATOR_VOLTAGE,259 .owner = THIS_MODULE,260 .supply_name = "pwm",261};262 263static int pwm_regulator_init_table(struct platform_device *pdev,264 struct pwm_regulator_data *drvdata)265{266 struct device_node *np = pdev->dev.of_node;267 struct pwm_voltages *duty_cycle_table;268 unsigned int length = 0;269 int ret;270 271 of_find_property(np, "voltage-table", &length);272 273 if ((length < sizeof(*duty_cycle_table)) ||274 (length % sizeof(*duty_cycle_table)))275 return dev_err_probe(&pdev->dev, -EINVAL,276 "voltage-table length(%d) is invalid\n",277 length);278 279 duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL);280 if (!duty_cycle_table)281 return -ENOMEM;282 283 ret = of_property_read_u32_array(np, "voltage-table",284 (u32 *)duty_cycle_table,285 length / sizeof(u32));286 if (ret)287 return dev_err_probe(&pdev->dev, ret,288 "Failed to read voltage-table\n");289 290 drvdata->state = -ENOTRECOVERABLE;291 drvdata->duty_cycle_table = duty_cycle_table;292 drvdata->desc.ops = &pwm_regulator_voltage_table_ops;293 drvdata->desc.n_voltages = length / sizeof(*duty_cycle_table);294 295 return 0;296}297 298static int pwm_regulator_init_continuous(struct platform_device *pdev,299 struct pwm_regulator_data *drvdata)300{301 u32 dutycycle_range[2] = { 0, 100 };302 u32 dutycycle_unit = 100;303 304 drvdata->desc.ops = &pwm_regulator_voltage_continuous_ops;305 drvdata->desc.continuous_voltage_range = true;306 307 of_property_read_u32_array(pdev->dev.of_node,308 "pwm-dutycycle-range",309 dutycycle_range, 2);310 of_property_read_u32(pdev->dev.of_node, "pwm-dutycycle-unit",311 &dutycycle_unit);312 313 if (dutycycle_range[0] > dutycycle_unit ||314 dutycycle_range[1] > dutycycle_unit)315 return -EINVAL;316 317 drvdata->continuous.dutycycle_unit = dutycycle_unit;318 drvdata->continuous.min_uV_dutycycle = dutycycle_range[0];319 drvdata->continuous.max_uV_dutycycle = dutycycle_range[1];320 321 return 0;322}323 324static int pwm_regulator_init_boot_on(struct platform_device *pdev,325 struct pwm_regulator_data *drvdata,326 const struct regulator_init_data *init_data)327{328 struct pwm_state pstate;329 330 if (!init_data->constraints.boot_on || drvdata->enb_gpio)331 return 0;332 333 pwm_get_state(drvdata->pwm, &pstate);334 if (pstate.enabled)335 return 0;336 337 /*338 * Update the duty cycle so the output does not change339 * when the regulator core enables the regulator (and340 * thus the PWM channel).341 */342 if (pstate.polarity == PWM_POLARITY_INVERSED)343 pstate.duty_cycle = pstate.period;344 else345 pstate.duty_cycle = 0;346 347 return pwm_apply_might_sleep(drvdata->pwm, &pstate);348}349 350static int pwm_regulator_probe(struct platform_device *pdev)351{352 const struct regulator_init_data *init_data;353 struct pwm_regulator_data *drvdata;354 struct regulator_dev *regulator;355 struct regulator_config config = { };356 struct device_node *np = pdev->dev.of_node;357 enum gpiod_flags gpio_flags;358 int ret;359 360 if (!np)361 return dev_err_probe(&pdev->dev, -EINVAL,362 "Device Tree node missing\n");363 364 drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);365 if (!drvdata)366 return -ENOMEM;367 368 memcpy(&drvdata->desc, &pwm_regulator_desc, sizeof(drvdata->desc));369 370 if (of_property_present(np, "voltage-table"))371 ret = pwm_regulator_init_table(pdev, drvdata);372 else373 ret = pwm_regulator_init_continuous(pdev, drvdata);374 if (ret)375 return ret;376 377 init_data = of_get_regulator_init_data(&pdev->dev, np,378 &drvdata->desc);379 if (!init_data)380 return -ENOMEM;381 382 config.of_node = np;383 config.dev = &pdev->dev;384 config.driver_data = drvdata;385 config.init_data = init_data;386 387 drvdata->pwm = devm_pwm_get(&pdev->dev, NULL);388 if (IS_ERR(drvdata->pwm))389 return dev_err_probe(&pdev->dev, PTR_ERR(drvdata->pwm),390 "Failed to get PWM\n");391 392 if (init_data->constraints.boot_on || init_data->constraints.always_on)393 gpio_flags = GPIOD_OUT_HIGH;394 else395 gpio_flags = GPIOD_OUT_LOW;396 drvdata->enb_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",397 gpio_flags);398 if (IS_ERR(drvdata->enb_gpio)) {399 ret = PTR_ERR(drvdata->enb_gpio);400 return dev_err_probe(&pdev->dev, ret, "Failed to get enable GPIO\n");401 }402 403 ret = pwm_adjust_config(drvdata->pwm);404 if (ret)405 return ret;406 407 ret = pwm_regulator_init_boot_on(pdev, drvdata, init_data);408 if (ret)409 return dev_err_probe(&pdev->dev, ret,410 "Failed to apply boot_on settings\n");411 412 regulator = devm_regulator_register(&pdev->dev,413 &drvdata->desc, &config);414 if (IS_ERR(regulator)) {415 ret = PTR_ERR(regulator);416 return dev_err_probe(&pdev->dev, ret,417 "Failed to register regulator %s\n",418 drvdata->desc.name);419 }420 421 return 0;422}423 424static const struct of_device_id __maybe_unused pwm_of_match[] = {425 { .compatible = "pwm-regulator" },426 { },427};428MODULE_DEVICE_TABLE(of, pwm_of_match);429 430static struct platform_driver pwm_regulator_driver = {431 .driver = {432 .name = "pwm-regulator",433 .probe_type = PROBE_PREFER_ASYNCHRONOUS,434 .of_match_table = of_match_ptr(pwm_of_match),435 },436 .probe = pwm_regulator_probe,437};438 439module_platform_driver(pwm_regulator_driver);440 441MODULE_LICENSE("GPL");442MODULE_AUTHOR("Lee Jones <lee.jones@linaro.org>");443MODULE_DESCRIPTION("PWM Regulator Driver");444MODULE_ALIAS("platform:pwm-regulator");445