|
@@ -436,28 +436,31 @@ static bool mux_is_better_rate(unsigned long rate, unsigned long now,
|
|
return now <= rate && now > best;
|
|
return now <= rate && now > best;
|
|
}
|
|
}
|
|
|
|
|
|
-static long
|
|
|
|
-clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
|
|
|
|
- unsigned long min_rate,
|
|
|
|
- unsigned long max_rate,
|
|
|
|
- unsigned long *best_parent_rate,
|
|
|
|
- struct clk_hw **best_parent_p,
|
|
|
|
|
|
+static int
|
|
|
|
+clk_mux_determine_rate_flags(struct clk_hw *hw, struct clk_rate_request *req,
|
|
unsigned long flags)
|
|
unsigned long flags)
|
|
{
|
|
{
|
|
struct clk_core *core = hw->core, *parent, *best_parent = NULL;
|
|
struct clk_core *core = hw->core, *parent, *best_parent = NULL;
|
|
- int i, num_parents;
|
|
|
|
- unsigned long parent_rate, best = 0;
|
|
|
|
|
|
+ int i, num_parents, ret;
|
|
|
|
+ unsigned long best = 0;
|
|
|
|
+ struct clk_rate_request parent_req = *req;
|
|
|
|
|
|
/* if NO_REPARENT flag set, pass through to current parent */
|
|
/* if NO_REPARENT flag set, pass through to current parent */
|
|
if (core->flags & CLK_SET_RATE_NO_REPARENT) {
|
|
if (core->flags & CLK_SET_RATE_NO_REPARENT) {
|
|
parent = core->parent;
|
|
parent = core->parent;
|
|
- if (core->flags & CLK_SET_RATE_PARENT)
|
|
|
|
- best = __clk_determine_rate(parent ? parent->hw : NULL,
|
|
|
|
- rate, min_rate, max_rate);
|
|
|
|
- else if (parent)
|
|
|
|
|
|
+ if (core->flags & CLK_SET_RATE_PARENT) {
|
|
|
|
+ ret = __clk_determine_rate(parent ? parent->hw : NULL,
|
|
|
|
+ &parent_req);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ best = parent_req.rate;
|
|
|
|
+ } else if (parent) {
|
|
best = clk_core_get_rate_nolock(parent);
|
|
best = clk_core_get_rate_nolock(parent);
|
|
- else
|
|
|
|
|
|
+ } else {
|
|
best = clk_core_get_rate_nolock(core);
|
|
best = clk_core_get_rate_nolock(core);
|
|
|
|
+ }
|
|
|
|
+
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -467,24 +470,30 @@ clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
|
|
parent = clk_core_get_parent_by_index(core, i);
|
|
parent = clk_core_get_parent_by_index(core, i);
|
|
if (!parent)
|
|
if (!parent)
|
|
continue;
|
|
continue;
|
|
- if (core->flags & CLK_SET_RATE_PARENT)
|
|
|
|
- parent_rate = __clk_determine_rate(parent->hw, rate,
|
|
|
|
- min_rate,
|
|
|
|
- max_rate);
|
|
|
|
- else
|
|
|
|
- parent_rate = clk_core_get_rate_nolock(parent);
|
|
|
|
- if (mux_is_better_rate(rate, parent_rate, best, flags)) {
|
|
|
|
|
|
+
|
|
|
|
+ if (core->flags & CLK_SET_RATE_PARENT) {
|
|
|
|
+ parent_req = *req;
|
|
|
|
+ ret = __clk_determine_rate(parent->hw, &parent_req);
|
|
|
|
+ if (ret)
|
|
|
|
+ continue;
|
|
|
|
+ } else {
|
|
|
|
+ parent_req.rate = clk_core_get_rate_nolock(parent);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (mux_is_better_rate(req->rate, parent_req.rate,
|
|
|
|
+ best, flags)) {
|
|
best_parent = parent;
|
|
best_parent = parent;
|
|
- best = parent_rate;
|
|
|
|
|
|
+ best = parent_req.rate;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
out:
|
|
out:
|
|
if (best_parent)
|
|
if (best_parent)
|
|
- *best_parent_p = best_parent->hw;
|
|
|
|
- *best_parent_rate = best;
|
|
|
|
|
|
+ req->best_parent_hw = best_parent->hw;
|
|
|
|
+ req->best_parent_rate = best;
|
|
|
|
+ req->rate = best;
|
|
|
|
|
|
- return best;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
struct clk *__clk_lookup(const char *name)
|
|
struct clk *__clk_lookup(const char *name)
|
|
@@ -515,28 +524,17 @@ static void clk_core_get_boundaries(struct clk_core *core,
|
|
* directly as a determine_rate callback (e.g. for a mux), or from a more
|
|
* directly as a determine_rate callback (e.g. for a mux), or from a more
|
|
* complex clock that may combine a mux with other operations.
|
|
* complex clock that may combine a mux with other operations.
|
|
*/
|
|
*/
|
|
-long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
|
|
|
|
- unsigned long min_rate,
|
|
|
|
- unsigned long max_rate,
|
|
|
|
- unsigned long *best_parent_rate,
|
|
|
|
- struct clk_hw **best_parent_p)
|
|
|
|
|
|
+int __clk_mux_determine_rate(struct clk_hw *hw,
|
|
|
|
+ struct clk_rate_request *req)
|
|
{
|
|
{
|
|
- return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
|
|
|
|
- best_parent_rate,
|
|
|
|
- best_parent_p, 0);
|
|
|
|
|
|
+ return clk_mux_determine_rate_flags(hw, req, 0);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(__clk_mux_determine_rate);
|
|
EXPORT_SYMBOL_GPL(__clk_mux_determine_rate);
|
|
|
|
|
|
-long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
|
|
|
|
- unsigned long min_rate,
|
|
|
|
- unsigned long max_rate,
|
|
|
|
- unsigned long *best_parent_rate,
|
|
|
|
- struct clk_hw **best_parent_p)
|
|
|
|
|
|
+int __clk_mux_determine_rate_closest(struct clk_hw *hw,
|
|
|
|
+ struct clk_rate_request *req)
|
|
{
|
|
{
|
|
- return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
|
|
|
|
- best_parent_rate,
|
|
|
|
- best_parent_p,
|
|
|
|
- CLK_MUX_ROUND_CLOSEST);
|
|
|
|
|
|
+ return clk_mux_determine_rate_flags(hw, req, CLK_MUX_ROUND_CLOSEST);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest);
|
|
EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest);
|
|
|
|
|
|
@@ -759,14 +757,11 @@ int clk_enable(struct clk *clk)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(clk_enable);
|
|
EXPORT_SYMBOL_GPL(clk_enable);
|
|
|
|
|
|
-static unsigned long clk_core_round_rate_nolock(struct clk_core *core,
|
|
|
|
- unsigned long rate,
|
|
|
|
- unsigned long min_rate,
|
|
|
|
- unsigned long max_rate)
|
|
|
|
|
|
+static int clk_core_round_rate_nolock(struct clk_core *core,
|
|
|
|
+ struct clk_rate_request *req)
|
|
{
|
|
{
|
|
- unsigned long parent_rate = 0;
|
|
|
|
struct clk_core *parent;
|
|
struct clk_core *parent;
|
|
- struct clk_hw *parent_hw;
|
|
|
|
|
|
+ long rate;
|
|
|
|
|
|
lockdep_assert_held(&prepare_lock);
|
|
lockdep_assert_held(&prepare_lock);
|
|
|
|
|
|
@@ -774,21 +769,30 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *core,
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
parent = core->parent;
|
|
parent = core->parent;
|
|
- if (parent)
|
|
|
|
- parent_rate = parent->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;
|
|
|
|
+ }
|
|
|
|
|
|
if (core->ops->determine_rate) {
|
|
if (core->ops->determine_rate) {
|
|
- parent_hw = parent ? parent->hw : NULL;
|
|
|
|
- return core->ops->determine_rate(core->hw, rate,
|
|
|
|
- min_rate, max_rate,
|
|
|
|
- &parent_rate, &parent_hw);
|
|
|
|
- } else if (core->ops->round_rate)
|
|
|
|
- return core->ops->round_rate(core->hw, rate, &parent_rate);
|
|
|
|
- else if (core->flags & CLK_SET_RATE_PARENT)
|
|
|
|
- return clk_core_round_rate_nolock(core->parent, rate, min_rate,
|
|
|
|
- max_rate);
|
|
|
|
- else
|
|
|
|
- return core->rate;
|
|
|
|
|
|
+ return core->ops->determine_rate(core->hw, req);
|
|
|
|
+ } else if (core->ops->round_rate) {
|
|
|
|
+ rate = core->ops->round_rate(core->hw, req->rate,
|
|
|
|
+ &req->best_parent_rate);
|
|
|
|
+ if (rate < 0)
|
|
|
|
+ return rate;
|
|
|
|
+
|
|
|
|
+ req->rate = rate;
|
|
|
|
+ } else if (core->flags & CLK_SET_RATE_PARENT) {
|
|
|
|
+ return clk_core_round_rate_nolock(parent, req);
|
|
|
|
+ } else {
|
|
|
|
+ req->rate = core->rate;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -800,15 +804,14 @@ static unsigned long clk_core_round_rate_nolock(struct clk_core *core,
|
|
*
|
|
*
|
|
* Useful for clk_ops such as .set_rate and .determine_rate.
|
|
* Useful for clk_ops such as .set_rate and .determine_rate.
|
|
*/
|
|
*/
|
|
-unsigned long __clk_determine_rate(struct clk_hw *hw,
|
|
|
|
- unsigned long rate,
|
|
|
|
- unsigned long min_rate,
|
|
|
|
- unsigned long max_rate)
|
|
|
|
|
|
+int __clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
|
|
{
|
|
{
|
|
- if (!hw)
|
|
|
|
|
|
+ if (!hw) {
|
|
|
|
+ req->rate = 0;
|
|
return 0;
|
|
return 0;
|
|
|
|
+ }
|
|
|
|
|
|
- return clk_core_round_rate_nolock(hw->core, rate, min_rate, max_rate);
|
|
|
|
|
|
+ return clk_core_round_rate_nolock(hw->core, req);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(__clk_determine_rate);
|
|
EXPORT_SYMBOL_GPL(__clk_determine_rate);
|
|
|
|
|
|
@@ -821,15 +824,20 @@ EXPORT_SYMBOL_GPL(__clk_determine_rate);
|
|
*/
|
|
*/
|
|
unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
|
|
unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
|
|
{
|
|
{
|
|
- unsigned long min_rate;
|
|
|
|
- unsigned long max_rate;
|
|
|
|
|
|
+ struct clk_rate_request req;
|
|
|
|
+ int ret;
|
|
|
|
|
|
if (!clk)
|
|
if (!clk)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
- clk_core_get_boundaries(clk->core, &min_rate, &max_rate);
|
|
|
|
|
|
+ clk_core_get_boundaries(clk->core, &req.min_rate, &req.max_rate);
|
|
|
|
+ req.rate = rate;
|
|
|
|
+
|
|
|
|
+ ret = clk_core_round_rate_nolock(clk->core, &req);
|
|
|
|
+ if (ret)
|
|
|
|
+ return 0;
|
|
|
|
|
|
- return clk_core_round_rate_nolock(clk->core, rate, min_rate, max_rate);
|
|
|
|
|
|
+ return req.rate;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(__clk_round_rate);
|
|
EXPORT_SYMBOL_GPL(__clk_round_rate);
|
|
|
|
|
|
@@ -1249,7 +1257,6 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core,
|
|
{
|
|
{
|
|
struct clk_core *top = core;
|
|
struct clk_core *top = core;
|
|
struct clk_core *old_parent, *parent;
|
|
struct clk_core *old_parent, *parent;
|
|
- struct clk_hw *parent_hw;
|
|
|
|
unsigned long best_parent_rate = 0;
|
|
unsigned long best_parent_rate = 0;
|
|
unsigned long new_rate;
|
|
unsigned long new_rate;
|
|
unsigned long min_rate;
|
|
unsigned long min_rate;
|
|
@@ -1270,20 +1277,29 @@ static struct clk_core *clk_calc_new_rates(struct clk_core *core,
|
|
|
|
|
|
/* find the closest rate and parent clk/rate */
|
|
/* find the closest rate and parent clk/rate */
|
|
if (core->ops->determine_rate) {
|
|
if (core->ops->determine_rate) {
|
|
- parent_hw = parent ? parent->hw : NULL;
|
|
|
|
- ret = core->ops->determine_rate(core->hw, rate,
|
|
|
|
- min_rate,
|
|
|
|
- max_rate,
|
|
|
|
- &best_parent_rate,
|
|
|
|
- &parent_hw);
|
|
|
|
|
|
+ struct clk_rate_request req;
|
|
|
|
+
|
|
|
|
+ req.rate = rate;
|
|
|
|
+ req.min_rate = min_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);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
- new_rate = ret;
|
|
|
|
- parent = parent_hw ? parent_hw->core : NULL;
|
|
|
|
|
|
+ best_parent_rate = req.best_parent_rate;
|
|
|
|
+ new_rate = req.rate;
|
|
|
|
+ parent = req.best_parent_hw ? req.best_parent_hw->core : NULL;
|
|
} else if (core->ops->round_rate) {
|
|
} else if (core->ops->round_rate) {
|
|
ret = core->ops->round_rate(core->hw, rate,
|
|
ret = core->ops->round_rate(core->hw, rate,
|
|
- &best_parent_rate);
|
|
|
|
|
|
+ &best_parent_rate);
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|