Re: [PATCH v10 1/5] mmc: omap_hsmmc: Enable SDIO interrupt

2014-05-02 Thread Balaji T K

On Monday 28 April 2014 01:10 PM, Andreas Fenkart wrote:

There have been various patches floating around for enabling
the SDIO IRQ for hsmmc, but none of them ever got merged.

Probably the reason for not merging the SDIO interrupt patches
has been the lack of wake-up path for SDIO on some omaps that
has also needed remuxing the SDIO DAT1 line to a GPIO making
the patches complex.

This patch adds the minimal SDIO IRQ support to hsmmc for
omaps that do have the wake-up path. For those omaps, the
DAT1 line need to have the wake-up enable bit set, and the
wake-up interrupt is the same as for the MMC controller.

This patch has been tested on am3730 es1.2 with mwifiex
connected to MMC3 with mwifiex waking to Ethernet traffic
from off-idle mode. Note that for omaps that do not have
the SDIO wake-up path, this patch will not work for idle
modes and further patches for remuxing DAT1 to GPIO are
needed.

Based on earlier patches [1][2] by David Vrabel
, Steve Sakoman 

For now, only support SDIO interrupt if we are booted with
a separate wake-irq configued via device tree. This is
because omaps need the wake-irq for idle states, and some
omaps need special quirks. And we don't want to add new
legacy mux platform init code callbacks any longer as we
are moving to DT based booting anyways.

To use it, you need to specify the wake-irq using the
interrupts-extended property.

[1] 
http://www.sakoman.com/cgi-bin/gitweb.cgi?p=linux.git;a=commitdiff_plain;h=010810d22f6f49ac03da4ba384969432e0320453
[2] http://comments.gmane.org/gmane.linux.kernel.mmc/20446

Cc: Balaji T K 
Signed-off-by: Andreas Fenkart 
Signed-off-by: Tony Lindgren 

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 272e0ee..700fb91 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -29,6 +29,7 @@
  #include 
  #include 
  #include 
+#include 
  #include 
  #include 
  #include 
@@ -36,6 +37,7 @@
  #include 
  #include 
  #include 
+#include 
  #include 
  #include 
  #include 
@@ -106,6 +108,7 @@
  #define TC_EN (1 << 1)
  #define BWR_EN(1 << 4)
  #define BRR_EN(1 << 5)
+#define CIRQ_EN(1 << 8)
  #define ERR_EN(1 << 15)
  #define CTO_EN(1 << 16)
  #define CCRC_EN   (1 << 17)
@@ -140,7 +143,6 @@
  #define VDD_3V0   300 /* 30 uV */
  #define VDD_165_195   (ffs(MMC_VDD_165_195) - 1)

-#define AUTO_CMD23 (1 << 1)  /* Auto CMD23 support */
  /*
   * One controller can have multiple slots, like on some omap boards using
   * omap.c controller driver. Luckily this is not currently done on any known
@@ -194,6 +196,7 @@ struct omap_hsmmc_host {
u32 sysctl;
u32 capa;
int irq;
+   int wake_irq;
int use_dma, dma_ch;
struct dma_chan *tx_chan;
struct dma_chan *rx_chan;
@@ -206,6 +209,9 @@ struct omap_hsmmc_host {
int req_in_progress;
unsigned long   clk_rate;
unsigned intflags;
+#define AUTO_CMD23 (1 << 0)/* Auto CMD23 support */
+#define HSMMC_SDIO_IRQ_ENABLED (1 << 1)/* SDIO irq enabled */
+#define HSMMC_WAKE_IRQ_ENABLED (1 << 2)
struct omap_hsmmc_next  next_data;
struct  omap_mmc_platform_data  *pdata;
  };
@@ -510,27 +516,40 @@ static void omap_hsmmc_stop_clock(struct omap_hsmmc_host 
*host)
  static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
  struct mmc_command *cmd)
  {
-   unsigned int irq_mask;
+   u32 irq_mask = INT_EN_MASK;
+   unsigned long flags;

if (host->use_dma)
-   irq_mask = INT_EN_MASK & ~(BRR_EN | BWR_EN);
-   else
-   irq_mask = INT_EN_MASK;
+   irq_mask &= ~(BRR_EN | BWR_EN);

/* Disable timeout for erases */
if (cmd->opcode == MMC_ERASE)
irq_mask &= ~DTO_EN;

+   spin_lock_irqsave(&host->irq_lock, flags);
OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
+
+   /* latch pending CIRQ, but don't signal MMC core */
+   if (host->flags & HSMMC_SDIO_IRQ_ENABLED)
+   irq_mask |= CIRQ_EN;
OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
+   spin_unlock_irqrestore(&host->irq_lock, flags);
  }

  static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host)
  {
-   OMAP_HSMMC_WRITE(host->base, ISE, 0);
-   OMAP_HSMMC_WRITE(host->base, IE, 0);
+   u32 irq_mask = 0;
+   unsigned long flags;
+
+   spin_lock_irqsave(&host->irq_lock, flags);
+   /* no transfer running but need to keep cirq if enabled */
+   if (host->flags & HSMMC_SDIO_IRQ_ENABLED)
+

Re: [PATCH v10 1/5] mmc: omap_hsmmc: Enable SDIO interrupt

2014-04-30 Thread Andreas Fenkart
Hi Andreas,

2014-04-30 14:23 GMT+02:00 Andreas Müller :
> On Mon, Apr 28, 2014 at 9:40 AM, Andreas Fenkart  wrote:
>> @@ -2201,11 +2346,16 @@ static int omap_hsmmc_suspend(struct device *dev)
>> pm_runtime_get_sync(host->dev);
>>
>> if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) {
>> -   omap_hsmmc_disable_irq(host);
>> +   OMAP_HSMMC_WRITE(host->base, ISE, 0);
>> +   OMAP_HSMMC_WRITE(host->base, IE, 0);
>> +   OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
>> OMAP_HSMMC_WRITE(host->base, HCTL,
>> OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
>> }
>>
>> +   if (host->wake_irq && !(host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
>> +   disable_irq(host->wake_irq);
>> +

I think it says, "Do you want to wake up from deep power states when
an SDIO IRQ is pending"
Will try to bring this more to the point

>> if (host->dbclk)
>> clk_disable_unprepare(host->dbclk);
>>
>> @@ -2231,6 +2381,9 @@ static int omap_hsmmc_resume(struct device *dev)
>>
>> omap_hsmmc_protect_card(host);
>>
>> +   if (host->wake_irq & !(host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))

you're right should be '&&'

>> +   enable_irq(host->wake_irq);
>> +
>> pm_runtime_mark_last_busy(host->dev);
>> pm_runtime_put_autosuspend(host->dev);
>> return 0;
> Maybe I misunderstand something here but shouldn't
> disable_irq/enable_irq be swapped here?

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


Re: [PATCH v10 1/5] mmc: omap_hsmmc: Enable SDIO interrupt

2014-04-30 Thread Andreas Müller
On Mon, Apr 28, 2014 at 9:40 AM, Andreas Fenkart  wrote:
> @@ -2201,11 +2346,16 @@ static int omap_hsmmc_suspend(struct device *dev)
> pm_runtime_get_sync(host->dev);
>
> if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) {
> -   omap_hsmmc_disable_irq(host);
> +   OMAP_HSMMC_WRITE(host->base, ISE, 0);
> +   OMAP_HSMMC_WRITE(host->base, IE, 0);
> +   OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
> OMAP_HSMMC_WRITE(host->base, HCTL,
> OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
> }
>
> +   if (host->wake_irq && !(host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
> +   disable_irq(host->wake_irq);
> +
> if (host->dbclk)
> clk_disable_unprepare(host->dbclk);
>
> @@ -2231,6 +2381,9 @@ static int omap_hsmmc_resume(struct device *dev)
>
> omap_hsmmc_protect_card(host);
>
> +   if (host->wake_irq & !(host->mmc->pm_flags & MMC_PM_WAKE_SDIO_IRQ))
> +   enable_irq(host->wake_irq);
> +
> pm_runtime_mark_last_busy(host->dev);
> pm_runtime_put_autosuspend(host->dev);
> return 0;
Maybe I misunderstand something here but shouldn't
disable_irq/enable_irq be swapped here?

regards

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


Re: [PATCH v10 1/5] mmc: omap_hsmmc: Enable SDIO interrupt

2014-04-29 Thread Joel Fernandes
Minor nit...

On 04/28/2014 02:40 AM, Andreas Fenkart wrote:
[..]
>   /* Do not initialize card-specific things if the power is off */
>   if (host->power_mode == MMC_POWER_OFF)
> @@ -1117,8 +1138,12 @@ static irqreturn_t omap_hsmmc_irq(int irq, void 
> *dev_id)
>   int status;
>  
>   status = OMAP_HSMMC_READ(host->base, STAT);
> - while (status & INT_EN_MASK && host->req_in_progress) {
> - omap_hsmmc_do_irq(host, status);
> + while (status & (INT_EN_MASK | CIRQ_EN)) {
> + if (host->req_in_progress)
> + omap_hsmmc_do_irq(host, status);
> +
> + if (status & CIRQ_EN)
> + mmc_signal_sdio_irq(host->mmc);
>  
>   /* Flush posted write */
>   status = OMAP_HSMMC_READ(host->base, STAT);
> @@ -1127,6 +1152,23 @@ static irqreturn_t omap_hsmmc_irq(int irq, void 
> *dev_id)
>   return IRQ_HANDLED;
>  }
>  
> +static irqreturn_t omap_hsmmc_wake_irq(int irq, void *dev_id)
> +{
> + struct omap_hsmmc_host *host = dev_id;
> + unsigned long flags;
> +
> + /* cirq is level triggered, disable to avoid infinite loop */
> + spin_lock_irqsave(&host->irq_lock, flags);

Do you need to save restore flags here? IRQ is already disabled since
you're in hard IRQ context so spin_lock() seems sufficient.

> + if (host->flags & HSMMC_WAKE_IRQ_ENABLED) {
> + disable_irq_nosync(host->wake_irq);
> + host->flags &= ~HSMMC_WAKE_IRQ_ENABLED;
> + }
> + spin_unlock_irqrestore(&host->irq_lock, flags);

spin_unlock() seems sufficient.

regards,
-Joel


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


Re: [PATCH v10 1/5] mmc: omap_hsmmc: Enable SDIO interrupt

2014-04-29 Thread Joel Fernandes
Minor nit...

On 04/28/2014 02:40 AM, Andreas Fenkart wrote:
[..]
>   /* Do not initialize card-specific things if the power is off */
>   if (host->power_mode == MMC_POWER_OFF)
> @@ -1117,8 +1138,12 @@ static irqreturn_t omap_hsmmc_irq(int irq, void 
> *dev_id)
>   int status;
>  
>   status = OMAP_HSMMC_READ(host->base, STAT);
> - while (status & INT_EN_MASK && host->req_in_progress) {
> - omap_hsmmc_do_irq(host, status);
> + while (status & (INT_EN_MASK | CIRQ_EN)) {
> + if (host->req_in_progress)
> + omap_hsmmc_do_irq(host, status);
> +
> + if (status & CIRQ_EN)
> + mmc_signal_sdio_irq(host->mmc);
>  
>   /* Flush posted write */
>   status = OMAP_HSMMC_READ(host->base, STAT);
> @@ -1127,6 +1152,23 @@ static irqreturn_t omap_hsmmc_irq(int irq, void 
> *dev_id)
>   return IRQ_HANDLED;
>  }
>  
> +static irqreturn_t omap_hsmmc_wake_irq(int irq, void *dev_id)
> +{
> + struct omap_hsmmc_host *host = dev_id;
> + unsigned long flags;
> +
> + /* cirq is level triggered, disable to avoid infinite loop */
> + spin_lock_irqsave(&host->irq_lock, flags);

Do you need to save restore flags here? IRQ is already disabled since
you're in hard IRQ context so spin_lock() seems sufficient.

> + if (host->flags & HSMMC_WAKE_IRQ_ENABLED) {
> + disable_irq_nosync(host->wake_irq);
> + host->flags &= ~HSMMC_WAKE_IRQ_ENABLED;
> + }
> + spin_unlock_irqrestore(&host->irq_lock, flags);

spin_unlock() seems sufficient.

regards,
-Joel

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


Re: [PATCH v10 1/5] mmc: omap_hsmmc: Enable SDIO interrupt

2014-04-29 Thread Andreas Müller
On Mon, Apr 28, 2014 at 9:40 AM, Andreas Fenkart  wrote:
> There have been various patches floating around for enabling
> the SDIO IRQ for hsmmc, but none of them ever got merged.
>
> Probably the reason for not merging the SDIO interrupt patches
> has been the lack of wake-up path for SDIO on some omaps that
> has also needed remuxing the SDIO DAT1 line to a GPIO making
> the patches complex.
>
> This patch adds the minimal SDIO IRQ support to hsmmc for
> omaps that do have the wake-up path. For those omaps, the
> DAT1 line need to have the wake-up enable bit set, and the
> wake-up interrupt is the same as for the MMC controller.
>
> This patch has been tested on am3730 es1.2 with mwifiex
> connected to MMC3 with mwifiex waking to Ethernet traffic
> from off-idle mode. Note that for omaps that do not have
> the SDIO wake-up path, this patch will not work for idle
> modes and further patches for remuxing DAT1 to GPIO are
> needed.
>
> Based on earlier patches [1][2] by David Vrabel
> , Steve Sakoman 
>
> For now, only support SDIO interrupt if we are booted with
> a separate wake-irq configued via device tree. This is
> because omaps need the wake-irq for idle states, and some
> omaps need special quirks. And we don't want to add new
> legacy mux platform init code callbacks any longer as we
> are moving to DT based booting anyways.
>
> To use it, you need to specify the wake-irq using the
> interrupts-extended property.
>
> [1] 
> http://www.sakoman.com/cgi-bin/gitweb.cgi?p=linux.git;a=commitdiff_plain;h=010810d22f6f49ac03da4ba384969432e0320453
> [2] http://comments.gmane.org/gmane.linux.kernel.mmc/20446
>
> Cc: Balaji T K 
> Signed-off-by: Andreas Fenkart 
> Signed-off-by: Tony Lindgren 
>
> diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
> index 272e0ee..700fb91 100644
> --- a/drivers/mmc/host/omap_hsmmc.c
> +++ b/drivers/mmc/host/omap_hsmmc.c
> @@ -29,6 +29,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -36,6 +37,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -106,6 +108,7 @@
>  #define TC_EN  (1 << 1)
>  #define BWR_EN (1 << 4)
>  #define BRR_EN (1 << 5)
> +#define CIRQ_EN(1 << 8)
>  #define ERR_EN (1 << 15)
>  #define CTO_EN (1 << 16)
>  #define CCRC_EN(1 << 17)
> @@ -140,7 +143,6 @@
>  #define VDD_3V0300 /* 30 uV */
>  #define VDD_165_195(ffs(MMC_VDD_165_195) - 1)
>
> -#define AUTO_CMD23 (1 << 1)/* Auto CMD23 support */
>  /*
>   * One controller can have multiple slots, like on some omap boards using
>   * omap.c controller driver. Luckily this is not currently done on any known
> @@ -194,6 +196,7 @@ struct omap_hsmmc_host {
> u32 sysctl;
> u32 capa;
> int irq;
> +   int wake_irq;
> int use_dma, dma_ch;
> struct dma_chan *tx_chan;
> struct dma_chan *rx_chan;
> @@ -206,6 +209,9 @@ struct omap_hsmmc_host {
> int req_in_progress;
> unsigned long   clk_rate;
> unsigned intflags;
> +#define AUTO_CMD23 (1 << 0)/* Auto CMD23 support */
> +#define HSMMC_SDIO_IRQ_ENABLED (1 << 1)/* SDIO irq enabled */
> +#define HSMMC_WAKE_IRQ_ENABLED (1 << 2)
> struct omap_hsmmc_next  next_data;
> struct  omap_mmc_platform_data  *pdata;
>  };
> @@ -510,27 +516,40 @@ static void omap_hsmmc_stop_clock(struct 
> omap_hsmmc_host *host)
>  static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
>   struct mmc_command *cmd)
>  {
> -   unsigned int irq_mask;
> +   u32 irq_mask = INT_EN_MASK;
> +   unsigned long flags;
>
> if (host->use_dma)
> -   irq_mask = INT_EN_MASK & ~(BRR_EN | BWR_EN);
> -   else
> -   irq_mask = INT_EN_MASK;
> +   irq_mask &= ~(BRR_EN | BWR_EN);
>
> /* Disable timeout for erases */
> if (cmd->opcode == MMC_ERASE)
> irq_mask &= ~DTO_EN;
>
> +   spin_lock_irqsave(&host->irq_lock, flags);
> OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
> OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
> +
> +   /* latch pending CIRQ, but don't signal MMC core */
> +   if (host->flags & HSMMC_SDIO_IRQ_ENABLED)
> +   irq_mask |= CIRQ_EN;
> OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
> +   spin_unlock_irqrestore(&host->irq_lock, flags);
>  }
>
>  static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host)
>  {
> -   OMAP_HSMMC_WRITE(host->base, ISE, 0);
> -   OMAP_HSMMC_WRITE(host->base, IE, 0);
> +   u32 irq_mask = 0;
> +   unsig

[PATCH v10 1/5] mmc: omap_hsmmc: Enable SDIO interrupt

2014-04-28 Thread Andreas Fenkart
There have been various patches floating around for enabling
the SDIO IRQ for hsmmc, but none of them ever got merged.

Probably the reason for not merging the SDIO interrupt patches
has been the lack of wake-up path for SDIO on some omaps that
has also needed remuxing the SDIO DAT1 line to a GPIO making
the patches complex.

This patch adds the minimal SDIO IRQ support to hsmmc for
omaps that do have the wake-up path. For those omaps, the
DAT1 line need to have the wake-up enable bit set, and the
wake-up interrupt is the same as for the MMC controller.

This patch has been tested on am3730 es1.2 with mwifiex
connected to MMC3 with mwifiex waking to Ethernet traffic
from off-idle mode. Note that for omaps that do not have
the SDIO wake-up path, this patch will not work for idle
modes and further patches for remuxing DAT1 to GPIO are
needed.

Based on earlier patches [1][2] by David Vrabel
, Steve Sakoman 

For now, only support SDIO interrupt if we are booted with
a separate wake-irq configued via device tree. This is
because omaps need the wake-irq for idle states, and some
omaps need special quirks. And we don't want to add new
legacy mux platform init code callbacks any longer as we
are moving to DT based booting anyways.

To use it, you need to specify the wake-irq using the
interrupts-extended property.

[1] 
http://www.sakoman.com/cgi-bin/gitweb.cgi?p=linux.git;a=commitdiff_plain;h=010810d22f6f49ac03da4ba384969432e0320453
[2] http://comments.gmane.org/gmane.linux.kernel.mmc/20446

Cc: Balaji T K 
Signed-off-by: Andreas Fenkart 
Signed-off-by: Tony Lindgren 

diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 272e0ee..700fb91 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -29,6 +29,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -36,6 +37,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -106,6 +108,7 @@
 #define TC_EN  (1 << 1)
 #define BWR_EN (1 << 4)
 #define BRR_EN (1 << 5)
+#define CIRQ_EN(1 << 8)
 #define ERR_EN (1 << 15)
 #define CTO_EN (1 << 16)
 #define CCRC_EN(1 << 17)
@@ -140,7 +143,6 @@
 #define VDD_3V0300 /* 30 uV */
 #define VDD_165_195(ffs(MMC_VDD_165_195) - 1)
 
-#define AUTO_CMD23 (1 << 1)/* Auto CMD23 support */
 /*
  * One controller can have multiple slots, like on some omap boards using
  * omap.c controller driver. Luckily this is not currently done on any known
@@ -194,6 +196,7 @@ struct omap_hsmmc_host {
u32 sysctl;
u32 capa;
int irq;
+   int wake_irq;
int use_dma, dma_ch;
struct dma_chan *tx_chan;
struct dma_chan *rx_chan;
@@ -206,6 +209,9 @@ struct omap_hsmmc_host {
int req_in_progress;
unsigned long   clk_rate;
unsigned intflags;
+#define AUTO_CMD23 (1 << 0)/* Auto CMD23 support */
+#define HSMMC_SDIO_IRQ_ENABLED (1 << 1)/* SDIO irq enabled */
+#define HSMMC_WAKE_IRQ_ENABLED (1 << 2)
struct omap_hsmmc_next  next_data;
struct  omap_mmc_platform_data  *pdata;
 };
@@ -510,27 +516,40 @@ static void omap_hsmmc_stop_clock(struct omap_hsmmc_host 
*host)
 static void omap_hsmmc_enable_irq(struct omap_hsmmc_host *host,
  struct mmc_command *cmd)
 {
-   unsigned int irq_mask;
+   u32 irq_mask = INT_EN_MASK;
+   unsigned long flags;
 
if (host->use_dma)
-   irq_mask = INT_EN_MASK & ~(BRR_EN | BWR_EN);
-   else
-   irq_mask = INT_EN_MASK;
+   irq_mask &= ~(BRR_EN | BWR_EN);
 
/* Disable timeout for erases */
if (cmd->opcode == MMC_ERASE)
irq_mask &= ~DTO_EN;
 
+   spin_lock_irqsave(&host->irq_lock, flags);
OMAP_HSMMC_WRITE(host->base, STAT, STAT_CLEAR);
OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
+
+   /* latch pending CIRQ, but don't signal MMC core */
+   if (host->flags & HSMMC_SDIO_IRQ_ENABLED)
+   irq_mask |= CIRQ_EN;
OMAP_HSMMC_WRITE(host->base, IE, irq_mask);
+   spin_unlock_irqrestore(&host->irq_lock, flags);
 }
 
 static void omap_hsmmc_disable_irq(struct omap_hsmmc_host *host)
 {
-   OMAP_HSMMC_WRITE(host->base, ISE, 0);
-   OMAP_HSMMC_WRITE(host->base, IE, 0);
+   u32 irq_mask = 0;
+   unsigned long flags;
+
+   spin_lock_irqsave(&host->irq_lock, flags);
+   /* no transfer running but need to keep cirq if enabled */
+   if (host->flags & HSMMC_SDIO_IRQ_ENABLED)
+   irq_mask |= CIRQ_EN;
+   OMAP_HSMMC_WRITE(host->base, ISE, irq_mask);
+   OMAP_HSMMC_WRITE