diff options
-rw-r--r-- | drivers/mmc/host/sdhci-esdhc-imx.c | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 67a2da961bb5..a19967d0bfc4 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c | |||
@@ -19,13 +19,31 @@ | |||
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/mmc/host.h> | 20 | #include <linux/mmc/host.h> |
21 | #include <linux/mmc/sdhci-pltfm.h> | 21 | #include <linux/mmc/sdhci-pltfm.h> |
22 | #include <linux/mmc/mmc.h> | ||
23 | #include <linux/mmc/sdio.h> | ||
22 | #include <mach/hardware.h> | 24 | #include <mach/hardware.h> |
23 | #include <mach/esdhc.h> | 25 | #include <mach/esdhc.h> |
24 | #include "sdhci.h" | 26 | #include "sdhci.h" |
25 | #include "sdhci-pltfm.h" | 27 | #include "sdhci-pltfm.h" |
26 | #include "sdhci-esdhc.h" | 28 | #include "sdhci-esdhc.h" |
27 | 29 | ||
30 | /* VENDOR SPEC register */ | ||
31 | #define SDHCI_VENDOR_SPEC 0xC0 | ||
32 | #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 | ||
33 | |||
28 | #define ESDHC_FLAG_GPIO_FOR_CD_WP (1 << 0) | 34 | #define ESDHC_FLAG_GPIO_FOR_CD_WP (1 << 0) |
35 | /* | ||
36 | * The CMDTYPE of the CMD register (offset 0xE) should be set to | ||
37 | * "11" when the STOP CMD12 is issued on imx53 to abort one | ||
38 | * open ended multi-blk IO. Otherwise the TC INT wouldn't | ||
39 | * be generated. | ||
40 | * In exact block transfer, the controller doesn't complete the | ||
41 | * operations automatically as required at the end of the | ||
42 | * transfer and remains on hold if the abort command is not sent. | ||
43 | * As a result, the TC flag is not asserted and SW received timeout | ||
44 | * exeception. Bit1 of Vendor Spec registor is used to fix it. | ||
45 | */ | ||
46 | #define ESDHC_FLAG_MULTIBLK_NO_INT (1 << 1) | ||
29 | 47 | ||
30 | struct pltfm_imx_data { | 48 | struct pltfm_imx_data { |
31 | int flags; | 49 | int flags; |
@@ -78,6 +96,15 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) | |||
78 | */ | 96 | */ |
79 | val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); | 97 | val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); |
80 | 98 | ||
99 | if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) | ||
100 | && (reg == SDHCI_INT_STATUS) | ||
101 | && (val & SDHCI_INT_DATA_END))) { | ||
102 | u32 v; | ||
103 | v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); | ||
104 | v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK; | ||
105 | writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); | ||
106 | } | ||
107 | |||
81 | writel(val, host->ioaddr + reg); | 108 | writel(val, host->ioaddr + reg); |
82 | } | 109 | } |
83 | 110 | ||
@@ -100,9 +127,21 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) | |||
100 | * Postpone this write, we must do it together with a | 127 | * Postpone this write, we must do it together with a |
101 | * command write that is down below. | 128 | * command write that is down below. |
102 | */ | 129 | */ |
130 | if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) | ||
131 | && (host->cmd->opcode == SD_IO_RW_EXTENDED) | ||
132 | && (host->cmd->data->blocks > 1) | ||
133 | && (host->cmd->data->flags & MMC_DATA_READ)) { | ||
134 | u32 v; | ||
135 | v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); | ||
136 | v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK; | ||
137 | writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); | ||
138 | } | ||
103 | imx_data->scratchpad = val; | 139 | imx_data->scratchpad = val; |
104 | return; | 140 | return; |
105 | case SDHCI_COMMAND: | 141 | case SDHCI_COMMAND: |
142 | if ((host->cmd->opcode == MMC_STOP_TRANSMISSION) | ||
143 | && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) | ||
144 | val |= SDHCI_CMD_ABORTCMD; | ||
106 | writel(val << 16 | imx_data->scratchpad, | 145 | writel(val << 16 | imx_data->scratchpad, |
107 | host->ioaddr + SDHCI_TRANSFER_MODE); | 146 | host->ioaddr + SDHCI_TRANSFER_MODE); |
108 | return; | 147 | return; |
@@ -215,6 +254,9 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd | |||
215 | sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro; | 254 | sdhci_esdhc_ops.get_ro = esdhc_pltfm_get_ro; |
216 | } | 255 | } |
217 | 256 | ||
257 | if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51())) | ||
258 | imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; | ||
259 | |||
218 | if (boarddata) { | 260 | if (boarddata) { |
219 | err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); | 261 | err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); |
220 | if (err) { | 262 | if (err) { |