Skip to content

Commit

Permalink
PM / OPP: Add dev_pm_opp_{set|put}_clkname()
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Viresh Kumar <[email protected]>
Reviewed-by: Stephen Boyd <[email protected]>
Signed-off-by: Rafael J. Wysocki <[email protected]>
  • Loading branch information
vireshk authored and rafaeljw committed Jun 23, 2017
1 parent b21569c commit 829a4e8
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 0 deletions.
67 changes: 67 additions & 0 deletions drivers/base/power/opp/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1362,6 +1362,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.
Expand Down
9 changes: 9 additions & 0 deletions include/linux/pm_opp.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name)
void dev_pm_opp_put_prop_name(struct opp_table *opp_table);
struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
void dev_pm_opp_put_regulators(struct opp_table *opp_table);
struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char * name);
void dev_pm_opp_put_clkname(struct opp_table *opp_table);
struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
void dev_pm_opp_register_put_opp_helper(struct opp_table *opp_table);
int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq);
Expand Down Expand Up @@ -257,6 +259,13 @@ static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, co

static inline void dev_pm_opp_put_regulators(struct opp_table *opp_table) {}

static inline struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char * name)
{
return ERR_PTR(-ENOTSUPP);
}

static inline void dev_pm_opp_put_clkname(struct opp_table *opp_table) {}

static inline int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
{
return -ENOTSUPP;
Expand Down

0 comments on commit 829a4e8

Please sign in to comment.