summaryrefslogtreecommitdiffstats
path: root/drivers/regulator/core.c
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2019-07-04 17:34:34 +0100
committerMark Brown <broonie@kernel.org>2019-07-04 17:34:34 +0100
commit0ed4513c9a32a479b4dc41685be68edf1e99c139 (patch)
tree56e2cab31df315ec4cf37f064a8df3404b3ea753 /drivers/regulator/core.c
parent65244e5b1f4fade54b490b47b871cefe1d7d07f0 (diff)
parentd22b85a1b97d12a4940ef9d778f6122546736f78 (diff)
downloadlinux-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.c194
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(&regulator_list_mutex);
+ list_add_tail(&coupler->list, &regulator_coupler_list);
+ mutex_unlock(&regulator_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, &regulator_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(&regulator_list_mutex);
ret = regulator_init_coupling(rdev);
+ mutex_unlock(&regulator_list_mutex);
if (ret < 0)
goto wash;
@@ -5087,6 +5176,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
unset_supplies:
mutex_lock(&regulator_list_mutex);
unset_regulator_supplies(rdev);
+ regulator_remove_coupling(rdev);
mutex_unlock(&regulator_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;
}