aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2009-05-11 15:27:43 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-05-11 15:27:43 -0400
commitb1f6cfe48c3cb1dfa77db3d2f42f765febaef9bc (patch)
treee5f2722c8ebd6dd64809a283133f60cbc50794df /arch/sh/kernel
parenta02cb230bb4fca04f091746c593de720a0e3a94a (diff)
sh: clkfwk: refactor rate propagation.
This resyncs the rate propagation strategy with the scheme used by the OMAP clock framework. Child clocks are tracked on a list under each parent and propagation happens there specifically rather than constantly iterating over the global clock list. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r--arch/sh/kernel/cpu/clock.c120
-rw-r--r--arch/sh/kernel/cpu/sh4a/clock-sh7722.c8
2 files changed, 79 insertions, 49 deletions
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c
index 17f6c078e85..0a06df8cde2 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 */
44static struct clk master_clk = { 44static 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
50static struct clk module_clk = { 50static 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
56static struct clk bus_clk = { 56static 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
62static struct clk cpu_clk = { 62static 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 */
79unsigned long followparent_recalc(struct clk *clk)
80{
81 return clk->parent->rate;
82}
83
78/* Propagate rate to children */ 84/* Propagate rate to children */
79static void propagate_rate(struct clk *clk) 85void 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 */
94unsigned long followparent_recalc(struct clk *clk)
95{
96 return clk->parent->rate;
97}
98
99static void __clk_init(struct clk *clk) 96static void __clk_init(struct clk *clk)
100{ 97{
101 /* 98 /*
@@ -180,10 +177,46 @@ void clk_disable(struct clk *clk)
180} 177}
181EXPORT_SYMBOL_GPL(clk_disable); 178EXPORT_SYMBOL_GPL(clk_disable);
182 179
180static 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 */
189void 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
183int clk_register(struct clk *clk) 200int 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);
205void clk_unregister(struct clk *clk) 238void 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}
242EXPORT_SYMBOL_GPL(clk_set_rate_ex); 278EXPORT_SYMBOL_GPL(clk_set_rate_ex);
243 279
244void clk_recalc_rate(struct clk *clk) 280void 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}
257EXPORT_SYMBOL_GPL(clk_recalc_rate); 292EXPORT_SYMBOL_GPL(clk_recalc_rate);
258 293
259int clk_set_parent(struct clk *clk, struct clk *parent) 294int 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}
280EXPORT_SYMBOL_GPL(clk_set_parent); 317EXPORT_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 4bdae84aa6b..8e53829ca07 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)
161static void master_clk_init(struct clk *clk) 161static 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
169static unsigned long module_clk_recalc(struct clk *clk) 167static unsigned long module_clk_recalc(struct clk *clk)
@@ -541,19 +539,16 @@ static struct clk_ops sh7722_video_clk_ops = {
541static struct clk sh7722_umem_clock = { 539static 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
547static struct clk sh7722_sh_clock = { 544static 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
553static struct clk sh7722_peripheral_clock = { 549static 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
559static struct clk sh7722_sdram_clock = { 554static struct clk sh7722_sdram_clock = {
@@ -564,7 +559,6 @@ static struct clk sh7722_sdram_clock = {
564static struct clk sh7722_r_clock = { 559static 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) &&\