diff options
Diffstat (limited to 'drivers/regulator/core.c')
-rw-r--r-- | drivers/regulator/core.c | 163 |
1 files changed, 144 insertions, 19 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 4d1463d2361a..750b538858d6 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -33,17 +33,6 @@ #include "dummy.h" #include "internal.h" -#define rdev_crit(rdev, fmt, ...) \ - pr_crit("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) -#define rdev_err(rdev, fmt, ...) \ - pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) -#define rdev_warn(rdev, fmt, ...) \ - pr_warn("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) -#define rdev_info(rdev, fmt, ...) \ - pr_info("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) -#define rdev_dbg(rdev, fmt, ...) \ - pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) - static DEFINE_WW_CLASS(regulator_ww_class); static DEFINE_MUTEX(regulator_nesting_mutex); static DEFINE_MUTEX(regulator_list_mutex); @@ -117,6 +106,7 @@ const char *rdev_get_name(struct regulator_dev *rdev) else return ""; } +EXPORT_SYMBOL_GPL(rdev_get_name); static bool have_full_constraints(void) { @@ -1305,6 +1295,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 +1426,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 +1454,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; @@ -4393,22 +4503,36 @@ unsigned int regulator_get_mode(struct regulator *regulator) } EXPORT_SYMBOL_GPL(regulator_get_mode); +static int rdev_get_cached_err_flags(struct regulator_dev *rdev) +{ + int ret = 0; + + if (rdev->use_cached_err) { + spin_lock(&rdev->err_lock); + ret = rdev->cached_err; + spin_unlock(&rdev->err_lock); + } + return ret; +} + static int _regulator_get_error_flags(struct regulator_dev *rdev, unsigned int *flags) { - int ret; + int cached_flags, ret = 0; regulator_lock(rdev); - /* sanity check */ - if (!rdev->desc->ops->get_error_flags) { + cached_flags = rdev_get_cached_err_flags(rdev); + + if (rdev->desc->ops->get_error_flags) + ret = rdev->desc->ops->get_error_flags(rdev, flags); + else if (!rdev->use_cached_err) ret = -EINVAL; - goto out; - } - ret = rdev->desc->ops->get_error_flags(rdev, flags); -out: + *flags |= cached_flags; + regulator_unlock(rdev); + return ret; } @@ -5241,6 +5365,7 @@ regulator_register(const struct regulator_desc *regulator_desc, goto rinse; } device_initialize(&rdev->dev); + spin_lock_init(&rdev->err_lock); /* * Duplicate the config so the driver could override it after |