aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c42
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
30struct pltfm_imx_data { 48struct 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) {