clk: rework calls to round and determine rate callbacks

Rework the way the callbacks round_rate() and determine_rate() are called.
The goal is to do this at a single point and make it easier to add
conditions before calling them.

Because of this factorization, rate returned by determine_rate() is also
checked against the min and max rate values

This rework is done to ease the integration of "protected" clock
functionality.

Acked-by: Linus Walleij <linus.walleij@linaro.org>
Tested-by: Quentin Schulz <quentin.schulz@free-electrons.com>
Tested-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Acked-by: Michael Turquette <mturquette@baylibre.com>
Signed-off-by: Jerome Brunet <jbrunet@baylibre.com>
Signed-off-by: Michael Turquette <mturquette@baylibre.com>
Link: lkml.kernel.org/r/20171201215200.23523-5-jbrunet@baylibre.com
This commit is contained in:
Jerome Brunet 2017-12-01 22:51:54 +01:00 committed by Michael Turquette
parent 9e4d04adeb
commit 0f6cc2b8e9

View file

@ -905,10 +905,9 @@ static int clk_disable_unused(void)
} }
late_initcall_sync(clk_disable_unused); late_initcall_sync(clk_disable_unused);
static int clk_core_round_rate_nolock(struct clk_core *core, static int clk_core_determine_round_nolock(struct clk_core *core,
struct clk_rate_request *req) struct clk_rate_request *req)
{ {
struct clk_core *parent;
long rate; long rate;
lockdep_assert_held(&prepare_lock); lockdep_assert_held(&prepare_lock);
@ -916,15 +915,6 @@ static int clk_core_round_rate_nolock(struct clk_core *core,
if (!core) if (!core)
return 0; return 0;
parent = core->parent;
if (parent) {
req->best_parent_hw = parent->hw;
req->best_parent_rate = parent->rate;
} else {
req->best_parent_hw = NULL;
req->best_parent_rate = 0;
}
if (core->ops->determine_rate) { if (core->ops->determine_rate) {
return core->ops->determine_rate(core->hw, req); return core->ops->determine_rate(core->hw, req);
} else if (core->ops->round_rate) { } else if (core->ops->round_rate) {
@ -934,15 +924,58 @@ static int clk_core_round_rate_nolock(struct clk_core *core,
return rate; return rate;
req->rate = rate; req->rate = rate;
} else if (core->flags & CLK_SET_RATE_PARENT) {
return clk_core_round_rate_nolock(parent, req);
} else { } else {
req->rate = core->rate; return -EINVAL;
} }
return 0; return 0;
} }
static void clk_core_init_rate_req(struct clk_core * const core,
struct clk_rate_request *req)
{
struct clk_core *parent;
if (WARN_ON(!core || !req))
return;
parent = core->parent;
if (parent) {
req->best_parent_hw = parent->hw;
req->best_parent_rate = parent->rate;
} else {
req->best_parent_hw = NULL;
req->best_parent_rate = 0;
}
}
static bool clk_core_can_round(struct clk_core * const core)
{
if (core->ops->determine_rate || core->ops->round_rate)
return true;
return false;
}
static int clk_core_round_rate_nolock(struct clk_core *core,
struct clk_rate_request *req)
{
lockdep_assert_held(&prepare_lock);
if (!core)
return 0;
clk_core_init_rate_req(core, req);
if (clk_core_can_round(core))
return clk_core_determine_round_nolock(core, req);
else if (core->flags & CLK_SET_RATE_PARENT)
return clk_core_round_rate_nolock(core->parent, req);
req->rate = core->rate;
return 0;
}
/** /**
* __clk_determine_rate - get the closest rate actually supported by a clock * __clk_determine_rate - get the closest rate actually supported by a clock
* @hw: determine the rate of this clock * @hw: determine the rate of this clock
@ -1432,34 +1465,23 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core,
clk_core_get_boundaries(core, &min_rate, &max_rate); clk_core_get_boundaries(core, &min_rate, &max_rate);
/* find the closest rate and parent clk/rate */ /* find the closest rate and parent clk/rate */
if (core->ops->determine_rate) { if (clk_core_can_round(core)) {
struct clk_rate_request req; struct clk_rate_request req;
req.rate = rate; req.rate = rate;
req.min_rate = min_rate; req.min_rate = min_rate;
req.max_rate = max_rate; req.max_rate = max_rate;
if (parent) {
req.best_parent_hw = parent->hw;
req.best_parent_rate = parent->rate;
} else {
req.best_parent_hw = NULL;
req.best_parent_rate = 0;
}
ret = core->ops->determine_rate(core->hw, &req); clk_core_init_rate_req(core, &req);
ret = clk_core_determine_round_nolock(core, &req);
if (ret < 0) if (ret < 0)
return NULL; return NULL;
best_parent_rate = req.best_parent_rate; best_parent_rate = req.best_parent_rate;
new_rate = req.rate; new_rate = req.rate;
parent = req.best_parent_hw ? req.best_parent_hw->core : NULL; parent = req.best_parent_hw ? req.best_parent_hw->core : NULL;
} else if (core->ops->round_rate) {
ret = core->ops->round_rate(core->hw, rate,
&best_parent_rate);
if (ret < 0)
return NULL;
new_rate = ret;
if (new_rate < min_rate || new_rate > max_rate) if (new_rate < min_rate || new_rate > max_rate)
return NULL; return NULL;
} else if (!parent || !(core->flags & CLK_SET_RATE_PARENT)) { } else if (!parent || !(core->flags & CLK_SET_RATE_PARENT)) {