diff options
-rw-r--r-- | drivers/opp/core.c | 28 | ||||
-rw-r--r-- | drivers/opp/opp.h | 2 |
2 files changed, 28 insertions, 2 deletions
diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 5e1035a041ae..8efe12a90ce8 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -664,7 +664,7 @@ static inline int _generic_set_opp_clk_only(struct device *dev, struct clk *clk, return ret; } -static int _generic_set_opp_regulator(const struct opp_table *opp_table, +static int _generic_set_opp_regulator(struct opp_table *opp_table, struct device *dev, unsigned long old_freq, unsigned long freq, @@ -699,6 +699,18 @@ static int _generic_set_opp_regulator(const struct opp_table *opp_table, goto restore_freq; } + /* + * Enable the regulator after setting its voltages, otherwise it breaks + * some boot-enabled regulators. + */ + if (unlikely(!opp_table->regulator_enabled)) { + ret = regulator_enable(reg); + if (ret < 0) + dev_warn(dev, "Failed to enable regulator: %d", ret); + else + opp_table->regulator_enabled = true; + } + return 0; restore_freq: @@ -825,12 +837,17 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) if (!_get_opp_count(opp_table)) return 0; - if (!opp_table->required_opp_tables) { + if (!opp_table->required_opp_tables && !opp_table->regulators) { dev_err(dev, "target frequency can't be 0\n"); ret = -EINVAL; goto put_opp_table; } + if (opp_table->regulator_enabled) { + regulator_disable(opp_table->regulators[0]); + opp_table->regulator_enabled = false; + } + ret = _set_required_opps(dev, opp_table, NULL); goto put_opp_table; } @@ -1718,6 +1735,13 @@ void dev_pm_opp_put_regulators(struct opp_table *opp_table) /* Make sure there are no concurrent readers while updating opp_table */ WARN_ON(!list_empty(&opp_table->opp_list)); + if (opp_table->regulator_enabled) { + for (i = opp_table->regulator_count - 1; i >= 0; i--) + regulator_disable(opp_table->regulators[i]); + + opp_table->regulator_enabled = false; + } + for (i = opp_table->regulator_count - 1; i >= 0; i--) regulator_put(opp_table->regulators[i]); diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h index 2b81ffef1ba4..e51646ff279e 100644 --- a/drivers/opp/opp.h +++ b/drivers/opp/opp.h @@ -147,6 +147,7 @@ enum opp_table_access { * @clk: Device's clock handle * @regulators: Supply regulators * @regulator_count: Number of power supply regulators. Its value can be -1 + * @regulator_enabled: Set to true if regulators were previously enabled. * (uninitialized), 0 (no opp-microvolt property) or > 0 (has opp-microvolt * property). * @paths: Interconnect path handles @@ -194,6 +195,7 @@ struct opp_table { struct clk *clk; struct regulator **regulators; int regulator_count; + bool regulator_enabled; struct icc_path **paths; unsigned int path_count; bool genpd_performance_state; |