Add dev_pm_opp_get_current() helper that returns OPP corresponding to the current clock rate of a device. Signed-off-by: Dmitry Osipenko <digetx@xxxxxxxxx> --- drivers/opp/core.c | 43 +++++++++++++++++++++++++++++++++++++++--- include/linux/pm_opp.h | 6 ++++++ 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 04b4691a8aac..dde8a5cc948c 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -939,7 +939,7 @@ 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 opp_table *opp_table) { struct dev_pm_opp *opp = ERR_PTR(-ENODEV); unsigned long freq; @@ -949,6 +949,18 @@ static void _find_current_opp(struct device *dev, struct opp_table *opp_table) opp = _find_freq_ceil(opp_table, &freq); } + return opp; +} + +static void _find_and_set_current_opp(struct opp_table *opp_table) +{ + struct dev_pm_opp *opp; + + if (opp_table->current_opp) + return; + + opp = _find_current_opp(opp_table); + /* * Unable to find the current OPP ? Pick the first from the list since * it is in ascending order, otherwise rest of the code will need to @@ -1002,8 +1014,7 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table, return _disable_opp_table(dev, 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); + _find_and_set_current_opp(opp_table); old_opp = opp_table->current_opp; @@ -2931,3 +2942,29 @@ int dev_pm_opp_sync_regulators(struct device *dev) return ret; } EXPORT_SYMBOL_GPL(dev_pm_opp_sync_regulators); + +/** + * dev_pm_opp_get_current() - Get current OPP + * @dev: device for which we do this operation + * + * Get current OPP of a device based on current clock rate or by other means. + * + * Return: pointer to 'struct dev_pm_opp' on success and errorno otherwise. + */ +struct dev_pm_opp *dev_pm_opp_get_current(struct device *dev) +{ + struct opp_table *opp_table; + struct dev_pm_opp *opp; + + opp_table = _find_opp_table(dev); + if (IS_ERR(opp_table)) + return ERR_CAST(opp_table); + + opp = _find_current_opp(opp_table); + + /* Drop reference taken by _find_opp_table() */ + dev_pm_opp_put_opp_table(opp_table); + + return opp; +} +EXPORT_SYMBOL_GPL(dev_pm_opp_get_current); diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 84150a22fd7c..c8091977efb8 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_get_current(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 inline struct dev_pm_opp *dev_pm_opp_get_current(struct device *dev) +{ + return ERR_PTR(-EOPNOTSUPP); +} + #endif /* CONFIG_PM_OPP */ #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF) -- 2.32.0