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 <asm/bitops.h> 25 26 #include <asm/io.h> 27 28 #include <asm/arch/clock.h> 29 #include <asm/arch/sram.h> 30 #include <asm/arch/cpu.h> 31 #include <asm/div64.h> 32 33 #include "memory.h" 34 #include "sdrc.h" 35 #include "clock.h" 36 #include "prm.h" 37 #include "prm-regbits-24xx.h" 38 #include "cm.h" 39 #include "cm-regbits-24xx.h" 40 #include "cm-regbits-34xx.h" 41 42 #define MAX_CLOCK_ENABLE_WAIT 100000 43 44 u8 cpu_mask; 45 46 /*------------------------------------------------------------------------- 47 * Omap2 specific clock functions 48 *-------------------------------------------------------------------------*/ 49 50 /** 51 * omap2_init_clksel_parent - set a clksel clk's parent field from the hardware 52 * @clk: OMAP clock struct ptr to use 53 * 54 * Given a pointer to a source-selectable struct clk, read the hardware 55 * register and determine what its parent is currently set to. Update the 56 * clk->parent field with the appropriate clk ptr. 57 */ 58 void omap2_init_clksel_parent(struct clk *clk) 59 { 60 const struct clksel *clks; 61 const struct clksel_rate *clkr; 62 u32 r, found = 0; 63 64 if (!clk->clksel) 65 return; 66 67 r = __raw_readl(clk->clksel_reg) & clk->clksel_mask; 68 r >>= __ffs(clk->clksel_mask); 69 70 for (clks = clk->clksel; clks->parent && !found; clks++) { 71 for (clkr = clks->rates; clkr->div && !found; clkr++) { 72 if ((clkr->flags & cpu_mask) && (clkr->val == r)) { 73 if (clk->parent != clks->parent) { 74 pr_debug("clock: inited %s parent " 75 "to %s (was %s)\n", 76 clk->name, clks->parent->name, 77 ((clk->parent) ? 78 clk->parent->name : "NULL")); 79 clk->parent = clks->parent; 80 }; 81 found = 1; 82 } 83 } 84 } 85 86 if (!found) 87 printk(KERN_ERR "clock: init parent: could not find " 88 "regval %0x for clock %s\n", r, clk->name); 89 90 return; 91 } 92 93 /* Returns the DPLL rate */ 94 u32 omap2_get_dpll_rate(struct clk *clk) 95 { 96 long long dpll_clk; 97 u32 dpll_mult, dpll_div, dpll; 98 const struct dpll_data *dd; 99 100 dd = clk->dpll_data; 101 /* REVISIT: What do we return on error? */ 102 if (!dd) 103 return 0; 104 105 dpll = __raw_readl(dd->mult_div1_reg); 106 dpll_mult = dpll & dd->mult_mask; 107 dpll_mult >>= __ffs(dd->mult_mask); 108 dpll_div = dpll & dd->div1_mask; 109 dpll_div >>= __ffs(dd->div1_mask); 110 111 dpll_clk = (long long)clk->parent->rate * dpll_mult; 112 do_div(dpll_clk, dpll_div + 1); 113 114 return dpll_clk; 115 } 116 117 /* 118 * Used for clocks that have the same value as the parent clock, 119 * divided by some factor 120 */ 121 void omap2_fixed_divisor_recalc(struct clk *clk) 122 { 123 WARN_ON(!clk->fixed_div); 124 125 clk->rate = clk->parent->rate / clk->fixed_div; 126 127 if (clk->flags & RATE_PROPAGATES) 128 propagate_rate(clk); 129 } 130 131 /** 132 * omap2_wait_clock_ready - wait for clock to enable 133 * @reg: physical address of clock IDLEST register 134 * @mask: value to mask against to determine if the clock is active 135 * @name: name of the clock (for printk) 136 * 137 * Returns 1 if the clock enabled in time, or 0 if it failed to enable 138 * in roughly MAX_CLOCK_ENABLE_WAIT microseconds. 139 */ 140 int omap2_wait_clock_ready(void __iomem *reg, u32 mask, const char *name) 141 { 142 int i = 0; 143 int ena = 0; 144 145 /* 146 * 24xx uses 0 to indicate not ready, and 1 to indicate ready. 147 * 34xx reverses this, just to keep us on our toes 148 */ 149 if (cpu_mask & (RATE_IN_242X | RATE_IN_243X)) { 150 ena = mask; 151 } else if (cpu_mask & RATE_IN_343X) { 152 ena = 0; 153 } 154 155 /* Wait for lock */ 156 while (((__raw_readl(reg) & mask) != ena) && 157 (i++ < MAX_CLOCK_ENABLE_WAIT)) { 158 udelay(1); 159 } 160 161 if (i < MAX_CLOCK_ENABLE_WAIT) 162 pr_debug("Clock %s stable after %d loops\n", name, i); 163 else 164 printk(KERN_ERR "Clock %s didn't enable in %d tries\n", 165 name, MAX_CLOCK_ENABLE_WAIT); 166 167 168 return (i < MAX_CLOCK_ENABLE_WAIT) ? 1 : 0; 169 }; 170 171 172 /* 173 * Note: We don't need special code here for INVERT_ENABLE 174 * for the time being since INVERT_ENABLE only applies to clocks enabled by 175 * CM_CLKEN_PLL 176 */ 177 static void omap2_clk_wait_ready(struct clk *clk) 178 { 179 void __iomem *reg, *other_reg, *st_reg; 180 u32 bit; 181 182 /* 183 * REVISIT: This code is pretty ugly. It would be nice to generalize 184 * it and pull it into struct clk itself somehow. 185 */ 186 reg = clk->enable_reg; 187 if ((((u32)reg & 0xff) >= CM_FCLKEN1) && 188 (((u32)reg & 0xff) <= OMAP24XX_CM_FCLKEN2)) 189 other_reg = (void __iomem *)(((u32)reg & ~0xf0) | 0x10); /* CM_ICLKEN* */ 190 else if ((((u32)reg & 0xff) >= CM_ICLKEN1) && 191 (((u32)reg & 0xff) <= OMAP24XX_CM_ICLKEN4)) 192 other_reg = (void __iomem *)(((u32)reg & ~0xf0) | 0x00); /* CM_FCLKEN* */ 193 else 194 return; 195 196 /* REVISIT: What are the appropriate exclusions for 34XX? */ 197 /* No check for DSS or cam clocks */ 198 if (cpu_is_omap24xx() && ((u32)reg & 0x0f) == 0) { /* CM_{F,I}CLKEN1 */ 199 if (clk->enable_bit == OMAP24XX_EN_DSS2_SHIFT || 200 clk->enable_bit == OMAP24XX_EN_DSS1_SHIFT || 201 clk->enable_bit == OMAP24XX_EN_CAM_SHIFT) 202 return; 203 } 204 205 /* REVISIT: What are the appropriate exclusions for 34XX? */ 206 /* OMAP3: ignore DSS-mod clocks */ 207 if (cpu_is_omap34xx() && 208 (((u32)reg & ~0xff) == (u32)OMAP_CM_REGADDR(OMAP3430_DSS_MOD, 0) || 209 ((((u32)reg & ~0xff) == (u32)OMAP_CM_REGADDR(CORE_MOD, 0)) && 210 clk->enable_bit == OMAP3430_EN_SSI_SHIFT))) 211 return; 212 213 /* Check if both functional and interface clocks 214 * are running. */ 215 bit = 1 << clk->enable_bit; 216 if (!(__raw_readl(other_reg) & bit)) 217 return; 218 st_reg = (void __iomem *)(((u32)other_reg & ~0xf0) | 0x20); /* CM_IDLEST* */ 219 220 omap2_wait_clock_ready(st_reg, bit, clk->name); 221 } 222 223 /* Enables clock without considering parent dependencies or use count 224 * REVISIT: Maybe change this to use clk->enable like on omap1? 225 */ 226 int _omap2_clk_enable(struct clk *clk) 227 { 228 u32 regval32; 229 230 if (clk->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK)) 231 return 0; 232 233 if (clk->enable) 234 return clk->enable(clk); 235 236 if (unlikely(clk->enable_reg == 0)) { 237 printk(KERN_ERR "clock.c: Enable for %s without enable code\n", 238 clk->name); 239 return 0; /* REVISIT: -EINVAL */ 240 } 241 242 regval32 = __raw_readl(clk->enable_reg); 243 if (clk->flags & INVERT_ENABLE) 244 regval32 &= ~(1 << clk->enable_bit); 245 else 246 regval32 |= (1 << clk->enable_bit); 247 __raw_writel(regval32, clk->enable_reg); 248 wmb(); 249 250 omap2_clk_wait_ready(clk); 251 252 return 0; 253 } 254 255 /* Disables clock without considering parent dependencies or use count */ 256 void _omap2_clk_disable(struct clk *clk) 257 { 258 u32 regval32; 259 260 if (clk->flags & (ALWAYS_ENABLED | PARENT_CONTROLS_CLOCK)) 261 return; 262 263 if (clk->disable) { 264 clk->disable(clk); 265 return; 266 } 267 268 if (clk->enable_reg == 0) { 269 /* 270 * 'Independent' here refers to a clock which is not 271 * controlled by its parent. 272 */ 273 printk(KERN_ERR "clock: clk_disable called on independent " 274 "clock %s which has no enable_reg\n", clk->name); 275 return; 276 } 277 278 regval32 = __raw_readl(clk->enable_reg); 279 if (clk->flags & INVERT_ENABLE) 280 regval32 |= (1 << clk->enable_bit); 281 else 282 regval32 &= ~(1 << clk->enable_bit); 283 __raw_writel(regval32, clk->enable_reg); 284 wmb(); 285 } 286 287 void omap2_clk_disable(struct clk *clk) 288 { 289 if (clk->usecount > 0 && !(--clk->usecount)) { 290 _omap2_clk_disable(clk); 291 if (likely((u32)clk->parent)) 292 omap2_clk_disable(clk->parent); 293 } 294 } 295 296 int omap2_clk_enable(struct clk *clk) 297 { 298 int ret = 0; 299 300 if (clk->usecount++ == 0) { 301 if (likely((u32)clk->parent)) 302 ret = omap2_clk_enable(clk->parent); 303 304 if (unlikely(ret != 0)) { 305 clk->usecount--; 306 return ret; 307 } 308 309 ret = _omap2_clk_enable(clk); 310 311 if (unlikely(ret != 0) && clk->parent) { 312 omap2_clk_disable(clk->parent); 313 clk->usecount--; 314 } 315 } 316 317 return ret; 318 } 319 320 /* 321 * Used for clocks that are part of CLKSEL_xyz governed clocks. 322 * REVISIT: Maybe change to use clk->enable() functions like on omap1? 323 */ 324 void omap2_clksel_recalc(struct clk *clk) 325 { 326 u32 div = 0; 327 328 pr_debug("clock: recalc'ing clksel clk %s\n", clk->name); 329 330 div = omap2_clksel_get_divisor(clk); 331 if (div == 0) 332 return; 333 334 if (unlikely(clk->rate == clk->parent->rate / div)) 335 return; 336 clk->rate = clk->parent->rate / div; 337 338 pr_debug("clock: new clock rate is %ld (div %d)\n", clk->rate, div); 339 340 if (unlikely(clk->flags & RATE_PROPAGATES)) 341 propagate_rate(clk); 342 } 343 344 /** 345 * omap2_get_clksel_by_parent - return clksel struct for a given clk & parent 346 * @clk: OMAP struct clk ptr to inspect 347 * @src_clk: OMAP struct clk ptr of the parent clk to search for 348 * 349 * Scan the struct clksel array associated with the clock to find 350 * the element associated with the supplied parent clock address. 351 * Returns a pointer to the struct clksel on success or NULL on error. 352 */ 353 const struct clksel *omap2_get_clksel_by_parent(struct clk *clk, 354 struct clk *src_clk) 355 { 356 const struct clksel *clks; 357 358 if (!clk->clksel) 359 return NULL; 360 361 for (clks = clk->clksel; clks->parent; clks++) { 362 if (clks->parent == src_clk) 363 break; /* Found the requested parent */ 364 } 365 366 if (!clks->parent) { 367 printk(KERN_ERR "clock: Could not find parent clock %s in " 368 "clksel array of clock %s\n", src_clk->name, 369 clk->name); 370 return NULL; 371 } 372 373 return clks; 374 } 375 376 /** 377 * omap2_clksel_round_rate_div - find divisor for the given clock and rate 378 * @clk: OMAP struct clk to use 379 * @target_rate: desired clock rate 380 * @new_div: ptr to where we should store the divisor 381 * 382 * Finds 'best' divider value in an array based on the source and target 383 * rates. The divider array must be sorted with smallest divider first. 384 * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT, 385 * they are only settable as part of virtual_prcm set. 386 * 387 * Returns the rounded clock rate or returns 0xffffffff on error. 388 */ 389 u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate, 390 u32 *new_div) 391 { 392 unsigned long test_rate; 393 const struct clksel *clks; 394 const struct clksel_rate *clkr; 395 u32 last_div = 0; 396 397 printk(KERN_INFO "clock: clksel_round_rate_div: %s target_rate %ld\n", 398 clk->name, target_rate); 399 400 *new_div = 1; 401 402 clks = omap2_get_clksel_by_parent(clk, clk->parent); 403 if (clks == NULL) 404 return ~0; 405 406 for (clkr = clks->rates; clkr->div; clkr++) { 407 if (!(clkr->flags & cpu_mask)) 408 continue; 409 410 /* Sanity check */ 411 if (clkr->div <= last_div) 412 printk(KERN_ERR "clock: clksel_rate table not sorted " 413 "for clock %s", clk->name); 414 415 last_div = clkr->div; 416 417 test_rate = clk->parent->rate / clkr->div; 418 419 if (test_rate <= target_rate) 420 break; /* found it */ 421 } 422 423 if (!clkr->div) { 424 printk(KERN_ERR "clock: Could not find divisor for target " 425 "rate %ld for clock %s parent %s\n", target_rate, 426 clk->name, clk->parent->name); 427 return ~0; 428 } 429 430 *new_div = clkr->div; 431 432 printk(KERN_INFO "clock: new_div = %d, new_rate = %ld\n", *new_div, 433 (clk->parent->rate / clkr->div)); 434 435 return (clk->parent->rate / clkr->div); 436 } 437 438 /** 439 * omap2_clksel_round_rate - find rounded rate for the given clock and rate 440 * @clk: OMAP struct clk to use 441 * @target_rate: desired clock rate 442 * 443 * Compatibility wrapper for OMAP clock framework 444 * Finds best target rate based on the source clock and possible dividers. 445 * rates. The divider array must be sorted with smallest divider first. 446 * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT, 447 * they are only settable as part of virtual_prcm set. 448 * 449 * Returns the rounded clock rate or returns 0xffffffff on error. 450 */ 451 long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate) 452 { 453 u32 new_div; 454 455 return omap2_clksel_round_rate_div(clk, target_rate, &new_div); 456 } 457 458 459 /* Given a clock and a rate apply a clock specific rounding function */ 460 long omap2_clk_round_rate(struct clk *clk, unsigned long rate) 461 { 462 if (clk->round_rate != 0) 463 return clk->round_rate(clk, rate); 464 465 if (clk->flags & RATE_FIXED) 466 printk(KERN_ERR "clock: generic omap2_clk_round_rate called " 467 "on fixed-rate clock %s\n", clk->name); 468 469 return clk->rate; 470 } 471 472 /** 473 * omap2_clksel_to_divisor() - turn clksel field value into integer divider 474 * @clk: OMAP struct clk to use 475 * @field_val: register field value to find 476 * 477 * Given a struct clk of a rate-selectable clksel clock, and a register field 478 * value to search for, find the corresponding clock divisor. The register 479 * field value should be pre-masked and shifted down so the LSB is at bit 0 480 * before calling. Returns 0 on error 481 */ 482 u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val) 483 { 484 const struct clksel *clks; 485 const struct clksel_rate *clkr; 486 487 clks = omap2_get_clksel_by_parent(clk, clk->parent); 488 if (clks == NULL) 489 return 0; 490 491 for (clkr = clks->rates; clkr->div; clkr++) { 492 if ((clkr->flags & cpu_mask) && (clkr->val == field_val)) 493 break; 494 } 495 496 if (!clkr->div) { 497 printk(KERN_ERR "clock: Could not find fieldval %d for " 498 "clock %s parent %s\n", field_val, clk->name, 499 clk->parent->name); 500 return 0; 501 } 502 503 return clkr->div; 504 } 505 506 /** 507 * omap2_divisor_to_clksel() - turn clksel integer divisor into a field value 508 * @clk: OMAP struct clk to use 509 * @div: integer divisor to search for 510 * 511 * Given a struct clk of a rate-selectable clksel clock, and a clock divisor, 512 * find the corresponding register field value. The return register value is 513 * the value before left-shifting. Returns 0xffffffff on error 514 */ 515 u32 omap2_divisor_to_clksel(struct clk *clk, u32 div) 516 { 517 const struct clksel *clks; 518 const struct clksel_rate *clkr; 519 520 /* should never happen */ 521 WARN_ON(div == 0); 522 523 clks = omap2_get_clksel_by_parent(clk, clk->parent); 524 if (clks == NULL) 525 return 0; 526 527 for (clkr = clks->rates; clkr->div; clkr++) { 528 if ((clkr->flags & cpu_mask) && (clkr->div == div)) 529 break; 530 } 531 532 if (!clkr->div) { 533 printk(KERN_ERR "clock: Could not find divisor %d for " 534 "clock %s parent %s\n", div, clk->name, 535 clk->parent->name); 536 return 0; 537 } 538 539 return clkr->val; 540 } 541 542 /** 543 * omap2_get_clksel - find clksel register addr & field mask for a clk 544 * @clk: struct clk to use 545 * @field_mask: ptr to u32 to store the register field mask 546 * 547 * Returns the address of the clksel register upon success or NULL on error. 548 */ 549 void __iomem *omap2_get_clksel(struct clk *clk, u32 *field_mask) 550 { 551 if (unlikely((clk->clksel_reg == 0) || (clk->clksel_mask == 0))) 552 return NULL; 553 554 *field_mask = clk->clksel_mask; 555 556 return clk->clksel_reg; 557 } 558 559 /** 560 * omap2_clksel_get_divisor - get current divider applied to parent clock. 561 * @clk: OMAP struct clk to use. 562 * 563 * Returns the integer divisor upon success or 0 on error. 564 */ 565 u32 omap2_clksel_get_divisor(struct clk *clk) 566 { 567 u32 field_mask, field_val; 568 void __iomem *div_addr; 569 570 div_addr = omap2_get_clksel(clk, &field_mask); 571 if (div_addr == 0) 572 return 0; 573 574 field_val = __raw_readl(div_addr) & field_mask; 575 field_val >>= __ffs(field_mask); 576 577 return omap2_clksel_to_divisor(clk, field_val); 578 } 579 580 int omap2_clksel_set_rate(struct clk *clk, unsigned long rate) 581 { 582 u32 field_mask, field_val, reg_val, validrate, new_div = 0; 583 void __iomem *div_addr; 584 585 validrate = omap2_clksel_round_rate_div(clk, rate, &new_div); 586 if (validrate != rate) 587 return -EINVAL; 588 589 div_addr = omap2_get_clksel(clk, &field_mask); 590 if (div_addr == 0) 591 return -EINVAL; 592 593 field_val = omap2_divisor_to_clksel(clk, new_div); 594 if (field_val == ~0) 595 return -EINVAL; 596 597 reg_val = __raw_readl(div_addr); 598 reg_val &= ~field_mask; 599 reg_val |= (field_val << __ffs(field_mask)); 600 __raw_writel(reg_val, div_addr); 601 wmb(); 602 603 clk->rate = clk->parent->rate / new_div; 604 605 if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) { 606 __raw_writel(OMAP24XX_VALID_CONFIG, OMAP24XX_PRCM_CLKCFG_CTRL); 607 wmb(); 608 } 609 610 return 0; 611 } 612 613 614 /* Set the clock rate for a clock source */ 615 int omap2_clk_set_rate(struct clk *clk, unsigned long rate) 616 { 617 int ret = -EINVAL; 618 619 pr_debug("clock: set_rate for clock %s to rate %ld\n", clk->name, rate); 620 621 /* CONFIG_PARTICIPANT clocks are changed only in sets via the 622 rate table mechanism, driven by mpu_speed */ 623 if (clk->flags & CONFIG_PARTICIPANT) 624 return -EINVAL; 625 626 /* dpll_ck, core_ck, virt_prcm_set; plus all clksel clocks */ 627 if (clk->set_rate != 0) 628 ret = clk->set_rate(clk, rate); 629 630 if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES))) 631 propagate_rate(clk); 632 633 return ret; 634 } 635 636 /* 637 * Converts encoded control register address into a full address 638 * On error, *src_addr will be returned as 0. 639 */ 640 static u32 omap2_clksel_get_src_field(void __iomem **src_addr, 641 struct clk *src_clk, u32 *field_mask, 642 struct clk *clk, u32 *parent_div) 643 { 644 const struct clksel *clks; 645 const struct clksel_rate *clkr; 646 647 *parent_div = 0; 648 *src_addr = 0; 649 650 clks = omap2_get_clksel_by_parent(clk, src_clk); 651 if (clks == NULL) 652 return 0; 653 654 for (clkr = clks->rates; clkr->div; clkr++) { 655 if (clkr->flags & (cpu_mask | DEFAULT_RATE)) 656 break; /* Found the default rate for this platform */ 657 } 658 659 if (!clkr->div) { 660 printk(KERN_ERR "clock: Could not find default rate for " 661 "clock %s parent %s\n", clk->name, 662 src_clk->parent->name); 663 return 0; 664 } 665 666 /* Should never happen. Add a clksel mask to the struct clk. */ 667 WARN_ON(clk->clksel_mask == 0); 668 669 *field_mask = clk->clksel_mask; 670 *src_addr = clk->clksel_reg; 671 *parent_div = clkr->div; 672 673 return clkr->val; 674 } 675 676 int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent) 677 { 678 void __iomem *src_addr; 679 u32 field_val, field_mask, reg_val, parent_div; 680 681 if (unlikely(clk->flags & CONFIG_PARTICIPANT)) 682 return -EINVAL; 683 684 if (!clk->clksel) 685 return -EINVAL; 686 687 field_val = omap2_clksel_get_src_field(&src_addr, new_parent, 688 &field_mask, clk, &parent_div); 689 if (src_addr == 0) 690 return -EINVAL; 691 692 if (clk->usecount > 0) 693 _omap2_clk_disable(clk); 694 695 /* Set new source value (previous dividers if any in effect) */ 696 reg_val = __raw_readl(src_addr) & ~field_mask; 697 reg_val |= (field_val << __ffs(field_mask)); 698 __raw_writel(reg_val, src_addr); 699 wmb(); 700 701 if (clk->flags & DELAYED_APP && cpu_is_omap24xx()) { 702 __raw_writel(OMAP24XX_VALID_CONFIG, OMAP24XX_PRCM_CLKCFG_CTRL); 703 wmb(); 704 } 705 706 if (clk->usecount > 0) 707 _omap2_clk_enable(clk); 708 709 clk->parent = new_parent; 710 711 /* CLKSEL clocks follow their parents' rates, divided by a divisor */ 712 clk->rate = new_parent->rate; 713 714 if (parent_div > 0) 715 clk->rate /= parent_div; 716 717 pr_debug("clock: set parent of %s to %s (new rate %ld)\n", 718 clk->name, clk->parent->name, clk->rate); 719 720 if (unlikely(clk->flags & RATE_PROPAGATES)) 721 propagate_rate(clk); 722 723 return 0; 724 } 725 726 /*------------------------------------------------------------------------- 727 * Omap2 clock reset and init functions 728 *-------------------------------------------------------------------------*/ 729 730 #ifdef CONFIG_OMAP_RESET_CLOCKS 731 void omap2_clk_disable_unused(struct clk *clk) 732 { 733 u32 regval32, v; 734 735 v = (clk->flags & INVERT_ENABLE) ? (1 << clk->enable_bit) : 0; 736 737 regval32 = __raw_readl(clk->enable_reg); 738 if ((regval32 & (1 << clk->enable_bit)) == v) 739 return; 740 741 printk(KERN_INFO "Disabling unused clock \"%s\"\n", clk->name); 742 _omap2_clk_disable(clk); 743 } 744 #endif 745