summaryrefslogtreecommitdiff
path: root/drivers/base/power
diff options
context:
space:
mode:
authorViresh Kumar <viresh.kumar@linaro.org>2017-06-21 07:59:13 +0300
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-06-24 02:41:55 +0300
commit829a4e8c0e9aab17bcfe2ddb070388b8ada26292 (patch)
treed81f8ee5aee499c3dac6115557bc740f9f98ec66 /drivers/base/power
parentb21569cf1de925e0a42c9964bd7f520cb4a4d875 (diff)
downloadlinux-829a4e8c0e9aab17bcfe2ddb070388b8ada26292.tar.xz
PM / OPP: Add dev_pm_opp_{set|put}_clkname()
In order to support OPP switching, OPP layer needs to get pointer to the clock for the device. Simple cases work fine without using the routines added by this patch (i.e. by passing connection-id as NULL), but for a device with multiple clocks available, the OPP core needs to know the exact name of the clk to use. Add a new set of APIs to get that done. Tested-by: Rajendra Nayak <rnayak@codeaurora.org> Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> Reviewed-by: Stephen Boyd <sboyd@codeaurora.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/base/power')
-rw-r--r--drivers/base/power/opp/core.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index 5ee7aadf0abf..a8cc14fd8ae4 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -1363,6 +1363,73 @@ void dev_pm_opp_put_regulators(struct opp_table *opp_table)
EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators);
/**
+ * dev_pm_opp_set_clkname() - Set clk name for the device
+ * @dev: Device for which clk name is being set.
+ * @name: Clk name.
+ *
+ * In order to support OPP switching, OPP layer needs to get pointer to the
+ * clock for the device. Simple cases work fine without using this routine (i.e.
+ * by passing connection-id as NULL), but for a device with multiple clocks
+ * available, the OPP core needs to know the exact name of the clk to use.
+ *
+ * This must be called before any OPPs are initialized for the device.
+ */
+struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name)
+{
+ struct opp_table *opp_table;
+ int ret;
+
+ opp_table = dev_pm_opp_get_opp_table(dev);
+ if (!opp_table)
+ return ERR_PTR(-ENOMEM);
+
+ /* This should be called before OPPs are initialized */
+ if (WARN_ON(!list_empty(&opp_table->opp_list))) {
+ ret = -EBUSY;
+ goto err;
+ }
+
+ /* Already have default clk set, free it */
+ if (!IS_ERR(opp_table->clk))
+ clk_put(opp_table->clk);
+
+ /* Find clk for the device */
+ opp_table->clk = clk_get(dev, name);
+ if (IS_ERR(opp_table->clk)) {
+ ret = PTR_ERR(opp_table->clk);
+ if (ret != -EPROBE_DEFER) {
+ dev_err(dev, "%s: Couldn't find clock: %d\n", __func__,
+ ret);
+ }
+ goto err;
+ }
+
+ return opp_table;
+
+err:
+ dev_pm_opp_put_opp_table(opp_table);
+
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_set_clkname);
+
+/**
+ * dev_pm_opp_put_clkname() - Releases resources blocked for clk.
+ * @opp_table: OPP table returned from dev_pm_opp_set_clkname().
+ */
+void dev_pm_opp_put_clkname(struct opp_table *opp_table)
+{
+ /* Make sure there are no concurrent readers while updating opp_table */
+ WARN_ON(!list_empty(&opp_table->opp_list));
+
+ clk_put(opp_table->clk);
+ opp_table->clk = ERR_PTR(-EINVAL);
+
+ dev_pm_opp_put_opp_table(opp_table);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_put_clkname);
+
+/**
* 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.