diff options
Diffstat (limited to 'extras/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0013-Enable-the-use-of-SDIO-card-interrupts.patch')
-rw-r--r-- | extras/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0013-Enable-the-use-of-SDIO-card-interrupts.patch | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/extras/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0013-Enable-the-use-of-SDIO-card-interrupts.patch b/extras/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0013-Enable-the-use-of-SDIO-card-interrupts.patch new file mode 100644 index 00000000..59d5ec47 --- /dev/null +++ b/extras/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0013-Enable-the-use-of-SDIO-card-interrupts.patch @@ -0,0 +1,288 @@ +From 948eeb1f03da5fca0f6734c10efbc35ad63a1d08 Mon Sep 17 00:00:00 2001 +From: David Vrabel <david.vrabel@csr.com> +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 <david.vrabel@csr.com> +--- + 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 + |