diff options
author | Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com> | 2021-06-03 08:42:12 +0300 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2021-06-21 13:08:41 +0100 |
commit | 89a6a5e56c8248a077d12424a1383a6b18ea840b (patch) | |
tree | 31a8361eae067daac0747acaac685a5db14cffad /drivers/regulator/core.c | |
parent | 7111c6d1b31b42c8c758f6681e895a5116e3bad6 (diff) |
regulator: add property parsing and callbacks to set protection limits
Add DT property parsing code and setting callback for regulator over/under
voltage, over-current and temperature error limits.
Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
Link: https://lore.kernel.org/r/e7b8007ba9eae7076178bf3363fb942ccb1cc9a5.1622628334.git.matti.vaittinen@fi.rohmeurope.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/regulator/core.c')
-rw-r--r-- | drivers/regulator/core.c | 122 |
1 files changed, 121 insertions, 1 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 85b6d3960369..92fe05178249 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1305,6 +1305,52 @@ static int machine_constraints_current(struct regulator_dev *rdev, static int _regulator_do_enable(struct regulator_dev *rdev); +static int notif_set_limit(struct regulator_dev *rdev, + int (*set)(struct regulator_dev *, int, int, bool), + int limit, int severity) +{ + bool enable; + + if (limit == REGULATOR_NOTIF_LIMIT_DISABLE) { + enable = false; + limit = 0; + } else { + enable = true; + } + + if (limit == REGULATOR_NOTIF_LIMIT_ENABLE) + limit = 0; + + return set(rdev, limit, severity, enable); +} + +static int handle_notify_limits(struct regulator_dev *rdev, + int (*set)(struct regulator_dev *, int, int, bool), + struct notification_limit *limits) +{ + int ret = 0; + + if (!set) + return -EOPNOTSUPP; + + if (limits->prot) + ret = notif_set_limit(rdev, set, limits->prot, + REGULATOR_SEVERITY_PROT); + if (ret) + return ret; + + if (limits->err) + ret = notif_set_limit(rdev, set, limits->err, + REGULATOR_SEVERITY_ERR); + if (ret) + return ret; + + if (limits->warn) + ret = notif_set_limit(rdev, set, limits->warn, + REGULATOR_SEVERITY_WARN); + + return ret; +} /** * set_machine_constraints - sets regulator constraints * @rdev: regulator source @@ -1390,9 +1436,27 @@ static int set_machine_constraints(struct regulator_dev *rdev) } } + /* + * Existing logic does not warn if over_current_protection is given as + * a constraint but driver does not support that. I think we should + * warn about this type of issues as it is possible someone changes + * PMIC on board to another type - and the another PMIC's driver does + * not support setting protection. Board composer may happily believe + * the DT limits are respected - especially if the new PMIC HW also + * supports protection but the driver does not. I won't change the logic + * without hearing more experienced opinion on this though. + * + * If warning is seen as a good idea then we can merge handling the + * over-curret protection and detection and get rid of this special + * handling. + */ if (rdev->constraints->over_current_protection && ops->set_over_current_protection) { - ret = ops->set_over_current_protection(rdev); + int lim = rdev->constraints->over_curr_limits.prot; + + ret = ops->set_over_current_protection(rdev, lim, + REGULATOR_SEVERITY_PROT, + true); if (ret < 0) { rdev_err(rdev, "failed to set over current protection: %pe\n", ERR_PTR(ret)); @@ -1400,6 +1464,62 @@ static int set_machine_constraints(struct regulator_dev *rdev) } } + if (rdev->constraints->over_current_detection) + ret = handle_notify_limits(rdev, + ops->set_over_current_protection, + &rdev->constraints->over_curr_limits); + if (ret) { + if (ret != -EOPNOTSUPP) { + rdev_err(rdev, "failed to set over current limits: %pe\n", + ERR_PTR(ret)); + return ret; + } + rdev_warn(rdev, + "IC does not support requested over-current limits\n"); + } + + if (rdev->constraints->over_voltage_detection) + ret = handle_notify_limits(rdev, + ops->set_over_voltage_protection, + &rdev->constraints->over_voltage_limits); + if (ret) { + if (ret != -EOPNOTSUPP) { + rdev_err(rdev, "failed to set over voltage limits %pe\n", + ERR_PTR(ret)); + return ret; + } + rdev_warn(rdev, + "IC does not support requested over voltage limits\n"); + } + + if (rdev->constraints->under_voltage_detection) + ret = handle_notify_limits(rdev, + ops->set_under_voltage_protection, + &rdev->constraints->under_voltage_limits); + if (ret) { + if (ret != -EOPNOTSUPP) { + rdev_err(rdev, "failed to set under voltage limits %pe\n", + ERR_PTR(ret)); + return ret; + } + rdev_warn(rdev, + "IC does not support requested under voltage limits\n"); + } + + if (rdev->constraints->over_temp_detection) + ret = handle_notify_limits(rdev, + ops->set_thermal_protection, + &rdev->constraints->temp_limits); + if (ret) { + if (ret != -EOPNOTSUPP) { + rdev_err(rdev, "failed to set temperature limits %pe\n", + ERR_PTR(ret)); + return ret; + } + rdev_warn(rdev, + "IC does not support requested temperature limits\n"); + } + if (rdev->constraints->active_discharge && ops->set_active_discharge) { bool ad_state = (rdev->constraints->active_discharge == REGULATOR_ACTIVE_DISCHARGE_ENABLE) ? true : false; |