aboutsummaryrefslogtreecommitdiffstats
path: root/extras/recipes-kernel/linux/linux-omap-2.6.39/sakoman/0013-Enable-the-use-of-SDIO-card-interrupts.patch
diff options
context:
space:
mode:
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.patch288
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
+