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