aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2010-05-18 20:40:24 -0400
committerPaul Walmsley <paul@pwsan.com>2010-05-20 14:31:06 -0400
commit435699db6a3d81bfd36d25150177399a4f6048d5 (patch)
treef6fa03a580c900178ea6b2b0c64e9272460d3cd3 /arch
parentd74b4949714741f4c58cd1801a6a92737b89a61c (diff)
OMAP2+ clock: clean up clkt_clksel.c
This patch cleans up arch/arm/mach-omap2/clkt_clksel.c. It: - makes several functions static that are not called outside the file; - adds documentation; - makes some code paths easier to read (hopefully), by breaking up compound statements and removing redundant checks; - converts some pr_err()s that indicate clock tree data problems into WARN()s, so they are more likely to be noticed; - and moves omap2_clk_round_rate() back into mach-omap2/clock.c, its proper home, since it is not clksel-specific. Signed-off-by: Paul Walmsley <paul@pwsan.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-omap2/clkt_clksel.c423
-rw-r--r--arch/arm/mach-omap2/clock.c9
-rw-r--r--arch/arm/mach-omap2/clock.h11
3 files changed, 266 insertions, 177 deletions
diff --git a/arch/arm/mach-omap2/clkt_clksel.c b/arch/arm/mach-omap2/clkt_clksel.c
index 9a23aebeea7e..a781cd6795a4 100644
--- a/arch/arm/mach-omap2/clkt_clksel.c
+++ b/arch/arm/mach-omap2/clkt_clksel.c
@@ -12,8 +12,26 @@
12 * it under the terms of the GNU General Public License version 2 as 12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation. 13 * published by the Free Software Foundation.
14 * 14 *
15 * XXX At some point these clksel clocks should be split into 15 *
16 * "divider" clocks and "mux" clocks to better match the hardware. 16 * clksel clocks are clocks that do not have a fixed parent, or that
17 * can divide their parent's rate, or possibly both at the same time, based
18 * on the contents of a hardware register bitfield.
19 *
20 * All of the various mux and divider settings can be encoded into
21 * struct clksel* data structures, and then these can be autogenerated
22 * from some hardware database for each new chip generation. This
23 * should avoid the need to write, review, and validate a lot of new
24 * clock code for each new chip, since it can be exported from the SoC
25 * design flow. This is now done on OMAP4.
26 *
27 * The fusion of mux and divider clocks is a software creation. In
28 * hardware reality, the multiplexer (parent selection) and the
29 * divider exist separately. XXX At some point these clksel clocks
30 * should be split into "divider" clocks and "mux" clocks to better
31 * match the hardware.
32 *
33 * (The name "clksel" comes from the name of the corresponding
34 * register field in the OMAP2/3 family of SoCs.)
17 * 35 *
18 * XXX Currently these clocks are only used in the OMAP2/3/4 code, but 36 * XXX Currently these clocks are only used in the OMAP2/3/4 code, but
19 * many of the OMAP1 clocks should be convertible to use this 37 * many of the OMAP1 clocks should be convertible to use this
@@ -29,14 +47,11 @@
29#include <plat/clock.h> 47#include <plat/clock.h>
30 48
31#include "clock.h" 49#include "clock.h"
32#include "cm.h"
33#include "cm-regbits-24xx.h"
34#include "cm-regbits-34xx.h"
35 50
36/* Private functions */ 51/* Private functions */
37 52
38/** 53/**
39 * _omap2_get_clksel_by_parent - return clksel struct for a given clk & parent 54 * _get_clksel_by_parent() - return clksel struct for a given clk & parent
40 * @clk: OMAP struct clk ptr to inspect 55 * @clk: OMAP struct clk ptr to inspect
41 * @src_clk: OMAP struct clk ptr of the parent clk to search for 56 * @src_clk: OMAP struct clk ptr of the parent clk to search for
42 * 57 *
@@ -44,23 +59,19 @@
44 * the element associated with the supplied parent clock address. 59 * the element associated with the supplied parent clock address.
45 * Returns a pointer to the struct clksel on success or NULL on error. 60 * Returns a pointer to the struct clksel on success or NULL on error.
46 */ 61 */
47static const struct clksel *_omap2_get_clksel_by_parent(struct clk *clk, 62static const struct clksel *_get_clksel_by_parent(struct clk *clk,
48 struct clk *src_clk) 63 struct clk *src_clk)
49{ 64{
50 const struct clksel *clks; 65 const struct clksel *clks;
51 66
52 if (!clk->clksel) 67 for (clks = clk->clksel; clks->parent; clks++)
53 return NULL;
54
55 for (clks = clk->clksel; clks->parent; clks++) {
56 if (clks->parent == src_clk) 68 if (clks->parent == src_clk)
57 break; /* Found the requested parent */ 69 break; /* Found the requested parent */
58 }
59 70
60 if (!clks->parent) { 71 if (!clks->parent) {
61 printk(KERN_ERR "clock: Could not find parent clock %s in " 72 /* This indicates a data problem */
62 "clksel array of clock %s\n", src_clk->name, 73 WARN(1, "clock: Could not find parent clock %s in clksel array "
63 clk->name); 74 "of clock %s\n", src_clk->name, clk->name);
64 return NULL; 75 return NULL;
65 } 76 }
66 77
@@ -68,7 +79,7 @@ static const struct clksel *_omap2_get_clksel_by_parent(struct clk *clk,
68} 79}
69 80
70/** 81/**
71 * _omap2_clksel_get_src_field - find the new clksel divisor to use 82 * _get_div_and_fieldval() - find the new clksel divisor and field value to use
72 * @src_clk: planned new parent struct clk * 83 * @src_clk: planned new parent struct clk *
73 * @clk: struct clk * that is being reparented 84 * @clk: struct clk * that is being reparented
74 * @field_val: pointer to a u32 to contain the register data for the divisor 85 * @field_val: pointer to a u32 to contain the register data for the divisor
@@ -82,14 +93,14 @@ static const struct clksel *_omap2_get_clksel_by_parent(struct clk *clk,
82 * success (in this latter case, the corresponding register bitfield 93 * success (in this latter case, the corresponding register bitfield
83 * value is passed back in the variable pointed to by @field_val) 94 * value is passed back in the variable pointed to by @field_val)
84 */ 95 */
85static u8 _omap2_clksel_get_src_field(struct clk *src_clk, struct clk *clk, 96static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk,
86 u32 *field_val) 97 u32 *field_val)
87{ 98{
88 const struct clksel *clks; 99 const struct clksel *clks;
89 const struct clksel_rate *clkr, *max_clkr; 100 const struct clksel_rate *clkr, *max_clkr;
90 u8 max_div = 0; 101 u8 max_div = 0;
91 102
92 clks = _omap2_get_clksel_by_parent(clk, src_clk); 103 clks = _get_clksel_by_parent(clk, src_clk);
93 if (!clks) 104 if (!clks)
94 return 0; 105 return 0;
95 106
@@ -113,9 +124,9 @@ static u8 _omap2_clksel_get_src_field(struct clk *src_clk, struct clk *clk,
113 } 124 }
114 125
115 if (max_div == 0) { 126 if (max_div == 0) {
116 WARN(1, "clock: Could not find divisor for " 127 /* This indicates an error in the clksel data */
117 "clock %s parent %s\n", clk->name, 128 WARN(1, "clock: Could not find divisor for clock %s parent %s"
118 src_clk->parent->name); 129 "\n", clk->name, src_clk->parent->name);
119 return 0; 130 return 0;
120 } 131 }
121 132
@@ -124,82 +135,141 @@ static u8 _omap2_clksel_get_src_field(struct clk *src_clk, struct clk *clk,
124 return max_div; 135 return max_div;
125} 136}
126 137
138/**
139 * _write_clksel_reg() - program a clock's clksel register in hardware
140 * @clk: struct clk * to program
141 * @v: clksel bitfield value to program (with LSB at bit 0)
142 *
143 * Shift the clksel register bitfield value @v to its appropriate
144 * location in the clksel register and write it in. This function
145 * will ensure that the write to the clksel_reg reaches its
146 * destination before returning -- important since PRM and CM register
147 * accesses can be quite slow compared to ARM cycles -- but does not
148 * take into account any time the hardware might take to switch the
149 * clock source.
150 */
151static void _write_clksel_reg(struct clk *clk, u32 field_val)
152{
153 u32 v;
127 154
128/* Public functions */ 155 v = __raw_readl(clk->clksel_reg);
156 v &= ~clk->clksel_mask;
157 v |= field_val << __ffs(clk->clksel_mask);
158 __raw_writel(v, clk->clksel_reg);
159
160 v = __raw_readl(clk->clksel_reg); /* OCP barrier */
161}
129 162
130/** 163/**
131 * omap2_init_clksel_parent - set a clksel clk's parent field from the hardware 164 * _clksel_to_divisor() - turn clksel field value into integer divider
132 * @clk: OMAP clock struct ptr to use 165 * @clk: OMAP struct clk to use
166 * @field_val: register field value to find
133 * 167 *
134 * Given a pointer to a source-selectable struct clk, read the hardware 168 * Given a struct clk of a rate-selectable clksel clock, and a register field
135 * register and determine what its parent is currently set to. Update the 169 * value to search for, find the corresponding clock divisor. The register
136 * clk->parent field with the appropriate clk ptr. 170 * field value should be pre-masked and shifted down so the LSB is at bit 0
171 * before calling. Returns 0 on error or returns the actual integer divisor
172 * upon success.
137 */ 173 */
138void omap2_init_clksel_parent(struct clk *clk) 174static u32 _clksel_to_divisor(struct clk *clk, u32 field_val)
139{ 175{
140 const struct clksel *clks; 176 const struct clksel *clks;
141 const struct clksel_rate *clkr; 177 const struct clksel_rate *clkr;
142 u32 r, found = 0;
143 178
144 if (!clk->clksel) 179 clks = _get_clksel_by_parent(clk, clk->parent);
145 return; 180 if (!clks)
181 return 0;
146 182
147 r = __raw_readl(clk->clksel_reg) & clk->clksel_mask; 183 for (clkr = clks->rates; clkr->div; clkr++) {
148 r >>= __ffs(clk->clksel_mask); 184 if (!(clkr->flags & cpu_mask))
185 continue;
149 186
150 for (clks = clk->clksel; clks->parent && !found; clks++) { 187 if (clkr->val == field_val)
151 for (clkr = clks->rates; clkr->div && !found; clkr++) { 188 break;
152 if ((clkr->flags & cpu_mask) && (clkr->val == r)) {
153 if (clk->parent != clks->parent) {
154 pr_debug("clock: inited %s parent "
155 "to %s (was %s)\n",
156 clk->name, clks->parent->name,
157 ((clk->parent) ?
158 clk->parent->name : "NULL"));
159 clk_reparent(clk, clks->parent);
160 };
161 found = 1;
162 }
163 }
164 } 189 }
165 190
166 if (!found) 191 if (!clkr->div) {
167 printk(KERN_ERR "clock: init parent: could not find " 192 /* This indicates a data error */
168 "regval %0x for clock %s\n", r, clk->name); 193 WARN(1, "clock: Could not find fieldval %d for clock %s parent "
194 "%s\n", field_val, clk->name, clk->parent->name);
195 return 0;
196 }
169 197
170 return; 198 return clkr->div;
171} 199}
172 200
173/* 201/**
174 * Used for clocks that are part of CLKSEL_xyz governed clocks. 202 * _divisor_to_clksel() - turn clksel integer divisor into a field value
175 * REVISIT: Maybe change to use clk->enable() functions like on omap1? 203 * @clk: OMAP struct clk to use
204 * @div: integer divisor to search for
205 *
206 * Given a struct clk of a rate-selectable clksel clock, and a clock
207 * divisor, find the corresponding register field value. Returns the
208 * register field value _before_ left-shifting (i.e., LSB is at bit
209 * 0); or returns 0xFFFFFFFF (~0) upon error.
176 */ 210 */
177unsigned long omap2_clksel_recalc(struct clk *clk) 211static u32 _divisor_to_clksel(struct clk *clk, u32 div)
178{ 212{
179 unsigned long rate; 213 const struct clksel *clks;
180 u32 div = 0; 214 const struct clksel_rate *clkr;
181 215
182 pr_debug("clock: recalc'ing clksel clk %s\n", clk->name); 216 /* should never happen */
217 WARN_ON(div == 0);
183 218
184 div = omap2_clksel_get_divisor(clk); 219 clks = _get_clksel_by_parent(clk, clk->parent);
185 if (div == 0) 220 if (!clks)
186 return clk->rate; 221 return ~0;
187 222
188 rate = clk->parent->rate / div; 223 for (clkr = clks->rates; clkr->div; clkr++) {
224 if (!(clkr->flags & cpu_mask))
225 continue;
189 226
190 pr_debug("clock: new clock rate is %ld (div %d)\n", rate, div); 227 if (clkr->div == div)
228 break;
229 }
191 230
192 return rate; 231 if (!clkr->div) {
232 pr_err("clock: Could not find divisor %d for clock %s parent "
233 "%s\n", div, clk->name, clk->parent->name);
234 return ~0;
235 }
236
237 return clkr->val;
193} 238}
194 239
195/** 240/**
196 * omap2_clksel_round_rate_div - find divisor for the given clock and rate 241 * _read_divisor() - get current divisor applied to parent clock (from hdwr)
242 * @clk: OMAP struct clk to use.
243 *
244 * Read the current divisor register value for @clk that is programmed
245 * into the hardware, convert it into the actual divisor value, and
246 * return it; or return 0 on error.
247 */
248static u32 _read_divisor(struct clk *clk)
249{
250 u32 v;
251
252 if (!clk->clksel || !clk->clksel_mask)
253 return 0;
254
255 v = __raw_readl(clk->clksel_reg);
256 v &= clk->clksel_mask;
257 v >>= __ffs(clk->clksel_mask);
258
259 return _clksel_to_divisor(clk, v);
260}
261
262/* Public functions */
263
264/**
265 * omap2_clksel_round_rate_div() - find divisor for the given clock and rate
197 * @clk: OMAP struct clk to use 266 * @clk: OMAP struct clk to use
198 * @target_rate: desired clock rate 267 * @target_rate: desired clock rate
199 * @new_div: ptr to where we should store the divisor 268 * @new_div: ptr to where we should store the divisor
200 * 269 *
201 * Finds 'best' divider value in an array based on the source and target 270 * Finds 'best' divider value in an array based on the source and target
202 * rates. The divider array must be sorted with smallest divider first. 271 * rates. The divider array must be sorted with smallest divider first.
272 * This function is also used by the DPLL3 M2 divider code.
203 * 273 *
204 * Returns the rounded clock rate or returns 0xffffffff on error. 274 * Returns the rounded clock rate or returns 0xffffffff on error.
205 */ 275 */
@@ -211,12 +281,15 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
211 const struct clksel_rate *clkr; 281 const struct clksel_rate *clkr;
212 u32 last_div = 0; 282 u32 last_div = 0;
213 283
284 if (!clk->clksel || !clk->clksel_mask)
285 return ~0;
286
214 pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n", 287 pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n",
215 clk->name, target_rate); 288 clk->name, target_rate);
216 289
217 *new_div = 1; 290 *new_div = 1;
218 291
219 clks = _omap2_get_clksel_by_parent(clk, clk->parent); 292 clks = _get_clksel_by_parent(clk, clk->parent);
220 if (!clks) 293 if (!clks)
221 return ~0; 294 return ~0;
222 295
@@ -252,168 +325,174 @@ u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
252 return clk->parent->rate / clkr->div; 325 return clk->parent->rate / clkr->div;
253} 326}
254 327
255/** 328/*
256 * omap2_clksel_round_rate - find rounded rate for the given clock and rate 329 * Clocktype interface functions to the OMAP clock code
257 * @clk: OMAP struct clk to use 330 * (i.e., those used in struct clk field function pointers, etc.)
258 * @target_rate: desired clock rate
259 *
260 * Compatibility wrapper for OMAP clock framework
261 * Finds best target rate based on the source clock and possible dividers.
262 * rates. The divider array must be sorted with smallest divider first.
263 * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT,
264 * they are only settable as part of virtual_prcm set.
265 *
266 * Returns the rounded clock rate or returns 0xffffffff on error.
267 */ 331 */
268long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate)
269{
270 u32 new_div;
271
272 return omap2_clksel_round_rate_div(clk, target_rate, &new_div);
273}
274
275
276/* Given a clock and a rate apply a clock specific rounding function */
277long omap2_clk_round_rate(struct clk *clk, unsigned long rate)
278{
279 if (clk->round_rate)
280 return clk->round_rate(clk, rate);
281
282 return clk->rate;
283}
284 332
285/** 333/**
286 * omap2_clksel_to_divisor() - turn clksel field value into integer divider 334 * omap2_init_clksel_parent() - set a clksel clk's parent field from the hdwr
287 * @clk: OMAP struct clk to use 335 * @clk: OMAP clock struct ptr to use
288 * @field_val: register field value to find
289 * 336 *
290 * Given a struct clk of a rate-selectable clksel clock, and a register field 337 * Given a pointer @clk to a source-selectable struct clk, read the
291 * value to search for, find the corresponding clock divisor. The register 338 * hardware register and determine what its parent is currently set
292 * field value should be pre-masked and shifted down so the LSB is at bit 0 339 * to. Update @clk's .parent field with the appropriate clk ptr. No
293 * before calling. Returns 0 on error 340 * return value.
294 */ 341 */
295u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val) 342void omap2_init_clksel_parent(struct clk *clk)
296{ 343{
297 const struct clksel *clks; 344 const struct clksel *clks;
298 const struct clksel_rate *clkr; 345 const struct clksel_rate *clkr;
346 u32 r, found = 0;
299 347
300 clks = _omap2_get_clksel_by_parent(clk, clk->parent); 348 if (!clk->clksel || !clk->clksel_mask)
301 if (!clks) 349 return;
302 return 0;
303 350
304 for (clkr = clks->rates; clkr->div; clkr++) { 351 r = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
305 if ((clkr->flags & cpu_mask) && (clkr->val == field_val)) 352 r >>= __ffs(clk->clksel_mask);
306 break;
307 }
308 353
309 if (!clkr->div) { 354 for (clks = clk->clksel; clks->parent && !found; clks++) {
310 printk(KERN_ERR "clock: Could not find fieldval %d for " 355 for (clkr = clks->rates; clkr->div && !found; clkr++) {
311 "clock %s parent %s\n", field_val, clk->name, 356 if (!(clkr->flags & cpu_mask))
312 clk->parent->name); 357 continue;
313 return 0; 358
359 if (clkr->val == r) {
360 if (clk->parent != clks->parent) {
361 pr_debug("clock: inited %s parent "
362 "to %s (was %s)\n",
363 clk->name, clks->parent->name,
364 ((clk->parent) ?
365 clk->parent->name : "NULL"));
366 clk_reparent(clk, clks->parent);
367 };
368 found = 1;
369 }
370 }
314 } 371 }
315 372
316 return clkr->div; 373 /* This indicates a data error */
374 WARN(!found, "clock: %s: init parent: could not find regval %0x\n",
375 clk->name, r);
376
377 return;
317} 378}
318 379
319/** 380/**
320 * omap2_divisor_to_clksel() - turn clksel integer divisor into a field value 381 * omap2_clksel_recalc() - function ptr to pass via struct clk .recalc field
321 * @clk: OMAP struct clk to use 382 * @clk: struct clk *
322 * @div: integer divisor to search for
323 * 383 *
324 * Given a struct clk of a rate-selectable clksel clock, and a clock divisor, 384 * This function is intended to be called only by the clock framework.
325 * find the corresponding register field value. The return register value is 385 * Each clksel clock should have its struct clk .recalc field set to this
326 * the value before left-shifting. Returns ~0 on error 386 * function. Returns the clock's current rate, based on its parent's rate
387 * and its current divisor setting in the hardware.
327 */ 388 */
328u32 omap2_divisor_to_clksel(struct clk *clk, u32 div) 389unsigned long omap2_clksel_recalc(struct clk *clk)
329{ 390{
330 const struct clksel *clks; 391 unsigned long rate;
331 const struct clksel_rate *clkr; 392 u32 div = 0;
332 393
333 /* should never happen */ 394 div = _read_divisor(clk);
334 WARN_ON(div == 0); 395 if (div == 0)
396 return clk->rate;
335 397
336 clks = _omap2_get_clksel_by_parent(clk, clk->parent); 398 rate = clk->parent->rate / div;
337 if (!clks)
338 return ~0;
339 399
340 for (clkr = clks->rates; clkr->div; clkr++) { 400 pr_debug("clock: %s: recalc'd rate is %ld (div %d)\n", clk->name,
341 if ((clkr->flags & cpu_mask) && (clkr->div == div)) 401 rate, div);
342 break;
343 }
344 402
345 if (!clkr->div) { 403 return rate;
346 printk(KERN_ERR "clock: Could not find divisor %d for "
347 "clock %s parent %s\n", div, clk->name,
348 clk->parent->name);
349 return ~0;
350 }
351
352 return clkr->val;
353} 404}
354 405
355/** 406/**
356 * omap2_clksel_get_divisor - get current divider applied to parent clock. 407 * omap2_clksel_round_rate() - find rounded rate for the given clock and rate
357 * @clk: OMAP struct clk to use. 408 * @clk: OMAP struct clk to use
409 * @target_rate: desired clock rate
410 *
411 * This function is intended to be called only by the clock framework.
412 * Finds best target rate based on the source clock and possible dividers.
413 * rates. The divider array must be sorted with smallest divider first.
358 * 414 *
359 * Returns the integer divisor upon success or 0 on error. 415 * Returns the rounded clock rate or returns 0xffffffff on error.
360 */ 416 */
361u32 omap2_clksel_get_divisor(struct clk *clk) 417long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate)
362{ 418{
363 u32 v; 419 u32 new_div;
364
365 if (!clk->clksel_mask)
366 return 0;
367
368 v = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
369 v >>= __ffs(clk->clksel_mask);
370 420
371 return omap2_clksel_to_divisor(clk, v); 421 return omap2_clksel_round_rate_div(clk, target_rate, &new_div);
372} 422}
373 423
424/**
425 * omap2_clksel_set_rate() - program clock rate in hardware
426 * @clk: struct clk * to program rate
427 * @rate: target rate to program
428 *
429 * This function is intended to be called only by the clock framework.
430 * Program @clk's rate to @rate in the hardware. The clock can be
431 * either enabled or disabled when this happens, although if the clock
432 * is enabled, some downstream devices may glitch or behave
433 * unpredictably when the clock rate is changed - this depends on the
434 * hardware. This function does not currently check the usecount of
435 * the clock, so if multiple drivers are using the clock, and the rate
436 * is changed, they will all be affected without any notification.
437 * Returns -EINVAL upon error, or 0 upon success.
438 */
374int omap2_clksel_set_rate(struct clk *clk, unsigned long rate) 439int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
375{ 440{
376 u32 v, field_val, validrate, new_div = 0; 441 u32 field_val, validrate, new_div = 0;
377 442
378 if (!clk->clksel_mask) 443 if (!clk->clksel || !clk->clksel_mask)
379 return -EINVAL; 444 return -EINVAL;
380 445
381 validrate = omap2_clksel_round_rate_div(clk, rate, &new_div); 446 validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
382 if (validrate != rate) 447 if (validrate != rate)
383 return -EINVAL; 448 return -EINVAL;
384 449
385 field_val = omap2_divisor_to_clksel(clk, new_div); 450 field_val = _divisor_to_clksel(clk, new_div);
386 if (field_val == ~0) 451 if (field_val == ~0)
387 return -EINVAL; 452 return -EINVAL;
388 453
389 v = __raw_readl(clk->clksel_reg); 454 _write_clksel_reg(clk, field_val);
390 v &= ~clk->clksel_mask;
391 v |= field_val << __ffs(clk->clksel_mask);
392 __raw_writel(v, clk->clksel_reg);
393 v = __raw_readl(clk->clksel_reg); /* OCP barrier */
394 455
395 clk->rate = clk->parent->rate / new_div; 456 clk->rate = clk->parent->rate / new_div;
396 457
458 pr_debug("clock: %s: set rate to %ld\n", clk->name, clk->rate);
459
397 return 0; 460 return 0;
398} 461}
399 462
463/*
464 * Clksel parent setting function - not passed in struct clk function
465 * pointer - instead, the OMAP clock code currently assumes that any
466 * parent-setting clock is a clksel clock, and calls
467 * omap2_clksel_set_parent() by default
468 */
469
470/**
471 * omap2_clksel_set_parent() - change a clock's parent clock
472 * @clk: struct clk * of the child clock
473 * @new_parent: struct clk * of the new parent clock
474 *
475 * This function is intended to be called only by the clock framework.
476 * Change the parent clock of clock @clk to @new_parent. This is
477 * intended to be used while @clk is disabled. This function does not
478 * currently check the usecount of the clock, so if multiple drivers
479 * are using the clock, and the parent is changed, they will all be
480 * affected without any notification. Returns -EINVAL upon error, or
481 * 0 upon success.
482 */
400int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent) 483int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent)
401{ 484{
402 u32 field_val, v, parent_div; 485 u32 field_val = 0;
486 u32 parent_div;
403 487
404 if (!clk->clksel || !clk->clksel_mask) 488 if (!clk->clksel || !clk->clksel_mask)
405 return -EINVAL; 489 return -EINVAL;
406 490
407 parent_div = _omap2_clksel_get_src_field(new_parent, clk, &field_val); 491 parent_div = _get_div_and_fieldval(new_parent, clk, &field_val);
408 if (!parent_div) 492 if (!parent_div)
409 return -EINVAL; 493 return -EINVAL;
410 494
411 /* Set new source value (previous dividers if any in effect) */ 495 _write_clksel_reg(clk, field_val);
412 v = __raw_readl(clk->clksel_reg);
413 v &= ~clk->clksel_mask;
414 v |= field_val << __ffs(clk->clksel_mask);
415 __raw_writel(v, clk->clksel_reg);
416 v = __raw_readl(clk->clksel_reg); /* OCP barrier */
417 496
418 clk_reparent(clk, new_parent); 497 clk_reparent(clk, new_parent);
419 498
@@ -423,7 +502,7 @@ int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent)
423 if (parent_div > 0) 502 if (parent_div > 0)
424 clk->rate /= parent_div; 503 clk->rate /= parent_div;
425 504
426 pr_debug("clock: set parent of %s to %s (new rate %ld)\n", 505 pr_debug("clock: %s: set parent to %s (new rate %ld)\n",
427 clk->name, clk->parent->name, clk->rate); 506 clk->name, clk->parent->name, clk->rate);
428 507
429 return 0; 508 return 0;
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index a6d0b34b7990..605f531783a8 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -334,6 +334,15 @@ oce_err1:
334 return ret; 334 return ret;
335} 335}
336 336
337/* Given a clock and a rate apply a clock specific rounding function */
338long omap2_clk_round_rate(struct clk *clk, unsigned long rate)
339{
340 if (clk->round_rate)
341 return clk->round_rate(clk, rate);
342
343 return clk->rate;
344}
345
337/* Set the clock rate for a clock source */ 346/* Set the clock rate for a clock source */
338int omap2_clk_set_rate(struct clk *clk, unsigned long rate) 347int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
339{ 348{
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index ad8a1f7c1afc..a535c7a2a62a 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -73,19 +73,20 @@ void omap2_clk_disable_unused(struct clk *clk);
73#define omap2_clk_disable_unused NULL 73#define omap2_clk_disable_unused NULL
74#endif 74#endif
75 75
76unsigned long omap2_clksel_recalc(struct clk *clk);
77void omap2_init_clk_clkdm(struct clk *clk); 76void omap2_init_clk_clkdm(struct clk *clk);
78void omap2_init_clksel_parent(struct clk *clk); 77
79u32 omap2_clksel_get_divisor(struct clk *clk); 78/* clkt_clksel.c public functions */
80u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, 79u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
81 u32 *new_div); 80 u32 *new_div);
82u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val); 81void omap2_init_clksel_parent(struct clk *clk);
83u32 omap2_divisor_to_clksel(struct clk *clk, u32 div); 82unsigned long omap2_clksel_recalc(struct clk *clk);
84long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate); 83long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate);
85int omap2_clksel_set_rate(struct clk *clk, unsigned long rate); 84int omap2_clksel_set_rate(struct clk *clk, unsigned long rate);
86int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent); 85int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent);
86
87u32 omap2_get_dpll_rate(struct clk *clk); 87u32 omap2_get_dpll_rate(struct clk *clk);
88void omap2_init_dpll_parent(struct clk *clk); 88void omap2_init_dpll_parent(struct clk *clk);
89
89int omap2_wait_clock_ready(void __iomem *reg, u32 cval, const char *name); 90int omap2_wait_clock_ready(void __iomem *reg, u32 cval, const char *name);
90 91
91 92