diff options
-rw-r--r-- | arch/sh/include/asm/clock.h | 9 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/clock.c | 120 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh4a/clock-sh7722.c | 8 |
3 files changed, 85 insertions, 52 deletions
diff --git a/arch/sh/include/asm/clock.h b/arch/sh/include/asm/clock.h index 241f1c1d9ce1..5dc8b73a2bd5 100644 --- a/arch/sh/include/asm/clock.h +++ b/arch/sh/include/asm/clock.h | |||
@@ -27,6 +27,9 @@ struct clk { | |||
27 | struct clk *parent; | 27 | struct clk *parent; |
28 | struct clk_ops *ops; | 28 | struct clk_ops *ops; |
29 | 29 | ||
30 | struct list_head children; | ||
31 | struct list_head sibling; /* node for children */ | ||
32 | |||
30 | int usecount; | 33 | int usecount; |
31 | 34 | ||
32 | unsigned long rate; | 35 | unsigned long rate; |
@@ -35,7 +38,6 @@ struct clk { | |||
35 | }; | 38 | }; |
36 | 39 | ||
37 | #define CLK_ALWAYS_ENABLED (1 << 0) | 40 | #define CLK_ALWAYS_ENABLED (1 << 0) |
38 | #define CLK_RATE_PROPAGATES (1 << 1) | ||
39 | #define CLK_NEEDS_INIT (1 << 2) | 41 | #define CLK_NEEDS_INIT (1 << 2) |
40 | 42 | ||
41 | /* Should be defined by processor-specific code */ | 43 | /* Should be defined by processor-specific code */ |
@@ -44,9 +46,10 @@ int __init arch_clk_init(void); | |||
44 | 46 | ||
45 | /* arch/sh/kernel/cpu/clock.c */ | 47 | /* arch/sh/kernel/cpu/clock.c */ |
46 | int clk_init(void); | 48 | int clk_init(void); |
47 | unsigned long followparent_recalc(struct clk *clk); | 49 | unsigned long followparent_recalc(struct clk *); |
50 | void recalculate_root_clocks(void); | ||
51 | void propagate_rate(struct clk *); | ||
48 | void clk_recalc_rate(struct clk *); | 52 | void clk_recalc_rate(struct clk *); |
49 | |||
50 | int clk_register(struct clk *); | 53 | int clk_register(struct clk *); |
51 | void clk_unregister(struct clk *); | 54 | void clk_unregister(struct clk *); |
52 | 55 | ||
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c index 17f6c078e851..0a06df8cde2b 100644 --- a/arch/sh/kernel/cpu/clock.c +++ b/arch/sh/kernel/cpu/clock.c | |||
@@ -1,11 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * arch/sh/kernel/cpu/clock.c - SuperH clock framework | 2 | * arch/sh/kernel/cpu/clock.c - SuperH clock framework |
3 | * | 3 | * |
4 | * Copyright (C) 2005, 2006, 2007 Paul Mundt | 4 | * Copyright (C) 2005 - 2009 Paul Mundt |
5 | * | 5 | * |
6 | * This clock framework is derived from the OMAP version by: | 6 | * This clock framework is derived from the OMAP version by: |
7 | * | 7 | * |
8 | * Copyright (C) 2004 - 2005 Nokia Corporation | 8 | * Copyright (C) 2004 - 2008 Nokia Corporation |
9 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> | 9 | * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> |
10 | * | 10 | * |
11 | * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com> | 11 | * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com> |
@@ -43,20 +43,20 @@ static DEFINE_MUTEX(clock_list_sem); | |||
43 | */ | 43 | */ |
44 | static struct clk master_clk = { | 44 | static struct clk master_clk = { |
45 | .name = "master_clk", | 45 | .name = "master_clk", |
46 | .flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES, | 46 | .flags = CLK_ALWAYS_ENABLED, |
47 | .rate = CONFIG_SH_PCLK_FREQ, | 47 | .rate = CONFIG_SH_PCLK_FREQ, |
48 | }; | 48 | }; |
49 | 49 | ||
50 | static struct clk module_clk = { | 50 | static struct clk module_clk = { |
51 | .name = "module_clk", | 51 | .name = "module_clk", |
52 | .parent = &master_clk, | 52 | .parent = &master_clk, |
53 | .flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES, | 53 | .flags = CLK_ALWAYS_ENABLED, |
54 | }; | 54 | }; |
55 | 55 | ||
56 | static struct clk bus_clk = { | 56 | static struct clk bus_clk = { |
57 | .name = "bus_clk", | 57 | .name = "bus_clk", |
58 | .parent = &master_clk, | 58 | .parent = &master_clk, |
59 | .flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES, | 59 | .flags = CLK_ALWAYS_ENABLED, |
60 | }; | 60 | }; |
61 | 61 | ||
62 | static struct clk cpu_clk = { | 62 | static struct clk cpu_clk = { |
@@ -75,27 +75,24 @@ static struct clk *onchip_clocks[] = { | |||
75 | &cpu_clk, | 75 | &cpu_clk, |
76 | }; | 76 | }; |
77 | 77 | ||
78 | /* Used for clocks that always have same value as the parent clock */ | ||
79 | unsigned long followparent_recalc(struct clk *clk) | ||
80 | { | ||
81 | return clk->parent->rate; | ||
82 | } | ||
83 | |||
78 | /* Propagate rate to children */ | 84 | /* Propagate rate to children */ |
79 | static void propagate_rate(struct clk *clk) | 85 | void propagate_rate(struct clk *tclk) |
80 | { | 86 | { |
81 | struct clk *clkp; | 87 | struct clk *clkp; |
82 | 88 | ||
83 | list_for_each_entry(clkp, &clock_list, node) { | 89 | list_for_each_entry(clkp, &tclk->children, sibling) { |
84 | if (likely(clkp->parent != clk)) | 90 | if (clkp->ops->recalc) |
85 | continue; | ||
86 | if (likely(clkp->ops && clkp->ops->recalc)) | ||
87 | clkp->rate = clkp->ops->recalc(clkp); | 91 | clkp->rate = clkp->ops->recalc(clkp); |
88 | if (unlikely(clkp->flags & CLK_RATE_PROPAGATES)) | 92 | propagate_rate(clkp); |
89 | propagate_rate(clkp); | ||
90 | } | 93 | } |
91 | } | 94 | } |
92 | 95 | ||
93 | /* Used for clocks that always have same value as the parent clock */ | ||
94 | unsigned long followparent_recalc(struct clk *clk) | ||
95 | { | ||
96 | return clk->parent->rate; | ||
97 | } | ||
98 | |||
99 | static void __clk_init(struct clk *clk) | 96 | static void __clk_init(struct clk *clk) |
100 | { | 97 | { |
101 | /* | 98 | /* |
@@ -180,10 +177,46 @@ void clk_disable(struct clk *clk) | |||
180 | } | 177 | } |
181 | EXPORT_SYMBOL_GPL(clk_disable); | 178 | EXPORT_SYMBOL_GPL(clk_disable); |
182 | 179 | ||
180 | static LIST_HEAD(root_clks); | ||
181 | |||
182 | /** | ||
183 | * recalculate_root_clocks - recalculate and propagate all root clocks | ||
184 | * | ||
185 | * Recalculates all root clocks (clocks with no parent), which if the | ||
186 | * clock's .recalc is set correctly, should also propagate their rates. | ||
187 | * Called at init. | ||
188 | */ | ||
189 | void recalculate_root_clocks(void) | ||
190 | { | ||
191 | struct clk *clkp; | ||
192 | |||
193 | list_for_each_entry(clkp, &root_clks, sibling) { | ||
194 | if (clkp->ops->recalc) | ||
195 | clkp->rate = clkp->ops->recalc(clkp); | ||
196 | propagate_rate(clkp); | ||
197 | } | ||
198 | } | ||
199 | |||
183 | int clk_register(struct clk *clk) | 200 | int clk_register(struct clk *clk) |
184 | { | 201 | { |
202 | if (clk == NULL || IS_ERR(clk)) | ||
203 | return -EINVAL; | ||
204 | |||
205 | /* | ||
206 | * trap out already registered clocks | ||
207 | */ | ||
208 | if (clk->node.next || clk->node.prev) | ||
209 | return 0; | ||
210 | |||
185 | mutex_lock(&clock_list_sem); | 211 | mutex_lock(&clock_list_sem); |
186 | 212 | ||
213 | INIT_LIST_HEAD(&clk->children); | ||
214 | |||
215 | if (clk->parent) | ||
216 | list_add(&clk->sibling, &clk->parent->children); | ||
217 | else | ||
218 | list_add(&clk->sibling, &root_clks); | ||
219 | |||
187 | list_add(&clk->node, &clock_list); | 220 | list_add(&clk->node, &clock_list); |
188 | clk->usecount = 0; | 221 | clk->usecount = 0; |
189 | clk->flags |= CLK_NEEDS_INIT; | 222 | clk->flags |= CLK_NEEDS_INIT; |
@@ -205,6 +238,7 @@ EXPORT_SYMBOL_GPL(clk_register); | |||
205 | void clk_unregister(struct clk *clk) | 238 | void clk_unregister(struct clk *clk) |
206 | { | 239 | { |
207 | mutex_lock(&clock_list_sem); | 240 | mutex_lock(&clock_list_sem); |
241 | list_del(&clk->sibling); | ||
208 | list_del(&clk->node); | 242 | list_del(&clk->node); |
209 | mutex_unlock(&clock_list_sem); | 243 | mutex_unlock(&clock_list_sem); |
210 | } | 244 | } |
@@ -231,50 +265,53 @@ int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id) | |||
231 | 265 | ||
232 | spin_lock_irqsave(&clock_lock, flags); | 266 | spin_lock_irqsave(&clock_lock, flags); |
233 | ret = clk->ops->set_rate(clk, rate, algo_id); | 267 | ret = clk->ops->set_rate(clk, rate, algo_id); |
268 | if (ret == 0) { | ||
269 | if (clk->ops->recalc) | ||
270 | clk->rate = clk->ops->recalc(clk); | ||
271 | propagate_rate(clk); | ||
272 | } | ||
234 | spin_unlock_irqrestore(&clock_lock, flags); | 273 | spin_unlock_irqrestore(&clock_lock, flags); |
235 | } | 274 | } |
236 | 275 | ||
237 | if (unlikely(clk->flags & CLK_RATE_PROPAGATES)) | ||
238 | propagate_rate(clk); | ||
239 | |||
240 | return ret; | 276 | return ret; |
241 | } | 277 | } |
242 | EXPORT_SYMBOL_GPL(clk_set_rate_ex); | 278 | EXPORT_SYMBOL_GPL(clk_set_rate_ex); |
243 | 279 | ||
244 | void clk_recalc_rate(struct clk *clk) | 280 | void clk_recalc_rate(struct clk *clk) |
245 | { | 281 | { |
246 | if (likely(clk->ops && clk->ops->recalc)) { | 282 | unsigned long flags; |
247 | unsigned long flags; | ||
248 | 283 | ||
249 | spin_lock_irqsave(&clock_lock, flags); | 284 | if (!clk->ops->recalc) |
250 | clk->rate = clk->ops->recalc(clk); | 285 | return; |
251 | spin_unlock_irqrestore(&clock_lock, flags); | ||
252 | } | ||
253 | 286 | ||
254 | if (unlikely(clk->flags & CLK_RATE_PROPAGATES)) | 287 | spin_lock_irqsave(&clock_lock, flags); |
255 | propagate_rate(clk); | 288 | clk->rate = clk->ops->recalc(clk); |
289 | propagate_rate(clk); | ||
290 | spin_unlock_irqrestore(&clock_lock, flags); | ||
256 | } | 291 | } |
257 | EXPORT_SYMBOL_GPL(clk_recalc_rate); | 292 | EXPORT_SYMBOL_GPL(clk_recalc_rate); |
258 | 293 | ||
259 | int clk_set_parent(struct clk *clk, struct clk *parent) | 294 | int clk_set_parent(struct clk *clk, struct clk *parent) |
260 | { | 295 | { |
296 | unsigned long flags; | ||
261 | int ret = -EINVAL; | 297 | int ret = -EINVAL; |
262 | struct clk *old; | ||
263 | 298 | ||
264 | if (!parent || !clk) | 299 | if (!parent || !clk) |
265 | return ret; | 300 | return ret; |
266 | 301 | ||
267 | old = clk->parent; | 302 | spin_lock_irqsave(&clock_lock, flags); |
268 | if (likely(clk->ops && clk->ops->set_parent)) { | 303 | if (clk->usecount == 0) { |
269 | unsigned long flags; | 304 | if (clk->ops->set_parent) |
270 | spin_lock_irqsave(&clock_lock, flags); | 305 | ret = clk->ops->set_parent(clk, parent); |
271 | ret = clk->ops->set_parent(clk, parent); | 306 | if (ret == 0) { |
272 | spin_unlock_irqrestore(&clock_lock, flags); | 307 | if (clk->ops->recalc) |
273 | clk->parent = (ret ? old : parent); | 308 | clk->rate = clk->ops->recalc(clk); |
274 | } | 309 | propagate_rate(clk); |
310 | } | ||
311 | } else | ||
312 | ret = -EBUSY; | ||
313 | spin_unlock_irqrestore(&clock_lock, flags); | ||
275 | 314 | ||
276 | if (unlikely(clk->flags & CLK_RATE_PROPAGATES)) | ||
277 | propagate_rate(clk); | ||
278 | return ret; | 315 | return ret; |
279 | } | 316 | } |
280 | EXPORT_SYMBOL_GPL(clk_set_parent); | 317 | EXPORT_SYMBOL_GPL(clk_set_parent); |
@@ -457,8 +494,7 @@ int __init clk_init(void) | |||
457 | ret |= arch_clk_init(); | 494 | ret |= arch_clk_init(); |
458 | 495 | ||
459 | /* Kick the child clocks.. */ | 496 | /* Kick the child clocks.. */ |
460 | propagate_rate(&master_clk); | 497 | recalculate_root_clocks(); |
461 | propagate_rate(&bus_clk); | ||
462 | 498 | ||
463 | return ret; | 499 | return ret; |
464 | } | 500 | } |
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c index 4bdae84aa6b0..8e53829ca078 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c | |||
@@ -161,9 +161,7 @@ static unsigned long master_clk_recalc(struct clk *clk) | |||
161 | static void master_clk_init(struct clk *clk) | 161 | static void master_clk_init(struct clk *clk) |
162 | { | 162 | { |
163 | clk->parent = NULL; | 163 | clk->parent = NULL; |
164 | clk->flags |= CLK_RATE_PROPAGATES; | 164 | clk->rate = master_clk_recalc(clk); |
165 | clk->rate = CONFIG_SH_PCLK_FREQ; | ||
166 | master_clk_recalc(clk); | ||
167 | } | 165 | } |
168 | 166 | ||
169 | static unsigned long module_clk_recalc(struct clk *clk) | 167 | static unsigned long module_clk_recalc(struct clk *clk) |
@@ -541,19 +539,16 @@ static struct clk_ops sh7722_video_clk_ops = { | |||
541 | static struct clk sh7722_umem_clock = { | 539 | static struct clk sh7722_umem_clock = { |
542 | .name = "umem_clk", | 540 | .name = "umem_clk", |
543 | .ops = &sh7722_frqcr_clk_ops, | 541 | .ops = &sh7722_frqcr_clk_ops, |
544 | .flags = CLK_RATE_PROPAGATES, | ||
545 | }; | 542 | }; |
546 | 543 | ||
547 | static struct clk sh7722_sh_clock = { | 544 | static struct clk sh7722_sh_clock = { |
548 | .name = "sh_clk", | 545 | .name = "sh_clk", |
549 | .ops = &sh7722_frqcr_clk_ops, | 546 | .ops = &sh7722_frqcr_clk_ops, |
550 | .flags = CLK_RATE_PROPAGATES, | ||
551 | }; | 547 | }; |
552 | 548 | ||
553 | static struct clk sh7722_peripheral_clock = { | 549 | static struct clk sh7722_peripheral_clock = { |
554 | .name = "peripheral_clk", | 550 | .name = "peripheral_clk", |
555 | .ops = &sh7722_frqcr_clk_ops, | 551 | .ops = &sh7722_frqcr_clk_ops, |
556 | .flags = CLK_RATE_PROPAGATES, | ||
557 | }; | 552 | }; |
558 | 553 | ||
559 | static struct clk sh7722_sdram_clock = { | 554 | static struct clk sh7722_sdram_clock = { |
@@ -564,7 +559,6 @@ static struct clk sh7722_sdram_clock = { | |||
564 | static struct clk sh7722_r_clock = { | 559 | static struct clk sh7722_r_clock = { |
565 | .name = "r_clk", | 560 | .name = "r_clk", |
566 | .rate = 32768, | 561 | .rate = 32768, |
567 | .flags = CLK_RATE_PROPAGATES, | ||
568 | }; | 562 | }; |
569 | 563 | ||
570 | #if !defined(CONFIG_CPU_SUBTYPE_SH7343) &&\ | 564 | #if !defined(CONFIG_CPU_SUBTYPE_SH7343) &&\ |