]>
Commit | Line | Data |
---|---|---|
6754ff8d GKH |
1 | From 8a5df8ac628f4febea1e6cd3044bff2d536dd096 Mon Sep 17 00:00:00 2001 |
2 | From: jjian zhou <jjian.zhou@mediatek.com> | |
3 | Date: Mon, 17 Jun 2019 19:04:07 +0800 | |
4 | Subject: mmc: mediatek: fix SDIO IRQ interrupt handle flow | |
5 | ||
6 | From: jjian zhou <jjian.zhou@mediatek.com> | |
7 | ||
8 | commit 8a5df8ac628f4febea1e6cd3044bff2d536dd096 upstream. | |
9 | ||
10 | SDIO IRQ is triggered by low level. It need disable SDIO IRQ | |
11 | detected function. Otherwise the interrupt register can't be cleared. | |
12 | It will process the interrupt more. | |
13 | ||
14 | Signed-off-by: Jjian Zhou <jjian.zhou@mediatek.com> | |
15 | Signed-off-by: Chaotian Jing <chaotian.jing@mediatek.com> | |
16 | Signed-off-by: Yong Mao <yong.mao@mediatek.com> | |
17 | Fixes: 5215b2e952f3 ("mmc: mediatek: Add MMC_CAP_SDIO_IRQ support") | |
18 | Cc: stable@vger.kernel.org | |
19 | Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> | |
20 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
21 | ||
22 | --- | |
23 | drivers/mmc/host/mtk-sd.c | 37 ++++++++++++++++++++----------------- | |
24 | 1 file changed, 20 insertions(+), 17 deletions(-) | |
25 | ||
26 | --- a/drivers/mmc/host/mtk-sd.c | |
27 | +++ b/drivers/mmc/host/mtk-sd.c | |
28 | @@ -1355,24 +1355,25 @@ static void msdc_request_timeout(struct | |
29 | } | |
30 | } | |
31 | ||
32 | -static void __msdc_enable_sdio_irq(struct mmc_host *mmc, int enb) | |
33 | +static void __msdc_enable_sdio_irq(struct msdc_host *host, int enb) | |
34 | { | |
35 | - unsigned long flags; | |
36 | - struct msdc_host *host = mmc_priv(mmc); | |
37 | - | |
38 | - spin_lock_irqsave(&host->lock, flags); | |
39 | - if (enb) | |
40 | + if (enb) { | |
41 | sdr_set_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ); | |
42 | - else | |
43 | + sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); | |
44 | + } else { | |
45 | sdr_clr_bits(host->base + MSDC_INTEN, MSDC_INTEN_SDIOIRQ); | |
46 | - spin_unlock_irqrestore(&host->lock, flags); | |
47 | + sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); | |
48 | + } | |
49 | } | |
50 | ||
51 | static void msdc_enable_sdio_irq(struct mmc_host *mmc, int enb) | |
52 | { | |
53 | + unsigned long flags; | |
54 | struct msdc_host *host = mmc_priv(mmc); | |
55 | ||
56 | - __msdc_enable_sdio_irq(mmc, enb); | |
57 | + spin_lock_irqsave(&host->lock, flags); | |
58 | + __msdc_enable_sdio_irq(host, enb); | |
59 | + spin_unlock_irqrestore(&host->lock, flags); | |
60 | ||
61 | if (enb) | |
62 | pm_runtime_get_noresume(host->dev); | |
63 | @@ -1394,6 +1395,8 @@ static irqreturn_t msdc_irq(int irq, voi | |
64 | spin_lock_irqsave(&host->lock, flags); | |
65 | events = readl(host->base + MSDC_INT); | |
66 | event_mask = readl(host->base + MSDC_INTEN); | |
67 | + if ((events & event_mask) & MSDC_INT_SDIOIRQ) | |
68 | + __msdc_enable_sdio_irq(host, 0); | |
69 | /* clear interrupts */ | |
70 | writel(events & event_mask, host->base + MSDC_INT); | |
71 | ||
72 | @@ -1402,10 +1405,8 @@ static irqreturn_t msdc_irq(int irq, voi | |
73 | data = host->data; | |
74 | spin_unlock_irqrestore(&host->lock, flags); | |
75 | ||
76 | - if ((events & event_mask) & MSDC_INT_SDIOIRQ) { | |
77 | - __msdc_enable_sdio_irq(host->mmc, 0); | |
78 | + if ((events & event_mask) & MSDC_INT_SDIOIRQ) | |
79 | sdio_signal_irq(host->mmc); | |
80 | - } | |
81 | ||
82 | if (!(events & (event_mask & ~MSDC_INT_SDIOIRQ))) | |
83 | break; | |
84 | @@ -1528,10 +1529,7 @@ static void msdc_init_hw(struct msdc_hos | |
85 | sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIO); | |
86 | ||
87 | /* Config SDIO device detect interrupt function */ | |
88 | - if (host->mmc->caps & MMC_CAP_SDIO_IRQ) | |
89 | - sdr_set_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); | |
90 | - else | |
91 | - sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); | |
92 | + sdr_clr_bits(host->base + SDC_CFG, SDC_CFG_SDIOIDE); | |
93 | ||
94 | /* Configure to default data timeout */ | |
95 | sdr_set_field(host->base + SDC_CFG, SDC_CFG_DTOC, 3); | |
96 | @@ -2052,7 +2050,12 @@ static void msdc_hw_reset(struct mmc_hos | |
97 | ||
98 | static void msdc_ack_sdio_irq(struct mmc_host *mmc) | |
99 | { | |
100 | - __msdc_enable_sdio_irq(mmc, 1); | |
101 | + unsigned long flags; | |
102 | + struct msdc_host *host = mmc_priv(mmc); | |
103 | + | |
104 | + spin_lock_irqsave(&host->lock, flags); | |
105 | + __msdc_enable_sdio_irq(host, 1); | |
106 | + spin_unlock_irqrestore(&host->lock, flags); | |
107 | } | |
108 | ||
109 | static const struct mmc_host_ops mt_msdc_ops = { |