diff options
author | Mark Brown <broonie@kernel.org> | 2019-07-04 17:34:34 +0100 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-07-04 17:34:34 +0100 |
commit | 0ed4513c9a32a479b4dc41685be68edf1e99c139 (patch) | |
tree | 56e2cab31df315ec4cf37f064a8df3404b3ea753 /drivers/regulator/core.c | |
parent | 65244e5b1f4fade54b490b47b871cefe1d7d07f0 (diff) | |
parent | d22b85a1b97d12a4940ef9d778f6122546736f78 (diff) | |
download | linux-0ed4513c9a32a479b4dc41685be68edf1e99c139.tar.bz2 |
Merge remote-tracking branch 'regulator/topic/coupled' into regulator-next
Diffstat (limited to 'drivers/regulator/core.c')
-rw-r--r-- | drivers/regulator/core.c | 194 |
1 files changed, 143 insertions, 51 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index df82e2a8442a..86ae1825cec1 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -22,6 +22,7 @@ #include <linux/regmap.h> #include <linux/regulator/of_regulator.h> #include <linux/regulator/consumer.h> +#include <linux/regulator/coupler.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/module.h> @@ -49,6 +50,7 @@ static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_map_list); static LIST_HEAD(regulator_ena_gpio_list); static LIST_HEAD(regulator_supply_alias_list); +static LIST_HEAD(regulator_coupler_list); static bool has_full_constraints; static struct dentry *debugfs_root; @@ -92,7 +94,6 @@ struct regulator_supply_alias { static int _regulator_is_enabled(struct regulator_dev *rdev); static int _regulator_disable(struct regulator *regulator); -static int _regulator_get_voltage(struct regulator_dev *rdev); static int _regulator_get_current_limit(struct regulator_dev *rdev); static unsigned int _regulator_get_mode(struct regulator_dev *rdev); static int _notifier_call_chain(struct regulator_dev *rdev, @@ -101,15 +102,12 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV); static int regulator_balance_voltage(struct regulator_dev *rdev, suspend_state_t state); -static int regulator_set_voltage_rdev(struct regulator_dev *rdev, - int min_uV, int max_uV, - suspend_state_t state); static struct regulator *create_regulator(struct regulator_dev *rdev, struct device *dev, const char *supply_name); static void _regulator_put(struct regulator *regulator); -static const char *rdev_get_name(struct regulator_dev *rdev) +const char *rdev_get_name(struct regulator_dev *rdev) { if (rdev->constraints && rdev->constraints->name) return rdev->constraints->name; @@ -423,8 +421,8 @@ static struct device_node *of_get_regulator(struct device *dev, const char *supp } /* Platform voltage constraint check */ -static int regulator_check_voltage(struct regulator_dev *rdev, - int *min_uV, int *max_uV) +int regulator_check_voltage(struct regulator_dev *rdev, + int *min_uV, int *max_uV) { BUG_ON(*min_uV > *max_uV); @@ -456,9 +454,9 @@ static int regulator_check_states(suspend_state_t state) /* Make sure we select a voltage that suits the needs of all * regulator consumers */ -static int regulator_check_consumers(struct regulator_dev *rdev, - int *min_uV, int *max_uV, - suspend_state_t state) +int regulator_check_consumers(struct regulator_dev *rdev, + int *min_uV, int *max_uV, + suspend_state_t state) { struct regulator *regulator; struct regulator_voltage *voltage; @@ -569,7 +567,7 @@ static ssize_t regulator_uV_show(struct device *dev, ssize_t ret; regulator_lock(rdev); - ret = sprintf(buf, "%d\n", _regulator_get_voltage(rdev)); + ret = sprintf(buf, "%d\n", regulator_get_voltage_rdev(rdev)); regulator_unlock(rdev); return ret; @@ -940,7 +938,7 @@ static int drms_uA_update(struct regulator_dev *rdev) rdev_err(rdev, "failed to set load %d\n", current_uA); } else { /* get output voltage */ - output_uV = _regulator_get_voltage(rdev); + output_uV = regulator_get_voltage_rdev(rdev); if (output_uV <= 0) { rdev_err(rdev, "invalid output voltage found\n"); return -EINVAL; @@ -1053,7 +1051,7 @@ static void print_constraints(struct regulator_dev *rdev) if (!constraints->min_uV || constraints->min_uV != constraints->max_uV) { - ret = _regulator_get_voltage(rdev); + ret = regulator_get_voltage_rdev(rdev); if (ret > 0) count += scnprintf(buf + count, len - count, "at %d mV ", ret / 1000); @@ -1112,7 +1110,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, if (rdev->constraints->apply_uV && rdev->constraints->min_uV && rdev->constraints->max_uV) { int target_min, target_max; - int current_uV = _regulator_get_voltage(rdev); + int current_uV = regulator_get_voltage_rdev(rdev); if (current_uV == -ENOTRECOVERABLE) { /* This regulator can't be read and must be initialized */ @@ -1122,7 +1120,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, _regulator_do_set_voltage(rdev, rdev->constraints->min_uV, rdev->constraints->max_uV); - current_uV = _regulator_get_voltage(rdev); + current_uV = regulator_get_voltage_rdev(rdev); } if (current_uV < 0) { @@ -3064,7 +3062,7 @@ static int _regulator_call_set_voltage(struct regulator_dev *rdev, struct pre_voltage_change_data data; int ret; - data.old_uV = _regulator_get_voltage(rdev); + data.old_uV = regulator_get_voltage_rdev(rdev); data.min_uV = min_uV; data.max_uV = max_uV; ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE, @@ -3088,7 +3086,7 @@ static int _regulator_call_set_voltage_sel(struct regulator_dev *rdev, struct pre_voltage_change_data data; int ret; - data.old_uV = _regulator_get_voltage(rdev); + data.old_uV = regulator_get_voltage_rdev(rdev); data.min_uV = uV; data.max_uV = uV; ret = _notifier_call_chain(rdev, REGULATOR_EVENT_PRE_VOLTAGE_CHANGE, @@ -3201,7 +3199,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, unsigned int selector; int old_selector = -1; const struct regulator_ops *ops = rdev->desc->ops; - int old_uV = _regulator_get_voltage(rdev); + int old_uV = regulator_get_voltage_rdev(rdev); trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); @@ -3228,7 +3226,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, best_val = ops->list_voltage(rdev, selector); else - best_val = _regulator_get_voltage(rdev); + best_val = regulator_get_voltage_rdev(rdev); } } else if (ops->set_voltage_sel) { @@ -3350,7 +3348,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, * changing the voltage. */ if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { - current_uV = _regulator_get_voltage(rdev); + current_uV = regulator_get_voltage_rdev(rdev); if (min_uV <= current_uV && current_uV <= max_uV) { voltage->min_uV = min_uV; voltage->max_uV = max_uV; @@ -3387,8 +3385,8 @@ out: return ret; } -static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, - int max_uV, suspend_state_t state) +int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, + int max_uV, suspend_state_t state) { int best_supply_uV = 0; int supply_change_uV = 0; @@ -3416,7 +3414,7 @@ static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV, best_supply_uV += rdev->desc->min_dropout_uV; - current_supply_uV = _regulator_get_voltage(rdev->supply->rdev); + current_supply_uV = regulator_get_voltage_rdev(rdev->supply->rdev); if (current_supply_uV < 0) { ret = current_supply_uV; goto out; @@ -3467,7 +3465,7 @@ static int regulator_limit_voltage_step(struct regulator_dev *rdev, return 1; if (*current_uV < 0) { - *current_uV = _regulator_get_voltage(rdev); + *current_uV = regulator_get_voltage_rdev(rdev); if (*current_uV < 0) return *current_uV; @@ -3496,11 +3494,10 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev, struct coupling_desc *c_desc = &rdev->coupling_desc; struct regulator_dev **c_rdevs = c_desc->coupled_rdevs; struct regulation_constraints *constraints = rdev->constraints; - int max_spread = constraints->max_spread; int desired_min_uV = 0, desired_max_uV = INT_MAX; int max_current_uV = 0, min_current_uV = INT_MAX; int highest_min_uV = 0, target_uV, possible_uV; - int i, ret; + int i, ret, max_spread; bool done; *current_uV = -1; @@ -3554,6 +3551,8 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev, } } + max_spread = constraints->max_spread[0]; + /* * Let target_uV be equal to the desired one if possible. * If not, set it to minimum voltage, allowed by other coupled @@ -3571,7 +3570,7 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev, if (!_regulator_is_enabled(c_rdevs[i])) continue; - tmp_act = _regulator_get_voltage(c_rdevs[i]); + tmp_act = regulator_get_voltage_rdev(c_rdevs[i]); if (tmp_act < 0) return tmp_act; @@ -3613,7 +3612,7 @@ finish: if (n_coupled > 1 && *current_uV == -1) { if (_regulator_is_enabled(rdev)) { - ret = _regulator_get_voltage(rdev); + ret = regulator_get_voltage_rdev(rdev); if (ret < 0) return ret; @@ -3635,9 +3634,11 @@ static int regulator_balance_voltage(struct regulator_dev *rdev, struct regulator_dev **c_rdevs; struct regulator_dev *best_rdev; struct coupling_desc *c_desc = &rdev->coupling_desc; + struct regulator_coupler *coupler = c_desc->coupler; int i, ret, n_coupled, best_min_uV, best_max_uV, best_c_rdev; - bool best_c_rdev_done, c_rdev_done[MAX_COUPLED]; unsigned int delta, best_delta; + unsigned long c_rdev_done = 0; + bool best_c_rdev_done; c_rdevs = c_desc->coupled_rdevs; n_coupled = c_desc->n_coupled; @@ -3654,8 +3655,9 @@ static int regulator_balance_voltage(struct regulator_dev *rdev, return -EPERM; } - for (i = 0; i < n_coupled; i++) - c_rdev_done[i] = false; + /* Invoke custom balancer for customized couplers */ + if (coupler && coupler->balance_voltage) + return coupler->balance_voltage(coupler, rdev, state); /* * Find the best possible voltage change on each loop. Leave the loop @@ -3682,7 +3684,7 @@ static int regulator_balance_voltage(struct regulator_dev *rdev, */ int optimal_uV = 0, optimal_max_uV = 0, current_uV = 0; - if (c_rdev_done[i]) + if (test_bit(i, &c_rdev_done)) continue; ret = regulator_get_optimal_voltage(c_rdevs[i], @@ -3717,7 +3719,8 @@ static int regulator_balance_voltage(struct regulator_dev *rdev, if (ret < 0) goto out; - c_rdev_done[best_c_rdev] = best_c_rdev_done; + if (best_c_rdev_done) + set_bit(best_c_rdev, &c_rdev_done); } while (n_coupled > 1); @@ -3973,7 +3976,7 @@ out: } EXPORT_SYMBOL_GPL(regulator_sync_voltage); -static int _regulator_get_voltage(struct regulator_dev *rdev) +int regulator_get_voltage_rdev(struct regulator_dev *rdev) { int sel, ret; bool bypassed; @@ -3990,7 +3993,7 @@ static int _regulator_get_voltage(struct regulator_dev *rdev) return -EPROBE_DEFER; } - return _regulator_get_voltage(rdev->supply->rdev); + return regulator_get_voltage_rdev(rdev->supply->rdev); } } @@ -4006,7 +4009,7 @@ static int _regulator_get_voltage(struct regulator_dev *rdev) } else if (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1)) { ret = rdev->desc->fixed_uV; } else if (rdev->supply) { - ret = _regulator_get_voltage(rdev->supply->rdev); + ret = regulator_get_voltage_rdev(rdev->supply->rdev); } else { return -EINVAL; } @@ -4031,7 +4034,7 @@ int regulator_get_voltage(struct regulator *regulator) int ret; regulator_lock_dependent(regulator->rdev, &ww_ctx); - ret = _regulator_get_voltage(regulator->rdev); + ret = regulator_get_voltage_rdev(regulator->rdev); regulator_unlock_dependent(regulator->rdev, &ww_ctx); return ret; @@ -4769,8 +4772,60 @@ static int regulator_register_resolve_supply(struct device *dev, void *data) return 0; } +int regulator_coupler_register(struct regulator_coupler *coupler) +{ + mutex_lock(®ulator_list_mutex); + list_add_tail(&coupler->list, ®ulator_coupler_list); + mutex_unlock(®ulator_list_mutex); + + return 0; +} + +static struct regulator_coupler * +regulator_find_coupler(struct regulator_dev *rdev) +{ + struct regulator_coupler *coupler; + int err; + + /* + * Note that regulators are appended to the list and the generic + * coupler is registered first, hence it will be attached at last + * if nobody cared. + */ + list_for_each_entry_reverse(coupler, ®ulator_coupler_list, list) { + err = coupler->attach_regulator(coupler, rdev); + if (!err) { + if (!coupler->balance_voltage && + rdev->coupling_desc.n_coupled > 2) + goto err_unsupported; + + return coupler; + } + + if (err < 0) + return ERR_PTR(err); + + if (err == 1) + continue; + + break; + } + + return ERR_PTR(-EINVAL); + +err_unsupported: + if (coupler->detach_regulator) + coupler->detach_regulator(coupler, rdev); + + rdev_err(rdev, + "Voltage balancing for multiple regulator couples is unimplemented\n"); + + return ERR_PTR(-EPERM); +} + static void regulator_resolve_coupling(struct regulator_dev *rdev) { + struct regulator_coupler *coupler = rdev->coupling_desc.coupler; struct coupling_desc *c_desc = &rdev->coupling_desc; int n_coupled = c_desc->n_coupled; struct regulator_dev *c_rdev; @@ -4786,6 +4841,12 @@ static void regulator_resolve_coupling(struct regulator_dev *rdev) if (!c_rdev) continue; + if (c_rdev->coupling_desc.coupler != coupler) { + rdev_err(rdev, "coupler mismatch with %s\n", + rdev_get_name(c_rdev)); + return; + } + regulator_lock(c_rdev); c_desc->coupled_rdevs[i] = c_rdev; @@ -4799,10 +4860,12 @@ static void regulator_resolve_coupling(struct regulator_dev *rdev) static void regulator_remove_coupling(struct regulator_dev *rdev) { + struct regulator_coupler *coupler = rdev->coupling_desc.coupler; struct coupling_desc *__c_desc, *c_desc = &rdev->coupling_desc; struct regulator_dev *__c_rdev, *c_rdev; unsigned int __n_coupled, n_coupled; int i, k; + int err; n_coupled = c_desc->n_coupled; @@ -4832,21 +4895,33 @@ static void regulator_remove_coupling(struct regulator_dev *rdev) c_desc->coupled_rdevs[i] = NULL; c_desc->n_resolved--; } + + if (coupler && coupler->detach_regulator) { + err = coupler->detach_regulator(coupler, rdev); + if (err) + rdev_err(rdev, "failed to detach from coupler: %d\n", + err); + } + + kfree(rdev->coupling_desc.coupled_rdevs); + rdev->coupling_desc.coupled_rdevs = NULL; } static int regulator_init_coupling(struct regulator_dev *rdev) { - int n_phandles; + int err, n_phandles; + size_t alloc_size; if (!IS_ENABLED(CONFIG_OF)) n_phandles = 0; else n_phandles = of_get_n_coupled(rdev); - if (n_phandles + 1 > MAX_COUPLED) { - rdev_err(rdev, "too many regulators coupled\n"); - return -EPERM; - } + alloc_size = sizeof(*rdev) * (n_phandles + 1); + + rdev->coupling_desc.coupled_rdevs = kzalloc(alloc_size, GFP_KERNEL); + if (!rdev->coupling_desc.coupled_rdevs) + return -ENOMEM; /* * Every regulator should always have coupling descriptor filled with @@ -4860,23 +4935,35 @@ static int regulator_init_coupling(struct regulator_dev *rdev) if (n_phandles == 0) return 0; - /* regulator, which can't change its voltage, can't be coupled */ - if (!regulator_ops_is_valid(rdev, REGULATOR_CHANGE_VOLTAGE)) { - rdev_err(rdev, "voltage operation not allowed\n"); + if (!of_check_coupling_data(rdev)) return -EPERM; - } - if (rdev->constraints->max_spread <= 0) { - rdev_err(rdev, "wrong max_spread value\n"); - return -EPERM; + rdev->coupling_desc.coupler = regulator_find_coupler(rdev); + if (IS_ERR(rdev->coupling_desc.coupler)) { + err = PTR_ERR(rdev->coupling_desc.coupler); + rdev_err(rdev, "failed to get coupler: %d\n", err); + return err; } - if (!of_check_coupling_data(rdev)) + return 0; +} + +static int generic_coupler_attach(struct regulator_coupler *coupler, + struct regulator_dev *rdev) +{ + if (rdev->coupling_desc.n_coupled > 2) { + rdev_err(rdev, + "Voltage balancing for multiple regulator couples is unimplemented\n"); return -EPERM; + } return 0; } +static struct regulator_coupler generic_regulator_coupler = { + .attach_regulator = generic_coupler_attach, +}; + /** * regulator_register - register regulator * @regulator_desc: regulator to register @@ -5038,7 +5125,9 @@ regulator_register(const struct regulator_desc *regulator_desc, if (ret < 0) goto wash; + mutex_lock(®ulator_list_mutex); ret = regulator_init_coupling(rdev); + mutex_unlock(®ulator_list_mutex); if (ret < 0) goto wash; @@ -5087,6 +5176,7 @@ regulator_register(const struct regulator_desc *regulator_desc, unset_supplies: mutex_lock(®ulator_list_mutex); unset_regulator_supplies(rdev); + regulator_remove_coupling(rdev); mutex_unlock(®ulator_list_mutex); wash: kfree(rdev->constraints); @@ -5340,7 +5430,7 @@ static void regulator_summary_show_subtree(struct seq_file *s, rdev->use_count, rdev->open_count, rdev->bypass_count, regulator_opmode_to_str(opmode)); - seq_printf(s, "%5dmV ", _regulator_get_voltage(rdev) / 1000); + seq_printf(s, "%5dmV ", regulator_get_voltage_rdev(rdev) / 1000); seq_printf(s, "%5dmA ", _regulator_get_current_limit_unlocked(rdev) / 1000); @@ -5542,6 +5632,8 @@ static int __init regulator_init(void) #endif regulator_dummy_init(); + regulator_coupler_register(&generic_regulator_coupler); + return ret; } |