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: Jjian Zhou <jjian.zhou@mediatek.com>
Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com>
Signed-off-by: Yong Mao <yong.mao@mediatek.com>
Fixes: 5215b2e952
("mmc: mediatek: Add MMC_CAP_SDIO_IRQ support")
Cc: stable@vger.kernel.org
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
parent
b0e370b95a
commit
8a5df8ac62
|
@ -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)
|
||||
{
|
||||
if (enb) {
|
||||
sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ);
|
||||
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 + SDC_CFG, SDC_CFG_SDIOIDE);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
__msdc_enable_sdio_irq(host, enb);
|
||||
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);
|
||||
|
@ -1414,6 +1415,8 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
|
|||
spin_lock_irqsave(&host->lock, flags);
|
||||
events = readl(host->base + MSDC_INT);
|
||||
event_mask = readl(host->base + MSDC_INTEN);
|
||||
if ((events & event_mask) & MSDC_INT_SDIOIRQ)
|
||||
__msdc_enable_sdio_irq(host, 0);
|
||||
/* clear interrupts */
|
||||
writel(events & event_mask, host->base + MSDC_INT);
|
||||
|
||||
|
@ -1422,10 +1425,8 @@ static irqreturn_t msdc_irq(int irq, void *dev_id)
|
|||
data = host->data;
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
|
||||
if ((events & event_mask) & MSDC_INT_SDIOIRQ) {
|
||||
__msdc_enable_sdio_irq(host->mmc, 0);
|
||||
if ((events & event_mask) & MSDC_INT_SDIOIRQ)
|
||||
sdio_signal_irq(host->mmc);
|
||||
}
|
||||
|
||||
if ((events & event_mask) & MSDC_INT_CDSC) {
|
||||
if (host->internal_cd)
|
||||
|
@ -1564,10 +1565,7 @@ static void msdc_init_hw(struct msdc_host *host)
|
|||
sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO);
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
|
@ -2095,7 +2093,12 @@ static void msdc_hw_reset(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)
|
||||
|
|
Loading…
Reference in New Issue
Block a user