mmc: msm_sdcc: Driver clocking/irq improvements
authorSan Mehat <san@google.com>
Fri, 13 Nov 2009 21:42:06 +0000 (13:42 -0800)
committerDaniel Walker <dwalker@codeaurora.org>
Thu, 18 Mar 2010 20:15:05 +0000 (13:15 -0700)
- Clocks are now disabled after 1 second of inactivity
- Fixed issue which was causing us to loop through our ISR twice
- Bump core clock enable delay to 30us

Signed-off-by: San Mehat <san@google.com>
Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
drivers/mmc/host/msm_sdcc.c
drivers/mmc/host/msm_sdcc.h

index 02bec7c..b4b6372 100644 (file)
@@ -57,6 +57,32 @@ static unsigned int msmsdcc_sdioirq;
 #define PIO_SPINMAX 30
 #define CMD_SPINMAX 20
 
+
+static inline int
+msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable)
+{
+       int rc;
+       WARN_ON(enable == host->clks_on);
+       if (enable) {
+               rc = clk_enable(host->pclk);
+               if (rc)
+                       return rc;
+               rc = clk_enable(host->clk);
+               if (rc) {
+                       clk_disable(host->pclk);
+                       return rc;
+               }
+               udelay(30);
+               host->clks_on = 1;
+       } else {
+               clk_disable(host->clk);
+               clk_disable(host->pclk);
+               host->clks_on = 0;
+       }
+       return 0;
+}
+
+
 static void
 msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd,
                      u32 c);
@@ -76,6 +102,8 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq)
        if (mrq->cmd->error == -ETIMEDOUT)
                mdelay(5);
 
+       if (host->use_bustimer)
+               mod_timer(&host->busclk_timer, jiffies + HZ);
        /*
         * Need to drop the host lock here; mmc_request_done may call
         * back into the driver...
@@ -676,6 +704,12 @@ msmsdcc_irq(int irq, void *dev_id)
                status &= (readl(base + MMCIMASK0) | MCI_DATABLOCKENDMASK);
                writel(status, base + MMCICLEAR);
 
+               if (status & MCI_SDIOINTR)
+                       status &= ~MCI_SDIOINTR;
+
+               if (!status)
+                       break;
+
                msmsdcc_handle_irq_data(host, status, base);
 
                if (status & (MCI_CMDSENT | MCI_CMDRESPEND | MCI_CMDCRCFAIL |
@@ -729,6 +763,8 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        }
 
        host->curr.mrq = mrq;
+       if (!host->clks_on)
+               msmsdcc_enable_clocks(host, 1);
 
        if (mrq->data && mrq->data->flags & MMC_DATA_READ)
                msmsdcc_start_data(host, mrq->data);
@@ -750,29 +786,6 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int inline
-msmsdcc_enable_clocks(struct msmsdcc_host *host, int enable)
-{
-       int rc;
-       if (enable) {
-               rc = clk_enable(host->pclk);
-               if (rc)
-                       return rc;
-               rc = clk_enable(host->clk);
-               if (rc) {
-                       clk_disable(host->pclk);
-                       return rc;
-               }
-               host->clks_on = 1;
-               udelay(10);
-       } else {
-               clk_disable(host->clk);
-               clk_disable(host->pclk);
-               host->clks_on = 0;
-       }
-       return 0;
-}
-
 static void
 msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
@@ -782,10 +795,10 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        unsigned long flags;
 
        spin_lock_irqsave(&host->lock, flags);
-       if (ios->clock) {
+       if (!host->clks_on)
+               msmsdcc_enable_clocks(host, 1);
 
-               if (!host->clks_on)
-                       msmsdcc_enable_clocks(host, 1);
+       if (ios->clock) {
                if (ios->clock != host->clk_rate) {
                        rc = clk_set_rate(host->clk, ios->clock);
                        if (rc < 0)
@@ -829,8 +842,7 @@ msmsdcc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                host->pwr = pwr;
                writel(pwr, host->base + MMCIPOWER);
        }
-
-       if (!(clk & MCI_CLK_ENABLE) && host->clks_on)
+       if (host->clks_on)
                msmsdcc_enable_clocks(host, 0);
        spin_unlock_irqrestore(&host->lock, flags);
 }
@@ -909,6 +921,19 @@ msmsdcc_status_notify_cb(int card_present, void *dev_id)
        msmsdcc_check_status((unsigned long) host);
 }
 
+static void
+msmsdcc_busclk_expired(unsigned long _data)
+{
+       struct msmsdcc_host     *host = (struct msmsdcc_host *) _data;
+       unsigned long           flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+       if (host->clks_on)
+               msmsdcc_enable_clocks(host, 0);
+
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
 /*
  * called when a command expires.
  * Dump some debugging, and then error
@@ -942,6 +967,8 @@ msmsdcc_command_expired(unsigned long _data)
        host->curr.mrq = NULL;
        host->curr.cmd = NULL;
 
+       if (host->clks_on)
+               msmsdcc_enable_clocks(host, 0);
        spin_unlock_irqrestore(&host->lock, flags);
        mmc_request_done(host->mmc, mrq);
 }
@@ -1048,6 +1075,8 @@ msmsdcc_probe(struct platform_device *pdev)
 
        host->cmdpoll = 1;
 
+       host->use_bustimer = 1;
+
        host->base = ioremap(memres->start, PAGE_SIZE);
        if (!host->base) {
                ret = -ENOMEM;
@@ -1167,6 +1196,10 @@ msmsdcc_probe(struct platform_device *pdev)
        host->command_timer.data = (unsigned long) host;
        host->command_timer.function = msmsdcc_command_expired;
 
+       init_timer(&host->busclk_timer);
+       host->busclk_timer.data = (unsigned long) host;
+       host->busclk_timer.function = msmsdcc_busclk_expired;
+
        ret = request_irq(cmd_irqres->start, msmsdcc_irq, IRQF_SHARED,
                          DRIVER_NAME " (cmd)", host);
        if (ret)
index 8c84484..6846bd7 100644 (file)
@@ -214,6 +214,8 @@ struct msmsdcc_host {
        struct clk              *pclk;          /* SDCC peripheral bus clock */
        unsigned int            clks_on;        /* set if clocks are enabled */
        struct timer_list       command_timer;
+       struct timer_list       busclk_timer;
+       int                     use_bustimer;
 
        unsigned int            eject;          /* eject state */