cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

clockdomain.c (38164B)


      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 */
     35static LIST_HEAD(clkdm_list);
     36
     37/* array of clockdomain deps to be added/removed when clkdm in hwsup mode */
     38static struct clkdm_autodep *autodeps;
     39
     40static struct clkdm_ops *arch_clkdm;
     41void clkdm_save_context(void);
     42void clkdm_restore_context(void);
     43
     44/* Private functions */
     45
     46static 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 */
     73static 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 */
    102static 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 */
    140static 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 */
    165static 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 */
    192static 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 */
    235static 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 */
    280static 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 */
    325static 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 */
    370int 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 */
    393int 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 */
    433int 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
    453static 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 */
    477int 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 */
    511struct 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 */
    544int 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 */
    570struct 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 */
    593int 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 */
    622int 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 */
    655int 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 */
    690int 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 */
    713int 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 */
    744int 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 */
    779int 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 */
    814int 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 */
    834int 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 */
    868int 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 */
    888int 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 */
    922int 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 */
    944void 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 */
    985void 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 - 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 */
   1002void 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 */
   1039void 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/**
   1047 * clkdm_in_hwsup - is clockdomain @clkdm have hardware-supervised idle enabled?
   1048 * @clkdm: struct clockdomain *
   1049 *
   1050 * Returns true if clockdomain @clkdm currently has
   1051 * hardware-supervised idle enabled, or false if it does not or if
   1052 * @clkdm is NULL.  It is only valid to call this function after
   1053 * clkdm_init() has been called.  This function does not actually read
   1054 * bits from the hardware; it instead tests an in-memory flag that is
   1055 * changed whenever the clockdomain code changes the auto-idle mode.
   1056 */
   1057bool clkdm_in_hwsup(struct clockdomain *clkdm)
   1058{
   1059	bool ret;
   1060
   1061	if (!clkdm)
   1062		return false;
   1063
   1064	ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false;
   1065
   1066	return ret;
   1067}
   1068
   1069/**
   1070 * clkdm_missing_idle_reporting - can @clkdm enter autoidle even if in use?
   1071 * @clkdm: struct clockdomain *
   1072 *
   1073 * Returns true if clockdomain @clkdm has the
   1074 * CLKDM_MISSING_IDLE_REPORTING flag set, or false if not or @clkdm is
   1075 * null.  More information is available in the documentation for the
   1076 * CLKDM_MISSING_IDLE_REPORTING macro.
   1077 */
   1078bool clkdm_missing_idle_reporting(struct clockdomain *clkdm)
   1079{
   1080	if (!clkdm)
   1081		return false;
   1082
   1083	return (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING) ? true : false;
   1084}
   1085
   1086/* Public autodep handling functions (deprecated) */
   1087
   1088/**
   1089 * clkdm_add_autodeps - add auto sleepdeps/wkdeps to clkdm upon clock enable
   1090 * @clkdm: struct clockdomain *
   1091 *
   1092 * Add the "autodep" sleep & wakeup dependencies to clockdomain 'clkdm'
   1093 * in hardware-supervised mode.  Meant to be called from clock framework
   1094 * when a clock inside clockdomain 'clkdm' is enabled.	No return value.
   1095 *
   1096 * XXX autodeps are deprecated and should be removed at the earliest
   1097 * opportunity
   1098 */
   1099void clkdm_add_autodeps(struct clockdomain *clkdm)
   1100{
   1101	struct clkdm_autodep *autodep;
   1102
   1103	if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
   1104		return;
   1105
   1106	for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
   1107		if (IS_ERR(autodep->clkdm.ptr))
   1108			continue;
   1109
   1110		pr_debug("clockdomain: %s: adding %s sleepdep/wkdep\n",
   1111			 clkdm->name, autodep->clkdm.ptr->name);
   1112
   1113		_clkdm_add_sleepdep(clkdm, autodep->clkdm.ptr);
   1114		_clkdm_add_wkdep(clkdm, autodep->clkdm.ptr);
   1115	}
   1116}
   1117
   1118/**
   1119 * clkdm_del_autodeps - remove auto sleepdeps/wkdeps from clkdm
   1120 * @clkdm: struct clockdomain *
   1121 *
   1122 * Remove the "autodep" sleep & wakeup dependencies from clockdomain 'clkdm'
   1123 * in hardware-supervised mode.  Meant to be called from clock framework
   1124 * when a clock inside clockdomain 'clkdm' is disabled.  No return value.
   1125 *
   1126 * XXX autodeps are deprecated and should be removed at the earliest
   1127 * opportunity
   1128 */
   1129void clkdm_del_autodeps(struct clockdomain *clkdm)
   1130{
   1131	struct clkdm_autodep *autodep;
   1132
   1133	if (!autodeps || clkdm->flags & CLKDM_NO_AUTODEPS)
   1134		return;
   1135
   1136	for (autodep = autodeps; autodep->clkdm.ptr; autodep++) {
   1137		if (IS_ERR(autodep->clkdm.ptr))
   1138			continue;
   1139
   1140		pr_debug("clockdomain: %s: removing %s sleepdep/wkdep\n",
   1141			 clkdm->name, autodep->clkdm.ptr->name);
   1142
   1143		_clkdm_del_sleepdep(clkdm, autodep->clkdm.ptr);
   1144		_clkdm_del_wkdep(clkdm, autodep->clkdm.ptr);
   1145	}
   1146}
   1147
   1148/* Clockdomain-to-clock/hwmod framework interface code */
   1149
   1150/**
   1151 * clkdm_clk_enable - add an enabled downstream clock to this clkdm
   1152 * @clkdm: struct clockdomain *
   1153 * @clk: struct clk * of the enabled downstream clock
   1154 *
   1155 * Increment the usecount of the clockdomain @clkdm and ensure that it
   1156 * is awake before @clk is enabled.  Intended to be called by
   1157 * clk_enable() code.  If the clockdomain is in software-supervised
   1158 * idle mode, force the clockdomain to wake.  If the clockdomain is in
   1159 * hardware-supervised idle mode, add clkdm-pwrdm autodependencies, to
   1160 * ensure that devices in the clockdomain can be read from/written to
   1161 * by on-chip processors.  Returns -EINVAL if passed null pointers;
   1162 * returns 0 upon success or if the clockdomain is in hwsup idle mode.
   1163 */
   1164int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *unused)
   1165{
   1166	if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable)
   1167		return -EINVAL;
   1168
   1169	pwrdm_lock(clkdm->pwrdm.ptr);
   1170
   1171	/*
   1172	 * For arch's with no autodeps, clkcm_clk_enable
   1173	 * should be called for every clock instance or hwmod that is
   1174	 * enabled, so the clkdm can be force woken up.
   1175	 */
   1176	clkdm->usecount++;
   1177	if (clkdm->usecount > 1 && autodeps) {
   1178		pwrdm_unlock(clkdm->pwrdm.ptr);
   1179		return 0;
   1180	}
   1181
   1182	arch_clkdm->clkdm_clk_enable(clkdm);
   1183	pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
   1184	pwrdm_unlock(clkdm->pwrdm.ptr);
   1185
   1186	pr_debug("clockdomain: %s: enabled\n", clkdm->name);
   1187
   1188	return 0;
   1189}
   1190
   1191/**
   1192 * clkdm_clk_disable - remove an enabled downstream clock from this clkdm
   1193 * @clkdm: struct clockdomain *
   1194 * @clk: struct clk * of the disabled downstream clock
   1195 *
   1196 * Decrement the usecount of this clockdomain @clkdm when @clk is
   1197 * disabled.  Intended to be called by clk_disable() code.  If the
   1198 * clockdomain usecount goes to 0, put the clockdomain to sleep
   1199 * (software-supervised mode) or remove the clkdm autodependencies
   1200 * (hardware-supervised mode).  Returns -EINVAL if passed null
   1201 * pointers; -ERANGE if the @clkdm usecount underflows; or returns 0
   1202 * upon success or if the clockdomain is in hwsup idle mode.
   1203 */
   1204int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
   1205{
   1206	if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
   1207		return -EINVAL;
   1208
   1209	pwrdm_lock(clkdm->pwrdm.ptr);
   1210
   1211	/* corner case: disabling unused clocks */
   1212	if (clk && (__clk_get_enable_count(clk) == 0) && clkdm->usecount == 0)
   1213		goto ccd_exit;
   1214
   1215	if (clkdm->usecount == 0) {
   1216		pwrdm_unlock(clkdm->pwrdm.ptr);
   1217		WARN_ON(1); /* underflow */
   1218		return -ERANGE;
   1219	}
   1220
   1221	clkdm->usecount--;
   1222	if (clkdm->usecount > 0) {
   1223		pwrdm_unlock(clkdm->pwrdm.ptr);
   1224		return 0;
   1225	}
   1226
   1227	arch_clkdm->clkdm_clk_disable(clkdm);
   1228	pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
   1229
   1230	pr_debug("clockdomain: %s: disabled\n", clkdm->name);
   1231
   1232ccd_exit:
   1233	pwrdm_unlock(clkdm->pwrdm.ptr);
   1234
   1235	return 0;
   1236}
   1237
   1238/**
   1239 * clkdm_hwmod_enable - add an enabled downstream hwmod to this clkdm
   1240 * @clkdm: struct clockdomain *
   1241 * @oh: struct omap_hwmod * of the enabled downstream hwmod
   1242 *
   1243 * Increment the usecount of the clockdomain @clkdm and ensure that it
   1244 * is awake before @oh is enabled. Intended to be called by
   1245 * module_enable() code.
   1246 * If the clockdomain is in software-supervised idle mode, force the
   1247 * clockdomain to wake.  If the clockdomain is in hardware-supervised idle
   1248 * mode, add clkdm-pwrdm autodependencies, to ensure that devices in the
   1249 * clockdomain can be read from/written to by on-chip processors.
   1250 * Returns -EINVAL if passed null pointers;
   1251 * returns 0 upon success or if the clockdomain is in hwsup idle mode.
   1252 */
   1253int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh)
   1254{
   1255	/* The clkdm attribute does not exist yet prior OMAP4 */
   1256	if (cpu_is_omap24xx() || cpu_is_omap34xx())
   1257		return 0;
   1258
   1259	/*
   1260	 * XXX Rewrite this code to maintain a list of enabled
   1261	 * downstream hwmods for debugging purposes?
   1262	 */
   1263
   1264	if (!oh)
   1265		return -EINVAL;
   1266
   1267	return clkdm_clk_enable(clkdm, NULL);
   1268}
   1269
   1270/**
   1271 * clkdm_hwmod_disable - remove an enabled downstream hwmod from this clkdm
   1272 * @clkdm: struct clockdomain *
   1273 * @oh: struct omap_hwmod * of the disabled downstream hwmod
   1274 *
   1275 * Decrement the usecount of this clockdomain @clkdm when @oh is
   1276 * disabled. Intended to be called by module_disable() code.
   1277 * If the clockdomain usecount goes to 0, put the clockdomain to sleep
   1278 * (software-supervised mode) or remove the clkdm autodependencies
   1279 * (hardware-supervised mode).
   1280 * Returns -EINVAL if passed null pointers; -ERANGE if the @clkdm usecount
   1281 * underflows; or returns 0 upon success or if the clockdomain is in hwsup
   1282 * idle mode.
   1283 */
   1284int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)
   1285{
   1286	/* The clkdm attribute does not exist yet prior OMAP4 */
   1287	if (cpu_is_omap24xx() || cpu_is_omap34xx())
   1288		return 0;
   1289
   1290	if (!oh)
   1291		return -EINVAL;
   1292
   1293	return clkdm_clk_disable(clkdm, NULL);
   1294}
   1295
   1296/**
   1297 * _clkdm_save_context - save the context for the control of this clkdm
   1298 *
   1299 * Due to a suspend or hibernation operation, the state of the registers
   1300 * controlling this clkdm will be lost, save their context.
   1301 */
   1302static int _clkdm_save_context(struct clockdomain *clkdm, void *unused)
   1303{
   1304	if (!arch_clkdm || !arch_clkdm->clkdm_save_context)
   1305		return -EINVAL;
   1306
   1307	return arch_clkdm->clkdm_save_context(clkdm);
   1308}
   1309
   1310/**
   1311 * _clkdm_restore_context - restore context for control of this clkdm
   1312 *
   1313 * Restore the register values for this clockdomain.
   1314 */
   1315static int _clkdm_restore_context(struct clockdomain *clkdm, void *unused)
   1316{
   1317	if (!arch_clkdm || !arch_clkdm->clkdm_restore_context)
   1318		return -EINVAL;
   1319
   1320	return arch_clkdm->clkdm_restore_context(clkdm);
   1321}
   1322
   1323/**
   1324 * clkdm_save_context - Saves the context for each registered clkdm
   1325 *
   1326 * Save the context for each registered clockdomain.
   1327 */
   1328void clkdm_save_context(void)
   1329{
   1330	clkdm_for_each(_clkdm_save_context, NULL);
   1331}
   1332
   1333/**
   1334 * clkdm_restore_context - Restores the context for each registered clkdm
   1335 *
   1336 * Restore the context for each registered clockdomain.
   1337 */
   1338void clkdm_restore_context(void)
   1339{
   1340	clkdm_for_each(_clkdm_restore_context, NULL);
   1341}