2 * Freescale eSDHC i.MX controller driver for the platform bus.
4 * derived from the OF-version.
6 * Copyright (c) 2010 Pengutronix e.K.
7 * Author: Wolfram Sang <w.sang@pengutronix.de>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License.
15 #include <linux/delay.h>
16 #include <linux/err.h>
17 #include <linux/clk.h>
18 #include <linux/gpio.h>
19 #include <linux/slab.h>
20 #include <linux/mmc/host.h>
21 #include <linux/mmc/sdhci-pltfm.h>
22 #include <linux/mmc/mmc.h>
23 #include <linux/mmc/sdio.h>
24 #include <mach/hardware.h>
25 #include <mach/esdhc.h>
27 #include "sdhci-pltfm.h"
28 #include "sdhci-esdhc.h"
30 /* VENDOR SPEC register */
31 #define SDHCI_VENDOR_SPEC 0xC0
32 #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002
34 #define ESDHC_FLAG_GPIO_FOR_CD_WP (1 << 0)
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
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.
46 #define ESDHC_FLAG_MULTIBLK_NO_INT (1 << 1)
48 struct pltfm_imx_data
{
53 static inline void esdhc_clrset_le(struct sdhci_host
*host
, u32 mask
, u32 val
, int reg
)
55 void __iomem
*base
= host
->ioaddr
+ (reg
& ~0x3);
56 u32 shift
= (reg
& 0x3) * 8;
58 writel(((readl(base
) & ~(mask
<< shift
)) | (val
<< shift
)), base
);
61 static u32
esdhc_readl_le(struct sdhci_host
*host
, int reg
)
63 struct sdhci_pltfm_host
*pltfm_host
= sdhci_priv(host
);
64 struct pltfm_imx_data
*imx_data
= pltfm_host
->priv
;
66 /* fake CARD_PRESENT flag on mx25/35 */
67 u32 val
= readl(host
->ioaddr
+ reg
);
69 if (unlikely((reg
== SDHCI_PRESENT_STATE
)
70 && (imx_data
->flags
& ESDHC_FLAG_GPIO_FOR_CD_WP
))) {
71 struct esdhc_platform_data
*boarddata
=
72 host
->mmc
->parent
->platform_data
;
74 if (boarddata
&& gpio_is_valid(boarddata
->cd_gpio
)
75 && gpio_get_value(boarddata
->cd_gpio
))
76 /* no card, if a valid gpio says so... */
77 val
&= SDHCI_CARD_PRESENT
;
79 /* ... in all other cases assume card is present */
80 val
|= SDHCI_CARD_PRESENT
;
86 static void esdhc_writel_le(struct sdhci_host
*host
, u32 val
, int reg
)
88 struct sdhci_pltfm_host
*pltfm_host
= sdhci_priv(host
);
89 struct pltfm_imx_data
*imx_data
= pltfm_host
->priv
;
91 if (unlikely((reg
== SDHCI_INT_ENABLE
|| reg
== SDHCI_SIGNAL_ENABLE
)
92 && (imx_data
->flags
& ESDHC_FLAG_GPIO_FOR_CD_WP
)))
94 * these interrupts won't work with a custom card_detect gpio
95 * (only applied to mx25/35)
97 val
&= ~(SDHCI_INT_CARD_REMOVE
| SDHCI_INT_CARD_INSERT
);
99 if (unlikely((imx_data
->flags
& ESDHC_FLAG_MULTIBLK_NO_INT
)
100 && (reg
== SDHCI_INT_STATUS
)
101 && (val
& SDHCI_INT_DATA_END
))) {
103 v
= readl(host
->ioaddr
+ SDHCI_VENDOR_SPEC
);
104 v
&= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK
;
105 writel(v
, host
->ioaddr
+ SDHCI_VENDOR_SPEC
);
108 writel(val
, host
->ioaddr
+ reg
);
111 static u16
esdhc_readw_le(struct sdhci_host
*host
, int reg
)
113 if (unlikely(reg
== SDHCI_HOST_VERSION
))
116 return readw(host
->ioaddr
+ reg
);
119 static void esdhc_writew_le(struct sdhci_host
*host
, u16 val
, int reg
)
121 struct sdhci_pltfm_host
*pltfm_host
= sdhci_priv(host
);
122 struct pltfm_imx_data
*imx_data
= pltfm_host
->priv
;
125 case SDHCI_TRANSFER_MODE
:
127 * Postpone this write, we must do it together with a
128 * command write that is down below.
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
)) {
135 v
= readl(host
->ioaddr
+ SDHCI_VENDOR_SPEC
);
136 v
|= SDHCI_VENDOR_SPEC_SDIO_QUIRK
;
137 writel(v
, host
->ioaddr
+ SDHCI_VENDOR_SPEC
);
139 imx_data
->scratchpad
= val
;
142 if ((host
->cmd
->opcode
== MMC_STOP_TRANSMISSION
)
143 && (imx_data
->flags
& ESDHC_FLAG_MULTIBLK_NO_INT
))
144 val
|= SDHCI_CMD_ABORTCMD
;
145 writel(val
<< 16 | imx_data
->scratchpad
,
146 host
->ioaddr
+ SDHCI_TRANSFER_MODE
);
148 case SDHCI_BLOCK_SIZE
:
149 val
&= ~SDHCI_MAKE_BLKSZ(0x7, 0);
152 esdhc_clrset_le(host
, 0xffff, val
, reg
);
155 static void esdhc_writeb_le(struct sdhci_host
*host
, u8 val
, int reg
)
160 case SDHCI_POWER_CONTROL
:
162 * FSL put some DMA bits here
163 * If your board has a regulator, code should be here
166 case SDHCI_HOST_CONTROL
:
167 /* FSL messed up here, so we can just keep those two */
168 new_val
= val
& (SDHCI_CTRL_LED
| SDHCI_CTRL_4BITBUS
);
169 /* ensure the endianess */
170 new_val
|= ESDHC_HOST_CONTROL_LE
;
171 /* DMA mode bits are shifted */
172 new_val
|= (val
& SDHCI_CTRL_DMA_MASK
) << 5;
174 esdhc_clrset_le(host
, 0xffff, new_val
, reg
);
177 esdhc_clrset_le(host
, 0xff, val
, reg
);
180 static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host
*host
)
182 struct sdhci_pltfm_host
*pltfm_host
= sdhci_priv(host
);
184 return clk_get_rate(pltfm_host
->clk
);
187 static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host
*host
)
189 struct sdhci_pltfm_host
*pltfm_host
= sdhci_priv(host
);
191 return clk_get_rate(pltfm_host
->clk
) / 256 / 16;
194 static unsigned int esdhc_pltfm_get_ro(struct sdhci_host
*host
)
196 struct esdhc_platform_data
*boarddata
= host
->mmc
->parent
->platform_data
;
198 if (boarddata
&& gpio_is_valid(boarddata
->wp_gpio
))
199 return gpio_get_value(boarddata
->wp_gpio
);
204 static struct sdhci_ops sdhci_esdhc_ops
= {
205 .read_l
= esdhc_readl_le
,
206 .read_w
= esdhc_readw_le
,
207 .write_l
= esdhc_writel_le
,
208 .write_w
= esdhc_writew_le
,
209 .write_b
= esdhc_writeb_le
,
210 .set_clock
= esdhc_set_clock
,
211 .get_max_clock
= esdhc_pltfm_get_max_clock
,
212 .get_min_clock
= esdhc_pltfm_get_min_clock
,
215 static irqreturn_t
cd_irq(int irq
, void *data
)
217 struct sdhci_host
*sdhost
= (struct sdhci_host
*)data
;
219 tasklet_schedule(&sdhost
->card_tasklet
);
223 static int esdhc_pltfm_init(struct sdhci_host
*host
, struct sdhci_pltfm_data
*pdata
)
225 struct sdhci_pltfm_host
*pltfm_host
= sdhci_priv(host
);
226 struct esdhc_platform_data
*boarddata
= host
->mmc
->parent
->platform_data
;
229 struct pltfm_imx_data
*imx_data
;
231 clk
= clk_get(mmc_dev(host
->mmc
), NULL
);
233 dev_err(mmc_dev(host
->mmc
), "clk err\n");
237 pltfm_host
->clk
= clk
;
239 imx_data
= kzalloc(sizeof(struct pltfm_imx_data
), GFP_KERNEL
);
241 clk_disable(pltfm_host
->clk
);
242 clk_put(pltfm_host
->clk
);
245 pltfm_host
->priv
= imx_data
;
248 host
->quirks
|= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
;
250 if (cpu_is_mx25() || cpu_is_mx35()) {
251 /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
252 host
->quirks
|= SDHCI_QUIRK_NO_MULTIBLOCK
;
253 /* write_protect can't be routed to controller, use gpio */
254 sdhci_esdhc_ops
.get_ro
= esdhc_pltfm_get_ro
;
257 if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51()))
258 imx_data
->flags
|= ESDHC_FLAG_MULTIBLK_NO_INT
;
261 err
= gpio_request_one(boarddata
->wp_gpio
, GPIOF_IN
, "ESDHC_WP");
263 dev_warn(mmc_dev(host
->mmc
),
264 "no write-protect pin available!\n");
265 boarddata
->wp_gpio
= err
;
268 err
= gpio_request_one(boarddata
->cd_gpio
, GPIOF_IN
, "ESDHC_CD");
270 dev_warn(mmc_dev(host
->mmc
),
271 "no card-detect pin available!\n");
272 goto no_card_detect_pin
;
275 /* i.MX5x has issues to be researched */
276 if (!cpu_is_mx25() && !cpu_is_mx35())
279 err
= request_irq(gpio_to_irq(boarddata
->cd_gpio
), cd_irq
,
280 IRQF_TRIGGER_FALLING
| IRQF_TRIGGER_RISING
,
281 mmc_hostname(host
->mmc
), host
);
283 dev_warn(mmc_dev(host
->mmc
), "request irq error\n");
284 goto no_card_detect_irq
;
287 imx_data
->flags
|= ESDHC_FLAG_GPIO_FOR_CD_WP
;
288 /* Now we have a working card_detect again */
289 host
->quirks
&= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION
;
295 gpio_free(boarddata
->cd_gpio
);
297 boarddata
->cd_gpio
= err
;
303 static void esdhc_pltfm_exit(struct sdhci_host
*host
)
305 struct sdhci_pltfm_host
*pltfm_host
= sdhci_priv(host
);
306 struct esdhc_platform_data
*boarddata
= host
->mmc
->parent
->platform_data
;
307 struct pltfm_imx_data
*imx_data
= pltfm_host
->priv
;
309 if (boarddata
&& gpio_is_valid(boarddata
->wp_gpio
))
310 gpio_free(boarddata
->wp_gpio
);
312 if (boarddata
&& gpio_is_valid(boarddata
->cd_gpio
)) {
313 gpio_free(boarddata
->cd_gpio
);
315 if (!(host
->quirks
& SDHCI_QUIRK_BROKEN_CARD_DETECTION
))
316 free_irq(gpio_to_irq(boarddata
->cd_gpio
), host
);
319 clk_disable(pltfm_host
->clk
);
320 clk_put(pltfm_host
->clk
);
324 struct sdhci_pltfm_data sdhci_esdhc_imx_pdata
= {
325 .quirks
= ESDHC_DEFAULT_QUIRKS
| SDHCI_QUIRK_BROKEN_ADMA
326 | SDHCI_QUIRK_BROKEN_CARD_DETECTION
,
327 /* ADMA has issues. Might be fixable */
328 .ops
= &sdhci_esdhc_ops
,
329 .init
= esdhc_pltfm_init
,
330 .exit
= esdhc_pltfm_exit
,