When supporting I2C/SPI based on-board PLLs like CDCE949,
it is essential that clk->set_rate be able to sleep.

Currently, this is not possible because clk->set_rate is
called from within spin-lock in clk_set_rate

This patch brings clk->set_rate outside of the spin-lock
and lets the individual set_rate implementations achieve
serialization through appropiate means.

Signed-off-by: Sekhar Nori <[email protected]>
---
This patch is a replacement for an earlier patch titled
"davinci: clock framework: remove spinlock usage"

 arch/arm/mach-davinci/cdce949.c |   10 +++++++---
 arch/arm/mach-davinci/clock.c   |    9 ++++++++-
 2 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-davinci/cdce949.c b/arch/arm/mach-davinci/cdce949.c
index 6af3289..aec3756 100644
--- a/arch/arm/mach-davinci/cdce949.c
+++ b/arch/arm/mach-davinci/cdce949.c
@@ -23,6 +23,7 @@
 #include "clock.h"
 
 static struct i2c_client *cdce_i2c_client;
+static DEFINE_MUTEX(cdce_mutex);
 
 /* CDCE register descriptor */
 struct cdce_reg {
@@ -231,16 +232,19 @@ int cdce_set_rate(struct clk *clk, unsigned long rate)
        if (!regs)
                return -EINVAL;
 
+       mutex_lock(&cdce_mutex);
        for (i = 0; regs[i].addr; i++) {
                ret = i2c_smbus_write_byte_data(cdce_i2c_client,
                                        regs[i].addr | 0x80, regs[i].val);
                if (ret)
-                       return ret;
+                       break;
        }
+       mutex_unlock(&cdce_mutex);
 
-       clk->rate = rate;
+       if (!ret)
+               clk->rate = rate;
 
-       return 0;
+       return ret;
 }
 
 static int cdce_probe(struct i2c_client *client,
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index 79d6ec8..bf6218e 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -125,9 +125,10 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
        if (clk == NULL || IS_ERR(clk))
                return ret;
 
-       spin_lock_irqsave(&clockfw_lock, flags);
        if (clk->set_rate)
                ret = clk->set_rate(clk, rate);
+
+       spin_lock_irqsave(&clockfw_lock, flags);
        if (ret == 0) {
                if (clk->recalc)
                        clk->rate = clk->recalc(clk);
@@ -364,6 +365,7 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int 
prediv,
 {
        u32 ctrl;
        unsigned int locktime;
+       unsigned long flags;
 
        if (pll->base == NULL)
                return -EINVAL;
@@ -384,6 +386,9 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int 
prediv,
        if (mult)
                mult = mult - 1;
 
+       /* Protect against simultaneous calls to PLL setting seqeunce */
+       spin_lock_irqsave(&clockfw_lock, flags);
+
        ctrl = __raw_readl(pll->base + PLLCTL);
 
        /* Switch the PLL to bypass mode */
@@ -416,6 +421,8 @@ int davinci_set_pllrate(struct pll_data *pll, unsigned int 
prediv,
        ctrl |= PLLCTL_PLLEN;
        __raw_writel(ctrl, pll->base + PLLCTL);
 
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+
        return 0;
 }
 EXPORT_SYMBOL(davinci_set_pllrate);
-- 
1.6.2.4

_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to