diff options
author | Tony Lin <tony.lin@freescale.com> | 2011-08-11 16:45:59 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-08-13 14:50:26 -0400 |
commit | 0d58864bf3472f8390e0c0a33bd875c7eec868bd (patch) | |
tree | f186f7e8d753841264497115b6ca599e24079f48 /drivers/mmc | |
parent | 55156d240a4d41d47310278c5139e24517f1c65b (diff) |
mmc: esdhc-imx: fix card interrupt loss on freescale eSDHC
Apply a workaround for the imx eSDHC controller to avoid missing
card interrupts. This makes SDIO work.
Signed-off-by: Tony Lin <tony.lin@freescale.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/sdhci-esdhc-imx.c | 40 |
1 files changed, 31 insertions, 9 deletions
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 9ebfb4b482f5..0e9780f5a4a9 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include "sdhci-pltfm.h" | 27 | #include "sdhci-pltfm.h" |
28 | #include "sdhci-esdhc.h" | 28 | #include "sdhci-esdhc.h" |
29 | 29 | ||
30 | #define SDHCI_CTRL_D3CD 0x08 | ||
30 | /* VENDOR SPEC register */ | 31 | /* VENDOR SPEC register */ |
31 | #define SDHCI_VENDOR_SPEC 0xC0 | 32 | #define SDHCI_VENDOR_SPEC 0xC0 |
32 | #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 | 33 | #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 |
@@ -141,13 +142,32 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) | |||
141 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | 142 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
142 | struct pltfm_imx_data *imx_data = pltfm_host->priv; | 143 | struct pltfm_imx_data *imx_data = pltfm_host->priv; |
143 | struct esdhc_platform_data *boarddata = &imx_data->boarddata; | 144 | struct esdhc_platform_data *boarddata = &imx_data->boarddata; |
144 | 145 | u32 data; | |
145 | if (unlikely((reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE) | 146 | |
146 | && (boarddata->cd_type == ESDHC_CD_GPIO))) | 147 | if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { |
147 | /* | 148 | if (boarddata->cd_type == ESDHC_CD_GPIO) |
148 | * these interrupts won't work with a custom card_detect gpio | 149 | /* |
149 | */ | 150 | * These interrupts won't work with a custom |
150 | val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); | 151 | * card_detect gpio (only applied to mx25/35) |
152 | */ | ||
153 | val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); | ||
154 | |||
155 | if (val & SDHCI_INT_CARD_INT) { | ||
156 | /* | ||
157 | * Clear and then set D3CD bit to avoid missing the | ||
158 | * card interrupt. This is a eSDHC controller problem | ||
159 | * so we need to apply the following workaround: clear | ||
160 | * and set D3CD bit will make eSDHC re-sample the card | ||
161 | * interrupt. In case a card interrupt was lost, | ||
162 | * re-sample it by the following steps. | ||
163 | */ | ||
164 | data = readl(host->ioaddr + SDHCI_HOST_CONTROL); | ||
165 | data &= ~SDHCI_CTRL_D3CD; | ||
166 | writel(data, host->ioaddr + SDHCI_HOST_CONTROL); | ||
167 | data |= SDHCI_CTRL_D3CD; | ||
168 | writel(data, host->ioaddr + SDHCI_HOST_CONTROL); | ||
169 | } | ||
170 | } | ||
151 | 171 | ||
152 | if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) | 172 | if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) |
153 | && (reg == SDHCI_INT_STATUS) | 173 | && (reg == SDHCI_INT_STATUS) |
@@ -217,8 +237,10 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) | |||
217 | */ | 237 | */ |
218 | return; | 238 | return; |
219 | case SDHCI_HOST_CONTROL: | 239 | case SDHCI_HOST_CONTROL: |
220 | /* FSL messed up here, so we can just keep those two */ | 240 | /* FSL messed up here, so we can just keep those three */ |
221 | new_val = val & (SDHCI_CTRL_LED | SDHCI_CTRL_4BITBUS); | 241 | new_val = val & (SDHCI_CTRL_LED | \ |
242 | SDHCI_CTRL_4BITBUS | \ | ||
243 | SDHCI_CTRL_D3CD); | ||
222 | /* ensure the endianess */ | 244 | /* ensure the endianess */ |
223 | new_val |= ESDHC_HOST_CONTROL_LE; | 245 | new_val |= ESDHC_HOST_CONTROL_LE; |
224 | /* DMA mode bits are shifted */ | 246 | /* DMA mode bits are shifted */ |