diff options
author | James Hogan <james.hogan@imgtec.com> | 2013-07-29 07:25:02 -0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2013-08-19 15:27:18 -0400 |
commit | e366fdd72529c545ccf327569ee250c1673be221 (patch) | |
tree | 69139adc59e6ab101555f09544669793c385c250 | |
parent | 819c1de344c5b8350bffd35be9a0fa74541292d3 (diff) |
clk: clk-mux: implement remuxing on set_rate
Implement clk-mux remuxing if the CLK_SET_RATE_NO_REPARENT flag isn't
set. This implements determine_rate for clk-mux to propagate to each
parent and to choose the best one (like clk-divider this chooses the
parent which provides the fastest rate <= the requested rate).
The determine_rate op is implemented as a core helper function so that
it can be easily used by more complex clocks which incorporate muxes.
Signed-off-by: James Hogan <james.hogan@imgtec.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Cc: Mike Turquette <mturquette@linaro.org>
Cc: linux-arm-kernel@lists.infradead.org
Signed-off-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r-- | drivers/clk/clk-mux.c | 1 | ||||
-rw-r--r-- | drivers/clk/clk.c | 49 | ||||
-rw-r--r-- | include/linux/clk-provider.h | 3 |
3 files changed, 53 insertions, 0 deletions
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index b918dc370bd0..0811633fcc4d 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c | |||
@@ -104,6 +104,7 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index) | |||
104 | const struct clk_ops clk_mux_ops = { | 104 | const struct clk_ops clk_mux_ops = { |
105 | .get_parent = clk_mux_get_parent, | 105 | .get_parent = clk_mux_get_parent, |
106 | .set_parent = clk_mux_set_parent, | 106 | .set_parent = clk_mux_set_parent, |
107 | .determine_rate = __clk_mux_determine_rate, | ||
107 | }; | 108 | }; |
108 | EXPORT_SYMBOL_GPL(clk_mux_ops); | 109 | EXPORT_SYMBOL_GPL(clk_mux_ops); |
109 | 110 | ||
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f33f1ccf1b2f..bc020372106b 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
@@ -692,6 +692,55 @@ struct clk *__clk_lookup(const char *name) | |||
692 | return NULL; | 692 | return NULL; |
693 | } | 693 | } |
694 | 694 | ||
695 | /* | ||
696 | * Helper for finding best parent to provide a given frequency. This can be used | ||
697 | * directly as a determine_rate callback (e.g. for a mux), or from a more | ||
698 | * complex clock that may combine a mux with other operations. | ||
699 | */ | ||
700 | long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
701 | unsigned long *best_parent_rate, | ||
702 | struct clk **best_parent_p) | ||
703 | { | ||
704 | struct clk *clk = hw->clk, *parent, *best_parent = NULL; | ||
705 | int i, num_parents; | ||
706 | unsigned long parent_rate, best = 0; | ||
707 | |||
708 | /* if NO_REPARENT flag set, pass through to current parent */ | ||
709 | if (clk->flags & CLK_SET_RATE_NO_REPARENT) { | ||
710 | parent = clk->parent; | ||
711 | if (clk->flags & CLK_SET_RATE_PARENT) | ||
712 | best = __clk_round_rate(parent, rate); | ||
713 | else if (parent) | ||
714 | best = __clk_get_rate(parent); | ||
715 | else | ||
716 | best = __clk_get_rate(clk); | ||
717 | goto out; | ||
718 | } | ||
719 | |||
720 | /* find the parent that can provide the fastest rate <= rate */ | ||
721 | num_parents = clk->num_parents; | ||
722 | for (i = 0; i < num_parents; i++) { | ||
723 | parent = clk_get_parent_by_index(clk, i); | ||
724 | if (!parent) | ||
725 | continue; | ||
726 | if (clk->flags & CLK_SET_RATE_PARENT) | ||
727 | parent_rate = __clk_round_rate(parent, rate); | ||
728 | else | ||
729 | parent_rate = __clk_get_rate(parent); | ||
730 | if (parent_rate <= rate && parent_rate > best) { | ||
731 | best_parent = parent; | ||
732 | best = parent_rate; | ||
733 | } | ||
734 | } | ||
735 | |||
736 | out: | ||
737 | if (best_parent) | ||
738 | *best_parent_p = best_parent; | ||
739 | *best_parent_rate = best; | ||
740 | |||
741 | return best; | ||
742 | } | ||
743 | |||
695 | /*** clk api ***/ | 744 | /*** clk api ***/ |
696 | 745 | ||
697 | void __clk_unprepare(struct clk *clk) | 746 | void __clk_unprepare(struct clk *clk) |
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 5c0bc3904c9b..1f0285b2f422 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h | |||
@@ -436,6 +436,9 @@ unsigned long __clk_get_flags(struct clk *clk); | |||
436 | bool __clk_is_prepared(struct clk *clk); | 436 | bool __clk_is_prepared(struct clk *clk); |
437 | bool __clk_is_enabled(struct clk *clk); | 437 | bool __clk_is_enabled(struct clk *clk); |
438 | struct clk *__clk_lookup(const char *name); | 438 | struct clk *__clk_lookup(const char *name); |
439 | long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate, | ||
440 | unsigned long *best_parent_rate, | ||
441 | struct clk **best_parent_p); | ||
439 | 442 | ||
440 | /* | 443 | /* |
441 | * FIXME clock api without lock protection | 444 | * FIXME clock api without lock protection |