summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/clockdomain.c
diff options
context:
space:
mode:
authorTero Kristo <t-kristo@ti.com>2016-06-30 15:15:02 +0200
committerTony Lindgren <tony@atomide.com>2016-07-04 16:15:38 +0200
commit1d9a5425654de6bb141c7ca1d5dde120ee8c5430 (patch)
tree84103ff301ecc87ba48339240b5b06ad1e816c4b /arch/arm/mach-omap2/clockdomain.c
parentARM: OMAP2+: timer: change order of hwmod data handling (diff)
downloadlinux-1d9a5425654de6bb141c7ca1d5dde120ee8c5430.tar.xz
linux-1d9a5425654de6bb141c7ca1d5dde120ee8c5430.zip
ARM: OMAP2+: clockdomain: add usecounting support to autoidle APIs
The previous implementation was racy in many locations, where the current status of the clockdomain was read out, some operations were executed, and the previous status info was used afterwards to decide next state for the clockdomain. Instead, fix the implementation of the allow_idle / deny_idle APIs to properly have usecounting support. This allows clean handling internally within the clockdomain core, and simplifies the usage also within hwmod. Signed-off-by: Tero Kristo <t-kristo@ti.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
Diffstat (limited to 'arch/arm/mach-omap2/clockdomain.c')
-rw-r--r--arch/arm/mach-omap2/clockdomain.c36
1 files changed, 24 insertions, 12 deletions
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index 2da3b5ec010c..b79b1ca9aee9 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -465,10 +465,7 @@ int clkdm_complete_init(void)
return -EACCES;
list_for_each_entry(clkdm, &clkdm_list, node) {
- if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
- clkdm_wakeup(clkdm);
- else if (clkdm->flags & CLKDM_CAN_DISABLE_AUTO)
- clkdm_deny_idle(clkdm);
+ clkdm_deny_idle(clkdm);
_resolve_clkdm_deps(clkdm, clkdm->wkdep_srcs);
clkdm_clear_all_wkdeps(clkdm);
@@ -925,11 +922,20 @@ void clkdm_allow_idle_nolock(struct clockdomain *clkdm)
if (!clkdm)
return;
- if (!(clkdm->flags & CLKDM_CAN_ENABLE_AUTO)) {
- pr_debug("clock: %s: automatic idle transitions cannot be enabled\n",
- clkdm->name);
+ if (!WARN_ON(!clkdm->forcewake_count))
+ clkdm->forcewake_count--;
+
+ if (clkdm->forcewake_count)
+ return;
+
+ if (!clkdm->usecount && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
+ clkdm_sleep_nolock(clkdm);
+
+ if (!(clkdm->flags & CLKDM_CAN_ENABLE_AUTO))
+ return;
+
+ if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING)
return;
- }
if (!arch_clkdm || !arch_clkdm->clkdm_allow_idle)
return;
@@ -974,11 +980,17 @@ void clkdm_deny_idle_nolock(struct clockdomain *clkdm)
if (!clkdm)
return;
- if (!(clkdm->flags & CLKDM_CAN_DISABLE_AUTO)) {
- pr_debug("clockdomain: %s: automatic idle transitions cannot be disabled\n",
- clkdm->name);
+ if (clkdm->forcewake_count++)
+ return;
+
+ if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
+ clkdm_wakeup_nolock(clkdm);
+
+ if (!(clkdm->flags & CLKDM_CAN_DISABLE_AUTO))
+ return;
+
+ if (clkdm->flags & CLKDM_MISSING_IDLE_REPORTING)
return;
- }
if (!arch_clkdm || !arch_clkdm->clkdm_deny_idle)
return;