mirror of
https://github.com/torvalds/linux.git
synced 2026-07-31 19:47:08 +02:00
clk: qcom: Add support for voting to multiple clk_vdd_class
Some clocks have requirement to vote on multiple clk_vdd_class for clock operations. So add the support to pass multiple vdd_class within the clock structure to support this functionality. A new clk_vdd_classes list is added in clk_vdd_class_data structure to pass clk_vdd_class as an array to support voting on multiple rail. Change-Id: I11732a39ef99fdbcb7874e1042776e7007bed35f Signed-off-by: Naveen Yadav <naveenky@codeaurora.org> Signed-off-by: Mike Tipton <mdtipton@codeaurora.org>
This commit is contained in:
parent
9bb68c3604
commit
9c9f3ff339
|
|
@ -108,7 +108,7 @@ int clk_pre_change_regmap(struct clk_hw *hw, unsigned long cur_rate,
|
|||
int new_vdd_level;
|
||||
int ret = 0;
|
||||
|
||||
if (!rclk->vdd_data.vdd_class)
|
||||
if (!rclk->vdd_data.rate_max)
|
||||
return 0;
|
||||
|
||||
new_vdd_level = clk_find_vdd_level(hw, &rclk->vdd_data, new_rate);
|
||||
|
|
@ -153,7 +153,7 @@ int clk_post_change_regmap(struct clk_hw *hw, unsigned long old_rate,
|
|||
int cur_vdd_level;
|
||||
int ret = 0;
|
||||
|
||||
if (!rclk->vdd_data.vdd_class)
|
||||
if (!rclk->vdd_data.rate_max)
|
||||
return 0;
|
||||
|
||||
cur_vdd_level = clk_find_vdd_level(hw, &rclk->vdd_data, cur_rate);
|
||||
|
|
@ -196,7 +196,7 @@ int clk_prepare_regmap(struct clk_hw *hw)
|
|||
int rate = clk_hw_get_rate(hw);
|
||||
int vdd_level;
|
||||
|
||||
if (!rclk->vdd_data.vdd_class)
|
||||
if (!rclk->vdd_data.rate_max)
|
||||
return 0;
|
||||
|
||||
vdd_level = clk_find_vdd_level(hw, &rclk->vdd_data, rate);
|
||||
|
|
@ -226,7 +226,7 @@ void clk_unprepare_regmap(struct clk_hw *hw)
|
|||
{
|
||||
struct clk_regmap *rclk = to_clk_regmap(hw);
|
||||
|
||||
if (!rclk->vdd_data.vdd_class)
|
||||
if (!rclk->vdd_data.rate_max)
|
||||
return;
|
||||
|
||||
clk_unvote_vdd_level(&rclk->vdd_data, rclk->vdd_data.vdd_level);
|
||||
|
|
|
|||
|
|
@ -68,22 +68,9 @@ static int clk_aggregate_vdd(struct clk_vdd_class *vdd_class)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_vote_vdd_level - Add a vote for a given voltage level
|
||||
* @vdd_data: vdd_class data for the clock
|
||||
* @level: voltage level to add a vote for
|
||||
*
|
||||
* Add a regulator framework voltage request for the vdd_class regulator(s)
|
||||
* by decrementing the reference count for a given voltage level. This ensures
|
||||
* that the supply regulator is allowed to potentially lower its voltage after
|
||||
* re-aggregating overall voltage requests.
|
||||
*
|
||||
* Returns 0 on success, -EERROR otherwise.
|
||||
*/
|
||||
int clk_vote_vdd_level(struct clk_vdd_class_data *vdd_data, int level)
|
||||
static int clk_vote_vdd_class_level(struct clk_vdd_class *vdd_class, int level)
|
||||
{
|
||||
struct clk_vdd_class *vdd_class = vdd_data->vdd_class;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
if (level >= vdd_class->num_levels)
|
||||
return -EINVAL;
|
||||
|
|
@ -99,6 +86,69 @@ int clk_vote_vdd_level(struct clk_vdd_class_data *vdd_data, int level)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int clk_unvote_vdd_class_level(struct clk_vdd_class *vdd_class, int level)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (level >= vdd_class->num_levels)
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN(!vdd_class->level_votes[level],
|
||||
"Reference counts are incorrect for %s level %d\n",
|
||||
vdd_class->class_name, level)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&vdd_lock);
|
||||
vdd_class->level_votes[level]--;
|
||||
|
||||
ret = clk_aggregate_vdd(vdd_class);
|
||||
if (ret)
|
||||
vdd_class->level_votes[level]++;
|
||||
|
||||
mutex_unlock(&vdd_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* clk_vote_vdd_level - Add a vote for a given voltage level
|
||||
* @vdd_data: vdd_class data for the clock
|
||||
* @level: voltage level to add a vote for
|
||||
*
|
||||
* Add a regulator framework voltage request for the vdd_class regulator(s)
|
||||
* by decrementing the reference count for a given voltage level. This ensures
|
||||
* that the supply regulator is allowed to potentially lower its voltage after
|
||||
* re-aggregating overall voltage requests.
|
||||
*
|
||||
* Returns 0 on success, -EERROR otherwise.
|
||||
*/
|
||||
int clk_vote_vdd_level(struct clk_vdd_class_data *vdd_data, int level)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
for (i = 0; i < vdd_data->num_vdd_classes; i++) {
|
||||
ret = clk_vote_vdd_class_level(vdd_data->vdd_classes[i], level);
|
||||
if (ret)
|
||||
goto vote_fail;
|
||||
}
|
||||
|
||||
if (vdd_data->vdd_class) {
|
||||
ret = clk_vote_vdd_class_level(vdd_data->vdd_class, level);
|
||||
if (ret)
|
||||
goto vote_fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
vote_fail:
|
||||
for (i--; i >= 0; i--)
|
||||
clk_unvote_vdd_class_level(vdd_data->vdd_classes[i], level);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(clk_vote_vdd_level);
|
||||
|
||||
/**
|
||||
|
|
@ -114,26 +164,25 @@ EXPORT_SYMBOL(clk_vote_vdd_level);
|
|||
*/
|
||||
int clk_unvote_vdd_level(struct clk_vdd_class_data *vdd_data, int level)
|
||||
{
|
||||
struct clk_vdd_class *vdd_class = vdd_data->vdd_class;
|
||||
int ret = 0;
|
||||
int ret, i;
|
||||
|
||||
if (level >= vdd_class->num_levels)
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN(!vdd_class->level_votes[level],
|
||||
"Reference counts are incorrect for %s level %d\n",
|
||||
vdd_class->class_name, level)) {
|
||||
return -EINVAL;
|
||||
for (i = 0; i < vdd_data->num_vdd_classes; i++) {
|
||||
ret = clk_unvote_vdd_class_level(vdd_data->vdd_classes[i], level);
|
||||
if (ret)
|
||||
goto unvote_fail;
|
||||
}
|
||||
|
||||
mutex_lock(&vdd_lock);
|
||||
vdd_class->level_votes[level]--;
|
||||
if (vdd_data->vdd_class) {
|
||||
ret = clk_unvote_vdd_class_level(vdd_data->vdd_class, level);
|
||||
if (ret)
|
||||
goto unvote_fail;
|
||||
}
|
||||
|
||||
ret = clk_aggregate_vdd(vdd_class);
|
||||
if (ret)
|
||||
vdd_class->level_votes[level]++;
|
||||
return 0;
|
||||
|
||||
mutex_unlock(&vdd_lock);
|
||||
unvote_fail:
|
||||
for (i--; i >= 0; i--)
|
||||
clk_vote_vdd_class_level(vdd_data->vdd_classes[i], level);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -213,16 +262,15 @@ int clk_regulator_init(struct device *dev, const struct qcom_cc_desc *desc)
|
|||
|
||||
int clk_vdd_proxy_vote(struct device *dev, const struct qcom_cc_desc *desc)
|
||||
{
|
||||
struct clk_vdd_class_data vdd_data;
|
||||
struct clk_vdd_class *vdd_class;
|
||||
u32 i;
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; i < desc->num_clk_regulators; i++) {
|
||||
vdd_data.vdd_class = vdd_class = desc->clk_regulators[i];
|
||||
vdd_class = desc->clk_regulators[i];
|
||||
|
||||
ret = clk_vote_vdd_level(&vdd_data,
|
||||
vdd_class->num_levels - 1);
|
||||
ret = clk_vote_vdd_class_level(vdd_class,
|
||||
vdd_class->num_levels - 1);
|
||||
if (ret)
|
||||
WARN(ret, "%s failed, ret=%d\n", __func__, ret);
|
||||
}
|
||||
|
|
@ -232,16 +280,15 @@ int clk_vdd_proxy_vote(struct device *dev, const struct qcom_cc_desc *desc)
|
|||
|
||||
int clk_vdd_proxy_unvote(struct device *dev, const struct qcom_cc_desc *desc)
|
||||
{
|
||||
struct clk_vdd_class_data vdd_data;
|
||||
struct clk_vdd_class *vdd_class;
|
||||
u32 i;
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; i < desc->num_clk_regulators; i++) {
|
||||
vdd_data.vdd_class = vdd_class = desc->clk_regulators[i];
|
||||
vdd_class = desc->clk_regulators[i];
|
||||
|
||||
ret = clk_unvote_vdd_level(&vdd_data,
|
||||
vdd_class->num_levels - 1);
|
||||
ret = clk_unvote_vdd_class_level(vdd_class,
|
||||
vdd_class->num_levels - 1);
|
||||
if (ret)
|
||||
WARN(ret, "clk_unvote_vdd_level failed ret=%d\n", ret);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,16 +35,20 @@ struct clk_vdd_class {
|
|||
* struct clk_vdd_class_data - per-clock vdd_class rate data
|
||||
*
|
||||
* @vdd_class: voltage scaling requirement class
|
||||
* @vdd_classes: array of voltage scaling requirement class
|
||||
* @rate_max: array of maximum clock rate in Hz supported at each
|
||||
* voltage level, indexed by voltage level
|
||||
* @num_rate_max: size of rate_max array
|
||||
* @vdd_rate: cached rate of current vdd vote
|
||||
* @num_vdd_classes: size of vdd_classes array
|
||||
*/
|
||||
struct clk_vdd_class_data {
|
||||
struct clk_vdd_class *vdd_class;
|
||||
struct clk_vdd_class **vdd_classes;
|
||||
unsigned long *rate_max;
|
||||
int num_rate_max;
|
||||
int vdd_level;
|
||||
int num_vdd_classes;
|
||||
};
|
||||
|
||||
#define DEFINE_VDD_REGULATORS(_name, _num_levels, _num_regulators, _vdd_uv) \
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user