msm: clock: Move to per-clock voltage class support in the top-level driver
Generalize the voltage voting logic so that it lives in the
top-level clock.c driver. This has a couple of advantages:
- Voltage voting is no longer restricted to clock-local drivers
and need not be duplicated for different driver types.
- Different clocks may specify requirements on different power rails
by using different voltage_class implementations.
- Fmax data (maximum frequency allowed at a given voltage level)
is separated from the frequency tables and captured as a
property of each clock, so that difference SoCs may share the
same frequency tables even if their voltage requirements differ.
- The per-clock lock can be managed entirely at the clock.c level
Change-Id: I2bbd16096c14cedefa2b7fdf77d9f20d842b1e4d
Signed-off-by: Matt Wagantall <mattw@codeaurora.org>
diff --git a/arch/arm/mach-msm/clock-local.c b/arch/arm/mach-msm/clock-local.c
index ea76512..4b30896 100644
--- a/arch/arm/mach-msm/clock-local.c
+++ b/arch/arm/mach-msm/clock-local.c
@@ -48,9 +48,6 @@
DEFINE_SPINLOCK(local_clock_reg_lock);
struct clk_freq_tbl rcg_dummy_freq = F_END;
-unsigned local_sys_vdd_votes[NUM_SYS_VDD_LEVELS];
-static DEFINE_SPINLOCK(sys_vdd_vote_lock);
-
/*
* Common Set-Rate Functions
*/
@@ -264,81 +261,6 @@
clk->ns_mask = new_bank_masks->ns_mask;
}
-int (*soc_update_sys_vdd)(enum sys_vdd_level level);
-
-/*
- * SYS_VDD voting functions
- */
-
-/* Update system voltage level given the current votes. */
-static int local_update_sys_vdd(void)
-{
- static int cur_level = NUM_SYS_VDD_LEVELS;
- int level, rc = 0;
-
- if (local_sys_vdd_votes[HIGH])
- level = HIGH;
- else if (local_sys_vdd_votes[NOMINAL])
- level = NOMINAL;
- else if (local_sys_vdd_votes[LOW])
- level = LOW;
- else
- level = NONE;
-
- if (level == cur_level)
- return rc;
-
- rc = soc_update_sys_vdd(level);
- if (!rc)
- cur_level = level;
-
- return rc;
-}
-
-/* Vote for a system voltage level. */
-int local_vote_sys_vdd(unsigned level)
-{
- int rc = 0;
- unsigned long flags;
-
- /* Bounds checking. */
- if (level >= ARRAY_SIZE(local_sys_vdd_votes))
- return -EINVAL;
-
- spin_lock_irqsave(&sys_vdd_vote_lock, flags);
- local_sys_vdd_votes[level]++;
- rc = local_update_sys_vdd();
- if (rc)
- local_sys_vdd_votes[level]--;
- spin_unlock_irqrestore(&sys_vdd_vote_lock, flags);
-
- return rc;
-}
-
-/* Remove vote for a system voltage level. */
-int local_unvote_sys_vdd(unsigned level)
-{
- int rc = 0;
- unsigned long flags;
-
- /* Bounds checking. */
- if (level >= ARRAY_SIZE(local_sys_vdd_votes))
- return -EINVAL;
-
- spin_lock_irqsave(&sys_vdd_vote_lock, flags);
-
- if (WARN(!local_sys_vdd_votes[level],
- "Reference counts are incorrect for level %d!\n", level))
- goto out;
-
- local_sys_vdd_votes[level]--;
- rc = local_update_sys_vdd();
- if (rc)
- local_sys_vdd_votes[level]++;
-out:
- spin_unlock_irqrestore(&sys_vdd_vote_lock, flags);
- return rc;
-}
/*
* Clock enable/disable functions
*/
@@ -486,19 +408,25 @@
}
}
-static void _rcg_clk_enable(struct rcg_clk *clk)
+/* Enable a rate-settable clock. */
+int rcg_clk_enable(struct clk *c)
{
unsigned long flags;
+ struct rcg_clk *clk = to_rcg_clk(c);
spin_lock_irqsave(&local_clock_reg_lock, flags);
__rcg_clk_enable_reg(clk);
clk->enabled = true;
spin_unlock_irqrestore(&local_clock_reg_lock, flags);
+
+ return 0;
}
-static void _rcg_clk_disable(struct rcg_clk *clk)
+/* Disable a rate-settable clock. */
+void rcg_clk_disable(struct clk *c)
{
unsigned long flags;
+ struct rcg_clk *clk = to_rcg_clk(c);
spin_lock_irqsave(&local_clock_reg_lock, flags);
__rcg_clk_disable_reg(clk);
@@ -506,32 +434,10 @@
spin_unlock_irqrestore(&local_clock_reg_lock, flags);
}
-/* Enable a clock and any related power rail. */
-int rcg_clk_enable(struct clk *c)
-{
- int rc;
- struct rcg_clk *clk = to_rcg_clk(c);
-
- rc = local_vote_sys_vdd(clk->current_freq->sys_vdd);
- if (rc)
- return rc;
- _rcg_clk_enable(clk);
- return rc;
-}
-
-/* Disable a clock and any related power rail. */
-void rcg_clk_disable(struct clk *c)
-{
- struct rcg_clk *clk = to_rcg_clk(c);
-
- _rcg_clk_disable(clk);
- local_unvote_sys_vdd(clk->current_freq->sys_vdd);
-}
-
/* Turn off a clock at boot, without checking refcounts. */
void rcg_clk_auto_off(struct clk *c)
{
- _rcg_clk_disable(to_rcg_clk(c));
+ rcg_clk_disable(c);
}
/*
@@ -544,25 +450,17 @@
struct clk_freq_tbl *cf;
int rc = 0;
struct clk *chld;
- unsigned long flags;
-
- spin_lock_irqsave(&clk->c.lock, flags);
/* Check if frequency is actually changed. */
cf = clk->current_freq;
if (nf == cf)
- goto unlock;
+ return 0;
if (clk->enabled) {
- /* Vote for voltage and source for new freq. */
- rc = local_vote_sys_vdd(nf->sys_vdd);
- if (rc)
- goto unlock;
+ /* Enable source clock dependency for the new freq. */
rc = clk_enable(nf->src_clk);
- if (rc) {
- local_unvote_sys_vdd(nf->sys_vdd);
- goto unlock;
- }
+ if (rc)
+ return rc;
}
spin_lock(&local_clock_reg_lock);
@@ -608,13 +506,9 @@
spin_unlock(&local_clock_reg_lock);
- /* Release requirements of the old freq. */
- if (clk->enabled) {
+ /* Release source requirements of the old freq. */
+ if (clk->enabled)
clk_disable(cf->src_clk);
- local_unvote_sys_vdd(cf->sys_vdd);
- }
-unlock:
- spin_unlock_irqrestore(&clk->c.lock, flags);
return rc;
}