|
@@ -92,6 +92,8 @@ static int _clkdm_register(struct clockdomain *clkdm)
|
|
|
|
|
|
pwrdm_add_clkdm(pwrdm, clkdm);
|
|
|
|
|
|
+ spin_lock_init(&clkdm->lock);
|
|
|
+
|
|
|
pr_debug("clockdomain: registered %s\n", clkdm->name);
|
|
|
|
|
|
return 0;
|
|
@@ -690,6 +692,9 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
|
|
|
*/
|
|
|
int clkdm_sleep(struct clockdomain *clkdm)
|
|
|
{
|
|
|
+ int ret;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
if (!clkdm)
|
|
|
return -EINVAL;
|
|
|
|
|
@@ -704,9 +709,11 @@ int clkdm_sleep(struct clockdomain *clkdm)
|
|
|
|
|
|
pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
|
|
|
|
|
|
+ spin_lock_irqsave(&clkdm->lock, flags);
|
|
|
clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
|
|
|
-
|
|
|
- return arch_clkdm->clkdm_sleep(clkdm);
|
|
|
+ ret = arch_clkdm->clkdm_sleep(clkdm);
|
|
|
+ spin_unlock_irqrestore(&clkdm->lock, flags);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -720,6 +727,9 @@ int clkdm_sleep(struct clockdomain *clkdm)
|
|
|
*/
|
|
|
int clkdm_wakeup(struct clockdomain *clkdm)
|
|
|
{
|
|
|
+ int ret;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
if (!clkdm)
|
|
|
return -EINVAL;
|
|
|
|
|
@@ -734,9 +744,11 @@ int clkdm_wakeup(struct clockdomain *clkdm)
|
|
|
|
|
|
pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
|
|
|
|
|
|
+ spin_lock_irqsave(&clkdm->lock, flags);
|
|
|
clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
|
|
|
-
|
|
|
- return arch_clkdm->clkdm_wakeup(clkdm);
|
|
|
+ ret = arch_clkdm->clkdm_wakeup(clkdm);
|
|
|
+ spin_unlock_irqrestore(&clkdm->lock, flags);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -751,6 +763,8 @@ int clkdm_wakeup(struct clockdomain *clkdm)
|
|
|
*/
|
|
|
void clkdm_allow_idle(struct clockdomain *clkdm)
|
|
|
{
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
if (!clkdm)
|
|
|
return;
|
|
|
|
|
@@ -766,10 +780,11 @@ void clkdm_allow_idle(struct clockdomain *clkdm)
|
|
|
pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
|
|
|
clkdm->name);
|
|
|
|
|
|
+ spin_lock_irqsave(&clkdm->lock, flags);
|
|
|
clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED;
|
|
|
-
|
|
|
arch_clkdm->clkdm_allow_idle(clkdm);
|
|
|
pwrdm_clkdm_state_switch(clkdm);
|
|
|
+ spin_unlock_irqrestore(&clkdm->lock, flags);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -783,6 +798,8 @@ void clkdm_allow_idle(struct clockdomain *clkdm)
|
|
|
*/
|
|
|
void clkdm_deny_idle(struct clockdomain *clkdm)
|
|
|
{
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
if (!clkdm)
|
|
|
return;
|
|
|
|
|
@@ -798,9 +815,10 @@ void clkdm_deny_idle(struct clockdomain *clkdm)
|
|
|
pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
|
|
|
clkdm->name);
|
|
|
|
|
|
+ spin_lock_irqsave(&clkdm->lock, flags);
|
|
|
clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
|
|
|
-
|
|
|
arch_clkdm->clkdm_deny_idle(clkdm);
|
|
|
+ spin_unlock_irqrestore(&clkdm->lock, flags);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -816,16 +834,25 @@ void clkdm_deny_idle(struct clockdomain *clkdm)
|
|
|
*/
|
|
|
bool clkdm_in_hwsup(struct clockdomain *clkdm)
|
|
|
{
|
|
|
+ bool ret;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
if (!clkdm)
|
|
|
return false;
|
|
|
|
|
|
- return (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false;
|
|
|
+ spin_lock_irqsave(&clkdm->lock, flags);
|
|
|
+ ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false;
|
|
|
+ spin_unlock_irqrestore(&clkdm->lock, flags);
|
|
|
+
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
/* Clockdomain-to-clock/hwmod framework interface code */
|
|
|
|
|
|
static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
|
|
|
{
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable)
|
|
|
return -EINVAL;
|
|
|
|
|
@@ -837,9 +864,11 @@ static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
|
|
|
if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps)
|
|
|
return 0;
|
|
|
|
|
|
+ spin_lock_irqsave(&clkdm->lock, flags);
|
|
|
arch_clkdm->clkdm_clk_enable(clkdm);
|
|
|
pwrdm_wait_transition(clkdm->pwrdm.ptr);
|
|
|
pwrdm_clkdm_state_switch(clkdm);
|
|
|
+ spin_unlock_irqrestore(&clkdm->lock, flags);
|
|
|
|
|
|
pr_debug("clockdomain: clkdm %s: enabled\n", clkdm->name);
|
|
|
|
|
@@ -848,6 +877,8 @@ static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
|
|
|
|
|
|
static int _clkdm_clk_hwmod_disable(struct clockdomain *clkdm)
|
|
|
{
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
|
|
|
return -EINVAL;
|
|
|
|
|
@@ -859,8 +890,10 @@ static int _clkdm_clk_hwmod_disable(struct clockdomain *clkdm)
|
|
|
if (atomic_dec_return(&clkdm->usecount) > 0)
|
|
|
return 0;
|
|
|
|
|
|
+ spin_lock_irqsave(&clkdm->lock, flags);
|
|
|
arch_clkdm->clkdm_clk_disable(clkdm);
|
|
|
pwrdm_clkdm_state_switch(clkdm);
|
|
|
+ spin_unlock_irqrestore(&clkdm->lock, flags);
|
|
|
|
|
|
pr_debug("clockdomain: clkdm %s: disabled\n", clkdm->name);
|
|
|
|