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