diff options
author | Colin Cross <ccross@android.com> | 2011-02-12 19:43:05 -0500 |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2011-02-21 03:10:43 -0500 |
commit | 4729fd7a7dfe7847b4870801ad12222adaeb016c (patch) | |
tree | 4e91328db46cc6c5ddd91d6e75323020c4623c42 /arch/arm/mach-tegra | |
parent | f151961173bf28047d01b410969f05e485f56d7e (diff) |
ARM: tegra: clock: Convert global lock to a lock per clock
Give each clock its own lock, and remove all lock traversals from
parent to child clocks to prevent AB-BA deadlocks.
This brings the locking in line with the common struct clk
patches and should make conversion simple.
Acked-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Colin Cross <ccross@android.com>
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r-- | arch/arm/mach-tegra/clock.c | 351 | ||||
-rw-r--r-- | arch/arm/mach-tegra/clock.h | 14 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/clk.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra2_clocks.c | 119 |
4 files changed, 318 insertions, 167 deletions
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 8fd96bfb0cde..aff4c5b8c378 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c | |||
@@ -18,83 +18,117 @@ | |||
18 | 18 | ||
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/clk.h> | 20 | #include <linux/clk.h> |
21 | #include <linux/list.h> | 21 | #include <linux/clkdev.h> |
22 | #include <linux/debugfs.h> | ||
23 | #include <linux/delay.h> | ||
22 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/list.h> | ||
23 | #include <linux/module.h> | 26 | #include <linux/module.h> |
24 | #include <linux/debugfs.h> | 27 | #include <linux/sched.h> |
25 | #include <linux/slab.h> | ||
26 | #include <linux/seq_file.h> | 28 | #include <linux/seq_file.h> |
27 | #include <linux/clkdev.h> | 29 | #include <linux/slab.h> |
30 | |||
31 | #include <mach/clk.h> | ||
28 | 32 | ||
29 | #include "board.h" | 33 | #include "board.h" |
30 | #include "clock.h" | 34 | #include "clock.h" |
31 | 35 | ||
36 | /* | ||
37 | * Locking: | ||
38 | * | ||
39 | * Each struct clk has a spinlock. | ||
40 | * | ||
41 | * To avoid AB-BA locking problems, locks must always be traversed from child | ||
42 | * clock to parent clock. For example, when enabling a clock, the clock's lock | ||
43 | * is taken, and then clk_enable is called on the parent, which take's the | ||
44 | * parent clock's lock. There is one exceptions to this ordering: When dumping | ||
45 | * the clock tree through debugfs. In this case, clk_lock_all is called, | ||
46 | * which attemps to iterate through the entire list of clocks and take every | ||
47 | * clock lock. If any call to spin_trylock fails, all locked clocks are | ||
48 | * unlocked, and the process is retried. When all the locks are held, | ||
49 | * the only clock operation that can be called is clk_get_rate_all_locked. | ||
50 | * | ||
51 | * Within a single clock, no clock operation can call another clock operation | ||
52 | * on itself, except for clk_get_rate_locked and clk_set_rate_locked. Any | ||
53 | * clock operation can call any other clock operation on any of it's possible | ||
54 | * parents. | ||
55 | * | ||
56 | * An additional mutex, clock_list_lock, is used to protect the list of all | ||
57 | * clocks. | ||
58 | * | ||
59 | * The clock operations must lock internally to protect against | ||
60 | * read-modify-write on registers that are shared by multiple clocks | ||
61 | */ | ||
62 | static DEFINE_MUTEX(clock_list_lock); | ||
32 | static LIST_HEAD(clocks); | 63 | static LIST_HEAD(clocks); |
33 | 64 | ||
34 | static DEFINE_SPINLOCK(clock_lock); | ||
35 | struct clk *tegra_get_clock_by_name(const char *name) | 65 | struct clk *tegra_get_clock_by_name(const char *name) |
36 | { | 66 | { |
37 | struct clk *c; | 67 | struct clk *c; |
38 | struct clk *ret = NULL; | 68 | struct clk *ret = NULL; |
39 | unsigned long flags; | 69 | mutex_lock(&clock_list_lock); |
40 | spin_lock_irqsave(&clock_lock, flags); | ||
41 | list_for_each_entry(c, &clocks, node) { | 70 | list_for_each_entry(c, &clocks, node) { |
42 | if (strcmp(c->name, name) == 0) { | 71 | if (strcmp(c->name, name) == 0) { |
43 | ret = c; | 72 | ret = c; |
44 | break; | 73 | break; |
45 | } | 74 | } |
46 | } | 75 | } |
47 | spin_unlock_irqrestore(&clock_lock, flags); | 76 | mutex_unlock(&clock_list_lock); |
48 | return ret; | 77 | return ret; |
49 | } | 78 | } |
50 | 79 | ||
51 | static void clk_recalculate_rate(struct clk *c) | 80 | /* Must be called with c->spinlock held */ |
81 | static unsigned long clk_predict_rate_from_parent(struct clk *c, struct clk *p) | ||
52 | { | 82 | { |
53 | u64 rate; | 83 | u64 rate; |
54 | 84 | ||
55 | if (!c->parent) | 85 | rate = clk_get_rate(p); |
56 | return; | ||
57 | |||
58 | rate = c->parent->rate; | ||
59 | 86 | ||
60 | if (c->mul != 0 && c->div != 0) { | 87 | if (c->mul != 0 && c->div != 0) { |
61 | rate = rate * c->mul; | 88 | rate *= c->mul; |
62 | do_div(rate, c->div); | 89 | do_div(rate, c->div); |
63 | } | 90 | } |
64 | 91 | ||
65 | if (rate > c->max_rate) | 92 | return rate; |
66 | pr_warn("clocks: Set clock %s to rate %llu, max is %lu\n", | ||
67 | c->name, rate, c->max_rate); | ||
68 | |||
69 | c->rate = rate; | ||
70 | } | 93 | } |
71 | 94 | ||
72 | int clk_reparent(struct clk *c, struct clk *parent) | 95 | /* Must be called with c->spinlock held */ |
96 | unsigned long clk_get_rate_locked(struct clk *c) | ||
73 | { | 97 | { |
74 | c->parent = parent; | 98 | unsigned long rate; |
75 | list_del(&c->sibling); | ||
76 | list_add_tail(&c->sibling, &parent->children); | ||
77 | return 0; | ||
78 | } | ||
79 | 99 | ||
80 | static void propagate_rate(struct clk *c) | 100 | if (c->parent) |
81 | { | 101 | rate = clk_predict_rate_from_parent(c, c->parent); |
82 | struct clk *clkp; | 102 | else |
103 | rate = c->rate; | ||
83 | 104 | ||
84 | list_for_each_entry(clkp, &c->children, sibling) { | 105 | return rate; |
85 | clk_recalculate_rate(clkp); | ||
86 | propagate_rate(clkp); | ||
87 | } | ||
88 | } | 106 | } |
89 | 107 | ||
90 | void clk_init(struct clk *c) | 108 | unsigned long clk_get_rate(struct clk *c) |
91 | { | 109 | { |
92 | unsigned long flags; | 110 | unsigned long flags; |
111 | unsigned long rate; | ||
93 | 112 | ||
94 | spin_lock_irqsave(&clock_lock, flags); | 113 | spin_lock_irqsave(&c->spinlock, flags); |
95 | 114 | ||
96 | INIT_LIST_HEAD(&c->children); | 115 | rate = clk_get_rate_locked(c); |
97 | INIT_LIST_HEAD(&c->sibling); | 116 | |
117 | spin_unlock_irqrestore(&c->spinlock, flags); | ||
118 | |||
119 | return rate; | ||
120 | } | ||
121 | EXPORT_SYMBOL(clk_get_rate); | ||
122 | |||
123 | int clk_reparent(struct clk *c, struct clk *parent) | ||
124 | { | ||
125 | c->parent = parent; | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | void clk_init(struct clk *c) | ||
130 | { | ||
131 | spin_lock_init(&c->spinlock); | ||
98 | 132 | ||
99 | if (c->ops && c->ops->init) | 133 | if (c->ops && c->ops->init) |
100 | c->ops->init(c); | 134 | c->ops->init(c); |
@@ -108,33 +142,31 @@ void clk_init(struct clk *c) | |||
108 | c->state = ON; | 142 | c->state = ON; |
109 | } | 143 | } |
110 | 144 | ||
111 | clk_recalculate_rate(c); | 145 | mutex_lock(&clock_list_lock); |
112 | |||
113 | list_add(&c->node, &clocks); | 146 | list_add(&c->node, &clocks); |
114 | 147 | mutex_unlock(&clock_list_lock); | |
115 | if (c->parent) | ||
116 | list_add_tail(&c->sibling, &c->parent->children); | ||
117 | |||
118 | spin_unlock_irqrestore(&clock_lock, flags); | ||
119 | } | 148 | } |
120 | 149 | ||
121 | int clk_enable_locked(struct clk *c) | 150 | int clk_enable(struct clk *c) |
122 | { | 151 | { |
123 | int ret; | 152 | int ret = 0; |
153 | unsigned long flags; | ||
154 | |||
155 | spin_lock_irqsave(&c->spinlock, flags); | ||
124 | 156 | ||
125 | if (c->refcnt == 0) { | 157 | if (c->refcnt == 0) { |
126 | if (c->parent) { | 158 | if (c->parent) { |
127 | ret = clk_enable_locked(c->parent); | 159 | ret = clk_enable(c->parent); |
128 | if (ret) | 160 | if (ret) |
129 | return ret; | 161 | goto out; |
130 | } | 162 | } |
131 | 163 | ||
132 | if (c->ops && c->ops->enable) { | 164 | if (c->ops && c->ops->enable) { |
133 | ret = c->ops->enable(c); | 165 | ret = c->ops->enable(c); |
134 | if (ret) { | 166 | if (ret) { |
135 | if (c->parent) | 167 | if (c->parent) |
136 | clk_disable_locked(c->parent); | 168 | clk_disable(c->parent); |
137 | return ret; | 169 | goto out; |
138 | } | 170 | } |
139 | c->state = ON; | 171 | c->state = ON; |
140 | #ifdef CONFIG_DEBUG_FS | 172 | #ifdef CONFIG_DEBUG_FS |
@@ -143,27 +175,21 @@ int clk_enable_locked(struct clk *c) | |||
143 | } | 175 | } |
144 | } | 176 | } |
145 | c->refcnt++; | 177 | c->refcnt++; |
146 | 178 | out: | |
147 | return 0; | 179 | spin_unlock_irqrestore(&c->spinlock, flags); |
180 | return ret; | ||
148 | } | 181 | } |
182 | EXPORT_SYMBOL(clk_enable); | ||
149 | 183 | ||
150 | int clk_enable(struct clk *c) | 184 | void clk_disable(struct clk *c) |
151 | { | 185 | { |
152 | int ret; | ||
153 | unsigned long flags; | 186 | unsigned long flags; |
154 | 187 | ||
155 | spin_lock_irqsave(&clock_lock, flags); | 188 | spin_lock_irqsave(&c->spinlock, flags); |
156 | ret = clk_enable_locked(c); | ||
157 | spin_unlock_irqrestore(&clock_lock, flags); | ||
158 | 189 | ||
159 | return ret; | ||
160 | } | ||
161 | EXPORT_SYMBOL(clk_enable); | ||
162 | |||
163 | void clk_disable_locked(struct clk *c) | ||
164 | { | ||
165 | if (c->refcnt == 0) { | 190 | if (c->refcnt == 0) { |
166 | WARN(1, "Attempting to disable clock %s with refcnt 0", c->name); | 191 | WARN(1, "Attempting to disable clock %s with refcnt 0", c->name); |
192 | spin_unlock_irqrestore(&c->spinlock, flags); | ||
167 | return; | 193 | return; |
168 | } | 194 | } |
169 | if (c->refcnt == 1) { | 195 | if (c->refcnt == 1) { |
@@ -171,49 +197,39 @@ void clk_disable_locked(struct clk *c) | |||
171 | c->ops->disable(c); | 197 | c->ops->disable(c); |
172 | 198 | ||
173 | if (c->parent) | 199 | if (c->parent) |
174 | clk_disable_locked(c->parent); | 200 | clk_disable(c->parent); |
175 | 201 | ||
176 | c->state = OFF; | 202 | c->state = OFF; |
177 | } | 203 | } |
178 | c->refcnt--; | 204 | c->refcnt--; |
179 | } | ||
180 | 205 | ||
181 | void clk_disable(struct clk *c) | 206 | spin_unlock_irqrestore(&c->spinlock, flags); |
182 | { | ||
183 | unsigned long flags; | ||
184 | |||
185 | spin_lock_irqsave(&clock_lock, flags); | ||
186 | clk_disable_locked(c); | ||
187 | spin_unlock_irqrestore(&clock_lock, flags); | ||
188 | } | 207 | } |
189 | EXPORT_SYMBOL(clk_disable); | 208 | EXPORT_SYMBOL(clk_disable); |
190 | 209 | ||
191 | int clk_set_parent_locked(struct clk *c, struct clk *parent) | 210 | int clk_set_parent(struct clk *c, struct clk *parent) |
192 | { | 211 | { |
193 | int ret; | 212 | int ret; |
213 | unsigned long flags; | ||
214 | unsigned long new_rate; | ||
215 | unsigned long old_rate; | ||
194 | 216 | ||
195 | if (!c->ops || !c->ops->set_parent) | 217 | spin_lock_irqsave(&c->spinlock, flags); |
196 | return -ENOSYS; | ||
197 | 218 | ||
198 | ret = c->ops->set_parent(c, parent); | 219 | if (!c->ops || !c->ops->set_parent) { |
199 | 220 | ret = -ENOSYS; | |
200 | if (ret) | 221 | goto out; |
201 | return ret; | 222 | } |
202 | |||
203 | clk_recalculate_rate(c); | ||
204 | 223 | ||
205 | propagate_rate(c); | 224 | new_rate = clk_predict_rate_from_parent(c, parent); |
225 | old_rate = clk_get_rate_locked(c); | ||
206 | 226 | ||
207 | return 0; | 227 | ret = c->ops->set_parent(c, parent); |
208 | } | 228 | if (ret) |
229 | goto out; | ||
209 | 230 | ||
210 | int clk_set_parent(struct clk *c, struct clk *parent) | 231 | out: |
211 | { | 232 | spin_unlock_irqrestore(&c->spinlock, flags); |
212 | int ret; | ||
213 | unsigned long flags; | ||
214 | spin_lock_irqsave(&clock_lock, flags); | ||
215 | ret = clk_set_parent_locked(c, parent); | ||
216 | spin_unlock_irqrestore(&clock_lock, flags); | ||
217 | return ret; | 233 | return ret; |
218 | } | 234 | } |
219 | EXPORT_SYMBOL(clk_set_parent); | 235 | EXPORT_SYMBOL(clk_set_parent); |
@@ -226,62 +242,75 @@ EXPORT_SYMBOL(clk_get_parent); | |||
226 | 242 | ||
227 | int clk_set_rate_locked(struct clk *c, unsigned long rate) | 243 | int clk_set_rate_locked(struct clk *c, unsigned long rate) |
228 | { | 244 | { |
229 | int ret; | ||
230 | |||
231 | if (rate > c->max_rate) | ||
232 | rate = c->max_rate; | ||
233 | |||
234 | if (!c->ops || !c->ops->set_rate) | 245 | if (!c->ops || !c->ops->set_rate) |
235 | return -ENOSYS; | 246 | return -ENOSYS; |
236 | 247 | ||
237 | ret = c->ops->set_rate(c, rate); | 248 | if (rate > c->max_rate) |
238 | 249 | rate = c->max_rate; | |
239 | if (ret) | ||
240 | return ret; | ||
241 | |||
242 | clk_recalculate_rate(c); | ||
243 | |||
244 | propagate_rate(c); | ||
245 | 250 | ||
246 | return 0; | 251 | return c->ops->set_rate(c, rate); |
247 | } | 252 | } |
248 | 253 | ||
249 | int clk_set_rate(struct clk *c, unsigned long rate) | 254 | int clk_set_rate(struct clk *c, unsigned long rate) |
250 | { | 255 | { |
251 | int ret = 0; | 256 | int ret; |
252 | unsigned long flags; | 257 | unsigned long flags; |
253 | 258 | ||
254 | spin_lock_irqsave(&clock_lock, flags); | 259 | spin_lock_irqsave(&c->spinlock, flags); |
260 | |||
255 | ret = clk_set_rate_locked(c, rate); | 261 | ret = clk_set_rate_locked(c, rate); |
256 | spin_unlock_irqrestore(&clock_lock, flags); | 262 | |
263 | spin_unlock_irqrestore(&c->spinlock, flags); | ||
257 | 264 | ||
258 | return ret; | 265 | return ret; |
259 | } | 266 | } |
260 | EXPORT_SYMBOL(clk_set_rate); | 267 | EXPORT_SYMBOL(clk_set_rate); |
261 | 268 | ||
262 | unsigned long clk_get_rate(struct clk *c) | ||
263 | { | ||
264 | unsigned long flags; | ||
265 | unsigned long ret; | ||
266 | 269 | ||
267 | spin_lock_irqsave(&clock_lock, flags); | 270 | /* Must be called with clocks lock and all indvidual clock locks held */ |
271 | unsigned long clk_get_rate_all_locked(struct clk *c) | ||
272 | { | ||
273 | u64 rate; | ||
274 | int mul = 1; | ||
275 | int div = 1; | ||
276 | struct clk *p = c; | ||
277 | |||
278 | while (p) { | ||
279 | c = p; | ||
280 | if (c->mul != 0 && c->div != 0) { | ||
281 | mul *= c->mul; | ||
282 | div *= c->div; | ||
283 | } | ||
284 | p = c->parent; | ||
285 | } | ||
268 | 286 | ||
269 | ret = c->rate; | 287 | rate = c->rate; |
288 | rate *= mul; | ||
289 | do_div(rate, div); | ||
270 | 290 | ||
271 | spin_unlock_irqrestore(&clock_lock, flags); | 291 | return rate; |
272 | return ret; | ||
273 | } | 292 | } |
274 | EXPORT_SYMBOL(clk_get_rate); | ||
275 | 293 | ||
276 | long clk_round_rate(struct clk *c, unsigned long rate) | 294 | long clk_round_rate(struct clk *c, unsigned long rate) |
277 | { | 295 | { |
278 | if (!c->ops || !c->ops->round_rate) | 296 | unsigned long flags; |
279 | return -ENOSYS; | 297 | long ret; |
298 | |||
299 | spin_lock_irqsave(&c->spinlock, flags); | ||
300 | |||
301 | if (!c->ops || !c->ops->round_rate) { | ||
302 | ret = -ENOSYS; | ||
303 | goto out; | ||
304 | } | ||
280 | 305 | ||
281 | if (rate > c->max_rate) | 306 | if (rate > c->max_rate) |
282 | rate = c->max_rate; | 307 | rate = c->max_rate; |
283 | 308 | ||
284 | return c->ops->round_rate(c, rate); | 309 | ret = c->ops->round_rate(c, rate); |
310 | |||
311 | out: | ||
312 | spin_unlock_irqrestore(&c->spinlock, flags); | ||
313 | return ret; | ||
285 | } | 314 | } |
286 | EXPORT_SYMBOL(clk_round_rate); | 315 | EXPORT_SYMBOL(clk_round_rate); |
287 | 316 | ||
@@ -364,13 +393,75 @@ void __init tegra_init_clock(void) | |||
364 | } | 393 | } |
365 | 394 | ||
366 | #ifdef CONFIG_DEBUG_FS | 395 | #ifdef CONFIG_DEBUG_FS |
396 | |||
397 | static int __clk_lock_all_spinlocks(void) | ||
398 | { | ||
399 | struct clk *c; | ||
400 | |||
401 | list_for_each_entry(c, &clocks, node) | ||
402 | if (!spin_trylock(&c->spinlock)) | ||
403 | goto unlock_spinlocks; | ||
404 | |||
405 | return 0; | ||
406 | |||
407 | unlock_spinlocks: | ||
408 | list_for_each_entry_continue_reverse(c, &clocks, node) | ||
409 | spin_unlock(&c->spinlock); | ||
410 | |||
411 | return -EAGAIN; | ||
412 | } | ||
413 | |||
414 | static void __clk_unlock_all_spinlocks(void) | ||
415 | { | ||
416 | struct clk *c; | ||
417 | |||
418 | list_for_each_entry_reverse(c, &clocks, node) | ||
419 | spin_unlock(&c->spinlock); | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | * This function retries until it can take all locks, and may take | ||
424 | * an arbitrarily long time to complete. | ||
425 | * Must be called with irqs enabled, returns with irqs disabled | ||
426 | * Must be called with clock_list_lock held | ||
427 | */ | ||
428 | static void clk_lock_all(void) | ||
429 | { | ||
430 | int ret; | ||
431 | retry: | ||
432 | local_irq_disable(); | ||
433 | |||
434 | ret = __clk_lock_all_spinlocks(); | ||
435 | if (ret) | ||
436 | goto failed_spinlocks; | ||
437 | |||
438 | /* All locks taken successfully, return */ | ||
439 | return; | ||
440 | |||
441 | failed_spinlocks: | ||
442 | local_irq_enable(); | ||
443 | yield(); | ||
444 | goto retry; | ||
445 | } | ||
446 | |||
447 | /* | ||
448 | * Unlocks all clocks after a clk_lock_all | ||
449 | * Must be called with irqs disabled, returns with irqs enabled | ||
450 | * Must be called with clock_list_lock held | ||
451 | */ | ||
452 | static void clk_unlock_all(void) | ||
453 | { | ||
454 | __clk_unlock_all_spinlocks(); | ||
455 | |||
456 | local_irq_enable(); | ||
457 | } | ||
458 | |||
367 | static struct dentry *clk_debugfs_root; | 459 | static struct dentry *clk_debugfs_root; |
368 | 460 | ||
369 | 461 | ||
370 | static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level) | 462 | static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level) |
371 | { | 463 | { |
372 | struct clk *child; | 464 | struct clk *child; |
373 | struct clk *safe; | ||
374 | const char *state = "uninit"; | 465 | const char *state = "uninit"; |
375 | char div[8] = {0}; | 466 | char div[8] = {0}; |
376 | 467 | ||
@@ -401,8 +492,12 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level) | |||
401 | c->rate > c->max_rate ? '!' : ' ', | 492 | c->rate > c->max_rate ? '!' : ' ', |
402 | !c->set ? '*' : ' ', | 493 | !c->set ? '*' : ' ', |
403 | 30 - level * 3, c->name, | 494 | 30 - level * 3, c->name, |
404 | state, c->refcnt, div, c->rate); | 495 | state, c->refcnt, div, clk_get_rate_all_locked(c)); |
405 | list_for_each_entry_safe(child, safe, &c->children, sibling) { | 496 | |
497 | list_for_each_entry(child, &clocks, node) { | ||
498 | if (child->parent != c) | ||
499 | continue; | ||
500 | |||
406 | clock_tree_show_one(s, child, level + 1); | 501 | clock_tree_show_one(s, child, level + 1); |
407 | } | 502 | } |
408 | } | 503 | } |
@@ -410,14 +505,20 @@ static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level) | |||
410 | static int clock_tree_show(struct seq_file *s, void *data) | 505 | static int clock_tree_show(struct seq_file *s, void *data) |
411 | { | 506 | { |
412 | struct clk *c; | 507 | struct clk *c; |
413 | unsigned long flags; | ||
414 | seq_printf(s, " clock state ref div rate\n"); | 508 | seq_printf(s, " clock state ref div rate\n"); |
415 | seq_printf(s, "--------------------------------------------------------------\n"); | 509 | seq_printf(s, "--------------------------------------------------------------\n"); |
416 | spin_lock_irqsave(&clock_lock, flags); | 510 | |
511 | mutex_lock(&clock_list_lock); | ||
512 | |||
513 | clk_lock_all(); | ||
514 | |||
417 | list_for_each_entry(c, &clocks, node) | 515 | list_for_each_entry(c, &clocks, node) |
418 | if (c->parent == NULL) | 516 | if (c->parent == NULL) |
419 | clock_tree_show_one(s, c, 0); | 517 | clock_tree_show_one(s, c, 0); |
420 | spin_unlock_irqrestore(&clock_lock, flags); | 518 | |
519 | clk_unlock_all(); | ||
520 | |||
521 | mutex_unlock(&clock_list_lock); | ||
421 | return 0; | 522 | return 0; |
422 | } | 523 | } |
423 | 524 | ||
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h index 20f0ce69bbaf..a63dbf93d9b0 100644 --- a/arch/arm/mach-tegra/clock.h +++ b/arch/arm/mach-tegra/clock.h | |||
@@ -20,8 +20,9 @@ | |||
20 | #ifndef __MACH_TEGRA_CLOCK_H | 20 | #ifndef __MACH_TEGRA_CLOCK_H |
21 | #define __MACH_TEGRA_CLOCK_H | 21 | #define __MACH_TEGRA_CLOCK_H |
22 | 22 | ||
23 | #include <linux/list.h> | ||
24 | #include <linux/clkdev.h> | 23 | #include <linux/clkdev.h> |
24 | #include <linux/list.h> | ||
25 | #include <linux/spinlock.h> | ||
25 | 26 | ||
26 | #define DIV_BUS (1 << 0) | 27 | #define DIV_BUS (1 << 0) |
27 | #define DIV_U71 (1 << 1) | 28 | #define DIV_U71 (1 << 1) |
@@ -75,8 +76,6 @@ enum clk_state { | |||
75 | struct clk { | 76 | struct clk { |
76 | /* node for master clocks list */ | 77 | /* node for master clocks list */ |
77 | struct list_head node; /* node for list of all clocks */ | 78 | struct list_head node; /* node for list of all clocks */ |
78 | struct list_head children; /* list of children */ | ||
79 | struct list_head sibling; /* node for children */ | ||
80 | struct clk_lookup lookup; | 79 | struct clk_lookup lookup; |
81 | 80 | ||
82 | #ifdef CONFIG_DEBUG_FS | 81 | #ifdef CONFIG_DEBUG_FS |
@@ -122,8 +121,9 @@ struct clk { | |||
122 | struct clk *backup; | 121 | struct clk *backup; |
123 | } cpu; | 122 | } cpu; |
124 | } u; | 123 | } u; |
125 | }; | ||
126 | 124 | ||
125 | spinlock_t spinlock; | ||
126 | }; | ||
127 | 127 | ||
128 | struct clk_duplicate { | 128 | struct clk_duplicate { |
129 | const char *name; | 129 | const char *name; |
@@ -143,11 +143,9 @@ void tegra2_periph_reset_assert(struct clk *c); | |||
143 | void clk_init(struct clk *clk); | 143 | void clk_init(struct clk *clk); |
144 | struct clk *tegra_get_clock_by_name(const char *name); | 144 | struct clk *tegra_get_clock_by_name(const char *name); |
145 | unsigned long clk_measure_input_freq(void); | 145 | unsigned long clk_measure_input_freq(void); |
146 | void clk_disable_locked(struct clk *c); | ||
147 | int clk_enable_locked(struct clk *c); | ||
148 | int clk_set_parent_locked(struct clk *c, struct clk *parent); | ||
149 | int clk_set_rate_locked(struct clk *c, unsigned long rate); | ||
150 | int clk_reparent(struct clk *c, struct clk *parent); | 146 | int clk_reparent(struct clk *c, struct clk *parent); |
151 | void tegra_clk_init_from_table(struct tegra_clk_init_table *table); | 147 | void tegra_clk_init_from_table(struct tegra_clk_init_table *table); |
148 | unsigned long clk_get_rate_locked(struct clk *c); | ||
149 | int clk_set_rate_locked(struct clk *c, unsigned long rate); | ||
152 | 150 | ||
153 | #endif | 151 | #endif |
diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h index 633865298ae4..fa7f9ca1fdbd 100644 --- a/arch/arm/mach-tegra/include/mach/clk.h +++ b/arch/arm/mach-tegra/include/mach/clk.h | |||
@@ -25,4 +25,5 @@ struct clk; | |||
25 | void tegra_periph_reset_deassert(struct clk *c); | 25 | void tegra_periph_reset_deassert(struct clk *c); |
26 | void tegra_periph_reset_assert(struct clk *c); | 26 | void tegra_periph_reset_assert(struct clk *c); |
27 | 27 | ||
28 | unsigned long clk_get_rate_all_locked(struct clk *c); | ||
28 | #endif | 29 | #endif |
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index 324c4d33ad16..ea07f513e90c 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c | |||
@@ -23,8 +23,8 @@ | |||
23 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/io.h> | 25 | #include <linux/io.h> |
26 | #include <linux/hrtimer.h> | ||
27 | #include <linux/clkdev.h> | 26 | #include <linux/clkdev.h> |
27 | #include <linux/clk.h> | ||
28 | 28 | ||
29 | #include <mach/iomap.h> | 29 | #include <mach/iomap.h> |
30 | #include <mach/suspend.h> | 30 | #include <mach/suspend.h> |
@@ -147,6 +147,13 @@ | |||
147 | static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE); | 147 | static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE); |
148 | static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); | 148 | static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); |
149 | 149 | ||
150 | /* | ||
151 | * Some clocks share a register with other clocks. Any clock op that | ||
152 | * non-atomically modifies a register used by another clock must lock | ||
153 | * clock_register_lock first. | ||
154 | */ | ||
155 | static DEFINE_SPINLOCK(clock_register_lock); | ||
156 | |||
150 | #define clk_writel(value, reg) \ | 157 | #define clk_writel(value, reg) \ |
151 | __raw_writel(value, (u32)reg_clk_base + (reg)) | 158 | __raw_writel(value, (u32)reg_clk_base + (reg)) |
152 | #define clk_readl(reg) \ | 159 | #define clk_readl(reg) \ |
@@ -330,12 +337,12 @@ static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p) | |||
330 | val |= sel->value << shift; | 337 | val |= sel->value << shift; |
331 | 338 | ||
332 | if (c->refcnt) | 339 | if (c->refcnt) |
333 | clk_enable_locked(p); | 340 | clk_enable(p); |
334 | 341 | ||
335 | clk_writel(val, c->reg); | 342 | clk_writel(val, c->reg); |
336 | 343 | ||
337 | if (c->refcnt && c->parent) | 344 | if (c->refcnt && c->parent) |
338 | clk_disable_locked(c->parent); | 345 | clk_disable(c->parent); |
339 | 346 | ||
340 | clk_reparent(c, p); | 347 | clk_reparent(c, p); |
341 | return 0; | 348 | return 0; |
@@ -378,22 +385,22 @@ static void tegra2_cpu_clk_disable(struct clk *c) | |||
378 | static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate) | 385 | static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate) |
379 | { | 386 | { |
380 | int ret; | 387 | int ret; |
381 | ret = clk_set_parent_locked(c->parent, c->u.cpu.backup); | 388 | ret = clk_set_parent(c->parent, c->u.cpu.backup); |
382 | if (ret) { | 389 | if (ret) { |
383 | pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.backup->name); | 390 | pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.backup->name); |
384 | return ret; | 391 | return ret; |
385 | } | 392 | } |
386 | 393 | ||
387 | if (rate == c->u.cpu.backup->rate) | 394 | if (rate == clk_get_rate(c->u.cpu.backup)) |
388 | goto out; | 395 | goto out; |
389 | 396 | ||
390 | ret = clk_set_rate_locked(c->u.cpu.main, rate); | 397 | ret = clk_set_rate(c->u.cpu.main, rate); |
391 | if (ret) { | 398 | if (ret) { |
392 | pr_err("Failed to change cpu pll to %lu\n", rate); | 399 | pr_err("Failed to change cpu pll to %lu\n", rate); |
393 | return ret; | 400 | return ret; |
394 | } | 401 | } |
395 | 402 | ||
396 | ret = clk_set_parent_locked(c->parent, c->u.cpu.main); | 403 | ret = clk_set_parent(c->parent, c->u.cpu.main); |
397 | if (ret) { | 404 | if (ret) { |
398 | pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.main->name); | 405 | pr_err("Failed to switch cpu to clock %s\n", c->u.cpu.main->name); |
399 | return ret; | 406 | return ret; |
@@ -421,24 +428,45 @@ static void tegra2_bus_clk_init(struct clk *c) | |||
421 | 428 | ||
422 | static int tegra2_bus_clk_enable(struct clk *c) | 429 | static int tegra2_bus_clk_enable(struct clk *c) |
423 | { | 430 | { |
424 | u32 val = clk_readl(c->reg); | 431 | u32 val; |
432 | unsigned long flags; | ||
433 | |||
434 | spin_lock_irqsave(&clock_register_lock, flags); | ||
435 | |||
436 | val = clk_readl(c->reg); | ||
425 | val &= ~(BUS_CLK_DISABLE << c->reg_shift); | 437 | val &= ~(BUS_CLK_DISABLE << c->reg_shift); |
426 | clk_writel(val, c->reg); | 438 | clk_writel(val, c->reg); |
439 | |||
440 | spin_unlock_irqrestore(&clock_register_lock, flags); | ||
441 | |||
427 | return 0; | 442 | return 0; |
428 | } | 443 | } |
429 | 444 | ||
430 | static void tegra2_bus_clk_disable(struct clk *c) | 445 | static void tegra2_bus_clk_disable(struct clk *c) |
431 | { | 446 | { |
432 | u32 val = clk_readl(c->reg); | 447 | u32 val; |
448 | unsigned long flags; | ||
449 | |||
450 | spin_lock_irqsave(&clock_register_lock, flags); | ||
451 | |||
452 | val = clk_readl(c->reg); | ||
433 | val |= BUS_CLK_DISABLE << c->reg_shift; | 453 | val |= BUS_CLK_DISABLE << c->reg_shift; |
434 | clk_writel(val, c->reg); | 454 | clk_writel(val, c->reg); |
455 | |||
456 | spin_unlock_irqrestore(&clock_register_lock, flags); | ||
435 | } | 457 | } |
436 | 458 | ||
437 | static int tegra2_bus_clk_set_rate(struct clk *c, unsigned long rate) | 459 | static int tegra2_bus_clk_set_rate(struct clk *c, unsigned long rate) |
438 | { | 460 | { |
439 | u32 val = clk_readl(c->reg); | 461 | u32 val; |
440 | unsigned long parent_rate = c->parent->rate; | 462 | unsigned long parent_rate = clk_get_rate(c->parent); |
463 | unsigned long flags; | ||
464 | int ret = -EINVAL; | ||
441 | int i; | 465 | int i; |
466 | |||
467 | spin_lock_irqsave(&clock_register_lock, flags); | ||
468 | |||
469 | val = clk_readl(c->reg); | ||
442 | for (i = 1; i <= 4; i++) { | 470 | for (i = 1; i <= 4; i++) { |
443 | if (rate == parent_rate / i) { | 471 | if (rate == parent_rate / i) { |
444 | val &= ~(BUS_CLK_DIV_MASK << c->reg_shift); | 472 | val &= ~(BUS_CLK_DIV_MASK << c->reg_shift); |
@@ -446,10 +474,14 @@ static int tegra2_bus_clk_set_rate(struct clk *c, unsigned long rate) | |||
446 | clk_writel(val, c->reg); | 474 | clk_writel(val, c->reg); |
447 | c->div = i; | 475 | c->div = i; |
448 | c->mul = 1; | 476 | c->mul = 1; |
449 | return 0; | 477 | ret = 0; |
478 | break; | ||
450 | } | 479 | } |
451 | } | 480 | } |
452 | return -EINVAL; | 481 | |
482 | spin_unlock_irqrestore(&clock_register_lock, flags); | ||
483 | |||
484 | return ret; | ||
453 | } | 485 | } |
454 | 486 | ||
455 | static struct clk_ops tegra_bus_ops = { | 487 | static struct clk_ops tegra_bus_ops = { |
@@ -511,14 +543,15 @@ static void tegra2_blink_clk_disable(struct clk *c) | |||
511 | 543 | ||
512 | static int tegra2_blink_clk_set_rate(struct clk *c, unsigned long rate) | 544 | static int tegra2_blink_clk_set_rate(struct clk *c, unsigned long rate) |
513 | { | 545 | { |
514 | if (rate >= c->parent->rate) { | 546 | unsigned long parent_rate = clk_get_rate(c->parent); |
547 | if (rate >= parent_rate) { | ||
515 | c->div = 1; | 548 | c->div = 1; |
516 | pmc_writel(0, c->reg); | 549 | pmc_writel(0, c->reg); |
517 | } else { | 550 | } else { |
518 | unsigned int on_off; | 551 | unsigned int on_off; |
519 | u32 val; | 552 | u32 val; |
520 | 553 | ||
521 | on_off = DIV_ROUND_UP(c->parent->rate / 8, rate); | 554 | on_off = DIV_ROUND_UP(parent_rate / 8, rate); |
522 | c->div = on_off * 8; | 555 | c->div = on_off * 8; |
523 | 556 | ||
524 | val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) << | 557 | val = (on_off & PMC_BLINK_TIMER_DATA_ON_MASK) << |
@@ -604,7 +637,7 @@ static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate) | |||
604 | 637 | ||
605 | pr_debug("%s: %s %lu\n", __func__, c->name, rate); | 638 | pr_debug("%s: %s %lu\n", __func__, c->name, rate); |
606 | 639 | ||
607 | input_rate = c->parent->rate; | 640 | input_rate = clk_get_rate(c->parent); |
608 | for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { | 641 | for (sel = c->u.pll.freq_table; sel->input_rate != 0; sel++) { |
609 | if (sel->input_rate == input_rate && sel->output_rate == rate) { | 642 | if (sel->input_rate == input_rate && sel->output_rate == rate) { |
610 | c->mul = sel->n; | 643 | c->mul = sel->n; |
@@ -717,9 +750,11 @@ static int tegra2_pll_div_clk_enable(struct clk *c) | |||
717 | { | 750 | { |
718 | u32 val; | 751 | u32 val; |
719 | u32 new_val; | 752 | u32 new_val; |
753 | unsigned long flags; | ||
720 | 754 | ||
721 | pr_debug("%s: %s\n", __func__, c->name); | 755 | pr_debug("%s: %s\n", __func__, c->name); |
722 | if (c->flags & DIV_U71) { | 756 | if (c->flags & DIV_U71) { |
757 | spin_lock_irqsave(&clock_register_lock, flags); | ||
723 | val = clk_readl(c->reg); | 758 | val = clk_readl(c->reg); |
724 | new_val = val >> c->reg_shift; | 759 | new_val = val >> c->reg_shift; |
725 | new_val &= 0xFFFF; | 760 | new_val &= 0xFFFF; |
@@ -729,12 +764,15 @@ static int tegra2_pll_div_clk_enable(struct clk *c) | |||
729 | val &= ~(0xFFFF << c->reg_shift); | 764 | val &= ~(0xFFFF << c->reg_shift); |
730 | val |= new_val << c->reg_shift; | 765 | val |= new_val << c->reg_shift; |
731 | clk_writel(val, c->reg); | 766 | clk_writel(val, c->reg); |
767 | spin_unlock_irqrestore(&clock_register_lock, flags); | ||
732 | return 0; | 768 | return 0; |
733 | } else if (c->flags & DIV_2) { | 769 | } else if (c->flags & DIV_2) { |
734 | BUG_ON(!(c->flags & PLLD)); | 770 | BUG_ON(!(c->flags & PLLD)); |
771 | spin_lock_irqsave(&clock_register_lock, flags); | ||
735 | val = clk_readl(c->reg); | 772 | val = clk_readl(c->reg); |
736 | val &= ~PLLD_MISC_DIV_RST; | 773 | val &= ~PLLD_MISC_DIV_RST; |
737 | clk_writel(val, c->reg); | 774 | clk_writel(val, c->reg); |
775 | spin_unlock_irqrestore(&clock_register_lock, flags); | ||
738 | return 0; | 776 | return 0; |
739 | } | 777 | } |
740 | return -EINVAL; | 778 | return -EINVAL; |
@@ -744,9 +782,11 @@ static void tegra2_pll_div_clk_disable(struct clk *c) | |||
744 | { | 782 | { |
745 | u32 val; | 783 | u32 val; |
746 | u32 new_val; | 784 | u32 new_val; |
785 | unsigned long flags; | ||
747 | 786 | ||
748 | pr_debug("%s: %s\n", __func__, c->name); | 787 | pr_debug("%s: %s\n", __func__, c->name); |
749 | if (c->flags & DIV_U71) { | 788 | if (c->flags & DIV_U71) { |
789 | spin_lock_irqsave(&clock_register_lock, flags); | ||
750 | val = clk_readl(c->reg); | 790 | val = clk_readl(c->reg); |
751 | new_val = val >> c->reg_shift; | 791 | new_val = val >> c->reg_shift; |
752 | new_val &= 0xFFFF; | 792 | new_val &= 0xFFFF; |
@@ -756,11 +796,14 @@ static void tegra2_pll_div_clk_disable(struct clk *c) | |||
756 | val &= ~(0xFFFF << c->reg_shift); | 796 | val &= ~(0xFFFF << c->reg_shift); |
757 | val |= new_val << c->reg_shift; | 797 | val |= new_val << c->reg_shift; |
758 | clk_writel(val, c->reg); | 798 | clk_writel(val, c->reg); |
799 | spin_unlock_irqrestore(&clock_register_lock, flags); | ||
759 | } else if (c->flags & DIV_2) { | 800 | } else if (c->flags & DIV_2) { |
760 | BUG_ON(!(c->flags & PLLD)); | 801 | BUG_ON(!(c->flags & PLLD)); |
802 | spin_lock_irqsave(&clock_register_lock, flags); | ||
761 | val = clk_readl(c->reg); | 803 | val = clk_readl(c->reg); |
762 | val |= PLLD_MISC_DIV_RST; | 804 | val |= PLLD_MISC_DIV_RST; |
763 | clk_writel(val, c->reg); | 805 | clk_writel(val, c->reg); |
806 | spin_unlock_irqrestore(&clock_register_lock, flags); | ||
764 | } | 807 | } |
765 | } | 808 | } |
766 | 809 | ||
@@ -769,10 +812,14 @@ static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate) | |||
769 | u32 val; | 812 | u32 val; |
770 | u32 new_val; | 813 | u32 new_val; |
771 | int divider_u71; | 814 | int divider_u71; |
815 | unsigned long parent_rate = clk_get_rate(c->parent); | ||
816 | unsigned long flags; | ||
817 | |||
772 | pr_debug("%s: %s %lu\n", __func__, c->name, rate); | 818 | pr_debug("%s: %s %lu\n", __func__, c->name, rate); |
773 | if (c->flags & DIV_U71) { | 819 | if (c->flags & DIV_U71) { |
774 | divider_u71 = clk_div71_get_divider(c->parent->rate, rate); | 820 | divider_u71 = clk_div71_get_divider(parent_rate, rate); |
775 | if (divider_u71 >= 0) { | 821 | if (divider_u71 >= 0) { |
822 | spin_lock_irqsave(&clock_register_lock, flags); | ||
776 | val = clk_readl(c->reg); | 823 | val = clk_readl(c->reg); |
777 | new_val = val >> c->reg_shift; | 824 | new_val = val >> c->reg_shift; |
778 | new_val &= 0xFFFF; | 825 | new_val &= 0xFFFF; |
@@ -786,10 +833,11 @@ static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate) | |||
786 | clk_writel(val, c->reg); | 833 | clk_writel(val, c->reg); |
787 | c->div = divider_u71 + 2; | 834 | c->div = divider_u71 + 2; |
788 | c->mul = 2; | 835 | c->mul = 2; |
836 | spin_unlock_irqrestore(&clock_register_lock, flags); | ||
789 | return 0; | 837 | return 0; |
790 | } | 838 | } |
791 | } else if (c->flags & DIV_2) { | 839 | } else if (c->flags & DIV_2) { |
792 | if (c->parent->rate == rate * 2) | 840 | if (parent_rate == rate * 2) |
793 | return 0; | 841 | return 0; |
794 | } | 842 | } |
795 | return -EINVAL; | 843 | return -EINVAL; |
@@ -798,15 +846,16 @@ static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate) | |||
798 | static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate) | 846 | static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate) |
799 | { | 847 | { |
800 | int divider; | 848 | int divider; |
849 | unsigned long parent_rate = clk_get_rate(c->parent); | ||
801 | pr_debug("%s: %s %lu\n", __func__, c->name, rate); | 850 | pr_debug("%s: %s %lu\n", __func__, c->name, rate); |
802 | 851 | ||
803 | if (c->flags & DIV_U71) { | 852 | if (c->flags & DIV_U71) { |
804 | divider = clk_div71_get_divider(c->parent->rate, rate); | 853 | divider = clk_div71_get_divider(parent_rate, rate); |
805 | if (divider < 0) | 854 | if (divider < 0) |
806 | return divider; | 855 | return divider; |
807 | return c->parent->rate * 2 / (divider + 2); | 856 | return parent_rate * 2 / (divider + 2); |
808 | } else if (c->flags & DIV_2) { | 857 | } else if (c->flags & DIV_2) { |
809 | return c->parent->rate / 2; | 858 | return parent_rate / 2; |
810 | } | 859 | } |
811 | return -EINVAL; | 860 | return -EINVAL; |
812 | } | 861 | } |
@@ -912,12 +961,12 @@ static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p) | |||
912 | val |= (sel->value) << PERIPH_CLK_SOURCE_SHIFT; | 961 | val |= (sel->value) << PERIPH_CLK_SOURCE_SHIFT; |
913 | 962 | ||
914 | if (c->refcnt) | 963 | if (c->refcnt) |
915 | clk_enable_locked(p); | 964 | clk_enable(p); |
916 | 965 | ||
917 | clk_writel(val, c->reg); | 966 | clk_writel(val, c->reg); |
918 | 967 | ||
919 | if (c->refcnt && c->parent) | 968 | if (c->refcnt && c->parent) |
920 | clk_disable_locked(c->parent); | 969 | clk_disable(c->parent); |
921 | 970 | ||
922 | clk_reparent(c, p); | 971 | clk_reparent(c, p); |
923 | return 0; | 972 | return 0; |
@@ -931,9 +980,10 @@ static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate) | |||
931 | { | 980 | { |
932 | u32 val; | 981 | u32 val; |
933 | int divider; | 982 | int divider; |
934 | pr_debug("%s: %lu\n", __func__, rate); | 983 | unsigned long parent_rate = clk_get_rate(c->parent); |
984 | |||
935 | if (c->flags & DIV_U71) { | 985 | if (c->flags & DIV_U71) { |
936 | divider = clk_div71_get_divider(c->parent->rate, rate); | 986 | divider = clk_div71_get_divider(parent_rate, rate); |
937 | if (divider >= 0) { | 987 | if (divider >= 0) { |
938 | val = clk_readl(c->reg); | 988 | val = clk_readl(c->reg); |
939 | val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK; | 989 | val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK; |
@@ -944,7 +994,7 @@ static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate) | |||
944 | return 0; | 994 | return 0; |
945 | } | 995 | } |
946 | } else if (c->flags & DIV_U16) { | 996 | } else if (c->flags & DIV_U16) { |
947 | divider = clk_div16_get_divider(c->parent->rate, rate); | 997 | divider = clk_div16_get_divider(parent_rate, rate); |
948 | if (divider >= 0) { | 998 | if (divider >= 0) { |
949 | val = clk_readl(c->reg); | 999 | val = clk_readl(c->reg); |
950 | val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK; | 1000 | val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK; |
@@ -954,7 +1004,7 @@ static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate) | |||
954 | c->mul = 1; | 1004 | c->mul = 1; |
955 | return 0; | 1005 | return 0; |
956 | } | 1006 | } |
957 | } else if (c->parent->rate <= rate) { | 1007 | } else if (parent_rate <= rate) { |
958 | c->div = 1; | 1008 | c->div = 1; |
959 | c->mul = 1; | 1009 | c->mul = 1; |
960 | return 0; | 1010 | return 0; |
@@ -966,19 +1016,20 @@ static long tegra2_periph_clk_round_rate(struct clk *c, | |||
966 | unsigned long rate) | 1016 | unsigned long rate) |
967 | { | 1017 | { |
968 | int divider; | 1018 | int divider; |
1019 | unsigned long parent_rate = clk_get_rate(c->parent); | ||
969 | pr_debug("%s: %s %lu\n", __func__, c->name, rate); | 1020 | pr_debug("%s: %s %lu\n", __func__, c->name, rate); |
970 | 1021 | ||
971 | if (c->flags & DIV_U71) { | 1022 | if (c->flags & DIV_U71) { |
972 | divider = clk_div71_get_divider(c->parent->rate, rate); | 1023 | divider = clk_div71_get_divider(parent_rate, rate); |
973 | if (divider < 0) | 1024 | if (divider < 0) |
974 | return divider; | 1025 | return divider; |
975 | 1026 | ||
976 | return c->parent->rate * 2 / (divider + 2); | 1027 | return parent_rate * 2 / (divider + 2); |
977 | } else if (c->flags & DIV_U16) { | 1028 | } else if (c->flags & DIV_U16) { |
978 | divider = clk_div16_get_divider(c->parent->rate, rate); | 1029 | divider = clk_div16_get_divider(parent_rate, rate); |
979 | if (divider < 0) | 1030 | if (divider < 0) |
980 | return divider; | 1031 | return divider; |
981 | return c->parent->rate / (divider + 1); | 1032 | return parent_rate / (divider + 1); |
982 | } | 1033 | } |
983 | return -EINVAL; | 1034 | return -EINVAL; |
984 | } | 1035 | } |
@@ -1006,7 +1057,7 @@ static void tegra2_clk_double_init(struct clk *c) | |||
1006 | 1057 | ||
1007 | static int tegra2_clk_double_set_rate(struct clk *c, unsigned long rate) | 1058 | static int tegra2_clk_double_set_rate(struct clk *c, unsigned long rate) |
1008 | { | 1059 | { |
1009 | if (rate != 2 * c->parent->rate) | 1060 | if (rate != 2 * clk_get_rate(c->parent)) |
1010 | return -EINVAL; | 1061 | return -EINVAL; |
1011 | c->mul = 2; | 1062 | c->mul = 2; |
1012 | c->div = 1; | 1063 | c->div = 1; |
@@ -1057,12 +1108,12 @@ static int tegra2_audio_sync_clk_set_parent(struct clk *c, struct clk *p) | |||
1057 | val |= sel->value; | 1108 | val |= sel->value; |
1058 | 1109 | ||
1059 | if (c->refcnt) | 1110 | if (c->refcnt) |
1060 | clk_enable_locked(p); | 1111 | clk_enable(p); |
1061 | 1112 | ||
1062 | clk_writel(val, c->reg); | 1113 | clk_writel(val, c->reg); |
1063 | 1114 | ||
1064 | if (c->refcnt && c->parent) | 1115 | if (c->refcnt && c->parent) |
1065 | clk_disable_locked(c->parent); | 1116 | clk_disable(c->parent); |
1066 | 1117 | ||
1067 | clk_reparent(c, p); | 1118 | clk_reparent(c, p); |
1068 | return 0; | 1119 | return 0; |