diff options
author | Shawn Guo <shawn.guo@linaro.org> | 2011-09-19 05:32:21 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-10-26 16:32:10 -0400 |
commit | 95a2482a9baaf55a3403d2e76f2abd7c0a32298c (patch) | |
tree | aa82292426d77cd3951f57afbe1354260d343975 /drivers/mmc | |
parent | cd8a3666987ba20908bbeb7c78ed9ba82b365643 (diff) |
mmc: sdhci-esdhc-imx: add basic imx6q usdhc support
This patch adds the basic support for imx6q usdhc, which is a
derivative of esdhc controller.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/Kconfig | 6 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-esdhc-imx.c | 36 |
2 files changed, 35 insertions, 7 deletions
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index c226d549fd2f..87d5067ba629 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig | |||
@@ -130,13 +130,13 @@ config MMC_SDHCI_CNS3XXX | |||
130 | If unsure, say N. | 130 | If unsure, say N. |
131 | 131 | ||
132 | config MMC_SDHCI_ESDHC_IMX | 132 | config MMC_SDHCI_ESDHC_IMX |
133 | tristate "SDHCI platform support for the Freescale eSDHC i.MX controller" | 133 | tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller" |
134 | depends on ARCH_MXC | 134 | depends on ARCH_MXC |
135 | depends on MMC_SDHCI_PLTFM | 135 | depends on MMC_SDHCI_PLTFM |
136 | select MMC_SDHCI_IO_ACCESSORS | 136 | select MMC_SDHCI_IO_ACCESSORS |
137 | help | 137 | help |
138 | This selects the Freescale eSDHC controller support on the platform | 138 | This selects the Freescale eSDHC/uSDHC controller support |
139 | bus, found on i.MX25, i.MX35 and i.MX5x. | 139 | found on i.MX25, i.MX35 i.MX5x and i.MX6x. |
140 | 140 | ||
141 | If you have a controller with this interface, say Y or M here. | 141 | If you have a controller with this interface, say Y or M here. |
142 | 142 | ||
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 4557aa1567a5..ae57769ba50d 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c | |||
@@ -32,6 +32,7 @@ | |||
32 | /* VENDOR SPEC register */ | 32 | /* VENDOR SPEC register */ |
33 | #define SDHCI_VENDOR_SPEC 0xC0 | 33 | #define SDHCI_VENDOR_SPEC 0xC0 |
34 | #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 | 34 | #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 |
35 | #define SDHCI_MIX_CTRL 0x48 | ||
35 | 36 | ||
36 | /* | 37 | /* |
37 | * There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC: | 38 | * There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC: |
@@ -59,6 +60,7 @@ enum imx_esdhc_type { | |||
59 | IMX35_ESDHC, | 60 | IMX35_ESDHC, |
60 | IMX51_ESDHC, | 61 | IMX51_ESDHC, |
61 | IMX53_ESDHC, | 62 | IMX53_ESDHC, |
63 | IMX6Q_USDHC, | ||
62 | }; | 64 | }; |
63 | 65 | ||
64 | struct pltfm_imx_data { | 66 | struct pltfm_imx_data { |
@@ -82,6 +84,9 @@ static struct platform_device_id imx_esdhc_devtype[] = { | |||
82 | .name = "sdhci-esdhc-imx53", | 84 | .name = "sdhci-esdhc-imx53", |
83 | .driver_data = IMX53_ESDHC, | 85 | .driver_data = IMX53_ESDHC, |
84 | }, { | 86 | }, { |
87 | .name = "sdhci-usdhc-imx6q", | ||
88 | .driver_data = IMX6Q_USDHC, | ||
89 | }, { | ||
85 | /* sentinel */ | 90 | /* sentinel */ |
86 | } | 91 | } |
87 | }; | 92 | }; |
@@ -92,6 +97,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { | |||
92 | { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], }, | 97 | { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], }, |
93 | { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], }, | 98 | { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], }, |
94 | { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], }, | 99 | { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], }, |
100 | { .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], }, | ||
95 | { /* sentinel */ } | 101 | { /* sentinel */ } |
96 | }; | 102 | }; |
97 | MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); | 103 | MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); |
@@ -116,6 +122,11 @@ static inline int is_imx53_esdhc(struct pltfm_imx_data *data) | |||
116 | return data->devtype == IMX53_ESDHC; | 122 | return data->devtype == IMX53_ESDHC; |
117 | } | 123 | } |
118 | 124 | ||
125 | static inline int is_imx6q_usdhc(struct pltfm_imx_data *data) | ||
126 | { | ||
127 | return data->devtype == IMX6Q_USDHC; | ||
128 | } | ||
129 | |||
119 | static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) | 130 | static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) |
120 | { | 131 | { |
121 | void __iomem *base = host->ioaddr + (reg & ~0x3); | 132 | void __iomem *base = host->ioaddr + (reg & ~0x3); |
@@ -220,8 +231,16 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) | |||
220 | 231 | ||
221 | static u16 esdhc_readw_le(struct sdhci_host *host, int reg) | 232 | static u16 esdhc_readw_le(struct sdhci_host *host, int reg) |
222 | { | 233 | { |
223 | if (unlikely(reg == SDHCI_HOST_VERSION)) | 234 | if (unlikely(reg == SDHCI_HOST_VERSION)) { |
224 | reg ^= 2; | 235 | u16 val = readw(host->ioaddr + (reg ^ 2)); |
236 | /* | ||
237 | * uSDHC supports SDHCI v3.0, but it's encoded as value | ||
238 | * 0x3 in host controller version register, which violates | ||
239 | * SDHCI_SPEC_300 definition. Work it around here. | ||
240 | */ | ||
241 | if ((val & SDHCI_SPEC_VER_MASK) == 3) | ||
242 | return --val; | ||
243 | } | ||
225 | 244 | ||
226 | return readw(host->ioaddr + reg); | 245 | return readw(host->ioaddr + reg); |
227 | } | 246 | } |
@@ -252,8 +271,17 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) | |||
252 | if ((host->cmd->opcode == MMC_STOP_TRANSMISSION) | 271 | if ((host->cmd->opcode == MMC_STOP_TRANSMISSION) |
253 | && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) | 272 | && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) |
254 | val |= SDHCI_CMD_ABORTCMD; | 273 | val |= SDHCI_CMD_ABORTCMD; |
255 | writel(val << 16 | imx_data->scratchpad, | 274 | |
256 | host->ioaddr + SDHCI_TRANSFER_MODE); | 275 | if (is_imx6q_usdhc(imx_data)) { |
276 | u32 m = readl(host->ioaddr + SDHCI_MIX_CTRL); | ||
277 | m = imx_data->scratchpad | (m & 0xffff0000); | ||
278 | writel(m, host->ioaddr + SDHCI_MIX_CTRL); | ||
279 | writel(val << 16, | ||
280 | host->ioaddr + SDHCI_TRANSFER_MODE); | ||
281 | } else { | ||
282 | writel(val << 16 | imx_data->scratchpad, | ||
283 | host->ioaddr + SDHCI_TRANSFER_MODE); | ||
284 | } | ||
257 | return; | 285 | return; |
258 | case SDHCI_BLOCK_SIZE: | 286 | case SDHCI_BLOCK_SIZE: |
259 | val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); | 287 | val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); |