Commit 8a5df8ac authored by jjian zhou's avatar jjian zhou Committed by Ulf Hansson

mmc: mediatek: fix SDIO IRQ interrupt handle flow

SDIO IRQ is triggered by low level. It need disable SDIO IRQ
detected function. Otherwise the interrupt register can't be cleared.
It will process the interrupt more.
Signed-off-by: default avatarJjian Zhou <jjian.zhou@mediatek.com>
Signed-off-by: default avatarChaotian Jing <chaotian.jing@mediatek.com>
Signed-off-by: default avatarYong Mao <yong.mao@mediatek.com>
Fixes: 5215b2e9 ("mmc: mediatek: Add MMC_CAP_SDIO_IRQ support")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent b0e370b9
...@@ -1375,24 +1375,25 @@ static void msdc_request_timeout(struct work_struct *work) ...@@ -1375,24 +1375,25 @@ static void msdc_request_timeout(struct work_struct *work)
} }
} }
static void __msdc_enable_sdio_irq(struct mmc_host *mmc, int enb) static void __msdc_enable_sdio_irq(struct msdc_host *host, int enb)
{ {
unsigned long flags; if (enb) {
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); sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ);
else sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
} else {
sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ); sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ);
spin_unlock_irqrestore(&host->lock, flags); sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
}
} }
static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb) static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb)
{ {
unsigned long flags;
struct msdc_host *host = mmc_priv(mmc); struct msdc_host *host = mmc_priv(mmc);
__msdc_enable_sdio_irq(mmc, enb); spin_lock_irqsave(&host->lock, flags);
__msdc_enable_sdio_irq(host, enb);
spin_unlock_irqrestore(&host->lock, flags);
if (enb) if (enb)
pm_runtime_get_noresume(host->dev); pm_runtime_get_noresume(host->dev);
...@@ -1414,6 +1415,8 @@ static irqreturn_t msdc_irq(int irq, void *dev_id) ...@@ -1414,6 +1415,8 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
events = readl(host->base + MSDC_INT); events = readl(host->base + MSDC_INT);
event_mask = readl(host->base + MSDC_INTEN); event_mask = readl(host->base + MSDC_INTEN);
if ((events & event_mask) & MSDC_INT_SDIOIRQ)
__msdc_enable_sdio_irq(host, 0);
/* clear interrupts */ /* clear interrupts */
writel(events & event_mask, host->base + MSDC_INT); writel(events & event_mask, host->base + MSDC_INT);
...@@ -1422,10 +1425,8 @@ static irqreturn_t msdc_irq(int irq, void *dev_id) ...@@ -1422,10 +1425,8 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
data = host->data; data = host->data;
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
if ((events & event_mask) & MSDC_INT_SDIOIRQ) { if ((events & event_mask) & MSDC_INT_SDIOIRQ)
__msdc_enable_sdio_irq(host->mmc, 0);
sdio_signal_irq(host->mmc); sdio_signal_irq(host->mmc);
}
if ((events & event_mask) & MSDC_INT_CDSC) { if ((events & event_mask) & MSDC_INT_CDSC) {
if (host->internal_cd) if (host->internal_cd)
...@@ -1564,10 +1565,7 @@ static void msdc_init_hw(struct msdc_host *host) ...@@ -1564,10 +1565,7 @@ static void msdc_init_hw(struct msdc_host *host)
sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO); sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO);
/* Config SDIO device detect interrupt function */ /* Config SDIO device detect interrupt function */
if (host->mmc->caps & MMC_CAP_SDIO_IRQ) sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE);
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 */ /* Configure to default data timeout */
sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3); sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3);
...@@ -2095,7 +2093,12 @@ static void msdc_hw_reset(struct mmc_host *mmc) ...@@ -2095,7 +2093,12 @@ static void msdc_hw_reset(struct mmc_host *mmc)
static void msdc_ack_sdio_irq(struct mmc_host *mmc) static void msdc_ack_sdio_irq(struct mmc_host *mmc)
{ {
__msdc_enable_sdio_irq(mmc, 1); unsigned long flags;
struct msdc_host *host = mmc_priv(mmc);
spin_lock_irqsave(&host->lock, flags);
__msdc_enable_sdio_irq(host, 1);
spin_unlock_irqrestore(&host->lock, flags);
} }
static int msdc_get_cd(struct mmc_host *mmc) static int msdc_get_cd(struct mmc_host *mmc)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment