Enable the use of SDIO card interrupts.

FCLK must be enabled while SDIO interrupts are enabled or the MMC
module won't wake-up (even though ENAWAKEUP in SYSCONFIG and IWE in
HTCL have been set).  Enabling the MMC module to wake-up would require
configuring the MMC module (and the mmci_dat[1] GPIO when the CORE
power domain is OFF) as wake-up sources in the PRCM.

The writes to STAT and ISE when starting a command are unnecessary and
have been removed.

Signed-off-by: David Vrabel <[email protected]>
---
 drivers/mmc/host/omap_hsmmc.c |  102 ++++++++++++++++++++++++++++------------
 1 files changed, 71 insertions(+), 31 deletions(-)

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 323a0e8..278b551 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -64,6 +64,7 @@
 #define SDVS_MASK              0x00000E00
 #define SDVSCLR                        0xFFFFF1FF
 #define SDVSDET                        0x00000400
+#define ENAWAKEUP              (1 << 2)
 #define AUTOIDLE               0x1
 #define SDBP                   (1 << 8)
 #define DTO                    0xe
@@ -74,9 +75,11 @@
 #define CLKD_SHIFT             6
 #define DTO_MASK               0x000F0000
 #define DTO_SHIFT              16
+#define CIRQ_ENABLE            (1 << 8)
 #define INT_EN_MASK            0x307F0033
 #define BWR_ENABLE             (1 << 4)
 #define BRR_ENABLE             (1 << 5)
+#define CTPL                   (1 << 11)
 #define INIT_STREAM            (1 << 1)
 #define DP_SELECT              (1 << 21)
 #define DDIR                   (1 << 4)
@@ -84,10 +87,12 @@
 #define MSBS                   (1 << 5)
 #define BCE                    (1 << 1)
 #define FOUR_BIT               (1 << 1)
+#define IWE                    (1 << 24)
 #define DW8                    (1 << 5)
 #define CC                     0x1
 #define TC                     0x02
 #define OD                     0x1
+#define CIRQ                   (1 << 8)
 #define ERR                    (1 << 15)
 #define CMD_TIMEOUT            (1 << 16)
 #define DATA_TIMEOUT           (1 << 20)
@@ -227,7 +232,7 @@ static int omap_hsmmc_context_restore(struct 
omap_hsmmc_host *host)
                ;
 
        OMAP_HSMMC_WRITE(host->base, SYSCONFIG,
-                       OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE);
+                       OMAP_HSMMC_READ(host->base, SYSCONFIG) | AUTOIDLE | 
ENAWAKEUP);
 
        if (host->id == OMAP_MMC1_DEVID) {
                if (host->power_mode != MMC_POWER_OFF &&
@@ -242,7 +247,7 @@ static int omap_hsmmc_context_restore(struct 
omap_hsmmc_host *host)
        }
 
        OMAP_HSMMC_WRITE(host->base, HCTL,
-                       OMAP_HSMMC_READ(host->base, HCTL) | hctl);
+                       OMAP_HSMMC_READ(host->base, HCTL) | hctl | IWE);
 
        OMAP_HSMMC_WRITE(host->base, CAPA,
                        OMAP_HSMMC_READ(host->base, CAPA) | capa);
@@ -256,7 +261,7 @@ static int omap_hsmmc_context_restore(struct 
omap_hsmmc_host *host)
                ;
 
        OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
-       OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
+       OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK | CIRQ);
        OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
 
        /* Do not initialize card-specific things if the power is off */
@@ -425,12 +430,6 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, 
struct mmc_command *cmd,
                mmc_hostname(host->mmc), cmd->opcode, cmd->arg);
        host->cmd = cmd;
 
-       /*
-        * Clear status bits and enable interrupts
-        */
-       OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
-       OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
-
        if (host->use_dma)
                OMAP_HSMMC_WRITE(host->base, IE,
                                 INT_EN_MASK & ~(BRR_ENABLE | BWR_ENABLE));
@@ -637,23 +636,26 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
 {
        struct omap_hsmmc_host *host = dev_id;
        struct mmc_data *data;
-       int end_cmd = 0, end_trans = 0, status;
+       u32 status;
+       int end_cmd = 0, end_trans = 0;
+       bool card_irq = false;
 
        spin_lock(&host->irq_lock);
 
-       if (host->mrq == NULL) {
-               OMAP_HSMMC_WRITE(host->base, STAT,
-                       OMAP_HSMMC_READ(host->base, STAT));
-               /* Flush posted write */
-               OMAP_HSMMC_READ(host->base, STAT);
-               spin_unlock(&host->irq_lock);
-               return IRQ_HANDLED;
-       }
-
-       data = host->data;
        status = OMAP_HSMMC_READ(host->base, STAT);
+       OMAP_HSMMC_WRITE(host->base, STAT, status);
+       OMAP_HSMMC_READ(host->base, STAT); /* Flush posted write. */
+
        dev_dbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
 
+       if (status & CIRQ)
+               card_irq = true;
+
+       if (host->mrq == NULL)
+               goto out;
+
+       data = host->data;
+
        if (status & ERR) {
 #ifdef CONFIG_MMC_DEBUG
                omap_hsmmc_report_irq(host, status);
@@ -703,17 +705,16 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
                }
        }
 
-       OMAP_HSMMC_WRITE(host->base, STAT, status);
-       /* Flush posted write */
-       OMAP_HSMMC_READ(host->base, STAT);
-
        if (end_cmd || ((status & CC) && host->cmd))
                omap_hsmmc_cmd_done(host, host->cmd);
        if ((end_trans || (status & TC)) && host->mrq)
                omap_hsmmc_xfer_done(host, data);
-
+out:
        spin_unlock(&host->irq_lock);
 
+       if (card_irq)
+               mmc_signal_sdio_irq(host->mmc);
+
        return IRQ_HANDLED;
 }
 
@@ -1255,6 +1256,45 @@ static int omap_hsmmc_get_ro(struct mmc_host *mmc)
        return mmc_slot(host).get_ro(host->dev, 0);
 }
 
+static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+       struct omap_hsmmc_host *host = mmc_priv(mmc);
+       u32 ie, con;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->irq_lock, flags);
+
+       /*
+        * When interrupts are enabled, CTPL must be set to enable
+        * DAT1 input buffer (or the card interrupt is always
+        * asserted) and FCLK must be enabled as wake-up does not
+        * work.  Take care to disable FCLK after all the register
+        * accesses as they might not complete if FCLK is off.
+        *
+        * FIXME: if the MMC module (and the mmci_dat[1] GPIO when the
+        * CORE power domain is OFF) are configured as a wake-up
+        * sources in the PRCM, then FCLK could be switched off.  This
+        * might add too much latency.
+        */
+       con = OMAP_HSMMC_READ(host->base, CON);
+       ie = OMAP_HSMMC_READ(host->base, IE);
+       if (enable) {
+               clk_enable(host->fclk);
+               ie |= CIRQ_ENABLE;
+               con |= CTPL;
+       } else {
+               ie &= ~CIRQ_ENABLE;
+               con &= ~CTPL;
+       }
+       OMAP_HSMMC_WRITE(host->base, CON, con);
+       OMAP_HSMMC_WRITE(host->base, IE, ie);
+       OMAP_HSMMC_READ(host->base, IE); /* flush posted write */
+       if (!enable)
+               clk_disable(host->fclk);
+
+       spin_unlock_irqrestore(&host->irq_lock, flags);
+}
+
 static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host)
 {
        u32 hctl, capa, value;
@@ -1269,14 +1309,14 @@ static void omap_hsmmc_conf_bus_power(struct 
omap_hsmmc_host *host)
        }
 
        value = OMAP_HSMMC_READ(host->base, HCTL) & ~SDVS_MASK;
-       OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl);
+       OMAP_HSMMC_WRITE(host->base, HCTL, value | hctl | IWE);
 
        value = OMAP_HSMMC_READ(host->base, CAPA);
        OMAP_HSMMC_WRITE(host->base, CAPA, value | capa);
 
        /* Set the controller to AUTO IDLE mode */
        value = OMAP_HSMMC_READ(host->base, SYSCONFIG);
-       OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE);
+       OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE | ENAWAKEUP);
 
        /* Set SD bus power bit */
        set_sd_bus_power(host);
@@ -1523,7 +1563,7 @@ static const struct mmc_host_ops omap_hsmmc_ops = {
        .set_ios = omap_hsmmc_set_ios,
        .get_cd = omap_hsmmc_get_cd,
        .get_ro = omap_hsmmc_get_ro,
-       /* NYET -- enable_sdio_irq */
+       .enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
 };
 
 static const struct mmc_host_ops omap_hsmmc_ps_ops = {
@@ -1533,7 +1573,7 @@ static const struct mmc_host_ops omap_hsmmc_ps_ops = {
        .set_ios = omap_hsmmc_set_ios,
        .get_cd = omap_hsmmc_get_cd,
        .get_ro = omap_hsmmc_get_ro,
-       /* NYET -- enable_sdio_irq */
+       .enable_sdio_irq = omap_hsmmc_enable_sdio_irq,
 };
 
 #ifdef CONFIG_DEBUG_FS
@@ -1738,7 +1778,7 @@ static int __init omap_hsmmc_probe(struct platform_device 
*pdev)
        mmc->max_seg_size = mmc->max_req_size;
 
        mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
-                    MMC_CAP_WAIT_WHILE_BUSY;
+                    MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_SDIO_IRQ;
 
        if (mmc_slot(host).wires >= 8)
                mmc->caps |= MMC_CAP_8_BIT_DATA;
@@ -1809,7 +1849,7 @@ static int __init omap_hsmmc_probe(struct platform_device 
*pdev)
                }
        }
 
-       OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
+       OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK | CIRQ);
        OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
 
        mmc_host_lazy_disable(host->mmc);
-- 
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to