diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2009-01-31 05:05:51 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-02-08 12:50:42 -0500 |
commit | 3f0a820c4c0b4670fb5f164baa5582e23c2ef118 (patch) | |
tree | 6af02e1456c0316791ab95e7da9c09496f29c232 /arch/arm/plat-omap/clock.c | |
parent | b5088c0d90b898802318c62caf2320a53df6ce57 (diff) |
[ARM] omap: create a proper tree of clocks
Traditionally, we've tracked the parent/child relationships between
clk structures by setting the child's parent member to point at the
upstream clock. As a result, when decending the tree, we have had
to scan all clocks to find the children.
Avoid this wasteful scanning by keeping a list of the clock's children.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/plat-omap/clock.c')
-rw-r--r-- | arch/arm/plat-omap/clock.c | 51 |
1 files changed, 32 insertions, 19 deletions
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c index 54da27af0bd5..6a1737a74477 100644 --- a/arch/arm/plat-omap/clock.c +++ b/arch/arm/plat-omap/clock.c | |||
@@ -143,8 +143,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate) | |||
143 | if (ret == 0) { | 143 | if (ret == 0) { |
144 | if (clk->recalc) | 144 | if (clk->recalc) |
145 | clk->recalc(clk); | 145 | clk->recalc(clk); |
146 | if (clk->flags & RATE_PROPAGATES) | 146 | propagate_rate(clk); |
147 | propagate_rate(clk); | ||
148 | } | 147 | } |
149 | spin_unlock_irqrestore(&clockfw_lock, flags); | 148 | spin_unlock_irqrestore(&clockfw_lock, flags); |
150 | 149 | ||
@@ -166,8 +165,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent) | |||
166 | if (ret == 0) { | 165 | if (ret == 0) { |
167 | if (clk->recalc) | 166 | if (clk->recalc) |
168 | clk->recalc(clk); | 167 | clk->recalc(clk); |
169 | if (clk->flags & RATE_PROPAGATES) | 168 | propagate_rate(clk); |
170 | propagate_rate(clk); | ||
171 | } | 169 | } |
172 | spin_unlock_irqrestore(&clockfw_lock, flags); | 170 | spin_unlock_irqrestore(&clockfw_lock, flags); |
173 | 171 | ||
@@ -214,24 +212,31 @@ void followparent_recalc(struct clk *clk) | |||
214 | clk->rate = clk->parent->rate; | 212 | clk->rate = clk->parent->rate; |
215 | } | 213 | } |
216 | 214 | ||
215 | void clk_reparent(struct clk *child, struct clk *parent) | ||
216 | { | ||
217 | list_del_init(&child->sibling); | ||
218 | if (parent) | ||
219 | list_add(&child->sibling, &parent->children); | ||
220 | child->parent = parent; | ||
221 | |||
222 | /* now do the debugfs renaming to reattach the child | ||
223 | to the proper parent */ | ||
224 | } | ||
225 | |||
217 | /* Propagate rate to children */ | 226 | /* Propagate rate to children */ |
218 | void propagate_rate(struct clk * tclk) | 227 | void propagate_rate(struct clk * tclk) |
219 | { | 228 | { |
220 | struct clk *clkp; | 229 | struct clk *clkp; |
221 | 230 | ||
222 | if (tclk == NULL || IS_ERR(tclk)) | 231 | list_for_each_entry(clkp, &tclk->children, sibling) { |
223 | return; | ||
224 | |||
225 | list_for_each_entry(clkp, &clocks, node) { | ||
226 | if (likely(clkp->parent != tclk)) | ||
227 | continue; | ||
228 | if (clkp->recalc) | 232 | if (clkp->recalc) |
229 | clkp->recalc(clkp); | 233 | clkp->recalc(clkp); |
230 | if (clkp->flags & RATE_PROPAGATES) | 234 | propagate_rate(clkp); |
231 | propagate_rate(clkp); | ||
232 | } | 235 | } |
233 | } | 236 | } |
234 | 237 | ||
238 | static LIST_HEAD(root_clks); | ||
239 | |||
235 | /** | 240 | /** |
236 | * recalculate_root_clocks - recalculate and propagate all root clocks | 241 | * recalculate_root_clocks - recalculate and propagate all root clocks |
237 | * | 242 | * |
@@ -243,16 +248,18 @@ void recalculate_root_clocks(void) | |||
243 | { | 248 | { |
244 | struct clk *clkp; | 249 | struct clk *clkp; |
245 | 250 | ||
246 | list_for_each_entry(clkp, &clocks, node) { | 251 | list_for_each_entry(clkp, &root_clks, sibling) { |
247 | if (!clkp->parent) { | 252 | if (clkp->recalc) |
248 | if (clkp->recalc) | 253 | clkp->recalc(clkp); |
249 | clkp->recalc(clkp); | 254 | propagate_rate(clkp); |
250 | if (clkp->flags & RATE_PROPAGATES) | ||
251 | propagate_rate(clkp); | ||
252 | } | ||
253 | } | 255 | } |
254 | } | 256 | } |
255 | 257 | ||
258 | void clk_init_one(struct clk *clk) | ||
259 | { | ||
260 | INIT_LIST_HEAD(&clk->children); | ||
261 | } | ||
262 | |||
256 | int clk_register(struct clk *clk) | 263 | int clk_register(struct clk *clk) |
257 | { | 264 | { |
258 | if (clk == NULL || IS_ERR(clk)) | 265 | if (clk == NULL || IS_ERR(clk)) |
@@ -265,6 +272,11 @@ int clk_register(struct clk *clk) | |||
265 | return 0; | 272 | return 0; |
266 | 273 | ||
267 | mutex_lock(&clocks_mutex); | 274 | mutex_lock(&clocks_mutex); |
275 | if (clk->parent) | ||
276 | list_add(&clk->sibling, &clk->parent->children); | ||
277 | else | ||
278 | list_add(&clk->sibling, &root_clks); | ||
279 | |||
268 | list_add(&clk->node, &clocks); | 280 | list_add(&clk->node, &clocks); |
269 | if (clk->init) | 281 | if (clk->init) |
270 | clk->init(clk); | 282 | clk->init(clk); |
@@ -280,6 +292,7 @@ void clk_unregister(struct clk *clk) | |||
280 | return; | 292 | return; |
281 | 293 | ||
282 | mutex_lock(&clocks_mutex); | 294 | mutex_lock(&clocks_mutex); |
295 | list_del(&clk->sibling); | ||
283 | list_del(&clk->node); | 296 | list_del(&clk->node); |
284 | mutex_unlock(&clocks_mutex); | 297 | mutex_unlock(&clocks_mutex); |
285 | } | 298 | } |