xref: /openbmc/linux/arch/arm/mach-omap2/clock.c (revision 0b96af68)
1 /*
2  *  linux/arch/arm/mach-omap2/clock.c
3  *
4  *  Copyright (C) 2005-2008 Texas Instruments, Inc.
5  *  Copyright (C) 2004-2008 Nokia Corporation
6  *
7  *  Contacts:
8  *  Richard Woodruff <r-woodruff2@ti.com>
9  *  Paul Walmsley
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License version 2 as
13  * published by the Free Software Foundation.
14  */
15 #undef DEBUG
16 
17 #include <linux/module.h>
18 #include <linux/kernel.h>
19 #include <linux/device.h>
20 #include <linux/list.h>
21 #include <linux/errno.h>
22 #include <linux/delay.h>
23 #include <linux/clk.h>
24 #include <linux/io.h>
25 #include <linux/bitops.h>
26 
27 #include <plat/clock.h>
28 #include <plat/clockdomain.h>
29 #include <plat/cpu.h>
30 #include <plat/prcm.h>
31 
32 #include "clock.h"
33 #include "prm.h"
34 #include "prm-regbits-24xx.h"
35 #include "cm.h"
36 #include "cm-regbits-24xx.h"
37 #include "cm-regbits-34xx.h"
38 
39 u8 cpu_mask;
40 
41 /*-------------------------------------------------------------------------
42  * OMAP2/3/4 specific clock functions
43  *-------------------------------------------------------------------------*/
44 
45 /**
46  * _omap2xxx_clk_commit - commit clock parent/rate changes in hardware
47  * @clk: struct clk *
48  *
49  * If @clk has the DELAYED_APP flag set, meaning that parent/rate changes
50  * don't take effect until the VALID_CONFIG bit is written, write the
51  * VALID_CONFIG bit and wait for the write to complete.  No return value.
52  */
53 static void _omap2xxx_clk_commit(struct clk *clk)
54 {
55 	if (!cpu_is_omap24xx())
56 		return;
57 
58 	if (!(clk->flags & DELAYED_APP))
59 		return;
60 
61 	prm_write_mod_reg(OMAP24XX_VALID_CONFIG, OMAP24XX_GR_MOD,
62 		OMAP2_PRCM_CLKCFG_CTRL_OFFSET);
63 	/* OCP barrier */
64 	prm_read_mod_reg(OMAP24XX_GR_MOD, OMAP2_PRCM_CLKCFG_CTRL_OFFSET);
65 }
66 
67 /**
68  * omap2_init_clk_clkdm - look up a clockdomain name, store pointer in clk
69  * @clk: OMAP clock struct ptr to use
70  *
71  * Convert a clockdomain name stored in a struct clk 'clk' into a
72  * clockdomain pointer, and save it into the struct clk.  Intended to be
73  * called during clk_register().  No return value.
74  */
75 void omap2_init_clk_clkdm(struct clk *clk)
76 {
77 	struct clockdomain *clkdm;
78 
79 	if (!clk->clkdm_name)
80 		return;
81 
82 	clkdm = clkdm_lookup(clk->clkdm_name);
83 	if (clkdm) {
84 		pr_debug("clock: associated clk %s to clkdm %s\n",
85 			 clk->name, clk->clkdm_name);
86 		clk->clkdm = clkdm;
87 	} else {
88 		pr_debug("clock: could not associate clk %s to "
89 			 "clkdm %s\n", clk->name, clk->clkdm_name);
90 	}
91 }
92 
93 /**
94  * omap2_init_clksel_parent - set a clksel clk's parent field from the hardware
95  * @clk: OMAP clock struct ptr to use
96  *
97  * Given a pointer to a source-selectable struct clk, read the hardware
98  * register and determine what its parent is currently set to.  Update the
99  * clk->parent field with the appropriate clk ptr.
100  */
101 void omap2_init_clksel_parent(struct clk *clk)
102 {
103 	const struct clksel *clks;
104 	const struct clksel_rate *clkr;
105 	u32 r, found = 0;
106 
107 	if (!clk->clksel)
108 		return;
109 
110 	r = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
111 	r >>= __ffs(clk->clksel_mask);
112 
113 	for (clks = clk->clksel; clks->parent && !found; clks++) {
114 		for (clkr = clks->rates; clkr->div && !found; clkr++) {
115 			if ((clkr->flags & cpu_mask) && (clkr->val == r)) {
116 				if (clk->parent != clks->parent) {
117 					pr_debug("clock: inited %s parent "
118 						 "to %s (was %s)\n",
119 						 clk->name, clks->parent->name,
120 						 ((clk->parent) ?
121 						  clk->parent->name : "NULL"));
122 					clk_reparent(clk, clks->parent);
123 				};
124 				found = 1;
125 			}
126 		}
127 	}
128 
129 	if (!found)
130 		printk(KERN_ERR "clock: init parent: could not find "
131 		       "regval %0x for clock %s\n", r,  clk->name);
132 
133 	return;
134 }
135 
136 /**
137  * omap2_clk_dflt_find_companion - find companion clock to @clk
138  * @clk: struct clk * to find the companion clock of
139  * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in
140  * @other_bit: u8 ** to return the companion clock bit shift in
141  *
142  * Note: We don't need special code here for INVERT_ENABLE for the
143  * time being since INVERT_ENABLE only applies to clocks enabled by
144  * CM_CLKEN_PLL
145  *
146  * Convert CM_ICLKEN* <-> CM_FCLKEN*.  This conversion assumes it's
147  * just a matter of XORing the bits.
148  *
149  * Some clocks don't have companion clocks.  For example, modules with
150  * only an interface clock (such as MAILBOXES) don't have a companion
151  * clock.  Right now, this code relies on the hardware exporting a bit
152  * in the correct companion register that indicates that the
153  * nonexistent 'companion clock' is active.  Future patches will
154  * associate this type of code with per-module data structures to
155  * avoid this issue, and remove the casts.  No return value.
156  */
157 void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg,
158 				   u8 *other_bit)
159 {
160 	u32 r;
161 
162 	/*
163 	 * Convert CM_ICLKEN* <-> CM_FCLKEN*.  This conversion assumes
164 	 * it's just a matter of XORing the bits.
165 	 */
166 	r = ((__force u32)clk->enable_reg ^ (CM_FCLKEN ^ CM_ICLKEN));
167 
168 	*other_reg = (__force void __iomem *)r;
169 	*other_bit = clk->enable_bit;
170 }
171 
172 /**
173  * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk
174  * @clk: struct clk * to find IDLEST info for
175  * @idlest_reg: void __iomem ** to return the CM_IDLEST va in
176  * @idlest_bit: u8 ** to return the CM_IDLEST bit shift in
177  *
178  * Return the CM_IDLEST register address and bit shift corresponding
179  * to the module that "owns" this clock.  This default code assumes
180  * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that
181  * the IDLEST register address ID corresponds to the CM_*CLKEN
182  * register address ID (e.g., that CM_FCLKEN2 corresponds to
183  * CM_IDLEST2).  This is not true for all modules.  No return value.
184  */
185 void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg,
186 				u8 *idlest_bit)
187 {
188 	u32 r;
189 
190 	r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
191 	*idlest_reg = (__force void __iomem *)r;
192 	*idlest_bit = clk->enable_bit;
193 }
194 
195 /**
196  * omap2_module_wait_ready - wait for an OMAP module to leave IDLE
197  * @clk: struct clk * belonging to the module
198  *
199  * If the necessary clocks for the OMAP hardware IP block that
200  * corresponds to clock @clk are enabled, then wait for the module to
201  * indicate readiness (i.e., to leave IDLE).  This code does not
202  * belong in the clock code and will be moved in the medium term to
203  * module-dependent code.  No return value.
204  */
205 static void omap2_module_wait_ready(struct clk *clk)
206 {
207 	void __iomem *companion_reg, *idlest_reg;
208 	u8 other_bit, idlest_bit;
209 
210 	/* Not all modules have multiple clocks that their IDLEST depends on */
211 	if (clk->ops->find_companion) {
212 		clk->ops->find_companion(clk, &companion_reg, &other_bit);
213 		if (!(__raw_readl(companion_reg) & (1 << other_bit)))
214 			return;
215 	}
216 
217 	clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit);
218 
219 	omap2_cm_wait_idlest(idlest_reg, (1 << idlest_bit), clk->name);
220 }
221 
222 int omap2_dflt_clk_enable(struct clk *clk)
223 {
224 	u32 v;
225 
226 	if (unlikely(clk->enable_reg == NULL)) {
227 		pr_err("clock.c: Enable for %s without enable code\n",
228 		       clk->name);
229 		return 0; /* REVISIT: -EINVAL */
230 	}
231 
232 	v = __raw_readl(clk->enable_reg);
233 	if (clk->flags & INVERT_ENABLE)
234 		v &= ~(1 << clk->enable_bit);
235 	else
236 		v |= (1 << clk->enable_bit);
237 	__raw_writel(v, clk->enable_reg);
238 	v = __raw_readl(clk->enable_reg); /* OCP barrier */
239 
240 	if (clk->ops->find_idlest)
241 		omap2_module_wait_ready(clk);
242 
243 	return 0;
244 }
245 
246 void omap2_dflt_clk_disable(struct clk *clk)
247 {
248 	u32 v;
249 
250 	if (!clk->enable_reg) {
251 		/*
252 		 * 'Independent' here refers to a clock which is not
253 		 * controlled by its parent.
254 		 */
255 		printk(KERN_ERR "clock: clk_disable called on independent "
256 		       "clock %s which has no enable_reg\n", clk->name);
257 		return;
258 	}
259 
260 	v = __raw_readl(clk->enable_reg);
261 	if (clk->flags & INVERT_ENABLE)
262 		v |= (1 << clk->enable_bit);
263 	else
264 		v &= ~(1 << clk->enable_bit);
265 	__raw_writel(v, clk->enable_reg);
266 	/* No OCP barrier needed here since it is a disable operation */
267 }
268 
269 const struct clkops clkops_omap2_dflt_wait = {
270 	.enable		= omap2_dflt_clk_enable,
271 	.disable	= omap2_dflt_clk_disable,
272 	.find_companion	= omap2_clk_dflt_find_companion,
273 	.find_idlest	= omap2_clk_dflt_find_idlest,
274 };
275 
276 const struct clkops clkops_omap2_dflt = {
277 	.enable		= omap2_dflt_clk_enable,
278 	.disable	= omap2_dflt_clk_disable,
279 };
280 
281 /* Enables clock without considering parent dependencies or use count
282  * REVISIT: Maybe change this to use clk->enable like on omap1?
283  */
284 static int _omap2_clk_enable(struct clk *clk)
285 {
286 	return clk->ops->enable(clk);
287 }
288 
289 /* Disables clock without considering parent dependencies or use count */
290 static void _omap2_clk_disable(struct clk *clk)
291 {
292 	clk->ops->disable(clk);
293 }
294 
295 void omap2_clk_disable(struct clk *clk)
296 {
297 	if (clk->usecount > 0 && !(--clk->usecount)) {
298 		_omap2_clk_disable(clk);
299 		if (clk->parent)
300 			omap2_clk_disable(clk->parent);
301 		if (clk->clkdm)
302 			omap2_clkdm_clk_disable(clk->clkdm, clk);
303 
304 	}
305 }
306 
307 int omap2_clk_enable(struct clk *clk)
308 {
309 	int ret = 0;
310 
311 	if (clk->usecount++ == 0) {
312 		if (clk->clkdm)
313 			omap2_clkdm_clk_enable(clk->clkdm, clk);
314 
315 		if (clk->parent) {
316 			ret = omap2_clk_enable(clk->parent);
317 			if (ret)
318 				goto err;
319 		}
320 
321 		ret = _omap2_clk_enable(clk);
322 		if (ret) {
323 			if (clk->parent)
324 				omap2_clk_disable(clk->parent);
325 
326 			goto err;
327 		}
328 	}
329 	return ret;
330 
331 err:
332 	if (clk->clkdm)
333 		omap2_clkdm_clk_disable(clk->clkdm, clk);
334 	clk->usecount--;
335 	return ret;
336 }
337 
338 /*
339  * Used for clocks that are part of CLKSEL_xyz governed clocks.
340  * REVISIT: Maybe change to use clk->enable() functions like on omap1?
341  */
342 unsigned long omap2_clksel_recalc(struct clk *clk)
343 {
344 	unsigned long rate;
345 	u32 div = 0;
346 
347 	pr_debug("clock: recalc'ing clksel clk %s\n", clk->name);
348 
349 	div = omap2_clksel_get_divisor(clk);
350 	if (div == 0)
351 		return clk->rate;
352 
353 	rate = clk->parent->rate / div;
354 
355 	pr_debug("clock: new clock rate is %ld (div %d)\n", rate, div);
356 
357 	return rate;
358 }
359 
360 /**
361  * omap2_get_clksel_by_parent - return clksel struct for a given clk & parent
362  * @clk: OMAP struct clk ptr to inspect
363  * @src_clk: OMAP struct clk ptr of the parent clk to search for
364  *
365  * Scan the struct clksel array associated with the clock to find
366  * the element associated with the supplied parent clock address.
367  * Returns a pointer to the struct clksel on success or NULL on error.
368  */
369 static const struct clksel *omap2_get_clksel_by_parent(struct clk *clk,
370 						       struct clk *src_clk)
371 {
372 	const struct clksel *clks;
373 
374 	if (!clk->clksel)
375 		return NULL;
376 
377 	for (clks = clk->clksel; clks->parent; clks++) {
378 		if (clks->parent == src_clk)
379 			break; /* Found the requested parent */
380 	}
381 
382 	if (!clks->parent) {
383 		printk(KERN_ERR "clock: Could not find parent clock %s in "
384 		       "clksel array of clock %s\n", src_clk->name,
385 		       clk->name);
386 		return NULL;
387 	}
388 
389 	return clks;
390 }
391 
392 /**
393  * omap2_clksel_round_rate_div - find divisor for the given clock and rate
394  * @clk: OMAP struct clk to use
395  * @target_rate: desired clock rate
396  * @new_div: ptr to where we should store the divisor
397  *
398  * Finds 'best' divider value in an array based on the source and target
399  * rates.  The divider array must be sorted with smallest divider first.
400  * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT,
401  * they are only settable as part of virtual_prcm set.
402  *
403  * Returns the rounded clock rate or returns 0xffffffff on error.
404  */
405 u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
406 				u32 *new_div)
407 {
408 	unsigned long test_rate;
409 	const struct clksel *clks;
410 	const struct clksel_rate *clkr;
411 	u32 last_div = 0;
412 
413 	pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n",
414 		 clk->name, target_rate);
415 
416 	*new_div = 1;
417 
418 	clks = omap2_get_clksel_by_parent(clk, clk->parent);
419 	if (!clks)
420 		return ~0;
421 
422 	for (clkr = clks->rates; clkr->div; clkr++) {
423 		if (!(clkr->flags & cpu_mask))
424 		    continue;
425 
426 		/* Sanity check */
427 		if (clkr->div <= last_div)
428 			pr_err("clock: clksel_rate table not sorted "
429 			       "for clock %s", clk->name);
430 
431 		last_div = clkr->div;
432 
433 		test_rate = clk->parent->rate / clkr->div;
434 
435 		if (test_rate <= target_rate)
436 			break; /* found it */
437 	}
438 
439 	if (!clkr->div) {
440 		pr_err("clock: Could not find divisor for target "
441 		       "rate %ld for clock %s parent %s\n", target_rate,
442 		       clk->name, clk->parent->name);
443 		return ~0;
444 	}
445 
446 	*new_div = clkr->div;
447 
448 	pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div,
449 		 (clk->parent->rate / clkr->div));
450 
451 	return (clk->parent->rate / clkr->div);
452 }
453 
454 /**
455  * omap2_clksel_round_rate - find rounded rate for the given clock and rate
456  * @clk: OMAP struct clk to use
457  * @target_rate: desired clock rate
458  *
459  * Compatibility wrapper for OMAP clock framework
460  * Finds best target rate based on the source clock and possible dividers.
461  * rates. The divider array must be sorted with smallest divider first.
462  * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT,
463  * they are only settable as part of virtual_prcm set.
464  *
465  * Returns the rounded clock rate or returns 0xffffffff on error.
466  */
467 long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate)
468 {
469 	u32 new_div;
470 
471 	return omap2_clksel_round_rate_div(clk, target_rate, &new_div);
472 }
473 
474 
475 /* Given a clock and a rate apply a clock specific rounding function */
476 long omap2_clk_round_rate(struct clk *clk, unsigned long rate)
477 {
478 	if (clk->round_rate)
479 		return clk->round_rate(clk, rate);
480 
481 	if (clk->flags & RATE_FIXED)
482 		printk(KERN_ERR "clock: generic omap2_clk_round_rate called "
483 		       "on fixed-rate clock %s\n", clk->name);
484 
485 	return clk->rate;
486 }
487 
488 /**
489  * omap2_clksel_to_divisor() - turn clksel field value into integer divider
490  * @clk: OMAP struct clk to use
491  * @field_val: register field value to find
492  *
493  * Given a struct clk of a rate-selectable clksel clock, and a register field
494  * value to search for, find the corresponding clock divisor.  The register
495  * field value should be pre-masked and shifted down so the LSB is at bit 0
496  * before calling.  Returns 0 on error
497  */
498 u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val)
499 {
500 	const struct clksel *clks;
501 	const struct clksel_rate *clkr;
502 
503 	clks = omap2_get_clksel_by_parent(clk, clk->parent);
504 	if (!clks)
505 		return 0;
506 
507 	for (clkr = clks->rates; clkr->div; clkr++) {
508 		if ((clkr->flags & cpu_mask) && (clkr->val == field_val))
509 			break;
510 	}
511 
512 	if (!clkr->div) {
513 		printk(KERN_ERR "clock: Could not find fieldval %d for "
514 		       "clock %s parent %s\n", field_val, clk->name,
515 		       clk->parent->name);
516 		return 0;
517 	}
518 
519 	return clkr->div;
520 }
521 
522 /**
523  * omap2_divisor_to_clksel() - turn clksel integer divisor into a field value
524  * @clk: OMAP struct clk to use
525  * @div: integer divisor to search for
526  *
527  * Given a struct clk of a rate-selectable clksel clock, and a clock divisor,
528  * find the corresponding register field value.  The return register value is
529  * the value before left-shifting.  Returns ~0 on error
530  */
531 u32 omap2_divisor_to_clksel(struct clk *clk, u32 div)
532 {
533 	const struct clksel *clks;
534 	const struct clksel_rate *clkr;
535 
536 	/* should never happen */
537 	WARN_ON(div == 0);
538 
539 	clks = omap2_get_clksel_by_parent(clk, clk->parent);
540 	if (!clks)
541 		return ~0;
542 
543 	for (clkr = clks->rates; clkr->div; clkr++) {
544 		if ((clkr->flags & cpu_mask) && (clkr->div == div))
545 			break;
546 	}
547 
548 	if (!clkr->div) {
549 		printk(KERN_ERR "clock: Could not find divisor %d for "
550 		       "clock %s parent %s\n", div, clk->name,
551 		       clk->parent->name);
552 		return ~0;
553 	}
554 
555 	return clkr->val;
556 }
557 
558 /**
559  * omap2_clksel_get_divisor - get current divider applied to parent clock.
560  * @clk: OMAP struct clk to use.
561  *
562  * Returns the integer divisor upon success or 0 on error.
563  */
564 u32 omap2_clksel_get_divisor(struct clk *clk)
565 {
566 	u32 v;
567 
568 	if (!clk->clksel_mask)
569 		return 0;
570 
571 	v = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
572 	v >>= __ffs(clk->clksel_mask);
573 
574 	return omap2_clksel_to_divisor(clk, v);
575 }
576 
577 int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
578 {
579 	u32 v, field_val, validrate, new_div = 0;
580 
581 	if (!clk->clksel_mask)
582 		return -EINVAL;
583 
584 	validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
585 	if (validrate != rate)
586 		return -EINVAL;
587 
588 	field_val = omap2_divisor_to_clksel(clk, new_div);
589 	if (field_val == ~0)
590 		return -EINVAL;
591 
592 	v = __raw_readl(clk->clksel_reg);
593 	v &= ~clk->clksel_mask;
594 	v |= field_val << __ffs(clk->clksel_mask);
595 	__raw_writel(v, clk->clksel_reg);
596 	v = __raw_readl(clk->clksel_reg); /* OCP barrier */
597 
598 	clk->rate = clk->parent->rate / new_div;
599 
600 	_omap2xxx_clk_commit(clk);
601 
602 	return 0;
603 }
604 
605 
606 /* Set the clock rate for a clock source */
607 int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
608 {
609 	int ret = -EINVAL;
610 
611 	pr_debug("clock: set_rate for clock %s to rate %ld\n", clk->name, rate);
612 
613 	/* CONFIG_PARTICIPANT clocks are changed only in sets via the
614 	   rate table mechanism, driven by mpu_speed  */
615 	if (clk->flags & CONFIG_PARTICIPANT)
616 		return -EINVAL;
617 
618 	/* dpll_ck, core_ck, virt_prcm_set; plus all clksel clocks */
619 	if (clk->set_rate)
620 		ret = clk->set_rate(clk, rate);
621 
622 	return ret;
623 }
624 
625 /*
626  * Converts encoded control register address into a full address
627  * On error, the return value (parent_div) will be 0.
628  */
629 static u32 _omap2_clksel_get_src_field(struct clk *src_clk, struct clk *clk,
630 				       u32 *field_val)
631 {
632 	const struct clksel *clks;
633 	const struct clksel_rate *clkr;
634 
635 	clks = omap2_get_clksel_by_parent(clk, src_clk);
636 	if (!clks)
637 		return 0;
638 
639 	for (clkr = clks->rates; clkr->div; clkr++) {
640 		if (clkr->flags & cpu_mask && clkr->flags & DEFAULT_RATE)
641 			break; /* Found the default rate for this platform */
642 	}
643 
644 	if (!clkr->div) {
645 		printk(KERN_ERR "clock: Could not find default rate for "
646 		       "clock %s parent %s\n", clk->name,
647 		       src_clk->parent->name);
648 		return 0;
649 	}
650 
651 	/* Should never happen.  Add a clksel mask to the struct clk. */
652 	WARN_ON(clk->clksel_mask == 0);
653 
654 	*field_val = clkr->val;
655 
656 	return clkr->div;
657 }
658 
659 int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
660 {
661 	u32 field_val, v, parent_div;
662 
663 	if (clk->flags & CONFIG_PARTICIPANT)
664 		return -EINVAL;
665 
666 	if (!clk->clksel)
667 		return -EINVAL;
668 
669 	parent_div = _omap2_clksel_get_src_field(new_parent, clk, &field_val);
670 	if (!parent_div)
671 		return -EINVAL;
672 
673 	/* Set new source value (previous dividers if any in effect) */
674 	v = __raw_readl(clk->clksel_reg);
675 	v &= ~clk->clksel_mask;
676 	v |= field_val << __ffs(clk->clksel_mask);
677 	__raw_writel(v, clk->clksel_reg);
678 	v = __raw_readl(clk->clksel_reg);    /* OCP barrier */
679 
680 	_omap2xxx_clk_commit(clk);
681 
682 	clk_reparent(clk, new_parent);
683 
684 	/* CLKSEL clocks follow their parents' rates, divided by a divisor */
685 	clk->rate = new_parent->rate;
686 
687 	if (parent_div > 0)
688 		clk->rate /= parent_div;
689 
690 	pr_debug("clock: set parent of %s to %s (new rate %ld)\n",
691 		 clk->name, clk->parent->name, clk->rate);
692 
693 	return 0;
694 }
695 
696 /*-------------------------------------------------------------------------
697  * Omap2 clock reset and init functions
698  *-------------------------------------------------------------------------*/
699 
700 #ifdef CONFIG_OMAP_RESET_CLOCKS
701 void omap2_clk_disable_unused(struct clk *clk)
702 {
703 	u32 regval32, v;
704 
705 	v = (clk->flags & INVERT_ENABLE) ? (1 << clk->enable_bit) : 0;
706 
707 	regval32 = __raw_readl(clk->enable_reg);
708 	if ((regval32 & (1 << clk->enable_bit)) == v)
709 		return;
710 
711 	printk(KERN_DEBUG "Disabling unused clock \"%s\"\n", clk->name);
712 	if (cpu_is_omap34xx()) {
713 		omap2_clk_enable(clk);
714 		omap2_clk_disable(clk);
715 	} else
716 		_omap2_clk_disable(clk);
717 	if (clk->clkdm != NULL)
718 		pwrdm_clkdm_state_switch(clk->clkdm);
719 }
720 #endif
721