Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Unverified Commit 0ed4513c authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branch 'regulator/topic/coupled' into regulator-next

parents 65244e5b d22b85a1
Loading
Loading
Loading
Loading
+143 −51
Original line number Diff line number Diff line
@@ -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,7 +421,7 @@ 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 regulator_check_voltage(struct regulator_dev *rdev,
			    int *min_uV, int *max_uV)
{
	BUG_ON(*min_uV > *max_uV);
@@ -456,7 +454,7 @@ 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 regulator_check_consumers(struct regulator_dev *rdev,
			      int *min_uV, int *max_uV,
			      suspend_state_t state)
{
@@ -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,7 +3385,7 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
	return ret;
}

static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV,
int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV,
			       int max_uV, suspend_state_t state)
{
	int best_supply_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 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
	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 @@ int regulator_sync_voltage(struct regulator *regulator)
}
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;

	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 (rdev->constraints->max_spread <= 0) {
		rdev_err(rdev, "wrong max_spread value\n");
		return -EPERM;
	return 0;
}

	if (!of_check_coupling_data(rdev))
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;
}

+43 −20
Original line number Diff line number Diff line
@@ -21,7 +21,8 @@ static const char *const regulator_states[PM_SUSPEND_MAX + 1] = {
	[PM_SUSPEND_MAX]	= "regulator-state-disk",
};

static void of_get_regulation_constraints(struct device_node *np,
static int of_get_regulation_constraints(struct device *dev,
					struct device_node *np,
					struct regulator_init_data **init_data,
					const struct regulator_desc *desc)
{
@@ -30,8 +31,13 @@ static void of_get_regulation_constraints(struct device_node *np,
	struct device_node *suspend_np;
	unsigned int mode;
	int ret, i, len;
	int n_phandles;
	u32 pval;

	n_phandles = of_count_phandle_with_args(np, "regulator-coupled-with",
						NULL);
	n_phandles = max(n_phandles, 0);

	constraints->name = of_get_property(np, "regulator-name", NULL);

	if (!of_property_read_u32(np, "regulator-min-microvolt", &pval))
@@ -163,9 +169,17 @@ static void of_get_regulation_constraints(struct device_node *np,
	if (!of_property_read_u32(np, "regulator-system-load", &pval))
		constraints->system_load = pval;

	if (!of_property_read_u32(np, "regulator-coupled-max-spread",
				  &pval))
		constraints->max_spread = pval;
	if (n_phandles) {
		constraints->max_spread = devm_kzalloc(dev,
				sizeof(*constraints->max_spread) * n_phandles,
				GFP_KERNEL);

		if (!constraints->max_spread)
			return -ENOMEM;

		of_property_read_u32_array(np, "regulator-coupled-max-spread",
					   constraints->max_spread, n_phandles);
	}

	if (!of_property_read_u32(np, "regulator-max-step-microvolt",
				  &pval))
@@ -242,6 +256,8 @@ static void of_get_regulation_constraints(struct device_node *np,
		suspend_state = NULL;
		suspend_np = NULL;
	}

	return 0;
}

/**
@@ -267,7 +283,9 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
	if (!init_data)
		return NULL; /* Out of memory? */

	of_get_regulation_constraints(node, &init_data, desc);
	if (of_get_regulation_constraints(dev, node, &init_data, desc))
		return NULL;

	return init_data;
}
EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
@@ -473,7 +491,8 @@ int of_get_n_coupled(struct regulator_dev *rdev)

/* Looks for "to_find" device_node in src's "regulator-coupled-with" property */
static bool of_coupling_find_node(struct device_node *src,
				  struct device_node *to_find)
				  struct device_node *to_find,
				  int *index)
{
	int n_phandles, i;
	bool found = false;
@@ -495,9 +514,11 @@ static bool of_coupling_find_node(struct device_node *src,

		of_node_put(tmp);

		if (found)
		if (found) {
			*index = i;
			break;
		}
	}

	return found;
}
@@ -517,22 +538,23 @@ static bool of_coupling_find_node(struct device_node *src,
 */
bool of_check_coupling_data(struct regulator_dev *rdev)
{
	int max_spread = rdev->constraints->max_spread;
	struct device_node *node = rdev->dev.of_node;
	int n_phandles = of_get_n_coupled(rdev);
	struct device_node *c_node;
	int index;
	int i;
	bool ret = true;

	/* iterate over rdev's phandles */
	for (i = 0; i < n_phandles; i++) {
		int max_spread = rdev->constraints->max_spread[i];
		int c_max_spread, c_n_phandles;

		if (max_spread <= 0) {
			dev_err(&rdev->dev, "max_spread value invalid\n");
			return false;
		}

	/* iterate over rdev's phandles */
	for (i = 0; i < n_phandles; i++) {
		int c_max_spread, c_n_phandles;

		c_node = of_parse_phandle(node,
					  "regulator-coupled-with", i);

@@ -549,22 +571,23 @@ bool of_check_coupling_data(struct regulator_dev *rdev)
			goto clean;
		}

		if (of_property_read_u32(c_node, "regulator-coupled-max-spread",
					 &c_max_spread)) {
		if (!of_coupling_find_node(c_node, node, &index)) {
			dev_err(&rdev->dev, "missing 2-way linking for coupled regulators\n");
			ret = false;
			goto clean;
		}

		if (c_max_spread != max_spread) {
			dev_err(&rdev->dev,
				"coupled regulators max_spread mismatch\n");
		if (of_property_read_u32_index(c_node, "regulator-coupled-max-spread",
					       index, &c_max_spread)) {
			ret = false;
			goto clean;
		}

		if (!of_coupling_find_node(c_node, node)) {
			dev_err(&rdev->dev, "missing 2-way linking for coupled regulators\n");
		if (c_max_spread != max_spread) {
			dev_err(&rdev->dev,
				"coupled regulators max_spread mismatch\n");
			ret = false;
			goto clean;
		}

clean:
+97 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * coupler.h -- SoC Regulator support, coupler API.
 *
 * Regulator Coupler Interface.
 */

#ifndef __LINUX_REGULATOR_COUPLER_H_
#define __LINUX_REGULATOR_COUPLER_H_

#include <linux/kernel.h>
#include <linux/suspend.h>

struct regulator_coupler;
struct regulator_dev;

/**
 * struct regulator_coupler - customized regulator's coupler
 *
 * Regulator's coupler allows to customize coupling algorithm.
 *
 * @list: couplers list entry
 * @attach_regulator: Callback invoked on creation of a coupled regulator,
 *                    couples are unresolved at this point. The callee should
 *                    check that it could handle the regulator and return 0 on
 *                    success, -errno on failure and 1 if given regulator is
 *                    not suitable for this coupler (case of having multiple
 *                    regulators in a system). Callback shall be implemented.
 * @detach_regulator: Callback invoked on destruction of a coupled regulator.
 *                    This callback is optional and could be NULL.
 * @balance_voltage: Callback invoked when voltage of a coupled regulator is
 *                   changing. Called with all of the coupled rdev's being held
 *                   under "consumer lock". The callee should perform voltage
 *                   balancing, changing voltage of the coupled regulators as
 *                   needed. It's up to the coupler to verify the voltage
 *                   before changing it in hardware, i.e. coupler should
 *                   check consumer's min/max and etc. This callback is
 *                   optional and could be NULL, in which case a generic
 *                   voltage balancer will be used.
 */
struct regulator_coupler {
	struct list_head list;

	int (*attach_regulator)(struct regulator_coupler *coupler,
				struct regulator_dev *rdev);
	int (*detach_regulator)(struct regulator_coupler *coupler,
				struct regulator_dev *rdev);
	int (*balance_voltage)(struct regulator_coupler *coupler,
			       struct regulator_dev *rdev,
			       suspend_state_t state);
};

#ifdef CONFIG_REGULATOR
int regulator_coupler_register(struct regulator_coupler *coupler);
const char *rdev_get_name(struct regulator_dev *rdev);
int regulator_check_consumers(struct regulator_dev *rdev,
			      int *min_uV, int *max_uV,
			      suspend_state_t state);
int regulator_check_voltage(struct regulator_dev *rdev,
			    int *min_uV, int *max_uV);
int regulator_get_voltage_rdev(struct regulator_dev *rdev);
int regulator_set_voltage_rdev(struct regulator_dev *rdev,
			       int min_uV, int max_uV,
			       suspend_state_t state);
#else
static inline int regulator_coupler_register(struct regulator_coupler *coupler)
{
	return 0;
}
static inline const char *rdev_get_name(struct regulator_dev *rdev)
{
	return NULL;
}
static inline int regulator_check_consumers(struct regulator_dev *rdev,
					    int *min_uV, int *max_uV,
					    suspend_state_t state)
{
	return -EINVAL;
}
static inline int regulator_check_voltage(struct regulator_dev *rdev,
					  int *min_uV, int *max_uV)
{
	return -EINVAL;
}
static inline int regulator_get_voltage_rdev(struct regulator_dev *rdev)
{
	return -EINVAL;
}
static inline int regulator_set_voltage_rdev(struct regulator_dev *rdev,
					     int min_uV, int max_uV,
					     suspend_state_t state)
{
	return -EINVAL;
}
#endif

#endif
+3 −3
Original line number Diff line number Diff line
@@ -12,8 +12,6 @@
#ifndef __LINUX_REGULATOR_DRIVER_H_
#define __LINUX_REGULATOR_DRIVER_H_

#define MAX_COUPLED		2

#include <linux/device.h>
#include <linux/notifier.h>
#include <linux/regulator/consumer.h>
@@ -429,7 +427,8 @@ struct regulator_config {
 * incremented.
 */
struct coupling_desc {
	struct regulator_dev *coupled_rdevs[MAX_COUPLED];
	struct regulator_dev **coupled_rdevs;
	struct regulator_coupler *coupler;
	int n_resolved;
	int n_coupled;
};
@@ -555,4 +554,5 @@ void regulator_unlock(struct regulator_dev *rdev);
 */
int regulator_desc_list_voltage_linear_range(const struct regulator_desc *desc,
					     unsigned int selector);

#endif
+1 −1
Original line number Diff line number Diff line
@@ -153,7 +153,7 @@ struct regulation_constraints {
	int system_load;

	/* used for coupled regulators */
	int max_spread;
	u32 *max_spread;

	/* used for changing voltage in steps */
	int max_uV_step;