struct mmc_request *mrq, struct mmc_command *cmd)
 {
        u32 rawcmd;
+       unsigned long flags;
 
        WARN_ON(host->cmd);
        host->cmd = cmd;
        cmd->error = 0;
        rawcmd = msdc_cmd_prepare_raw_cmd(host, mrq, cmd);
 
+       spin_lock_irqsave(&host->lock, flags);
        sdr_set_bits(host->base + MSDC_INTEN, cmd_ints_mask);
+       spin_unlock_irqrestore(&host->lock, flags);
+
        writel(cmd->arg, host->base + SDC_ARG);
        writel(rawcmd, host->base + SDC_CMD);
 }
        }
 }
 
+static void __msdc_enable_sdio_irq(struct mmc_host *mmc, int enb)
+{
+       unsigned long flags;
+       struct msdc_host *host = mmc_priv(mmc);
+
+       spin_lock_irqsave(&host->lock, flags);
+       if (enb)
+               sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ);
+       else
+               sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ);
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb)
+{
+       struct msdc_host *host = mmc_priv(mmc);
+
+       __msdc_enable_sdio_irq(mmc, enb);
+
+       if (enb)
+               pm_runtime_get_noresume(host->dev);
+       else
+               pm_runtime_put_noidle(host->dev);
+}
+
 static irqreturn_t msdc_irq(int irq, void *dev_id)
 {
        struct msdc_host *host = (struct msdc_host *) dev_id;
                data = host->data;
                spin_unlock_irqrestore(&host->lock, flags);
 
-               if (!(events & event_mask))
+               if ((events & event_mask) & MSDC_INT_SDIOIRQ) {
+                       __msdc_enable_sdio_irq(host->mmc, 0);
+                       sdio_signal_irq(host->mmc);
+               }
+
+               if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ)))
                        break;
 
                if (!mrq) {
         */
        sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO);
 
-       /* disable detect SDIO device interrupt function */
-       sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
+       /* Config SDIO device detect interrupt function */
+       if (host->mmc->caps & MMC_CAP_SDIO_IRQ)
+               sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
+       else
+               sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
 
        /* Configure to default data timeout */
        sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3);
        sdr_clr_bits(host->base + EMMC_IOCON, 1);
 }
 
+static void msdc_ack_sdio_irq(struct mmc_host *mmc)
+{
+       __msdc_enable_sdio_irq(mmc, 1);
+}
+
 static const struct mmc_host_ops mt_msdc_ops = {
        .post_req = msdc_post_req,
        .pre_req = msdc_pre_req,
        .set_ios = msdc_ops_set_ios,
        .get_ro = mmc_gpio_get_ro,
        .get_cd = mmc_gpio_get_cd,
+       .enable_sdio_irq = msdc_enable_sdio_irq,
+       .ack_sdio_irq = msdc_ack_sdio_irq,
        .start_signal_voltage_switch = msdc_ops_switch_volt,
        .card_busy = msdc_card_busy,
        .execute_tuning = msdc_execute_tuning,
        else
                mmc->f_min = DIV_ROUND_UP(host->src_clk_freq, 4 * 4095);
 
+       if (mmc->caps & MMC_CAP_SDIO_IRQ)
+               mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
+
        mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23;
        /* MMC core transfer sizes tunable parameters */
        mmc->max_segs = MAX_BD_NUM;