msm: clock: Move voltage scaling to prepare/unprepare
Move the voltage calls to a sleepable context so we can avoid
spinning for hundreds of microseconds with interrupts disabled
waiting for a regulator to increase. This change also paves the
way to making the clock driver into a real regulator consumer
that uses the proper regulator APIs instead of the MSM specific
rpm_vreg API.
Doing this also requires us to make clk_set_rate() a sleeping
call so that concurrent clk_prepare() and clk_set_rate() calls
are synchronized. Making clk_set_rate() sleepable also
necessitates moving the clk_set_rate() call in clock-voter.c to a
sleepable context. Do that by having clock-voter aggregate and
update the rate in prepare/unprepare instead of enable/disable
(note that enable/disable of voter clocks implicitly calls
enable/disable on the parent via generic clock code).
Now that clk_set_rate() is sleeping, call clk_prepare() and
clk_unprepare() in the clock-local code when a rate change
requires reparenting the clock. This cleans up a problem we have
where sources may be left unprepared by a clock rate switch
(hence the default true warned flag for PLLs and crystals).
Change-Id: I493a00261055001a68fa884daa52e3d281ec6a2d
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
diff --git a/arch/arm/mach-msm/clock-voter.c b/arch/arm/mach-msm/clock-voter.c
index 4cd9b1c..3e1cbb9 100644
--- a/arch/arm/mach-msm/clock-voter.c
+++ b/arch/arm/mach-msm/clock-voter.c
@@ -12,13 +12,13 @@
*/
#include <linux/err.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/clk.h>
#include "clock.h"
#include "clock-voter.h"
-static DEFINE_SPINLOCK(voter_clk_lock);
+static DEFINE_MUTEX(voter_clk_lock);
/* Aggregate the rate of clocks that are currently on. */
static unsigned long voter_clk_aggregate_rate(const struct clk *parent)
@@ -37,12 +37,11 @@
static int voter_clk_set_rate(struct clk *clk, unsigned long rate)
{
int ret = 0;
- unsigned long flags;
struct clk *clkp;
struct clk_voter *clkh, *v = to_clk_voter(clk);
unsigned long cur_rate, new_rate, other_rate = 0;
- spin_lock_irqsave(&voter_clk_lock, flags);
+ mutex_lock(&voter_clk_lock);
if (v->enabled) {
struct clk *parent = v->parent;
@@ -68,20 +67,19 @@
}
clk->rate = rate;
unlock:
- spin_unlock_irqrestore(&voter_clk_lock, flags);
+ mutex_unlock(&voter_clk_lock);
return ret;
}
-static int voter_clk_enable(struct clk *clk)
+static int voter_clk_prepare(struct clk *clk)
{
int ret = 0;
- unsigned long flags;
unsigned long cur_rate;
struct clk *parent;
struct clk_voter *v = to_clk_voter(clk);
- spin_lock_irqsave(&voter_clk_lock, flags);
+ mutex_lock(&voter_clk_lock);
parent = v->parent;
/*
@@ -96,18 +94,18 @@
}
v->enabled = true;
out:
- spin_unlock_irqrestore(&voter_clk_lock, flags);
+ mutex_unlock(&voter_clk_lock);
return ret;
}
-static void voter_clk_disable(struct clk *clk)
+static void voter_clk_unprepare(struct clk *clk)
{
- unsigned long flags, cur_rate, new_rate;
+ unsigned long cur_rate, new_rate;
struct clk *parent;
struct clk_voter *v = to_clk_voter(clk);
- spin_lock_irqsave(&voter_clk_lock, flags);
+ mutex_lock(&voter_clk_lock);
parent = v->parent;
/*
@@ -121,7 +119,7 @@
if (new_rate < cur_rate)
clk_set_rate(parent, new_rate);
- spin_unlock_irqrestore(&voter_clk_lock, flags);
+ mutex_unlock(&voter_clk_lock);
}
static int voter_clk_is_enabled(struct clk *clk)
@@ -157,8 +155,8 @@
}
struct clk_ops clk_ops_voter = {
- .enable = voter_clk_enable,
- .disable = voter_clk_disable,
+ .prepare = voter_clk_prepare,
+ .unprepare = voter_clk_unprepare,
.set_rate = voter_clk_set_rate,
.is_enabled = voter_clk_is_enabled,
.round_rate = voter_clk_round_rate,