[PATCH v7 2/3] clk: introduce the common clock framework
From: Turquette, Mike <hidden>
Date: 2012-03-20 23:47:04
Also in:
lkml
On Tue, Mar 20, 2012 at 7:02 AM, Shawn Guo [off-list ref] wrote:
On Thu, Mar 15, 2012 at 11:11:19PM -0700, Mike Turquette wrote: ...quoted
+struct clk_ops { + ? ? int ? ? ? ? ? ? (*prepare)(struct clk_hw *hw); + ? ? void ? ? ? ? ? ?(*unprepare)(struct clk_hw *hw); + ? ? int ? ? ? ? ? ? (*enable)(struct clk_hw *hw); + ? ? void ? ? ? ? ? ?(*disable)(struct clk_hw *hw); + ? ? int ? ? ? ? ? ? (*is_enabled)(struct clk_hw *hw); + ? ? unsigned long ? (*recalc_rate)(struct clk_hw *hw, + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long parent_rate);I believe I have heard people love the interface with parent_rate passed in. ?I love that too. ?But I would like to ask the same thing on .round_rate and .set_rate as well for the same reason why we have it for .recalc_rate.
This is something that was discussed on the list but not taken in due to rapid flux in code. I always liked the idea however.
quoted
+ ? ? long ? ? ? ? ? ?(*round_rate)(struct clk_hw *hw, unsigned long, + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long *);Yes, we already have parent_rate passed in .round_rate with an pointer. But I think it'd be better to have it passed in no matter flag CLK_SET_RATE_PARENT is set or not. ?Something like:
This places the burden of checking the flags onto the .round_rate implementation with __clk_get_flags, but that's not a problem really.
quoted hunk ↗ jump to hunk
8<---@@ -584,7 +584,7 @@ EXPORT_SYMBOL_GPL(clk_get_rate);?*/ ?unsigned long __clk_round_rate(struct clk *clk, unsigned long rate) ?{ - ? ? ? unsigned long unused; + ? ? ? unsigned long parent_rate = 0; ? ? ? ?if (!clk) ? ? ? ? ? ? ? ?return -EINVAL;@@ -592,10 +592,10 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)? ? ? ?if (!clk->ops->round_rate) ? ? ? ? ? ? ? ?return clk->rate; - ? ? ? if (clk->flags & CLK_SET_RATE_PARENT) - ? ? ? ? ? ? ? return clk->ops->round_rate(clk->hw, rate, &unused); - ? ? ? else - ? ? ? ? ? ? ? return clk->ops->round_rate(clk->hw, rate, NULL); + ? ? ? if (clk->parent) + ? ? ? ? ? ? ? parent_rate = clk->parent->rate; + + ? ? ? return clk->ops->round_rate(clk->hw, rate, &parent_rate); ?} ?/**@@ -765,9 +765,12 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)?static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate) ?{ ? ? ? ?struct clk *top = clk; - ? ? ? unsigned long best_parent_rate = clk->parent->rate; + ? ? ? unsigned long best_parent_rate = 0; ? ? ? ?unsigned long new_rate; + ? ? ? if (clk->parent) + ? ? ? ? ? ? ? best_parent_rate = clk->parent->rate; + ? ? ? ?if (!clk->ops->round_rate && !(clk->flags & CLK_SET_RATE_PARENT)) { ? ? ? ? ? ? ? ?clk->new_rate = clk->rate; ? ? ? ? ? ? ? ?return NULL;@@ -780,10 +783,7 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)? ? ? ? ? ? ? ?goto out; ? ? ? ?} - ? ? ? if (clk->flags & CLK_SET_RATE_PARENT) - ? ? ? ? ? ? ? new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate); - ? ? ? else - ? ? ? ? ? ? ? new_rate = clk->ops->round_rate(clk->hw, rate, NULL); + ? ? ? new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate); ? ? ? ?if (best_parent_rate != clk->parent->rate) { ? ? ? ? ? ? ? ?top = clk_calc_new_rates(clk->parent, best_parent_rate); --->8
ACK
quoted hunk ↗ jump to hunk
The reason behind the change is that any clk implements .round_rate will mostly need to get the parent rate, no matter flag CLK_SET_RATE_PARENT is set or not. ?Instead of expecting every .round_rate implementation to get the parent rate in the way beloe ? ? ? ? parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); we can just pass the parent rate into .round_rate.quoted
+ ? ? int ? ? ? ? ? ? (*set_parent)(struct clk_hw *hw, u8 index); + ? ? u8 ? ? ? ? ? ? ?(*get_parent)(struct clk_hw *hw); + ? ? int ? ? ? ? ? ? (*set_rate)(struct clk_hw *hw, unsigned long);For the same reason, I would change .set_rate interface like below. 8<---diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index d5ac6a7..6bd8037 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c@@ -119,7 +119,8 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,?} ?EXPORT_SYMBOL_GPL(clk_divider_round_rate); -static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate) +static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long parent_rate) ?{ ? ? ? ?struct clk_divider *divider = to_clk_divider(hw); ? ? ? ?unsigned int div;diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index dbc310a..d74ac4b 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c@@ -833,17 +833,18 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even?static void clk_change_rate(struct clk *clk) ?{ ? ? ? ?struct clk *child; - ? ? ? unsigned long old_rate; + ? ? ? unsigned long old_rate, parent_rate = 0; ? ? ? ?struct hlist_node *tmp; ? ? ? ?old_rate = clk->rate; + ? ? ? if (clk->parent) + ? ? ? ? ? ? ? parent_rate = clk->parent->rate; ? ? ? ?if (clk->ops->set_rate) - ? ? ? ? ? ? ? clk->ops->set_rate(clk->hw, clk->new_rate); + ? ? ? ? ? ? ? clk->ops->set_rate(clk->hw, clk->new_rate, parent_rate); ? ? ? ?if (clk->ops->recalc_rate) - ? ? ? ? ? ? ? clk->rate = clk->ops->recalc_rate(clk->hw, - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? clk->parent->rate); + ? ? ? ? ? ? ? clk->rate = clk->ops->recalc_rate(clk->hw, parent_rate); ? ? ? ?else ? ? ? ? ? ? ? ?clk->rate = clk->parent->rate;diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 5508897..1031f1f 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h@@ -125,7 +125,8 @@ struct clk_ops {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?unsigned long *); ? ? ? ?int ? ? ? ? ? ? (*set_parent)(struct clk_hw *hw, u8 index); ? ? ? ?u8 ? ? ? ? ? ? ?(*get_parent)(struct clk_hw *hw); - ? ? ? int ? ? ? ? ? ? (*set_rate)(struct clk_hw *hw, unsigned long); + ? ? ? int ? ? ? ? ? ? (*set_rate)(struct clk_hw *hw, unsigned long, + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? unsigned long); ? ? ? ?void ? ? ? ? ? ?(*init)(struct clk_hw *hw); ?}; --->8
ACK
quoted hunk ↗ jump to hunk
Then with parent rate passed into .round_rate and .set_rate like what we do with .recalc_rate right now, we can save particular clk implementation from calling __clk_get_parent() and __clk_get_rate to get parent rate. For example, the following will the be diff we gain on clk-divider. 8<---diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 6bd8037..8a28ffb 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c@@ -68,8 +68,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,? ? ? ?if (divider->flags & CLK_DIVIDER_ONE_BASED) ? ? ? ? ? ? ? ?maxdiv--; - ? ? ? if (!best_parent_rate) { - ? ? ? ? ? ? ? parent_rate = __clk_get_rate(__clk_get_parent(hw->clk)); + ? ? ? if (!(divider->flags & CLK_SET_RATE_PARENT)) {
This is wrong. CLK_SET_RATE_PARENT is a common clock flag applied to struct clk's .flags member, not the divider. This function must still use __clk_get_flags(hw->clk) here, but that's OK.
quoted hunk ↗ jump to hunk
+ ? ? ? ? ? ? ? parent_rate = *best_parent_rate; ? ? ? ? ? ? ? ?bestdiv = DIV_ROUND_UP(parent_rate, rate); ? ? ? ? ? ? ? ?bestdiv = bestdiv == 0 ? 1 : bestdiv; ? ? ? ? ? ? ? ?bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;@@ -109,13 +109,7 @@ static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,? ? ? ?int div; ? ? ? ?div = clk_divider_bestdiv(hw, rate, prate); - ? ? ? if (prate) - ? ? ? ? ? ? ? return *prate / div; - ? ? ? else { - ? ? ? ? ? ? ? unsigned long r; - ? ? ? ? ? ? ? r = __clk_get_rate(__clk_get_parent(hw->clk)); - ? ? ? ? ? ? ? return r / div; - ? ? ? } + ? ? ? return *prate / div; ?} ?EXPORT_SYMBOL_GPL(clk_divider_round_rate);@@ -127,7 +121,7 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,? ? ? ?unsigned long flags = 0; ? ? ? ?u32 val; - ? ? ? div = __clk_get_rate(__clk_get_parent(hw->clk)) / rate; + ? ? ? div = parent_rate / rate; ? ? ? ?if (!(divider->flags & CLK_DIVIDER_ONE_BASED)) ? ? ? ? ? ? ? ?div--; --->8
ACK, besides my comment above.
I always get a sense of worry in using functions named in __xxx which sounds like something somehow internal. ?With the requested interface change above, I can get all __xxx functions out of my clk_ops implementation.
As mentioned above, you'll still need to check for CLK_SET_RATE_PARENT in your .round_rate implementation with __clk_get_flags(hw->clk). Did you want to send a formal patch or just have me absorb this into the fixes I'm brewing already? I've already fixed the potential null ptr dereferences in clk_calc_new_rates, but that's no big deal. Regards, Mike