1 /* 2 * OMAP2/3/4 clockdomain framework functions 3 * 4 * Copyright (C) 2008-2011 Texas Instruments, Inc. 5 * Copyright (C) 2008-2011 Nokia Corporation 6 * 7 * Written by Paul Walmsley and Jouni Högander 8 * Added OMAP4 specific support by Abhijit Pagare <abhijitpagare@ti.com> 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13 */ 14 #undef DEBUG 15 16 #include <linux/kernel.h> 17 #include <linux/device.h> 18 #include <linux/list.h> 19 #include <linux/errno.h> 20 #include <linux/string.h> 21 #include <linux/delay.h> 22 #include <linux/clk.h> 23 #include <linux/limits.h> 24 #include <linux/err.h> 25 #include <linux/clk-provider.h> 26 #include <linux/cpu_pm.h> 27 28 #include <linux/io.h> 29 30 #include <linux/bitops.h> 31 32 #include "soc.h" 33 #include "clock.h" 34 #include "clockdomain.h" 35 #include "pm.h" 36 37 /* clkdm_list contains all registered struct clockdomains */ 38 static LIST_HEAD(clkdm_list); 39 40 /* array of clockdomain deps to be added/removed when clkdm in hwsup mode */ 41 static struct clkdm_autodep *autodeps; 42 43 static struct clkdm_ops *arch_clkdm; 44 void clkdm_save_context(void); 45 void clkdm_restore_context(void); 46 47 /* Private functions */ 48 49 static struct clockdomain *_clkdm_lookup(const char *name) 50 { 51 struct clockdomain *clkdm, *temp_clkdm; 52 53 if (!name) 54 return NULL; 55 56 clkdm = NULL; 57 58 list_for_each_entry(temp_clkdm, &clkdm_list, node) { 59 if (!strcmp(name, temp_clkdm->name)) { 60 clkdm = temp_clkdm; 61 break; 62 } 63 } 64 65 return clkdm; 66 } 67 68 /** 69 * _clkdm_register - register a clockdomain 70 * @clkdm: struct clockdomain * to register 71 * 72 * Adds a clockdomain to the internal clockdomain list. 73 * Returns -EINVAL if given a null pointer, -EEXIST if a clockdomain is 74 * already registered by the provided name, or 0 upon success. 75 */ 76 static int _clkdm_register(struct clockdomain *clkdm) 77 { 78 struct powerdomain *pwrdm; 79 80 if (!clkdm || !clkdm->name) 81 return -EINVAL; 82 83 pwrdm = pwrdm_lookup(clkdm->pwrdm.name); 84 if (!pwrdm) { 85 pr_err("clockdomain: %s: powerdomain %s does not exist\n", 86 clkdm->name, clkdm->pwrdm.name); 87 return -EINVAL; 88 } 89 clkdm->pwrdm.ptr = pwrdm; 90 91 /* Verify that the clockdomain is not already registered */ 92 if (_clkdm_lookup(clkdm->name)) 93 return -EEXIST; 94 95 list_add(&clkdm->node, &clkdm_list); 96 97 pwrdm_add_clkdm(pwrdm, clkdm); 98 99 pr_debug("clockdomain: registered %s\n", clkdm->name); 100 101 return 0; 102 } 103 104 /* _clkdm_deps_lookup - look up the specified clockdomain in a clkdm list */ 105 static struct clkdm_dep *_clkdm_deps_lookup(struct clockdomain *clkdm, 106 struct clkdm_dep *deps) 107 { 108 struct clkdm_dep *cd; 109 110 if (!clkdm || !deps) 111 return ERR_PTR(-EINVAL); 112 113 for (cd = deps; cd->clkdm_name; cd++) { 114 if (!cd->clkdm && cd->clkdm_name) 115 cd->clkdm = _clkdm_lookup(cd->clkdm_name); 116 117 if (cd->clkdm == clkdm) 118 break; 119 } 120 121 if (!cd->clkdm_name) 122 return ERR_PTR(-ENOENT); 123 124 return cd; 125 } 126 127 /** 128 * _autodep_lookup - resolve autodep clkdm names to clkdm pointers; store 129 * @autodep: struct clkdm_autodep * to resolve 130 * 131 * Resolve autodep clockdomain names to clockdomain pointers via 132 * clkdm_lookup() and store the pointers in the autodep structure. An 133 * "autodep" is a clockdomain sleep/wakeup dependency that is 134 * automatically added and removed whenever clocks in the associated 135 * clockdomain are enabled or disabled (respectively) when the 136 * clockdomain is in hardware-supervised mode. Meant to be called 137 * once at clockdomain layer initialization, since these should remain 138 * fixed for a particular architecture. No return value. 139 * 140 * XXX autodeps are deprecated and should be removed at the earliest 141 * opportunity 142 */ 143 static void _autodep_lookup(struct clkdm_autodep *autodep) 144 { 145 struct clockdomain *clkdm; 146 147 if (!autodep) 148 return; 149 150 clkdm = clkdm_lookup(autodep->clkdm.name); 151 if (!clkdm) { 152 pr_err("clockdomain: autodeps: clockdomain %s does not exist\n", 153 autodep->clkdm.name); 154 clkdm = ERR_PTR(-ENOENT); 155 } 156 autodep->clkdm.ptr = clkdm; 157 } 158 159 /** 160 * _resolve_clkdm_deps() - resolve clkdm_names in @clkdm_deps to clkdms 161 * @clkdm: clockdomain that we are resolving dependencies for 162 * @clkdm_deps: ptr to array of struct clkdm_deps to resolve 163 * 164 * Iterates through @clkdm_deps, looking up the struct clockdomain named by 165 * clkdm_name and storing the clockdomain pointer in the struct clkdm_dep. 166 * No return value. 167 */ 168 static void _resolve_clkdm_deps(struct clockdomain *clkdm, 169 struct clkdm_dep *clkdm_deps) 170 { 171 struct clkdm_dep *cd; 172 173 for (cd = clkdm_deps; cd && cd->clkdm_name; cd++) { 174 if (cd->clkdm) 175 continue; 176 cd->clkdm = _clkdm_lookup(cd->clkdm_name); 177 178 WARN(!cd->clkdm, "clockdomain: %s: could not find clkdm %s while resolving dependencies - should never happen", 179 clkdm->name, cd->clkdm_name); 180 } 181 } 182 183 /** 184 * _clkdm_add_wkdep - add a wakeup dependency from clkdm2 to clkdm1 (lockless) 185 * @clkdm1: wake this struct clockdomain * up (dependent) 186 * @clkdm2: when this struct clockdomain * wakes up (source) 187 * 188 * When the clockdomain represented by @clkdm2 wakes up, wake up 189 * @clkdm1. Implemented in hardware on the OMAP, this feature is 190 * designed to reduce wakeup latency of the dependent clockdomain @clkdm1. 191 * Returns -EINVAL if presented with invalid clockdomain pointers, 192 * -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 0 upon 193 * success. 194 */ 195 static int _clkdm_add_wkdep(struct clockdomain *clkdm1, 196 struct clockdomain *clkdm2) 197 { 198 struct clkdm_dep *cd; 199 int ret = 0; 200 201 if (!clkdm1 || !clkdm2) 202 return -EINVAL; 203 204 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 205 if (IS_ERR(cd)) 206 ret = PTR_ERR(cd); 207 208 if (!arch_clkdm || !arch_clkdm->clkdm_add_wkdep) 209 ret = -EINVAL; 210 211 if (ret) { 212 pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n", 213 clkdm1->name, clkdm2->name); 214 return ret; 215 } 216 217 cd->wkdep_usecount++; 218 if (cd->wkdep_usecount == 1) { 219 pr_debug("clockdomain: hardware will wake up %s when %s wakes up\n", 220 clkdm1->name, clkdm2->name); 221 222 ret = arch_clkdm->clkdm_add_wkdep(clkdm1, clkdm2); 223 } 224 225 return ret; 226 } 227 228 /** 229 * _clkdm_del_wkdep - remove a wakeup dep from clkdm2 to clkdm1 (lockless) 230 * @clkdm1: wake this struct clockdomain * up (dependent) 231 * @clkdm2: when this struct clockdomain * wakes up (source) 232 * 233 * Remove a wakeup dependency causing @clkdm1 to wake up when @clkdm2 234 * wakes up. Returns -EINVAL if presented with invalid clockdomain 235 * pointers, -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 236 * 0 upon success. 237 */ 238 static int _clkdm_del_wkdep(struct clockdomain *clkdm1, 239 struct clockdomain *clkdm2) 240 { 241 struct clkdm_dep *cd; 242 int ret = 0; 243 244 if (!clkdm1 || !clkdm2) 245 return -EINVAL; 246 247 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 248 if (IS_ERR(cd)) 249 ret = PTR_ERR(cd); 250 251 if (!arch_clkdm || !arch_clkdm->clkdm_del_wkdep) 252 ret = -EINVAL; 253 254 if (ret) { 255 pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n", 256 clkdm1->name, clkdm2->name); 257 return ret; 258 } 259 260 cd->wkdep_usecount--; 261 if (cd->wkdep_usecount == 0) { 262 pr_debug("clockdomain: hardware will no longer wake up %s after %s wakes up\n", 263 clkdm1->name, clkdm2->name); 264 265 ret = arch_clkdm->clkdm_del_wkdep(clkdm1, clkdm2); 266 } 267 268 return ret; 269 } 270 271 /** 272 * _clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1 (lockless) 273 * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) 274 * @clkdm2: when this struct clockdomain * is active (source) 275 * 276 * Prevent @clkdm1 from automatically going inactive (and then to 277 * retention or off) if @clkdm2 is active. Returns -EINVAL if 278 * presented with invalid clockdomain pointers or called on a machine 279 * that does not support software-configurable hardware sleep 280 * dependencies, -ENOENT if the specified dependency cannot be set in 281 * hardware, or 0 upon success. 282 */ 283 static int _clkdm_add_sleepdep(struct clockdomain *clkdm1, 284 struct clockdomain *clkdm2) 285 { 286 struct clkdm_dep *cd; 287 int ret = 0; 288 289 if (!clkdm1 || !clkdm2) 290 return -EINVAL; 291 292 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); 293 if (IS_ERR(cd)) 294 ret = PTR_ERR(cd); 295 296 if (!arch_clkdm || !arch_clkdm->clkdm_add_sleepdep) 297 ret = -EINVAL; 298 299 if (ret) { 300 pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n", 301 clkdm1->name, clkdm2->name); 302 return ret; 303 } 304 305 cd->sleepdep_usecount++; 306 if (cd->sleepdep_usecount == 1) { 307 pr_debug("clockdomain: will prevent %s from sleeping if %s is active\n", 308 clkdm1->name, clkdm2->name); 309 310 ret = arch_clkdm->clkdm_add_sleepdep(clkdm1, clkdm2); 311 } 312 313 return ret; 314 } 315 316 /** 317 * _clkdm_del_sleepdep - remove a sleep dep from clkdm2 to clkdm1 (lockless) 318 * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) 319 * @clkdm2: when this struct clockdomain * is active (source) 320 * 321 * Allow @clkdm1 to automatically go inactive (and then to retention or 322 * off), independent of the activity state of @clkdm2. Returns -EINVAL 323 * if presented with invalid clockdomain pointers or called on a machine 324 * that does not support software-configurable hardware sleep dependencies, 325 * -ENOENT if the specified dependency cannot be cleared in hardware, or 326 * 0 upon success. 327 */ 328 static int _clkdm_del_sleepdep(struct clockdomain *clkdm1, 329 struct clockdomain *clkdm2) 330 { 331 struct clkdm_dep *cd; 332 int ret = 0; 333 334 if (!clkdm1 || !clkdm2) 335 return -EINVAL; 336 337 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); 338 if (IS_ERR(cd)) 339 ret = PTR_ERR(cd); 340 341 if (!arch_clkdm || !arch_clkdm->clkdm_del_sleepdep) 342 ret = -EINVAL; 343 344 if (ret) { 345 pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n", 346 clkdm1->name, clkdm2->name); 347 return ret; 348 } 349 350 cd->sleepdep_usecount--; 351 if (cd->sleepdep_usecount == 0) { 352 pr_debug("clockdomain: will no longer prevent %s from sleeping if %s is active\n", 353 clkdm1->name, clkdm2->name); 354 355 ret = arch_clkdm->clkdm_del_sleepdep(clkdm1, clkdm2); 356 } 357 358 return ret; 359 } 360 361 /* Public functions */ 362 363 /** 364 * clkdm_register_platform_funcs - register clockdomain implementation fns 365 * @co: func pointers for arch specific implementations 366 * 367 * Register the list of function pointers used to implement the 368 * clockdomain functions on different OMAP SoCs. Should be called 369 * before any other clkdm_register*() function. Returns -EINVAL if 370 * @co is null, -EEXIST if platform functions have already been 371 * registered, or 0 upon success. 372 */ 373 int clkdm_register_platform_funcs(struct clkdm_ops *co) 374 { 375 if (!co) 376 return -EINVAL; 377 378 if (arch_clkdm) 379 return -EEXIST; 380 381 arch_clkdm = co; 382 383 return 0; 384 }; 385 386 /** 387 * clkdm_register_clkdms - register SoC clockdomains 388 * @cs: pointer to an array of struct clockdomain to register 389 * 390 * Register the clockdomains available on a particular OMAP SoC. Must 391 * be called after clkdm_register_platform_funcs(). May be called 392 * multiple times. Returns -EACCES if called before 393 * clkdm_register_platform_funcs(); -EINVAL if the argument @cs is 394 * null; or 0 upon success. 395 */ 396 int clkdm_register_clkdms(struct clockdomain **cs) 397 { 398 struct clockdomain **c = NULL; 399 400 if (!arch_clkdm) 401 return -EACCES; 402 403 if (!cs) 404 return -EINVAL; 405 406 for (c = cs; *c; c++) 407 _clkdm_register(*c); 408 409 return 0; 410 } 411 412 /** 413 * clkdm_register_autodeps - register autodeps (if required) 414 * @ia: pointer to a static array of struct clkdm_autodep to register 415 * 416 * Register clockdomain "automatic dependencies." These are 417 * clockdomain wakeup and sleep dependencies that are automatically 418 * added whenever the first clock inside a clockdomain is enabled, and 419 * removed whenever the last clock inside a clockdomain is disabled. 420 * These are currently only used on OMAP3 devices, and are deprecated, 421 * since they waste energy. However, until the OMAP2/3 IP block 422 * enable/disable sequence can be converted to match the OMAP4 423 * sequence, they are needed. 424 * 425 * Must be called only after all of the SoC clockdomains are 426 * registered, since the function will resolve autodep clockdomain 427 * names into clockdomain pointers. 428 * 429 * The struct clkdm_autodep @ia array must be static, as this function 430 * does not copy the array elements. 431 * 432 * Returns -EACCES if called before any clockdomains have been 433 * registered, -EINVAL if called with a null @ia argument, -EEXIST if 434 * autodeps have already been registered, or 0 upon success. 435 */ 436 int clkdm_register_autodeps(struct clkdm_autodep *ia) 437 { 438 struct clkdm_autodep *a = NULL; 439 440 if (list_empty(&clkdm_list)) 441 return -EACCES; 442 443 if (!ia) 444 return -EINVAL; 445 446 if (autodeps) 447 return -EEXIST; 448 449 autodeps = ia; 450 for (a = autodeps; a->clkdm.ptr; a++) 451 _autodep_lookup(a); 452 453 return 0; 454 } 455 456 static int cpu_notifier(struct notifier_block *nb, unsigned long cmd, void *v) 457 { 458 switch (cmd) { 459 case CPU_CLUSTER_PM_ENTER: 460 if (enable_off_mode) 461 clkdm_save_context(); 462 break; 463 case CPU_CLUSTER_PM_EXIT: 464 if (enable_off_mode) 465 clkdm_restore_context(); 466 break; 467 } 468 469 return NOTIFY_OK; 470 } 471 472 /** 473 * clkdm_complete_init - set up the clockdomain layer 474 * 475 * Put all clockdomains into software-supervised mode; PM code should 476 * later enable hardware-supervised mode as appropriate. Must be 477 * called after clkdm_register_clkdms(). Returns -EACCES if called 478 * before clkdm_register_clkdms(), or 0 upon success. 479 */ 480 int clkdm_complete_init(void) 481 { 482 struct clockdomain *clkdm; 483 static struct notifier_block nb; 484 485 if (list_empty(&clkdm_list)) 486 return -EACCES; 487 488 list_for_each_entry(clkdm, &clkdm_list, node) { 489 clkdm_deny_idle(clkdm); 490 491 _resolve_clkdm_deps(clkdm, clkdm->wkdep_srcs); 492 clkdm_clear_all_wkdeps(clkdm); 493 494 _resolve_clkdm_deps(clkdm, clkdm->sleepdep_srcs); 495 clkdm_clear_all_sleepdeps(clkdm); 496 } 497 498 /* Only AM43XX can lose clkdm context during rtc-ddr suspend */ 499 if (soc_is_am43xx()) { 500 nb.notifier_call = cpu_notifier; 501 cpu_pm_register_notifier(&nb); 502 } 503 504 return 0; 505 } 506 507 /** 508 * clkdm_lookup - look up a clockdomain by name, return a pointer 509 * @name: name of clockdomain 510 * 511 * Find a registered clockdomain by its name @name. Returns a pointer 512 * to the struct clockdomain if found, or NULL otherwise. 513 */ 514 struct clockdomain *clkdm_lookup(const char *name) 515 { 516 struct clockdomain *clkdm, *temp_clkdm; 517 518 if (!name) 519 return NULL; 520 521 clkdm = NULL; 522 523 list_for_each_entry(temp_clkdm, &clkdm_list, node) { 524 if (!strcmp(name, temp_clkdm->name)) { 525 clkdm = temp_clkdm; 526 break; 527 } 528 } 529 530 return clkdm; 531 } 532 533 /** 534 * clkdm_for_each - call function on each registered clockdomain 535 * @fn: callback function * 536 * 537 * Call the supplied function @fn for each registered clockdomain. 538 * The callback function @fn can return anything but 0 to bail 539 * out early from the iterator. The callback function is called with 540 * the clkdm_mutex held, so no clockdomain structure manipulation 541 * functions should be called from the callback, although hardware 542 * clockdomain control functions are fine. Returns the last return 543 * value of the callback function, which should be 0 for success or 544 * anything else to indicate failure; or -EINVAL if the function pointer 545 * is null. 546 */ 547 int clkdm_for_each(int (*fn)(struct clockdomain *clkdm, void *user), 548 void *user) 549 { 550 struct clockdomain *clkdm; 551 int ret = 0; 552 553 if (!fn) 554 return -EINVAL; 555 556 list_for_each_entry(clkdm, &clkdm_list, node) { 557 ret = (*fn)(clkdm, user); 558 if (ret) 559 break; 560 } 561 562 return ret; 563 } 564 565 566 /** 567 * clkdm_get_pwrdm - return a ptr to the pwrdm that this clkdm resides in 568 * @clkdm: struct clockdomain * 569 * 570 * Return a pointer to the struct powerdomain that the specified clockdomain 571 * @clkdm exists in, or returns NULL if @clkdm is NULL. 572 */ 573 struct powerdomain *clkdm_get_pwrdm(struct clockdomain *clkdm) 574 { 575 if (!clkdm) 576 return NULL; 577 578 return clkdm->pwrdm.ptr; 579 } 580 581 582 /* Hardware clockdomain control */ 583 584 /** 585 * clkdm_add_wkdep - add a wakeup dependency from clkdm2 to clkdm1 586 * @clkdm1: wake this struct clockdomain * up (dependent) 587 * @clkdm2: when this struct clockdomain * wakes up (source) 588 * 589 * When the clockdomain represented by @clkdm2 wakes up, wake up 590 * @clkdm1. Implemented in hardware on the OMAP, this feature is 591 * designed to reduce wakeup latency of the dependent clockdomain @clkdm1. 592 * Returns -EINVAL if presented with invalid clockdomain pointers, 593 * -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 0 upon 594 * success. 595 */ 596 int clkdm_add_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 597 { 598 struct clkdm_dep *cd; 599 int ret; 600 601 if (!clkdm1 || !clkdm2) 602 return -EINVAL; 603 604 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 605 if (IS_ERR(cd)) 606 return PTR_ERR(cd); 607 608 pwrdm_lock(cd->clkdm->pwrdm.ptr); 609 ret = _clkdm_add_wkdep(clkdm1, clkdm2); 610 pwrdm_unlock(cd->clkdm->pwrdm.ptr); 611 612 return ret; 613 } 614 615 /** 616 * clkdm_del_wkdep - remove a wakeup dependency from clkdm2 to clkdm1 617 * @clkdm1: wake this struct clockdomain * up (dependent) 618 * @clkdm2: when this struct clockdomain * wakes up (source) 619 * 620 * Remove a wakeup dependency causing @clkdm1 to wake up when @clkdm2 621 * wakes up. Returns -EINVAL if presented with invalid clockdomain 622 * pointers, -ENOENT if @clkdm2 cannot wake up clkdm1 in hardware, or 623 * 0 upon success. 624 */ 625 int clkdm_del_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 626 { 627 struct clkdm_dep *cd; 628 int ret; 629 630 if (!clkdm1 || !clkdm2) 631 return -EINVAL; 632 633 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 634 if (IS_ERR(cd)) 635 return PTR_ERR(cd); 636 637 pwrdm_lock(cd->clkdm->pwrdm.ptr); 638 ret = _clkdm_del_wkdep(clkdm1, clkdm2); 639 pwrdm_unlock(cd->clkdm->pwrdm.ptr); 640 641 return ret; 642 } 643 644 /** 645 * clkdm_read_wkdep - read wakeup dependency state from clkdm2 to clkdm1 646 * @clkdm1: wake this struct clockdomain * up (dependent) 647 * @clkdm2: when this struct clockdomain * wakes up (source) 648 * 649 * Return 1 if a hardware wakeup dependency exists wherein @clkdm1 will be 650 * awoken when @clkdm2 wakes up; 0 if dependency is not set; -EINVAL 651 * if either clockdomain pointer is invalid; or -ENOENT if the hardware 652 * is incapable. 653 * 654 * REVISIT: Currently this function only represents software-controllable 655 * wakeup dependencies. Wakeup dependencies fixed in hardware are not 656 * yet handled here. 657 */ 658 int clkdm_read_wkdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 659 { 660 struct clkdm_dep *cd; 661 int ret = 0; 662 663 if (!clkdm1 || !clkdm2) 664 return -EINVAL; 665 666 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 667 if (IS_ERR(cd)) 668 ret = PTR_ERR(cd); 669 670 if (!arch_clkdm || !arch_clkdm->clkdm_read_wkdep) 671 ret = -EINVAL; 672 673 if (ret) { 674 pr_debug("clockdomain: hardware cannot set/clear wake up of %s when %s wakes up\n", 675 clkdm1->name, clkdm2->name); 676 return ret; 677 } 678 679 /* XXX It's faster to return the wkdep_usecount */ 680 return arch_clkdm->clkdm_read_wkdep(clkdm1, clkdm2); 681 } 682 683 /** 684 * clkdm_clear_all_wkdeps - remove all wakeup dependencies from target clkdm 685 * @clkdm: struct clockdomain * to remove all wakeup dependencies from 686 * 687 * Remove all inter-clockdomain wakeup dependencies that could cause 688 * @clkdm to wake. Intended to be used during boot to initialize the 689 * PRCM to a known state, after all clockdomains are put into swsup idle 690 * and woken up. Returns -EINVAL if @clkdm pointer is invalid, or 691 * 0 upon success. 692 */ 693 int clkdm_clear_all_wkdeps(struct clockdomain *clkdm) 694 { 695 if (!clkdm) 696 return -EINVAL; 697 698 if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_wkdeps) 699 return -EINVAL; 700 701 return arch_clkdm->clkdm_clear_all_wkdeps(clkdm); 702 } 703 704 /** 705 * clkdm_add_sleepdep - add a sleep dependency from clkdm2 to clkdm1 706 * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) 707 * @clkdm2: when this struct clockdomain * is active (source) 708 * 709 * Prevent @clkdm1 from automatically going inactive (and then to 710 * retention or off) if @clkdm2 is active. Returns -EINVAL if 711 * presented with invalid clockdomain pointers or called on a machine 712 * that does not support software-configurable hardware sleep 713 * dependencies, -ENOENT if the specified dependency cannot be set in 714 * hardware, or 0 upon success. 715 */ 716 int clkdm_add_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 717 { 718 struct clkdm_dep *cd; 719 int ret; 720 721 if (!clkdm1 || !clkdm2) 722 return -EINVAL; 723 724 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 725 if (IS_ERR(cd)) 726 return PTR_ERR(cd); 727 728 pwrdm_lock(cd->clkdm->pwrdm.ptr); 729 ret = _clkdm_add_sleepdep(clkdm1, clkdm2); 730 pwrdm_unlock(cd->clkdm->pwrdm.ptr); 731 732 return ret; 733 } 734 735 /** 736 * clkdm_del_sleepdep - remove a sleep dependency from clkdm2 to clkdm1 737 * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) 738 * @clkdm2: when this struct clockdomain * is active (source) 739 * 740 * Allow @clkdm1 to automatically go inactive (and then to retention or 741 * off), independent of the activity state of @clkdm2. Returns -EINVAL 742 * if presented with invalid clockdomain pointers or called on a machine 743 * that does not support software-configurable hardware sleep dependencies, 744 * -ENOENT if the specified dependency cannot be cleared in hardware, or 745 * 0 upon success. 746 */ 747 int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 748 { 749 struct clkdm_dep *cd; 750 int ret; 751 752 if (!clkdm1 || !clkdm2) 753 return -EINVAL; 754 755 cd = _clkdm_deps_lookup(clkdm2, clkdm1->wkdep_srcs); 756 if (IS_ERR(cd)) 757 return PTR_ERR(cd); 758 759 pwrdm_lock(cd->clkdm->pwrdm.ptr); 760 ret = _clkdm_del_sleepdep(clkdm1, clkdm2); 761 pwrdm_unlock(cd->clkdm->pwrdm.ptr); 762 763 return ret; 764 } 765 766 /** 767 * clkdm_read_sleepdep - read sleep dependency state from clkdm2 to clkdm1 768 * @clkdm1: prevent this struct clockdomain * from sleeping (dependent) 769 * @clkdm2: when this struct clockdomain * is active (source) 770 * 771 * Return 1 if a hardware sleep dependency exists wherein @clkdm1 will 772 * not be allowed to automatically go inactive if @clkdm2 is active; 773 * 0 if @clkdm1's automatic power state inactivity transition is independent 774 * of @clkdm2's; -EINVAL if either clockdomain pointer is invalid or called 775 * on a machine that does not support software-configurable hardware sleep 776 * dependencies; or -ENOENT if the hardware is incapable. 777 * 778 * REVISIT: Currently this function only represents software-controllable 779 * sleep dependencies. Sleep dependencies fixed in hardware are not 780 * yet handled here. 781 */ 782 int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2) 783 { 784 struct clkdm_dep *cd; 785 int ret = 0; 786 787 if (!clkdm1 || !clkdm2) 788 return -EINVAL; 789 790 cd = _clkdm_deps_lookup(clkdm2, clkdm1->sleepdep_srcs); 791 if (IS_ERR(cd)) 792 ret = PTR_ERR(cd); 793 794 if (!arch_clkdm || !arch_clkdm->clkdm_read_sleepdep) 795 ret = -EINVAL; 796 797 if (ret) { 798 pr_debug("clockdomain: hardware cannot set/clear sleep dependency affecting %s from %s\n", 799 clkdm1->name, clkdm2->name); 800 return ret; 801 } 802 803 /* XXX It's faster to return the sleepdep_usecount */ 804 return arch_clkdm->clkdm_read_sleepdep(clkdm1, clkdm2); 805 } 806 807 /** 808 * clkdm_clear_all_sleepdeps - remove all sleep dependencies from target clkdm 809 * @clkdm: struct clockdomain * to remove all sleep dependencies from 810 * 811 * Remove all inter-clockdomain sleep dependencies that could prevent 812 * @clkdm from idling. Intended to be used during boot to initialize the 813 * PRCM to a known state, after all clockdomains are put into swsup idle 814 * and woken up. Returns -EINVAL if @clkdm pointer is invalid, or 815 * 0 upon success. 816 */ 817 int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm) 818 { 819 if (!clkdm) 820 return -EINVAL; 821 822 if (!arch_clkdm || !arch_clkdm->clkdm_clear_all_sleepdeps) 823 return -EINVAL; 824 825 return arch_clkdm->clkdm_clear_all_sleepdeps(clkdm); 826 } 827 828 /** 829 * clkdm_sleep_nolock - force clockdomain sleep transition (lockless) 830 * @clkdm: struct clockdomain * 831 * 832 * Instruct the CM to force a sleep transition on the specified 833 * clockdomain @clkdm. Only for use by the powerdomain code. Returns 834 * -EINVAL if @clkdm is NULL or if clockdomain does not support 835 * software-initiated sleep; 0 upon success. 836 */ 837 int clkdm_sleep_nolock(struct clockdomain *clkdm) 838 { 839 int ret; 840 841 if (!clkdm) 842 return -EINVAL; 843 844 if (!(clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) { 845 pr_debug("clockdomain: %s does not support forcing sleep via software\n", 846 clkdm->name); 847 return -EINVAL; 848 } 849 850 if (!arch_clkdm || !arch_clkdm->clkdm_sleep) 851 return -EINVAL; 852 853 pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); 854 855 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; 856 ret = arch_clkdm->clkdm_sleep(clkdm); 857 ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); 858 859 return ret; 860 } 861 862 /** 863 * clkdm_sleep - force clockdomain sleep transition 864 * @clkdm: struct clockdomain * 865 * 866 * Instruct the CM to force a sleep transition on the specified 867 * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if 868 * clockdomain does not support software-initiated sleep; 0 upon 869 * success. 870 */ 871 int clkdm_sleep(struct clockdomain *clkdm) 872 { 873 int ret; 874 875 pwrdm_lock(clkdm->pwrdm.ptr); 876 ret = clkdm_sleep_nolock(clkdm); 877 pwrdm_unlock(clkdm->pwrdm.ptr); 878 879 return ret; 880 } 881 882 /** 883 * clkdm_wakeup_nolock - force clockdomain wakeup transition (lockless) 884 * @clkdm: struct clockdomain * 885 * 886 * Instruct the CM to force a wakeup transition on the specified 887 * clockdomain @clkdm. Only for use by the powerdomain code. Returns 888 * -EINVAL if @clkdm is NULL or if the clockdomain does not support 889 * software-controlled wakeup; 0 upon success. 890 */ 891 int clkdm_wakeup_nolock(struct clockdomain *clkdm) 892 { 893 int ret; 894 895 if (!clkdm) 896 return -EINVAL; 897 898 if (!(clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)) { 899 pr_debug("clockdomain: %s does not support forcing wakeup via software\n", 900 clkdm->name); 901 return -EINVAL; 902 } 903 904 if (!arch_clkdm || !arch_clkdm->clkdm_wakeup) 905 return -EINVAL; 906 907 pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); 908 909 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; 910 ret = arch_clkdm->clkdm_wakeup(clkdm); 911 ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); 912 913 return ret; 914 } 915 916 /** 917 * clkdm_wakeup - force clockdomain wakeup transition 918 * @clkdm: struct clockdomain * 919 * 920 * Instruct the CM to force a wakeup transition on the specified 921 * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the 922 * clockdomain does not support software-controlled wakeup; 0 upon 923 * success. 924 */ 925 int clkdm_wakeup(struct clockdomain *clkdm) 926 { 927 int ret; 928 929 pwrdm_lock(clkdm->pwrdm.ptr); 930 ret = clkdm_wakeup_nolock(clkdm); 931 pwrdm_unlock(clkdm->pwrdm.ptr); 932 933 return ret; 934 } 935 936 /** 937 * clkdm_allow_idle_nolock - enable hwsup idle transitions for clkdm 938 * @clkdm: struct clockdomain * 939 * 940 * Allow the hardware to automatically switch the clockdomain @clkdm 941 * into active or idle states, as needed by downstream clocks. If the 942 * clockdomain has any downstream clocks enabled in the clock 943 * framework, wkdep/sleepdep autodependencies are added; this is so 944 * device drivers can read and write to the device. Only for use by 945 * the powerdomain code. No return value. 946 */ 947 void clkdm_allow_idle_nolock(struct clockdomain *clkdm) 948 { 949 if (!clkdm) 950 return; 951 952 if (!WARN_ON(!clkdm->forcewake_count)) 953 clkdm->forcewake_count--; 954 955 if (clkdm->forcewake_count) 956 return; 957 958 if (!clkdm->usecount && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)) 959 clkdm_sleep_nolock(clkdm); 960 961 if (!(clkdm->flags & CLKDM_CAN_ENABLE_AUTO)) 962 return; 963 964 if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) 965 return; 966 967 if (!arch_clkdm || !arch_clkdm->clkdm_allow_idle) 968 return; 969 970 pr_debug("clockdomain: enabling automatic idle transitions for %s\n", 971 clkdm->name); 972 973 clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED; 974 arch_clkdm->clkdm_allow_idle(clkdm); 975 pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); 976 } 977 978 /** 979 * clkdm_allow_idle - enable hwsup idle transitions for clkdm 980 * @clkdm: struct clockdomain * 981 * 982 * Allow the hardware to automatically switch the clockdomain @clkdm into 983 * active or idle states, as needed by downstream clocks. If the 984 * clockdomain has any downstream clocks enabled in the clock 985 * framework, wkdep/sleepdep autodependencies are added; this is so 986 * device drivers can read and write to the device. No return value. 987 */ 988 void clkdm_allow_idle(struct clockdomain *clkdm) 989 { 990 pwrdm_lock(clkdm->pwrdm.ptr); 991 clkdm_allow_idle_nolock(clkdm); 992 pwrdm_unlock(clkdm->pwrdm.ptr); 993 } 994 995 /** 996 * clkdm_deny_idle - disable hwsup idle transitions for clkdm 997 * @clkdm: struct clockdomain * 998 * 999 * Prevent the hardware from automatically switching the clockdomain 1000 * @clkdm into inactive or idle states. If the clockdomain has 1001 * downstream clocks enabled in the clock framework, wkdep/sleepdep 1002 * autodependencies are removed. Only for use by the powerdomain 1003 * code. No return value. 1004 */ 1005 void clkdm_deny_idle_nolock(struct clockdomain *clkdm) 1006 { 1007 if (!clkdm) 1008 return; 1009 1010 if (clkdm->forcewake_count++) 1011 return; 1012 1013 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP) 1014 clkdm_wakeup_nolock(clkdm); 1015 1016 if (!(clkdm->flags & CLKDM_CAN_DISABLE_AUTO)) 1017 return; 1018 1019 if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) 1020 return; 1021 1022 if (!arch_clkdm || !arch_clkdm->clkdm_deny_idle) 1023 return; 1024 1025 pr_debug("clockdomain: disabling automatic idle transitions for %s\n", 1026 clkdm->name); 1027 1028 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; 1029 arch_clkdm->clkdm_deny_idle(clkdm); 1030 pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); 1031 } 1032 1033 /** 1034 * clkdm_deny_idle - disable hwsup idle transitions for clkdm 1035 * @clkdm: struct clockdomain * 1036 * 1037 * Prevent the hardware from automatically switching the clockdomain 1038 * @clkdm into inactive or idle states. If the clockdomain has 1039 * downstream clocks enabled in the clock framework, wkdep/sleepdep 1040 * autodependencies are removed. No return value. 1041 */ 1042 void clkdm_deny_idle(struct clockdomain *clkdm) 1043 { 1044 pwrdm_lock(clkdm->pwrdm.ptr); 1045 clkdm_deny_idle_nolock(clkdm); 1046 pwrdm_unlock(clkdm->pwrdm.ptr); 1047 } 1048 1049 /** 1050 * clkdm_in_hwsup - is clockdomain @clkdm have hardware-supervised idle enabled? 1051 * @clkdm: struct clockdomain * 1052 * 1053 * Returns true if clockdomain @clkdm currently has 1054 * hardware-supervised idle enabled, or false if it does not or if 1055 * @clkdm is NULL. It is only valid to call this function after 1056 * clkdm_init() has been called. This function does not actually read 1057 * bits from the hardware; it instead tests an in-memory flag that is 1058 * changed whenever the clockdomain code changes the auto-idle mode. 1059 */ 1060 bool clkdm_in_hwsup(struct clockdomain *clkdm) 1061 { 1062 bool ret; 1063 1064 if (!clkdm) 1065 return false; 1066 1067 ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false; 1068 1069 return ret; 1070 } 1071 1072 /** 1073 * clkdm_missing_idle_reporting - can @clkdm enter autoidle even if in use? 1074 * @clkdm: struct clockdomain * 1075 * 1076 * Returns true if clockdomain @clkdm has the 1077 * CLKDM_MISSING_IDLE_REPORTING flag set, or false if not or @clkdm is 1078 * null. More information is available in the documentation for the 1079 * CLKDM_MISSING_IDLE_REPORTING macro. 1080 */ 1081 bool clkdm_missing_idle_reporting(struct clockdomain *clkdm) 1082 { 1083 if (!clkdm) 1084 return false; 1085 1086 return (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) ? true : false; 1087 } 1088 1089 /* Public autodep handling functions (deprecated) */ 1090 1091 /** 1092 * clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable 1093 * @clkdm: struct clockdomain * 1094 * 1095 * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm' 1096 * in hardware-supervised mode. Meant to be called from clock framework 1097 * when a clock inside clockdomain 'clkdm' is enabled. No return value. 1098 * 1099 * XXX autodeps are deprecated and should be removed at the earliest 1100 * opportunity 1101 */ 1102 void clkdm_add_autodeps(struct clockdomain *clkdm) 1103 { 1104 struct clkdm_autodep *autodep; 1105 1106 if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) 1107 return; 1108 1109 for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { 1110 if (IS_ERR(autodep->clkdm.ptr)) 1111 continue; 1112 1113 pr_debug("clockdomain: %s: adding %s sleepdep/wkdep\n", 1114 clkdm->name, autodep->clkdm.ptr->name); 1115 1116 _clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr); 1117 _clkdm_add_wkdep(clkdm, autodep->clkdm.ptr); 1118 } 1119 } 1120 1121 /** 1122 * clkdm_del_autodeps - remove auto sleepdeps/wkdeps from clkdm 1123 * @clkdm: struct clockdomain * 1124 * 1125 * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm' 1126 * in hardware-supervised mode. Meant to be called from clock framework 1127 * when a clock inside clockdomain 'clkdm' is disabled. No return value. 1128 * 1129 * XXX autodeps are deprecated and should be removed at the earliest 1130 * opportunity 1131 */ 1132 void clkdm_del_autodeps(struct clockdomain *clkdm) 1133 { 1134 struct clkdm_autodep *autodep; 1135 1136 if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS) 1137 return; 1138 1139 for (autodep = autodeps; autodep->clkdm.ptr; autodep++) { 1140 if (IS_ERR(autodep->clkdm.ptr)) 1141 continue; 1142 1143 pr_debug("clockdomain: %s: removing %s sleepdep/wkdep\n", 1144 clkdm->name, autodep->clkdm.ptr->name); 1145 1146 _clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr); 1147 _clkdm_del_wkdep(clkdm, autodep->clkdm.ptr); 1148 } 1149 } 1150 1151 /* Clockdomain-to-clock/hwmod framework interface code */ 1152 1153 static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm) 1154 { 1155 if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable) 1156 return -EINVAL; 1157 1158 pwrdm_lock(clkdm->pwrdm.ptr); 1159 1160 /* 1161 * For arch's with no autodeps, clkcm_clk_enable 1162 * should be called for every clock instance or hwmod that is 1163 * enabled, so the clkdm can be force woken up. 1164 */ 1165 clkdm->usecount++; 1166 if (clkdm->usecount > 1 && autodeps) { 1167 pwrdm_unlock(clkdm->pwrdm.ptr); 1168 return 0; 1169 } 1170 1171 arch_clkdm->clkdm_clk_enable(clkdm); 1172 pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); 1173 pwrdm_unlock(clkdm->pwrdm.ptr); 1174 1175 pr_debug("clockdomain: %s: enabled\n", clkdm->name); 1176 1177 return 0; 1178 } 1179 1180 /** 1181 * clkdm_clk_enable - add an enabled downstream clock to this clkdm 1182 * @clkdm: struct clockdomain * 1183 * @clk: struct clk * of the enabled downstream clock 1184 * 1185 * Increment the usecount of the clockdomain @clkdm and ensure that it 1186 * is awake before @clk is enabled. Intended to be called by 1187 * clk_enable() code. If the clockdomain is in software-supervised 1188 * idle mode, force the clockdomain to wake. If the clockdomain is in 1189 * hardware-supervised idle mode, add clkdm-pwrdm autodependencies, to 1190 * ensure that devices in the clockdomain can be read from/written to 1191 * by on-chip processors. Returns -EINVAL if passed null pointers; 1192 * returns 0 upon success or if the clockdomain is in hwsup idle mode. 1193 */ 1194 int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk) 1195 { 1196 /* 1197 * XXX Rewrite this code to maintain a list of enabled 1198 * downstream clocks for debugging purposes? 1199 */ 1200 1201 if (!clk) 1202 return -EINVAL; 1203 1204 return _clkdm_clk_hwmod_enable(clkdm); 1205 } 1206 1207 /** 1208 * clkdm_clk_disable - remove an enabled downstream clock from this clkdm 1209 * @clkdm: struct clockdomain * 1210 * @clk: struct clk * of the disabled downstream clock 1211 * 1212 * Decrement the usecount of this clockdomain @clkdm when @clk is 1213 * disabled. Intended to be called by clk_disable() code. If the 1214 * clockdomain usecount goes to 0, put the clockdomain to sleep 1215 * (software-supervised mode) or remove the clkdm autodependencies 1216 * (hardware-supervised mode). Returns -EINVAL if passed null 1217 * pointers; -ERANGE if the @clkdm usecount underflows; or returns 0 1218 * upon success or if the clockdomain is in hwsup idle mode. 1219 */ 1220 int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) 1221 { 1222 if (!clkdm || !clk || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) 1223 return -EINVAL; 1224 1225 pwrdm_lock(clkdm->pwrdm.ptr); 1226 1227 /* corner case: disabling unused clocks */ 1228 if ((__clk_get_enable_count(clk) == 0) && clkdm->usecount == 0) 1229 goto ccd_exit; 1230 1231 if (clkdm->usecount == 0) { 1232 pwrdm_unlock(clkdm->pwrdm.ptr); 1233 WARN_ON(1); /* underflow */ 1234 return -ERANGE; 1235 } 1236 1237 clkdm->usecount--; 1238 if (clkdm->usecount > 0) { 1239 pwrdm_unlock(clkdm->pwrdm.ptr); 1240 return 0; 1241 } 1242 1243 arch_clkdm->clkdm_clk_disable(clkdm); 1244 pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); 1245 1246 pr_debug("clockdomain: %s: disabled\n", clkdm->name); 1247 1248 ccd_exit: 1249 pwrdm_unlock(clkdm->pwrdm.ptr); 1250 1251 return 0; 1252 } 1253 1254 /** 1255 * clkdm_hwmod_enable - add an enabled downstream hwmod to this clkdm 1256 * @clkdm: struct clockdomain * 1257 * @oh: struct omap_hwmod * of the enabled downstream hwmod 1258 * 1259 * Increment the usecount of the clockdomain @clkdm and ensure that it 1260 * is awake before @oh is enabled. Intended to be called by 1261 * module_enable() code. 1262 * If the clockdomain is in software-supervised idle mode, force the 1263 * clockdomain to wake. If the clockdomain is in hardware-supervised idle 1264 * mode, add clkdm-pwrdm autodependencies, to ensure that devices in the 1265 * clockdomain can be read from/written to by on-chip processors. 1266 * Returns -EINVAL if passed null pointers; 1267 * returns 0 upon success or if the clockdomain is in hwsup idle mode. 1268 */ 1269 int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh) 1270 { 1271 /* The clkdm attribute does not exist yet prior OMAP4 */ 1272 if (cpu_is_omap24xx() || cpu_is_omap34xx()) 1273 return 0; 1274 1275 /* 1276 * XXX Rewrite this code to maintain a list of enabled 1277 * downstream hwmods for debugging purposes? 1278 */ 1279 1280 if (!oh) 1281 return -EINVAL; 1282 1283 return _clkdm_clk_hwmod_enable(clkdm); 1284 } 1285 1286 /** 1287 * clkdm_hwmod_disable - remove an enabled downstream hwmod from this clkdm 1288 * @clkdm: struct clockdomain * 1289 * @oh: struct omap_hwmod * of the disabled downstream hwmod 1290 * 1291 * Decrement the usecount of this clockdomain @clkdm when @oh is 1292 * disabled. Intended to be called by module_disable() code. 1293 * If the clockdomain usecount goes to 0, put the clockdomain to sleep 1294 * (software-supervised mode) or remove the clkdm autodependencies 1295 * (hardware-supervised mode). 1296 * Returns -EINVAL if passed null pointers; -ERANGE if the @clkdm usecount 1297 * underflows; or returns 0 upon success or if the clockdomain is in hwsup 1298 * idle mode. 1299 */ 1300 int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh) 1301 { 1302 /* The clkdm attribute does not exist yet prior OMAP4 */ 1303 if (cpu_is_omap24xx() || cpu_is_omap34xx()) 1304 return 0; 1305 1306 /* 1307 * XXX Rewrite this code to maintain a list of enabled 1308 * downstream hwmods for debugging purposes? 1309 */ 1310 1311 if (!clkdm || !oh || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) 1312 return -EINVAL; 1313 1314 pwrdm_lock(clkdm->pwrdm.ptr); 1315 1316 if (clkdm->usecount == 0) { 1317 pwrdm_unlock(clkdm->pwrdm.ptr); 1318 WARN_ON(1); /* underflow */ 1319 return -ERANGE; 1320 } 1321 1322 clkdm->usecount--; 1323 if (clkdm->usecount > 0) { 1324 pwrdm_unlock(clkdm->pwrdm.ptr); 1325 return 0; 1326 } 1327 1328 arch_clkdm->clkdm_clk_disable(clkdm); 1329 pwrdm_state_switch_nolock(clkdm->pwrdm.ptr); 1330 pwrdm_unlock(clkdm->pwrdm.ptr); 1331 1332 pr_debug("clockdomain: %s: disabled\n", clkdm->name); 1333 1334 return 0; 1335 } 1336 1337 /** 1338 * _clkdm_save_context - save the context for the control of this clkdm 1339 * 1340 * Due to a suspend or hibernation operation, the state of the registers 1341 * controlling this clkdm will be lost, save their context. 1342 */ 1343 static int _clkdm_save_context(struct clockdomain *clkdm, void *ununsed) 1344 { 1345 if (!arch_clkdm || !arch_clkdm->clkdm_save_context) 1346 return -EINVAL; 1347 1348 return arch_clkdm->clkdm_save_context(clkdm); 1349 } 1350 1351 /** 1352 * _clkdm_restore_context - restore context for control of this clkdm 1353 * 1354 * Restore the register values for this clockdomain. 1355 */ 1356 static int _clkdm_restore_context(struct clockdomain *clkdm, void *ununsed) 1357 { 1358 if (!arch_clkdm || !arch_clkdm->clkdm_restore_context) 1359 return -EINVAL; 1360 1361 return arch_clkdm->clkdm_restore_context(clkdm); 1362 } 1363 1364 /** 1365 * clkdm_save_context - Saves the context for each registered clkdm 1366 * 1367 * Save the context for each registered clockdomain. 1368 */ 1369 void clkdm_save_context(void) 1370 { 1371 clkdm_for_each(_clkdm_save_context, NULL); 1372 } 1373 1374 /** 1375 * clkdm_restore_context - Restores the context for each registered clkdm 1376 * 1377 * Restore the context for each registered clockdomain. 1378 */ 1379 void clkdm_restore_context(void) 1380 { 1381 clkdm_for_each(_clkdm_restore_context, NULL); 1382 } 1383