Hi, On 10/20/2016 03:44 AM, Viresh Kumar wrote:
This patch adds infrastructure to manage multiple regulators and updates the only user (cpufreq-dt) of dev_pm_opp_set{put}_regulator().
This is preparatory work for adding full support for devices with multiple regulators.
Signed-off-by: Viresh Kumar viresh.kumar@linaro.org
drivers/base/power/opp/core.c | 220 ++++++++++++++++++++++++++------------- drivers/base/power/opp/debugfs.c | 48 +++++++-- drivers/base/power/opp/of.c | 102 +++++++++++++----- drivers/base/power/opp/opp.h | 10 +- drivers/cpufreq/cpufreq-dt.c | 9 +- include/linux/pm_opp.h | 8 +- 6 files changed, 276 insertions(+), 121 deletions(-)
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index 37fad2eb0f47..45c70ce07864 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c @@ -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->supply.u_volt;
v = tmp_opp->supplies[0].u_volt;
return v;
} @@ -222,10 +224,10 @@ 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;
unsigned long *min_uV, *max_uV;
int ret, size, i, count;
rcu_read_lock();
@@ -235,21 +237,44 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev) return 0; }
- reg = opp_table->regulator;
- if (IS_ERR(reg)) {
- count = opp_table->regulator_count;
- if (!count) { /* Regulator may not be required for device */ rcu_read_unlock(); return 0; }
- list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
if (!opp->available)
continue;
- size = count * sizeof(*regulators);
- regulators = kmemdup(opp_table->regulators, size, GFP_KERNEL);
- if (!regulators) {
rcu_read_unlock();
return 0;
- }
- min_uV = kmalloc(count * (sizeof(*min_uV) + sizeof(*max_uV)),
GFP_KERNEL);
- if (!min_uV) {
kfree(regulators);
rcu_read_unlock();
return 0;
- }
- max_uV = min_uV + count;
- for (i = 0; i < count; i++) {
min_uV[i] = ~0;
max_uV[i] = 0;
list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
if (!opp->available)
continue;
if (opp->supply.u_volt_min < min_uV)
min_uV = opp->supply.u_volt_min;
if (opp->supply.u_volt_max > max_uV)
max_uV = opp->supply.u_volt_max;
if (opp->supplies[i].u_volt_min < min_uV[i])
min_uV[i] = opp->supplies[i].u_volt_min;
if (opp->supplies[i].u_volt_max > max_uV[i])
max_uV[i] = opp->supplies[i].u_volt_max;
}
}
rcu_read_unlock();
@@ -258,9 +283,14 @@ 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);
- if (ret > 0)
latency_ns = ret * 1000;
for (i = 0; reg = regulators[i], i < count; i++) {
ret = regulator_set_voltage_time(reg, min_uV[i], max_uV[i]);
if (ret > 0)
latency_ns += ret * 1000;
}
kfree(min_uV);
kfree(regulators);
return latency_ns;
} @@ -580,7 +610,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) { struct opp_table *opp_table; struct dev_pm_opp *old_opp, *opp;
- struct regulator *reg;
- struct regulator *reg = ERR_PTR(-ENXIO); struct clk *clk; unsigned long freq, old_freq; struct dev_pm_opp_supply old_supply, new_supply;
@@ -633,14 +663,23 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) return ret; }
- if (opp_table->regulators) {
/* This function only supports single regulator per device */
if (WARN_ON(opp_table->regulator_count > 1)) {
dev_err(dev, "multiple regulators not supported\n");
rcu_read_unlock();
return -EINVAL;
}
reg = opp_table->regulators[0];
- }
- if (IS_ERR(old_opp)) old_supply.u_volt = 0; else
memcpy(&old_supply, &old_opp->supply, sizeof(old_supply));
memcpy(&old_supply, old_opp->supplies, sizeof(old_supply));
- memcpy(&new_supply, &opp->supply, sizeof(new_supply));
- reg = opp_table->regulator;
memcpy(&new_supply, opp->supplies, sizeof(new_supply));
rcu_read_unlock();
@@ -764,9 +803,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 +851,7 @@ 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;
/* Release clk */
@@ -924,35 +960,49 @@ 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; }
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;
- if (!IS_ERR(reg) &&
!regulator_is_supported_voltage(reg, opp->supply.u_volt_min,
opp->supply.u_volt_max)) {
pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported by regulator\n",
__func__, opp->supply.u_volt_min,
opp->supply.u_volt_max);
return false;
struct regulator *reg;
int i;
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->supplies[i].u_volt_min,
opp->supplies[i].u_volt_max);
return false;
}
}
return true;
@@ -984,12 +1034,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->supply.u_volt,
opp->available, new_opp->rate, new_opp->supply.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);
/* Should we compare voltages for all regulators here ? */
return opp->available &&
new_opp->supply.u_volt == opp->supply.u_volt ? 0 : -EEXIST;
new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? 0 : -EEXIST;
}
new_opp->opp_table = opp_table;
@@ -1056,9 +1107,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->supply.u_volt = u_volt;
- new_opp->supply.u_volt_min = u_volt - tol;
- new_opp->supply.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;
@@ -1303,12 +1354,14 @@ void dev_pm_opp_put_prop_name(struct device *dev) EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
/**
- 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.
@@ -1318,11 +1371,12 @@ 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) +int dev_pm_opp_set_regulators(struct device *dev, const char *names[],
unsigned int count)
{ struct opp_table *opp_table; struct regulator *reg;
- int ret;
int ret, i;
mutex_lock(&opp_table_lock);
@@ -1338,26 +1392,43 @@ 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 (WARN_ON(opp_table->regulators)) { ret = -EBUSY; goto err; }
- /* Allocate the regulator */
- reg = regulator_get_optional(dev, name);
- 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);
- opp_table->regulators = kmalloc_array(count,
sizeof(*opp_table->regulators),
GFP_KERNEL);
- if (!opp_table->regulators) goto err;
- for (i = 0; i < count; i++) {
reg = regulator_get_optional(dev, names[i]);
pr_info("%s: %d: %p: %s\n", __func__, __LINE__, reg, names[i]);
Think this is leftover debug msg?
if (IS_ERR(reg)) {
ret = PTR_ERR(reg);
if (ret != -EPROBE_DEFER)
dev_err(dev, "%s: regulator (%s) not found: %d\n",
__func__, names[i], ret);
goto free_regulators;
}
}opp_table->regulators[i] = reg;
- opp_table->regulator = reg;
opp_table->regulator_count = count;
mutex_unlock(&opp_table_lock); return 0;
+free_regulators:
- while (i != 0)
regulator_put(opp_table->regulators[--i]);
- kfree(opp_table->regulators);
- opp_table->regulators = NULL;
err: _remove_opp_table(opp_table); unlock: @@ -1365,11 +1436,11 @@ 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_set_regulators);
/**
- dev_pm_opp_put_regulator() - Releases resources blocked for regulator
- @dev: Device for which regulator was set.
- dev_pm_opp_put_regulators() - Releases resources blocked for regulators
- @dev: Device for which regulators were set.
- Locking: The internal opp_table and opp structures are RCU protected.
- Hence this function internally uses RCU updater strategy with mutex locks
@@ -1377,9 +1448,10 @@ 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_put_regulators(struct device *dev) { struct opp_table *opp_table;
int i;
mutex_lock(&opp_table_lock);
@@ -1391,16 +1463,20 @@ 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->regulators) {
dev_err(dev, "%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));
- regulator_put(opp_table->regulator);
- opp_table->regulator = ERR_PTR(-ENXIO);
for (i = opp_table->regulator_count - 1; i >= 0; i--)
regulator_put(opp_table->regulators[i]);
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);
@@ -1408,7 +1484,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_put_regulators);
/**
- dev_pm_opp_add() - Add an OPP table from a table definitions
diff --git a/drivers/base/power/opp/debugfs.c b/drivers/base/power/opp/debugfs.c index c897676ca35f..cb5e5fde3d39 100644 --- a/drivers/base/power/opp/debugfs.c +++ b/drivers/base/power/opp/debugfs.c @@ -34,6 +34,43 @@ 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[] = "supply-X"; /* support only 0-9 supplies */
- /* Always create at least supply-0 directory */
- do {
name[7] = i + '0';
/* Create per-opp directory */
d = debugfs_create_dir(name, pdentry);
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 +100,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->supply.u_volt))
return -ENOMEM;
- if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d, &opp->supply.u_volt_min))
return -ENOMEM;
- if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d, &opp->supply.u_volt_max))
return -ENOMEM;
- if (!debugfs_create_ulong("u_amp", S_IRUGO, d, &opp->supply.u_amp))
if (!opp_debug_create_supplies(opp, opp_table, d)) return -ENOMEM;
if (!debugfs_create_ulong("clock_latency_ns", S_IRUGO, d,
diff --git a/drivers/base/power/opp/of.c b/drivers/base/power/opp/of.c index b7fcd0a1b58b..c857fb07a5bc 100644 --- a/drivers/base/power/opp/of.c +++ b/drivers/base/power/opp/of.c @@ -17,6 +17,7 @@ #include <linux/errno.h> #include <linux/device.h> #include <linux/of.h> +#include <linux/slab.h> #include <linux/export.h>
#include "opp.h" @@ -105,12 +106,13 @@ static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
Though not in the patch there's a comment to
/* TODO: Support multiple regulators */
in the file right above the below opp_parse_supplies function that can probably be removed as part of this patch.
Otherwise this patch looks good to me.
Regards, Dave
static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev, struct opp_table *opp_table) {
- u32 microvolt[3] = {0};
- u32 val;
- int count, ret;
u32 *microvolt, *microamp = NULL;
int supplies, vcount, icount, ret, i, j; struct property *prop = NULL; char name[NAME_MAX];
supplies = opp_table->regulator_count ? opp_table->regulator_count : 1;
/* Search for "opp-microvolt-<name>" */ if (opp_table->prop_name) { snprintf(name, sizeof(name), "opp-microvolt-%s",
@@ -128,34 +130,29 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev, return 0; }
- count = of_property_count_u32_elems(opp->np, name);
- if (count < 0) {
- vcount = of_property_count_u32_elems(opp->np, name);
- if (vcount < 0) { dev_err(dev, "%s: Invalid %s property (%d)\n",
__func__, name, count);
return count;
__func__, name, vcount);
}return vcount;
- /* There can be one or three elements here */
- if (count != 1 && count != 3) {
dev_err(dev, "%s: Invalid number of elements in %s property (%d)\n",
__func__, name, count);
- /* There can be one or three elements per supply */
- if (vcount != supplies && vcount != supplies * 3) {
dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
return -EINVAL; }__func__, name, vcount, supplies);
- ret = of_property_read_u32_array(opp->np, name, microvolt, count);
- microvolt = kmalloc_array(vcount, sizeof(*microvolt), GFP_KERNEL);
- if (!microvolt)
return -ENOMEM;
- ret = of_property_read_u32_array(opp->np, name, microvolt, vcount); if (ret) { dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
return -EINVAL;
- }
- opp->supply.u_volt = microvolt[0];
- if (count == 1) {
opp->supply.u_volt_min = opp->supply.u_volt;
opp->supply.u_volt_max = opp->supply.u_volt;
- } else {
opp->supply.u_volt_min = microvolt[1];
opp->supply.u_volt_max = microvolt[2];
ret = -EINVAL;
goto free_microvolt;
}
/* Search for "opp-microamp-<name>" */
@@ -172,10 +169,59 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev, prop = of_find_property(opp->np, name, NULL); }
- if (prop && !of_property_read_u32(opp->np, name, &val))
opp->supply.u_amp = val;
- if (prop) {
icount = of_property_count_u32_elems(opp->np, name);
if (icount < 0) {
dev_err(dev, "%s: Invalid %s property (%d)\n", __func__,
name, icount);
ret = icount;
goto free_microvolt;
}
- return 0;
if (icount != supplies) {
dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
__func__, name, icount, supplies);
ret = -EINVAL;
goto free_microvolt;
}
microamp = kmalloc_array(icount, sizeof(*microamp), GFP_KERNEL);
if (!microamp) {
ret = -EINVAL;
goto free_microvolt;
}
ret = of_property_read_u32_array(opp->np, name, microamp,
icount);
if (ret) {
dev_err(dev, "%s: error parsing %s: %d\n", __func__,
name, ret);
ret = -EINVAL;
goto free_microamp;
}
- }
- for (i = 0, j = 0; i < supplies; i++) {
opp->supplies[i].u_volt = microvolt[j++];
if (vcount == supplies) {
opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
} else {
opp->supplies[i].u_volt_min = microvolt[j++];
opp->supplies[i].u_volt_max = microvolt[j++];
}
if (microamp)
opp->supplies[i].u_amp = microamp[i];
- }
+free_microamp:
- kfree(microamp);
+free_microvolt:
- kfree(microvolt);
- return ret;
}
/** @@ -304,8 +350,8 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu\n", __func__, new_opp->turbo, new_opp->rate,
new_opp->supply.u_volt, new_opp->supply.u_volt_min,
new_opp->supply.u_volt_max, new_opp->clock_latency_ns);
new_opp->supplies[0].u_volt, new_opp->supplies[0].u_volt_min,
new_opp->supplies[0].u_volt_max, new_opp->clock_latency_ns);
/*
- Notify the changes in the availability of the operable
diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h index 1bda0d35c486..d3f0861f9bff 100644 --- a/drivers/base/power/opp/opp.h +++ b/drivers/base/power/opp/opp.h @@ -77,7 +77,7 @@ struct dev_pm_opp_supply {
- @turbo: true if turbo (boost) OPP
- @suspend: true if suspend OPP
- @rate: Frequency in hertz
- @supply: Power supply voltage/current values
- @supplies: Power supplies voltage/current values
- @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
frequency from any other OPP's frequency.
- @opp_table: points back to the opp_table struct this opp belongs to
@@ -96,7 +96,7 @@ struct dev_pm_opp { bool suspend; unsigned long rate;
- struct dev_pm_opp_supply supply;
struct dev_pm_opp_supply *supplies;
unsigned long clock_latency_ns;
@@ -155,7 +155,8 @@ enum opp_table_access {
- @supported_hw_count: Number of elements in supported_hw array.
- @prop_name: A name to postfix to many DT properties, while parsing them.
- @clk: Device's clock handle
- @regulator: Supply regulator
- @regulators: Supply regulators
- @regulator_count: Number of Power Supply regulators
- @dentry: debugfs dentry pointer of the real device directory (not links).
- @dentry_name: Name of the real dentry.
@@ -190,7 +191,8 @@ struct opp_table { unsigned int supported_hw_count; const char *prop_name; struct clk *clk;
- struct regulator *regulator;
- struct regulator **regulators;
- unsigned int regulator_count;
#ifdef CONFIG_DEBUG_FS struct dentry *dentry; diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 5c07ae05d69a..15cb26118dc7 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -186,7 +186,10 @@ static int cpufreq_init(struct cpufreq_policy *policy) */ name = find_supply_name(cpu_dev); if (name) {
ret = dev_pm_opp_set_regulator(cpu_dev, name);
const char *names[] = {name};
ret = dev_pm_opp_set_regulators(cpu_dev, names,
if (ret) { dev_err(cpu_dev, "Failed to set regulator for cpu%d: %d\n", policy->cpu, ret);ARRAY_SIZE(names));
@@ -285,7 +288,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) out_free_opp: dev_pm_opp_of_cpumask_remove_table(policy->cpus); if (name)
dev_pm_opp_put_regulator(cpu_dev);
dev_pm_opp_put_regulators(cpu_dev);
out_put_clk: clk_put(cpu_clk);
@@ -300,7 +303,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy) dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); dev_pm_opp_of_cpumask_remove_table(policy->related_cpus); if (priv->reg_name)
dev_pm_opp_put_regulator(priv->cpu_dev);
dev_pm_opp_put_regulators(priv->cpu_dev);
clk_put(policy->clk); kfree(priv);
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index bca26157f5b6..0606b70a8b97 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -62,8 +62,8 @@ int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, void dev_pm_opp_put_supported_hw(struct device *dev); int dev_pm_opp_set_prop_name(struct device *dev, const char *name); void dev_pm_opp_put_prop_name(struct device *dev); -int dev_pm_opp_set_regulator(struct device *dev, const char *name); -void dev_pm_opp_put_regulator(struct device *dev); +int dev_pm_opp_set_regulators(struct device *dev, const char *names[], unsigned int count); +void dev_pm_opp_put_regulators(struct device *dev); int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq); int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask); int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask); @@ -170,12 +170,12 @@ static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
static inline void dev_pm_opp_put_prop_name(struct device *dev) {}
-static inline int dev_pm_opp_set_regulator(struct device *dev, const char *name) +static inline int dev_pm_opp_set_regulators(struct device *dev, const char *names[], unsigned int count) { return -ENOTSUPP; }
-static inline void dev_pm_opp_put_regulator(struct device *dev) {} +static inline void dev_pm_opp_put_regulators(struct device *dev) {}
static inline int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) {