Add dev_pm_opp_from_clk_rate() helper that returns OPP corresponding to the current clock rate of a device. Signed-off-by: Dmitry Osipenko <digetx@xxxxxxxxx> --- drivers/opp/core.c | 42 +++++++++++++++++++++++++++++++++++++++--- include/linux/pm_opp.h | 6 ++++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 04b4691a8aac..fae5267f5218 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -939,7 +939,8 @@ static int _set_required_opps(struct device *dev, return ret; } -static void _find_current_opp(struct device *dev, struct opp_table *opp_table) +static struct dev_pm_opp * +_find_current_opp(struct device *dev, struct opp_table *opp_table) { struct dev_pm_opp *opp = ERR_PTR(-ENODEV); unsigned long freq; @@ -961,7 +962,7 @@ static void _find_current_opp(struct device *dev, struct opp_table *opp_table) mutex_unlock(&opp_table->lock); } - opp_table->current_opp = opp; + return opp; } static int _disable_opp_table(struct device *dev, struct opp_table *opp_table) @@ -1003,7 +1004,7 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table, /* Find the currently set OPP if we don't know already */ if (unlikely(!opp_table->current_opp)) - _find_current_opp(dev, opp_table); + opp_table->current_opp = _find_current_opp(dev, opp_table); old_opp = opp_table->current_opp; @@ -2931,3 +2932,38 @@ int dev_pm_opp_sync_regulators(struct device *dev) return ret; } EXPORT_SYMBOL_GPL(dev_pm_opp_sync_regulators); + +/** + * dev_pm_opp_from_clk_rate() - Get OPP from current clock rate + * @dev: device for which we do this operation + * + * Get OPP which corresponds to the current clock rate of a device. + * + * Return: pointer to 'struct dev_pm_opp' on success and errorno otherwise. + */ +struct dev_pm_opp *dev_pm_opp_from_clk_rate(struct device *dev) +{ + struct dev_pm_opp *opp = ERR_PTR(-ENOENT); + struct opp_table *opp_table; + unsigned long freq; + + opp_table = _find_opp_table(dev); + if (IS_ERR(opp_table)) + return ERR_CAST(opp_table); + + if (IS_ERR(opp_table->clk)) { + opp = ERR_CAST(opp_table->clk); + goto put_table; + } + + if (opp_table->clk) { + freq = clk_get_rate(opp_table->clk); + opp = _find_freq_ceil(opp_table, &freq); + } +put_table: + /* Drop reference taken by _find_opp_table() */ + dev_pm_opp_put_opp_table(opp_table); + + return opp; +} +EXPORT_SYMBOL_GPL(dev_pm_opp_from_clk_rate); diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 84150a22fd7c..57e75144dd88 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -168,6 +168,7 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) void dev_pm_opp_remove_table(struct device *dev); void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask); int dev_pm_opp_sync_regulators(struct device *dev); +struct dev_pm_opp *dev_pm_opp_from_clk_rate(struct device *dev); #else static inline struct opp_table *dev_pm_opp_get_opp_table(struct device *dev) { @@ -434,6 +435,11 @@ static inline int dev_pm_opp_sync_regulators(struct device *dev) return -EOPNOTSUPP; } +static struct inline dev_pm_opp *dev_pm_opp_from_clk_rate(struct device *dev) +{ + return ERR_PTR(-EOPNOTSUPP); +} + #endif /* CONFIG_PM_OPP */ #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF) -- 2.32.0