From 948eeb1f03da5fca0f6734c10efbc35ad63a1d08 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Fri, 2 Apr 2010 08:42:22 -0700 Subject: [PATCH 13/32] 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 --- drivers/mmc/host/omap_hsmmc.c | 118 +++++++++++++++++++++++++++++------------ 1 files changed, 83 insertions(+), 35 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 83f93ab..d57686c 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -67,6 +67,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 @@ -77,10 +78,13 @@ #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 DTO_ENABLE (1 << 20) +#define CTPL (1 << 11) +#define CLKEXTFREE (1 << 16) #define INIT_STREAM (1 << 1) #define DP_SELECT (1 << 21) #define DDIR (1 << 4) @@ -88,10 +92,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) @@ -186,6 +192,7 @@ struct omap_hsmmc_host { int protect_card; int reqs_blocked; int use_reg; + int sdio_int; struct omap_mmc_platform_data *pdata; }; @@ -598,7 +605,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 && @@ -613,7 +620,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); @@ -627,7 +634,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 */ @@ -791,22 +798,19 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd, struct mmc_data *data) { int cmdreg = 0, resptype = 0, cmdtype = 0; + int int_en_mask = INT_EN_MASK; dev_dbg(mmc_dev(host->mmc), "%s: CMD%d, argument 0x%08x\n", 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)); - else - OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK); + int_en_mask &= ~(BRR_ENABLE | BWR_ENABLE); + + if (host->sdio_int) + int_en_mask |= CIRQ; + + OMAP_HSMMC_WRITE(host->base, IE, int_en_mask); host->response_busy = 0; if (cmd->flags & MMC_RSP_PRESENT) { @@ -1019,23 +1023,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); @@ -1085,17 +1092,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; } @@ -1643,6 +1649,47 @@ static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card) mmc_slot(host).init_card(card); } +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 | CLKEXTFREE; + host->sdio_int = 1; + } else { + ie &= ~CIRQ_ENABLE; + con &= ~(CTPL | CLKEXTFREE); + host->sdio_int = 0; + } + 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; @@ -1657,14 +1704,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); @@ -1918,7 +1965,7 @@ static const struct mmc_host_ops omap_hsmmc_ops = { .get_cd = omap_hsmmc_get_cd, .get_ro = omap_hsmmc_get_ro, .init_card = omap_hsmmc_init_card, - /* NYET -- enable_sdio_irq */ + .enable_sdio_irq = omap_hsmmc_enable_sdio_irq, }; static const struct mmc_host_ops omap_hsmmc_ps_ops = { @@ -1929,7 +1976,7 @@ static const struct mmc_host_ops omap_hsmmc_ps_ops = { .get_cd = omap_hsmmc_get_cd, .get_ro = omap_hsmmc_get_ro, .init_card = omap_hsmmc_init_card, - /* NYET -- enable_sdio_irq */ + .enable_sdio_irq = omap_hsmmc_enable_sdio_irq, }; #ifdef CONFIG_DEBUG_FS @@ -2145,7 +2192,8 @@ 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_ERASE; + MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE | + MMC_CAP_SDIO_IRQ; mmc->caps |= mmc_slot(host).caps; if (mmc->caps & MMC_CAP_8_BIT_DATA) @@ -2224,7 +2272,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev) pdata->resume = omap_hsmmc_resume_cdirq; } - 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.6.1