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

Commit 57def856 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branch 'pm-opp'

* pm-opp:
  PM / OPP: Don't WARN on multiple calls to dev_pm_opp_set_regulators()
  PM / OPP: Allow platform specific custom set_opp() callbacks
  PM / OPP: Separate out _generic_set_opp()
  PM / OPP: Add infrastructure to manage multiple regulators
  PM / OPP: Pass struct dev_pm_opp_supply to _set_opp_voltage()
  PM / OPP: Manage supply's voltage/current in a separate structure
  PM / OPP: Don't use OPP structure outside of rcu protected section
  PM / OPP: Reword binding supporting multiple regulators per device
  PM / OPP: Fix incorrect cpu-supply property in binding
  PM / OPP: Pass opp_table to dev_pm_opp_put_regulator()
  PM / OPP: fix debug/error messages in dev_pm_opp_of_get_sharing_cpus()
  PM / OPP: make _of_get_opp_desc_node() a static function
parents 852b7fa2 e231f8d7
Loading
Loading
Loading
Loading
+19 −8
Original line number Diff line number Diff line
@@ -86,8 +86,14 @@ Optional properties:
  Single entry is for target voltage and three entries are for <target min max>
  voltages.

  Entries for multiple regulators must be present in the same order as
  regulators are specified in device's DT node.
  Entries for multiple regulators shall be provided in the same field separated
  by angular brackets <>. The OPP binding doesn't provide any provisions to
  relate the values to their power supplies or the order in which the supplies
  need to be configured and that is left for the implementation specific
  binding.

  Entries for all regulators shall be of the same size, i.e. either all use a
  single value or triplets.

- opp-microvolt-<name>: Named opp-microvolt property. This is exactly similar to
  the above opp-microvolt property, but allows multiple voltage ranges to be
@@ -104,10 +110,13 @@ Optional properties:

  Should only be set if opp-microvolt is set for the OPP.

  Entries for multiple regulators must be present in the same order as
  regulators are specified in device's DT node. If this property isn't required
  for few regulators, then this should be marked as zero for them. If it isn't
  required for any regulator, then this property need not be present.
  Entries for multiple regulators shall be provided in the same field separated
  by angular brackets <>. If current values aren't required for a regulator,
  then it shall be filled with 0. If current values aren't required for any of
  the regulators, then this field is not required. The OPP binding doesn't
  provide any provisions to relate the values to their power supplies or the
  order in which the supplies need to be configured and that is left for the
  implementation specific binding.

- opp-microamp-<name>: Named opp-microamp property. Similar to
  opp-microvolt-<name> property, but for microamp instead.
@@ -386,10 +395,12 @@ Example 4: Handling multiple regulators
/ {
	cpus {
		cpu@0 {
			compatible = "arm,cortex-a7";
			compatible = "vendor,cpu-type";
			...

			cpu-supply = <&cpu_supply0>, <&cpu_supply1>, <&cpu_supply2>;
			vcc0-supply = <&cpu_supply0>;
			vcc1-supply = <&cpu_supply1>;
			vcc2-supply = <&cpu_supply2>;
			operating-points-v2 = <&cpu0_opp_table>;
		};
	};
+397 −124
Original line number Diff line number Diff line
@@ -93,6 +93,8 @@ struct opp_table *_find_opp_table(struct device *dev)
 * Return: voltage in micro volt corresponding to the opp, else
 * return 0
 *
 * This is useful only for devices with single power supply.
 *
 * Locking: This function must be called under rcu_read_lock(). opp is a rcu
 * protected pointer. This means that opp which could have been fetched by
 * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are
@@ -112,7 +114,7 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
	if (IS_ERR_OR_NULL(tmp_opp))
		pr_err("%s: Invalid parameters\n", __func__);
	else
		v = tmp_opp->u_volt;
		v = tmp_opp->supplies[0].u_volt;

	return v;
}
@@ -210,6 +212,24 @@ unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev)
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency);

static int _get_regulator_count(struct device *dev)
{
	struct opp_table *opp_table;
	int count;

	rcu_read_lock();

	opp_table = _find_opp_table(dev);
	if (!IS_ERR(opp_table))
		count = opp_table->regulator_count;
	else
		count = 0;

	rcu_read_unlock();

	return count;
}

/**
 * dev_pm_opp_get_max_volt_latency() - Get max voltage latency in nanoseconds
 * @dev: device for which we do this operation
@@ -222,34 +242,51 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
{
	struct opp_table *opp_table;
	struct dev_pm_opp *opp;
	struct regulator *reg;
	struct regulator *reg, **regulators;
	unsigned long latency_ns = 0;
	unsigned long min_uV = ~0, max_uV = 0;
	int ret;
	int ret, i, count;
	struct {
		unsigned long min;
		unsigned long max;
	} *uV;

	count = _get_regulator_count(dev);

	/* Regulator may not be required for the device */
	if (!count)
		return 0;

	regulators = kmalloc_array(count, sizeof(*regulators), GFP_KERNEL);
	if (!regulators)
		return 0;

	uV = kmalloc_array(count, sizeof(*uV), GFP_KERNEL);
	if (!uV)
		goto free_regulators;

	rcu_read_lock();

	opp_table = _find_opp_table(dev);
	if (IS_ERR(opp_table)) {
		rcu_read_unlock();
		return 0;
		goto free_uV;
	}

	reg = opp_table->regulator;
	if (IS_ERR(reg)) {
		/* Regulator may not be required for device */
		rcu_read_unlock();
		return 0;
	}
	memcpy(regulators, opp_table->regulators, count * sizeof(*regulators));

	for (i = 0; i < count; i++) {
		uV[i].min = ~0;
		uV[i].max = 0;

		list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
			if (!opp->available)
				continue;

		if (opp->u_volt_min < min_uV)
			min_uV = opp->u_volt_min;
		if (opp->u_volt_max > max_uV)
			max_uV = opp->u_volt_max;
			if (opp->supplies[i].u_volt_min < uV[i].min)
				uV[i].min = opp->supplies[i].u_volt_min;
			if (opp->supplies[i].u_volt_max > uV[i].max)
				uV[i].max = opp->supplies[i].u_volt_max;
		}
	}

	rcu_read_unlock();
@@ -258,9 +295,16 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
	 * The caller needs to ensure that opp_table (and hence the regulator)
	 * isn't freed, while we are executing this routine.
	 */
	ret = regulator_set_voltage_time(reg, min_uV, max_uV);
	for (i = 0; reg = regulators[i], i < count; i++) {
		ret = regulator_set_voltage_time(reg, uV[i].min, uV[i].max);
		if (ret > 0)
		latency_ns = ret * 1000;
			latency_ns += ret * 1000;
	}

free_uV:
	kfree(uV);
free_regulators:
	kfree(regulators);

	return latency_ns;
}
@@ -542,8 +586,7 @@ static struct clk *_get_opp_clk(struct device *dev)
}

static int _set_opp_voltage(struct device *dev, struct regulator *reg,
			    unsigned long u_volt, unsigned long u_volt_min,
			    unsigned long u_volt_max)
			    struct dev_pm_opp_supply *supply)
{
	int ret;

@@ -554,14 +597,78 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg,
		return 0;
	}

	dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__, u_volt_min,
		u_volt, u_volt_max);
	dev_dbg(dev, "%s: voltages (mV): %lu %lu %lu\n", __func__,
		supply->u_volt_min, supply->u_volt, supply->u_volt_max);

	ret = regulator_set_voltage_triplet(reg, u_volt_min, u_volt,
					    u_volt_max);
	ret = regulator_set_voltage_triplet(reg, supply->u_volt_min,
					    supply->u_volt, supply->u_volt_max);
	if (ret)
		dev_err(dev, "%s: failed to set voltage (%lu %lu %lu mV): %d\n",
			__func__, u_volt_min, u_volt, u_volt_max, ret);
			__func__, supply->u_volt_min, supply->u_volt,
			supply->u_volt_max, ret);

	return ret;
}

static inline int
_generic_set_opp_clk_only(struct device *dev, struct clk *clk,
			  unsigned long old_freq, unsigned long freq)
{
	int ret;

	ret = clk_set_rate(clk, freq);
	if (ret) {
		dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
			ret);
	}

	return ret;
}

static int _generic_set_opp(struct dev_pm_set_opp_data *data)
{
	struct dev_pm_opp_supply *old_supply = data->old_opp.supplies;
	struct dev_pm_opp_supply *new_supply = data->new_opp.supplies;
	unsigned long old_freq = data->old_opp.rate, freq = data->new_opp.rate;
	struct regulator *reg = data->regulators[0];
	struct device *dev= data->dev;
	int ret;

	/* This function only supports single regulator per device */
	if (WARN_ON(data->regulator_count > 1)) {
		dev_err(dev, "multiple regulators are not supported\n");
		return -EINVAL;
	}

	/* Scaling up? Scale voltage before frequency */
	if (freq > old_freq) {
		ret = _set_opp_voltage(dev, reg, new_supply);
		if (ret)
			goto restore_voltage;
	}

	/* Change frequency */
	ret = _generic_set_opp_clk_only(dev, data->clk, old_freq, freq);
	if (ret)
		goto restore_voltage;

	/* Scaling down? Scale voltage after frequency */
	if (freq < old_freq) {
		ret = _set_opp_voltage(dev, reg, new_supply);
		if (ret)
			goto restore_freq;
	}

	return 0;

restore_freq:
	if (_generic_set_opp_clk_only(dev, data->clk, freq, old_freq))
		dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
			__func__, old_freq);
restore_voltage:
	/* This shouldn't harm even if the voltages weren't updated earlier */
	if (old_supply->u_volt)
		_set_opp_voltage(dev, reg, old_supply);

	return ret;
}
@@ -579,12 +686,13 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg,
int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
{
	struct opp_table *opp_table;
	unsigned long freq, old_freq;
	int (*set_opp)(struct dev_pm_set_opp_data *data);
	struct dev_pm_opp *old_opp, *opp;
	struct regulator *reg;
	struct regulator **regulators;
	struct dev_pm_set_opp_data *data;
	struct clk *clk;
	unsigned long freq, old_freq;
	unsigned long u_volt, u_volt_min, u_volt_max;
	int ret;
	int ret, size;

	if (unlikely(!target_freq)) {
		dev_err(dev, "%s: Invalid target frequency %lu\n", __func__,
@@ -633,55 +741,41 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
		return ret;
	}

	u_volt = opp->u_volt;
	u_volt_min = opp->u_volt_min;
	u_volt_max = opp->u_volt_max;
	dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n", __func__,
		old_freq, freq);

	reg = opp_table->regulator;
	regulators = opp_table->regulators;

	/* Only frequency scaling */
	if (!regulators) {
		rcu_read_unlock();

	/* Scaling up? Scale voltage before frequency */
	if (freq > old_freq) {
		ret = _set_opp_voltage(dev, reg, u_volt, u_volt_min,
				       u_volt_max);
		if (ret)
			goto restore_voltage;
	}

	/* Change frequency */

	dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n",
		__func__, old_freq, freq);

	ret = clk_set_rate(clk, freq);
	if (ret) {
		dev_err(dev, "%s: failed to set clock rate: %d\n", __func__,
			ret);
		goto restore_voltage;
		return _generic_set_opp_clk_only(dev, clk, old_freq, freq);
	}

	/* Scaling down? Scale voltage after frequency */
	if (freq < old_freq) {
		ret = _set_opp_voltage(dev, reg, u_volt, u_volt_min,
				       u_volt_max);
		if (ret)
			goto restore_freq;
	}
	if (opp_table->set_opp)
		set_opp = opp_table->set_opp;
	else
		set_opp = _generic_set_opp;

	data = opp_table->set_opp_data;
	data->regulators = regulators;
	data->regulator_count = opp_table->regulator_count;
	data->clk = clk;
	data->dev = dev;

	data->old_opp.rate = old_freq;
	size = sizeof(*opp->supplies) * opp_table->regulator_count;
	if (IS_ERR(old_opp))
		memset(data->old_opp.supplies, 0, size);
	else
		memcpy(data->old_opp.supplies, old_opp->supplies, size);

	return 0;
	data->new_opp.rate = freq;
	memcpy(data->new_opp.supplies, opp->supplies, size);

restore_freq:
	if (clk_set_rate(clk, old_freq))
		dev_err(dev, "%s: failed to restore old-freq (%lu Hz)\n",
			__func__, old_freq);
restore_voltage:
	/* This shouldn't harm even if the voltages weren't updated earlier */
	if (!IS_ERR(old_opp))
		_set_opp_voltage(dev, reg, old_opp->u_volt,
				 old_opp->u_volt_min, old_opp->u_volt_max);
	rcu_read_unlock();

	return ret;
	return set_opp(data);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_set_rate);

@@ -764,9 +858,6 @@ static struct opp_table *_add_opp_table(struct device *dev)

	_of_init_opp_table(opp_table, dev);

	/* Set regulator to a non-NULL error value */
	opp_table->regulator = ERR_PTR(-ENXIO);

	/* Find clk for the device */
	opp_table->clk = clk_get(dev, NULL);
	if (IS_ERR(opp_table->clk)) {
@@ -815,7 +906,10 @@ static void _remove_opp_table(struct opp_table *opp_table)
	if (opp_table->prop_name)
		return;

	if (!IS_ERR(opp_table->regulator))
	if (opp_table->regulators)
		return;

	if (opp_table->set_opp)
		return;

	/* Release clk */
@@ -924,35 +1018,51 @@ struct dev_pm_opp *_allocate_opp(struct device *dev,
				 struct opp_table **opp_table)
{
	struct dev_pm_opp *opp;
	int count, supply_size;
	struct opp_table *table;

	/* allocate new OPP node */
	opp = kzalloc(sizeof(*opp), GFP_KERNEL);
	if (!opp)
	table = _add_opp_table(dev);
	if (!table)
		return NULL;

	INIT_LIST_HEAD(&opp->node);
	/* Allocate space for at least one supply */
	count = table->regulator_count ? table->regulator_count : 1;
	supply_size = sizeof(*opp->supplies) * count;

	*opp_table = _add_opp_table(dev);
	if (!*opp_table) {
		kfree(opp);
	/* allocate new OPP node and supplies structures */
	opp = kzalloc(sizeof(*opp) + supply_size, GFP_KERNEL);
	if (!opp) {
		kfree(table);
		return NULL;
	}

	/* Put the supplies at the end of the OPP structure as an empty array */
	opp->supplies = (struct dev_pm_opp_supply *)(opp + 1);
	INIT_LIST_HEAD(&opp->node);

	*opp_table = table;

	return opp;
}

static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,
					 struct opp_table *opp_table)
{
	struct regulator *reg = opp_table->regulator;
	struct regulator *reg;
	int i;

	if (!IS_ERR(reg) &&
	    !regulator_is_supported_voltage(reg, opp->u_volt_min,
					    opp->u_volt_max)) {
	for (i = 0; i < opp_table->regulator_count; i++) {
		reg = opp_table->regulators[i];

		if (!regulator_is_supported_voltage(reg,
					opp->supplies[i].u_volt_min,
					opp->supplies[i].u_volt_max)) {
			pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported by regulator\n",
			__func__, opp->u_volt_min, opp->u_volt_max);
				__func__, opp->supplies[i].u_volt_min,
				opp->supplies[i].u_volt_max);
			return false;
		}
	}

	return true;
}
@@ -983,11 +1093,13 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,

		/* Duplicate OPPs */
		dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n",
			 __func__, opp->rate, opp->u_volt, opp->available,
			 new_opp->rate, new_opp->u_volt, new_opp->available);
			 __func__, opp->rate, opp->supplies[0].u_volt,
			 opp->available, new_opp->rate,
			 new_opp->supplies[0].u_volt, new_opp->available);

		return opp->available && new_opp->u_volt == opp->u_volt ?
			0 : -EEXIST;
		/* Should we compare voltages for all regulators here ? */
		return opp->available &&
		       new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? 0 : -EEXIST;
	}

	new_opp->opp_table = opp_table;
@@ -1054,9 +1166,9 @@ int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt,
	/* populate the opp table */
	new_opp->rate = freq;
	tol = u_volt * opp_table->voltage_tolerance_v1 / 100;
	new_opp->u_volt = u_volt;
	new_opp->u_volt_min = u_volt - tol;
	new_opp->u_volt_max = u_volt + tol;
	new_opp->supplies[0].u_volt = u_volt;
	new_opp->supplies[0].u_volt_min = u_volt - tol;
	new_opp->supplies[0].u_volt_max = u_volt + tol;
	new_opp->available = true;
	new_opp->dynamic = dynamic;

@@ -1300,13 +1412,47 @@ void dev_pm_opp_put_prop_name(struct device *dev)
}
EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);

static int _allocate_set_opp_data(struct opp_table *opp_table)
{
	struct dev_pm_set_opp_data *data;
	int len, count = opp_table->regulator_count;

	if (WARN_ON(!count))
		return -EINVAL;

	/* space for set_opp_data */
	len = sizeof(*data);

	/* space for old_opp.supplies and new_opp.supplies */
	len += 2 * sizeof(struct dev_pm_opp_supply) * count;

	data = kzalloc(len, GFP_KERNEL);
	if (!data)
		return -ENOMEM;

	data->old_opp.supplies = (void *)(data + 1);
	data->new_opp.supplies = data->old_opp.supplies + count;

	opp_table->set_opp_data = data;

	return 0;
}

static void _free_set_opp_data(struct opp_table *opp_table)
{
	kfree(opp_table->set_opp_data);
	opp_table->set_opp_data = NULL;
}

/**
 * dev_pm_opp_set_regulator() - Set regulator name for the device
 * dev_pm_opp_set_regulators() - Set regulator names for the device
 * @dev: Device for which regulator name is being set.
 * @name: Name of the regulator.
 * @names: Array of pointers to the names of the regulator.
 * @count: Number of regulators.
 *
 * In order to support OPP switching, OPP layer needs to know the name of the
 * device's regulator, as the core would be required to switch voltages as well.
 * device's regulators, as the core would be required to switch voltages as
 * well.
 *
 * This must be called before any OPPs are initialized for the device.
 *
@@ -1316,11 +1462,13 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
 * that this function is *NOT* called under RCU protection or in contexts where
 * mutex cannot be locked.
 */
int dev_pm_opp_set_regulator(struct device *dev, const char *name)
struct opp_table *dev_pm_opp_set_regulators(struct device *dev,
					    const char * const names[],
					    unsigned int count)
{
	struct opp_table *opp_table;
	struct regulator *reg;
	int ret;
	int ret, i;

	mutex_lock(&opp_table_lock);

@@ -1336,22 +1484,146 @@ int dev_pm_opp_set_regulator(struct device *dev, const char *name)
		goto err;
	}

	/* Already have a regulator set */
	if (WARN_ON(!IS_ERR(opp_table->regulator))) {
	/* Already have regulators set */
	if (opp_table->regulators) {
		ret = -EBUSY;
		goto err;
	}
	/* Allocate the regulator */
	reg = regulator_get_optional(dev, name);

	opp_table->regulators = kmalloc_array(count,
					      sizeof(*opp_table->regulators),
					      GFP_KERNEL);
	if (!opp_table->regulators) {
		ret = -ENOMEM;
		goto err;
	}

	for (i = 0; i < count; i++) {
		reg = regulator_get_optional(dev, names[i]);
		if (IS_ERR(reg)) {
			ret = PTR_ERR(reg);
			if (ret != -EPROBE_DEFER)
				dev_err(dev, "%s: no regulator (%s) found: %d\n",
				__func__, name, ret);
					__func__, names[i], ret);
			goto free_regulators;
		}

		opp_table->regulators[i] = reg;
	}

	opp_table->regulator_count = count;

	/* Allocate block only once to pass to set_opp() routines */
	ret = _allocate_set_opp_data(opp_table);
	if (ret)
		goto free_regulators;

	mutex_unlock(&opp_table_lock);
	return opp_table;

free_regulators:
	while (i != 0)
		regulator_put(opp_table->regulators[--i]);

	kfree(opp_table->regulators);
	opp_table->regulators = NULL;
	opp_table->regulator_count = 0;
err:
	_remove_opp_table(opp_table);
unlock:
	mutex_unlock(&opp_table_lock);

	return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulators);

/**
 * dev_pm_opp_put_regulators() - Releases resources blocked for regulator
 * @opp_table: OPP table returned from dev_pm_opp_set_regulators().
 *
 * Locking: The internal opp_table and opp structures are RCU protected.
 * Hence this function internally uses RCU updater strategy with mutex locks
 * to keep the integrity of the internal data structures. Callers should ensure
 * that this function is *NOT* called under RCU protection or in contexts where
 * mutex cannot be locked.
 */
void dev_pm_opp_put_regulators(struct opp_table *opp_table)
{
	int i;

	mutex_lock(&opp_table_lock);

	if (!opp_table->regulators) {
		pr_err("%s: Doesn't have regulators set\n", __func__);
		goto unlock;
	}

	/* Make sure there are no concurrent readers while updating opp_table */
	WARN_ON(!list_empty(&opp_table->opp_list));

	for (i = opp_table->regulator_count - 1; i >= 0; i--)
		regulator_put(opp_table->regulators[i]);

	_free_set_opp_data(opp_table);

	kfree(opp_table->regulators);
	opp_table->regulators = NULL;
	opp_table->regulator_count = 0;

	/* Try freeing opp_table if this was the last blocking resource */
	_remove_opp_table(opp_table);

unlock:
	mutex_unlock(&opp_table_lock);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators);

/**
 * dev_pm_opp_register_set_opp_helper() - Register custom set OPP helper
 * @dev: Device for which the helper is getting registered.
 * @set_opp: Custom set OPP helper.
 *
 * This is useful to support complex platforms (like platforms with multiple
 * regulators per device), instead of the generic OPP set rate helper.
 *
 * This must be called before any OPPs are initialized for the device.
 *
 * Locking: The internal opp_table and opp structures are RCU protected.
 * Hence this function internally uses RCU updater strategy with mutex locks
 * to keep the integrity of the internal data structures. Callers should ensure
 * that this function is *NOT* called under RCU protection or in contexts where
 * mutex cannot be locked.
 */
int dev_pm_opp_register_set_opp_helper(struct device *dev,
			int (*set_opp)(struct dev_pm_set_opp_data *data))
{
	struct opp_table *opp_table;
	int ret;

	if (!set_opp)
		return -EINVAL;

	mutex_lock(&opp_table_lock);

	opp_table = _add_opp_table(dev);
	if (!opp_table) {
		ret = -ENOMEM;
		goto unlock;
	}

	/* This should be called before OPPs are initialized */
	if (WARN_ON(!list_empty(&opp_table->opp_list))) {
		ret = -EBUSY;
		goto err;
	}

	opp_table->regulator = reg;
	/* Already have custom set_opp helper */
	if (WARN_ON(opp_table->set_opp)) {
		ret = -EBUSY;
		goto err;
	}

	opp_table->set_opp = set_opp;

	mutex_unlock(&opp_table_lock);
	return 0;
@@ -1363,11 +1635,12 @@ int dev_pm_opp_set_regulator(struct device *dev, const char *name)

	return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator);
EXPORT_SYMBOL_GPL(dev_pm_opp_register_set_opp_helper);

/**
 * dev_pm_opp_put_regulator() - Releases resources blocked for regulator
 * @dev: Device for which regulator was set.
 * dev_pm_opp_register_put_opp_helper() - Releases resources blocked for
 *					   set_opp helper
 * @dev: Device for which custom set_opp helper has to be cleared.
 *
 * Locking: The internal opp_table and opp structures are RCU protected.
 * Hence this function internally uses RCU updater strategy with mutex locks
@@ -1375,7 +1648,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator);
 * that this function is *NOT* called under RCU protection or in contexts where
 * mutex cannot be locked.
 */
void dev_pm_opp_put_regulator(struct device *dev)
void dev_pm_opp_register_put_opp_helper(struct device *dev)
{
	struct opp_table *opp_table;

@@ -1389,16 +1662,16 @@ void dev_pm_opp_put_regulator(struct device *dev)
		goto unlock;
	}

	if (IS_ERR(opp_table->regulator)) {
		dev_err(dev, "%s: Doesn't have regulator set\n", __func__);
	if (!opp_table->set_opp) {
		dev_err(dev, "%s: Doesn't have custom set_opp helper set\n",
			__func__);
		goto unlock;
	}

	/* Make sure there are no concurrent readers while updating opp_table */
	WARN_ON(!list_empty(&opp_table->opp_list));

	regulator_put(opp_table->regulator);
	opp_table->regulator = ERR_PTR(-ENXIO);
	opp_table->set_opp = NULL;

	/* Try freeing opp_table if this was the last blocking resource */
	_remove_opp_table(opp_table);
@@ -1406,7 +1679,7 @@ void dev_pm_opp_put_regulator(struct device *dev)
unlock:
	mutex_unlock(&opp_table_lock);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulator);
EXPORT_SYMBOL_GPL(dev_pm_opp_register_put_opp_helper);

/**
 * dev_pm_opp_add()  - Add an OPP table from a table definitions
+42 −10
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/limits.h>
#include <linux/slab.h>

#include "opp.h"

@@ -34,6 +35,46 @@ void opp_debug_remove_one(struct dev_pm_opp *opp)
	debugfs_remove_recursive(opp->dentry);
}

static bool opp_debug_create_supplies(struct dev_pm_opp *opp,
				      struct opp_table *opp_table,
				      struct dentry *pdentry)
{
	struct dentry *d;
	int i = 0;
	char *name;

	/* Always create at least supply-0 directory */
	do {
		name = kasprintf(GFP_KERNEL, "supply-%d", i);

		/* Create per-opp directory */
		d = debugfs_create_dir(name, pdentry);

		kfree(name);

		if (!d)
			return false;

		if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d,
					  &opp->supplies[i].u_volt))
			return false;

		if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d,
					  &opp->supplies[i].u_volt_min))
			return false;

		if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d,
					  &opp->supplies[i].u_volt_max))
			return false;

		if (!debugfs_create_ulong("u_amp", S_IRUGO, d,
					  &opp->supplies[i].u_amp))
			return false;
	} while (++i < opp_table->regulator_count);

	return true;
}

int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
{
	struct dentry *pdentry = opp_table->dentry;
@@ -63,16 +104,7 @@ int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
	if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate))
		return -ENOMEM;

	if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d, &opp->u_volt))
		return -ENOMEM;

	if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d, &opp->u_volt_min))
		return -ENOMEM;

	if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d, &opp->u_volt_max))
		return -ENOMEM;

	if (!debugfs_create_ulong("u_amp", S_IRUGO, d, &opp->u_amp))
	if (!opp_debug_create_supplies(opp, opp_table, d))
		return -ENOMEM;

	if (!debugfs_create_ulong("clock_latency_ns", S_IRUGO, d,
Loading