> -----Original Message----- > From: David Vrabel [mailto:david.vrabel@xxxxxxx] > Sent: Wednesday, February 10, 2010 5:52 AM > To: linux-mmc@xxxxxxxxxxxxxxx > Cc: David Vrabel; linux-omap@xxxxxxxxxxxxxxx; madhu.cr@xxxxxx > Subject: [PATCH 3/3] mmc: omap_hsmmc: enable SDIO card interrupts > > Enable the use of SDIO card interrupts. This requires setting ENAWAKEUP > in SYSCONFIG and IWE in HTCL to allow the MMC block to wake-up when in > smart-idle mode. > > FCLK must be enabled while SDIO interrupts are enabled or the MMC block > won't wake-up. > > The writes to STAT and ISE when starting a command are unnecessary and > have been removed. > > Signed-off-by: David Vrabel <david.vrabel@xxxxxxx> > --- > As noted in the FIXME comment, I think the correct thing to do is to > always leave FCLK enabled. The clock/clockdomain subsystems should be > configuring smart-idle mode making explicit calls to disable FCLK > unnecessary. I couldn't follow the clock subsystem to see if it was > actually doing this, though. I Just noticed that SD cards stopped working on Zoom2 if I apply this patch. I will come back with details on what's going on in a bit unless someone else beats me on that. Regards, Madhu > --- > drivers/mmc/host/omap_hsmmc.c | 94 ++++++++++++++++++++++++++++-------- > ----- > 1 files changed, 65 insertions(+), 29 deletions(-) > > diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c > index e6d8cb3..ad0f867 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) > @@ -228,7 +233,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 && > @@ -243,7 +248,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); > @@ -257,7 +262,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 */ > @@ -426,12 +431,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)); > @@ -638,18 +637,21 @@ 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; > - } > + status = OMAP_HSMMC_READ(host->base, STAT); > + OMAP_HSMMC_WRITE(host->base, STAT, status); > + OMAP_HSMMC_READ(host->base, STAT); /* Flush posted write. */ > + > + if (status & CIRQ) > + card_irq = true; > + > + if (host->mrq == NULL) > + goto out; > > data = host->data; > status = OMAP_HSMMC_READ(host->base, STAT); > @@ -704,17 +706,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; > } > > @@ -1248,6 +1249,41 @@ 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 else wakeup does not > + * work. > + * > + * FIXME: the power save code probably shouldn't be playing > + * with FCLK and allow the clock subsystem to put it into > + * smart-idle mode instead. > + */ > + 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 { > + clk_disable(host->fclk); > + ie &= ~CIRQ_ENABLE; > + con &= ~CTPL; > + } > + OMAP_HSMMC_WRITE(host->base, CON, con); > + OMAP_HSMMC_WRITE(host->base, IE, ie); > + > + spin_unlock_irqrestore(&host->irq_lock, flags); > +} > + > static void omap_hsmmc_conf_bus_power(struct omap_hsmmc_host *host) > { > u32 hctl, capa, value; > @@ -1262,14 +1298,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); > @@ -1516,7 +1552,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 = { > @@ -1526,7 +1562,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 > @@ -1731,7 +1767,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; > @@ -1802,7 +1838,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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html