Commit | Line | Data |
---|---|---|
95f25efe WS |
1 | /* |
2 | * Freescale eSDHC i.MX controller driver for the platform bus. | |
3 | * | |
4 | * derived from the OF-version. | |
5 | * | |
6 | * Copyright (c) 2010 Pengutronix e.K. | |
7 | * Author: Wolfram Sang <w.sang@pengutronix.de> | |
8 | * | |
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. | |
12 | */ | |
13 | ||
14 | #include <linux/io.h> | |
15 | #include <linux/delay.h> | |
16 | #include <linux/err.h> | |
17 | #include <linux/clk.h> | |
0c6d49ce | 18 | #include <linux/gpio.h> |
66506f76 | 19 | #include <linux/module.h> |
e149860d | 20 | #include <linux/slab.h> |
95f25efe | 21 | #include <linux/mmc/host.h> |
58ac8177 RZ |
22 | #include <linux/mmc/mmc.h> |
23 | #include <linux/mmc/sdio.h> | |
abfafc2d SG |
24 | #include <linux/of.h> |
25 | #include <linux/of_device.h> | |
26 | #include <linux/of_gpio.h> | |
e62d8b8f | 27 | #include <linux/pinctrl/consumer.h> |
82906b13 | 28 | #include <linux/platform_data/mmc-esdhc-imx.h> |
95f25efe WS |
29 | #include "sdhci-pltfm.h" |
30 | #include "sdhci-esdhc.h" | |
31 | ||
0d58864b | 32 | #define SDHCI_CTRL_D3CD 0x08 |
58ac8177 RZ |
33 | /* VENDOR SPEC register */ |
34 | #define SDHCI_VENDOR_SPEC 0xC0 | |
35 | #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 | |
f750ba9b | 36 | #define SDHCI_WTMK_LVL 0x44 |
95a2482a | 37 | #define SDHCI_MIX_CTRL 0x48 |
58ac8177 | 38 | |
97e4ba6a RZ |
39 | /* |
40 | * There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC: | |
41 | * Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design, | |
42 | * but bit28 is used as the INT DMA ERR in fsl eSDHC design. | |
43 | * Define this macro DMA error INT for fsl eSDHC | |
44 | */ | |
45 | #define SDHCI_INT_VENDOR_SPEC_DMA_ERR 0x10000000 | |
46 | ||
58ac8177 RZ |
47 | /* |
48 | * The CMDTYPE of the CMD register (offset 0xE) should be set to | |
49 | * "11" when the STOP CMD12 is issued on imx53 to abort one | |
50 | * open ended multi-blk IO. Otherwise the TC INT wouldn't | |
51 | * be generated. | |
52 | * In exact block transfer, the controller doesn't complete the | |
53 | * operations automatically as required at the end of the | |
54 | * transfer and remains on hold if the abort command is not sent. | |
55 | * As a result, the TC flag is not asserted and SW received timeout | |
56 | * exeception. Bit1 of Vendor Spec registor is used to fix it. | |
57 | */ | |
58 | #define ESDHC_FLAG_MULTIBLK_NO_INT (1 << 1) | |
e149860d | 59 | |
57ed3314 SG |
60 | enum imx_esdhc_type { |
61 | IMX25_ESDHC, | |
62 | IMX35_ESDHC, | |
63 | IMX51_ESDHC, | |
64 | IMX53_ESDHC, | |
95a2482a | 65 | IMX6Q_USDHC, |
57ed3314 SG |
66 | }; |
67 | ||
e149860d RZ |
68 | struct pltfm_imx_data { |
69 | int flags; | |
70 | u32 scratchpad; | |
57ed3314 | 71 | enum imx_esdhc_type devtype; |
e62d8b8f | 72 | struct pinctrl *pinctrl; |
842afc02 | 73 | struct esdhc_platform_data boarddata; |
52dac615 SH |
74 | struct clk *clk_ipg; |
75 | struct clk *clk_ahb; | |
76 | struct clk *clk_per; | |
e149860d RZ |
77 | }; |
78 | ||
57ed3314 SG |
79 | static struct platform_device_id imx_esdhc_devtype[] = { |
80 | { | |
81 | .name = "sdhci-esdhc-imx25", | |
82 | .driver_data = IMX25_ESDHC, | |
83 | }, { | |
84 | .name = "sdhci-esdhc-imx35", | |
85 | .driver_data = IMX35_ESDHC, | |
86 | }, { | |
87 | .name = "sdhci-esdhc-imx51", | |
88 | .driver_data = IMX51_ESDHC, | |
89 | }, { | |
90 | .name = "sdhci-esdhc-imx53", | |
91 | .driver_data = IMX53_ESDHC, | |
95a2482a SG |
92 | }, { |
93 | .name = "sdhci-usdhc-imx6q", | |
94 | .driver_data = IMX6Q_USDHC, | |
57ed3314 SG |
95 | }, { |
96 | /* sentinel */ | |
97 | } | |
98 | }; | |
99 | MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype); | |
100 | ||
abfafc2d SG |
101 | static const struct of_device_id imx_esdhc_dt_ids[] = { |
102 | { .compatible = "fsl,imx25-esdhc", .data = &imx_esdhc_devtype[IMX25_ESDHC], }, | |
103 | { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], }, | |
104 | { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], }, | |
105 | { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], }, | |
95a2482a | 106 | { .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], }, |
abfafc2d SG |
107 | { /* sentinel */ } |
108 | }; | |
109 | MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); | |
110 | ||
57ed3314 SG |
111 | static inline int is_imx25_esdhc(struct pltfm_imx_data *data) |
112 | { | |
113 | return data->devtype == IMX25_ESDHC; | |
114 | } | |
115 | ||
116 | static inline int is_imx35_esdhc(struct pltfm_imx_data *data) | |
117 | { | |
118 | return data->devtype == IMX35_ESDHC; | |
119 | } | |
120 | ||
121 | static inline int is_imx51_esdhc(struct pltfm_imx_data *data) | |
122 | { | |
123 | return data->devtype == IMX51_ESDHC; | |
124 | } | |
125 | ||
126 | static inline int is_imx53_esdhc(struct pltfm_imx_data *data) | |
127 | { | |
128 | return data->devtype == IMX53_ESDHC; | |
129 | } | |
130 | ||
95a2482a SG |
131 | static inline int is_imx6q_usdhc(struct pltfm_imx_data *data) |
132 | { | |
133 | return data->devtype == IMX6Q_USDHC; | |
134 | } | |
135 | ||
95f25efe WS |
136 | static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) |
137 | { | |
138 | void __iomem *base = host->ioaddr + (reg & ~0x3); | |
139 | u32 shift = (reg & 0x3) * 8; | |
140 | ||
141 | writel(((readl(base) & ~(mask << shift)) | (val << shift)), base); | |
142 | } | |
143 | ||
7e29c306 WS |
144 | static u32 esdhc_readl_le(struct sdhci_host *host, int reg) |
145 | { | |
842afc02 SG |
146 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
147 | struct pltfm_imx_data *imx_data = pltfm_host->priv; | |
148 | struct esdhc_platform_data *boarddata = &imx_data->boarddata; | |
e149860d | 149 | |
913413c3 | 150 | /* fake CARD_PRESENT flag */ |
7e29c306 WS |
151 | u32 val = readl(host->ioaddr + reg); |
152 | ||
e149860d | 153 | if (unlikely((reg == SDHCI_PRESENT_STATE) |
913413c3 SG |
154 | && gpio_is_valid(boarddata->cd_gpio))) { |
155 | if (gpio_get_value(boarddata->cd_gpio)) | |
7e29c306 | 156 | /* no card, if a valid gpio says so... */ |
803862a6 | 157 | val &= ~SDHCI_CARD_PRESENT; |
7e29c306 WS |
158 | else |
159 | /* ... in all other cases assume card is present */ | |
160 | val |= SDHCI_CARD_PRESENT; | |
161 | } | |
162 | ||
97e4ba6a RZ |
163 | if (unlikely(reg == SDHCI_CAPABILITIES)) { |
164 | /* In FSL esdhc IC module, only bit20 is used to indicate the | |
165 | * ADMA2 capability of esdhc, but this bit is messed up on | |
166 | * some SOCs (e.g. on MX25, MX35 this bit is set, but they | |
167 | * don't actually support ADMA2). So set the BROKEN_ADMA | |
168 | * uirk on MX25/35 platforms. | |
169 | */ | |
170 | ||
171 | if (val & SDHCI_CAN_DO_ADMA1) { | |
172 | val &= ~SDHCI_CAN_DO_ADMA1; | |
173 | val |= SDHCI_CAN_DO_ADMA2; | |
174 | } | |
175 | } | |
176 | ||
177 | if (unlikely(reg == SDHCI_INT_STATUS)) { | |
178 | if (val & SDHCI_INT_VENDOR_SPEC_DMA_ERR) { | |
179 | val &= ~SDHCI_INT_VENDOR_SPEC_DMA_ERR; | |
180 | val |= SDHCI_INT_ADMA_ERROR; | |
181 | } | |
182 | } | |
183 | ||
7e29c306 WS |
184 | return val; |
185 | } | |
186 | ||
187 | static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) | |
188 | { | |
e149860d RZ |
189 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
190 | struct pltfm_imx_data *imx_data = pltfm_host->priv; | |
842afc02 | 191 | struct esdhc_platform_data *boarddata = &imx_data->boarddata; |
0d58864b TL |
192 | u32 data; |
193 | ||
194 | if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { | |
195 | if (boarddata->cd_type == ESDHC_CD_GPIO) | |
196 | /* | |
197 | * These interrupts won't work with a custom | |
198 | * card_detect gpio (only applied to mx25/35) | |
199 | */ | |
200 | val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); | |
201 | ||
202 | if (val & SDHCI_INT_CARD_INT) { | |
203 | /* | |
204 | * Clear and then set D3CD bit to avoid missing the | |
205 | * card interrupt. This is a eSDHC controller problem | |
206 | * so we need to apply the following workaround: clear | |
207 | * and set D3CD bit will make eSDHC re-sample the card | |
208 | * interrupt. In case a card interrupt was lost, | |
209 | * re-sample it by the following steps. | |
210 | */ | |
211 | data = readl(host->ioaddr + SDHCI_HOST_CONTROL); | |
212 | data &= ~SDHCI_CTRL_D3CD; | |
213 | writel(data, host->ioaddr + SDHCI_HOST_CONTROL); | |
214 | data |= SDHCI_CTRL_D3CD; | |
215 | writel(data, host->ioaddr + SDHCI_HOST_CONTROL); | |
216 | } | |
217 | } | |
7e29c306 | 218 | |
58ac8177 RZ |
219 | if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) |
220 | && (reg == SDHCI_INT_STATUS) | |
221 | && (val & SDHCI_INT_DATA_END))) { | |
222 | u32 v; | |
223 | v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); | |
224 | v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK; | |
225 | writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); | |
226 | } | |
227 | ||
97e4ba6a RZ |
228 | if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { |
229 | if (val & SDHCI_INT_ADMA_ERROR) { | |
230 | val &= ~SDHCI_INT_ADMA_ERROR; | |
231 | val |= SDHCI_INT_VENDOR_SPEC_DMA_ERR; | |
232 | } | |
233 | } | |
234 | ||
7e29c306 WS |
235 | writel(val, host->ioaddr + reg); |
236 | } | |
237 | ||
95f25efe WS |
238 | static u16 esdhc_readw_le(struct sdhci_host *host, int reg) |
239 | { | |
95a2482a SG |
240 | if (unlikely(reg == SDHCI_HOST_VERSION)) { |
241 | u16 val = readw(host->ioaddr + (reg ^ 2)); | |
242 | /* | |
243 | * uSDHC supports SDHCI v3.0, but it's encoded as value | |
244 | * 0x3 in host controller version register, which violates | |
245 | * SDHCI_SPEC_300 definition. Work it around here. | |
246 | */ | |
247 | if ((val & SDHCI_SPEC_VER_MASK) == 3) | |
248 | return --val; | |
249 | } | |
95f25efe WS |
250 | |
251 | return readw(host->ioaddr + reg); | |
252 | } | |
253 | ||
254 | static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) | |
255 | { | |
256 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | |
e149860d | 257 | struct pltfm_imx_data *imx_data = pltfm_host->priv; |
95f25efe WS |
258 | |
259 | switch (reg) { | |
260 | case SDHCI_TRANSFER_MODE: | |
261 | /* | |
262 | * Postpone this write, we must do it together with a | |
263 | * command write that is down below. | |
264 | */ | |
58ac8177 RZ |
265 | if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) |
266 | && (host->cmd->opcode == SD_IO_RW_EXTENDED) | |
267 | && (host->cmd->data->blocks > 1) | |
268 | && (host->cmd->data->flags & MMC_DATA_READ)) { | |
269 | u32 v; | |
270 | v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); | |
271 | v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK; | |
272 | writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); | |
273 | } | |
e149860d | 274 | imx_data->scratchpad = val; |
95f25efe WS |
275 | return; |
276 | case SDHCI_COMMAND: | |
5b6b0ad6 SH |
277 | if ((host->cmd->opcode == MMC_STOP_TRANSMISSION || |
278 | host->cmd->opcode == MMC_SET_BLOCK_COUNT) && | |
279 | (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) | |
58ac8177 | 280 | val |= SDHCI_CMD_ABORTCMD; |
95a2482a SG |
281 | |
282 | if (is_imx6q_usdhc(imx_data)) { | |
283 | u32 m = readl(host->ioaddr + SDHCI_MIX_CTRL); | |
284 | m = imx_data->scratchpad | (m & 0xffff0000); | |
285 | writel(m, host->ioaddr + SDHCI_MIX_CTRL); | |
286 | writel(val << 16, | |
287 | host->ioaddr + SDHCI_TRANSFER_MODE); | |
288 | } else { | |
289 | writel(val << 16 | imx_data->scratchpad, | |
290 | host->ioaddr + SDHCI_TRANSFER_MODE); | |
291 | } | |
95f25efe WS |
292 | return; |
293 | case SDHCI_BLOCK_SIZE: | |
294 | val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); | |
295 | break; | |
296 | } | |
297 | esdhc_clrset_le(host, 0xffff, val, reg); | |
298 | } | |
299 | ||
300 | static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) | |
301 | { | |
9a0985b7 WC |
302 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
303 | struct pltfm_imx_data *imx_data = pltfm_host->priv; | |
95f25efe WS |
304 | u32 new_val; |
305 | ||
306 | switch (reg) { | |
307 | case SDHCI_POWER_CONTROL: | |
308 | /* | |
309 | * FSL put some DMA bits here | |
310 | * If your board has a regulator, code should be here | |
311 | */ | |
312 | return; | |
313 | case SDHCI_HOST_CONTROL: | |
0d58864b TL |
314 | /* FSL messed up here, so we can just keep those three */ |
315 | new_val = val & (SDHCI_CTRL_LED | \ | |
316 | SDHCI_CTRL_4BITBUS | \ | |
317 | SDHCI_CTRL_D3CD); | |
7122bbb0 | 318 | /* ensure the endianness */ |
95f25efe | 319 | new_val |= ESDHC_HOST_CONTROL_LE; |
9a0985b7 WC |
320 | /* bits 8&9 are reserved on mx25 */ |
321 | if (!is_imx25_esdhc(imx_data)) { | |
322 | /* DMA mode bits are shifted */ | |
323 | new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; | |
324 | } | |
95f25efe WS |
325 | |
326 | esdhc_clrset_le(host, 0xffff, new_val, reg); | |
327 | return; | |
328 | } | |
329 | esdhc_clrset_le(host, 0xff, val, reg); | |
913413c3 SG |
330 | |
331 | /* | |
332 | * The esdhc has a design violation to SDHC spec which tells | |
333 | * that software reset should not affect card detection circuit. | |
334 | * But esdhc clears its SYSCTL register bits [0..2] during the | |
335 | * software reset. This will stop those clocks that card detection | |
336 | * circuit relies on. To work around it, we turn the clocks on back | |
337 | * to keep card detection circuit functional. | |
338 | */ | |
339 | if ((reg == SDHCI_SOFTWARE_RESET) && (val & 1)) | |
340 | esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL); | |
95f25efe WS |
341 | } |
342 | ||
343 | static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host) | |
344 | { | |
345 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | |
346 | ||
347 | return clk_get_rate(pltfm_host->clk); | |
348 | } | |
349 | ||
350 | static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host) | |
351 | { | |
352 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | |
353 | ||
354 | return clk_get_rate(pltfm_host->clk) / 256 / 16; | |
355 | } | |
356 | ||
913413c3 SG |
357 | static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) |
358 | { | |
842afc02 SG |
359 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
360 | struct pltfm_imx_data *imx_data = pltfm_host->priv; | |
361 | struct esdhc_platform_data *boarddata = &imx_data->boarddata; | |
913413c3 SG |
362 | |
363 | switch (boarddata->wp_type) { | |
364 | case ESDHC_WP_GPIO: | |
365 | if (gpio_is_valid(boarddata->wp_gpio)) | |
366 | return gpio_get_value(boarddata->wp_gpio); | |
367 | case ESDHC_WP_CONTROLLER: | |
368 | return !(readl(host->ioaddr + SDHCI_PRESENT_STATE) & | |
369 | SDHCI_WRITE_PROTECT); | |
370 | case ESDHC_WP_NONE: | |
371 | break; | |
372 | } | |
373 | ||
374 | return -ENOSYS; | |
375 | } | |
376 | ||
0c6d49ce | 377 | static struct sdhci_ops sdhci_esdhc_ops = { |
e149860d | 378 | .read_l = esdhc_readl_le, |
0c6d49ce | 379 | .read_w = esdhc_readw_le, |
e149860d | 380 | .write_l = esdhc_writel_le, |
0c6d49ce WS |
381 | .write_w = esdhc_writew_le, |
382 | .write_b = esdhc_writeb_le, | |
383 | .set_clock = esdhc_set_clock, | |
384 | .get_max_clock = esdhc_pltfm_get_max_clock, | |
385 | .get_min_clock = esdhc_pltfm_get_min_clock, | |
913413c3 | 386 | .get_ro = esdhc_pltfm_get_ro, |
0c6d49ce WS |
387 | }; |
388 | ||
85d6509d | 389 | static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { |
97e4ba6a RZ |
390 | .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT |
391 | | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | |
392 | | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | |
85d6509d | 393 | | SDHCI_QUIRK_BROKEN_CARD_DETECTION, |
85d6509d SG |
394 | .ops = &sdhci_esdhc_ops, |
395 | }; | |
396 | ||
7e29c306 WS |
397 | static irqreturn_t cd_irq(int irq, void *data) |
398 | { | |
399 | struct sdhci_host *sdhost = (struct sdhci_host *)data; | |
400 | ||
401 | tasklet_schedule(&sdhost->card_tasklet); | |
402 | return IRQ_HANDLED; | |
403 | }; | |
404 | ||
abfafc2d | 405 | #ifdef CONFIG_OF |
c3be1efd | 406 | static int |
abfafc2d SG |
407 | sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, |
408 | struct esdhc_platform_data *boarddata) | |
409 | { | |
410 | struct device_node *np = pdev->dev.of_node; | |
411 | ||
412 | if (!np) | |
413 | return -ENODEV; | |
414 | ||
7f217794 | 415 | if (of_get_property(np, "non-removable", NULL)) |
abfafc2d SG |
416 | boarddata->cd_type = ESDHC_CD_PERMANENT; |
417 | ||
418 | if (of_get_property(np, "fsl,cd-controller", NULL)) | |
419 | boarddata->cd_type = ESDHC_CD_CONTROLLER; | |
420 | ||
421 | if (of_get_property(np, "fsl,wp-controller", NULL)) | |
422 | boarddata->wp_type = ESDHC_WP_CONTROLLER; | |
423 | ||
424 | boarddata->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); | |
425 | if (gpio_is_valid(boarddata->cd_gpio)) | |
426 | boarddata->cd_type = ESDHC_CD_GPIO; | |
427 | ||
428 | boarddata->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); | |
429 | if (gpio_is_valid(boarddata->wp_gpio)) | |
430 | boarddata->wp_type = ESDHC_WP_GPIO; | |
431 | ||
432 | return 0; | |
433 | } | |
434 | #else | |
435 | static inline int | |
436 | sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, | |
437 | struct esdhc_platform_data *boarddata) | |
438 | { | |
439 | return -ENODEV; | |
440 | } | |
441 | #endif | |
442 | ||
c3be1efd | 443 | static int sdhci_esdhc_imx_probe(struct platform_device *pdev) |
95f25efe | 444 | { |
abfafc2d SG |
445 | const struct of_device_id *of_id = |
446 | of_match_device(imx_esdhc_dt_ids, &pdev->dev); | |
85d6509d SG |
447 | struct sdhci_pltfm_host *pltfm_host; |
448 | struct sdhci_host *host; | |
449 | struct esdhc_platform_data *boarddata; | |
0c6d49ce | 450 | int err; |
e149860d | 451 | struct pltfm_imx_data *imx_data; |
95f25efe | 452 | |
85d6509d SG |
453 | host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata); |
454 | if (IS_ERR(host)) | |
455 | return PTR_ERR(host); | |
456 | ||
457 | pltfm_host = sdhci_priv(host); | |
458 | ||
e3af31c6 | 459 | imx_data = devm_kzalloc(&pdev->dev, sizeof(*imx_data), GFP_KERNEL); |
abfafc2d SG |
460 | if (!imx_data) { |
461 | err = -ENOMEM; | |
e3af31c6 | 462 | goto free_sdhci; |
abfafc2d | 463 | } |
57ed3314 | 464 | |
abfafc2d SG |
465 | if (of_id) |
466 | pdev->id_entry = of_id->data; | |
57ed3314 | 467 | imx_data->devtype = pdev->id_entry->driver_data; |
85d6509d SG |
468 | pltfm_host->priv = imx_data; |
469 | ||
52dac615 SH |
470 | imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); |
471 | if (IS_ERR(imx_data->clk_ipg)) { | |
472 | err = PTR_ERR(imx_data->clk_ipg); | |
e3af31c6 | 473 | goto free_sdhci; |
95f25efe | 474 | } |
52dac615 SH |
475 | |
476 | imx_data->clk_ahb = devm_clk_get(&pdev->dev, "ahb"); | |
477 | if (IS_ERR(imx_data->clk_ahb)) { | |
478 | err = PTR_ERR(imx_data->clk_ahb); | |
e3af31c6 | 479 | goto free_sdhci; |
52dac615 SH |
480 | } |
481 | ||
482 | imx_data->clk_per = devm_clk_get(&pdev->dev, "per"); | |
483 | if (IS_ERR(imx_data->clk_per)) { | |
484 | err = PTR_ERR(imx_data->clk_per); | |
e3af31c6 | 485 | goto free_sdhci; |
52dac615 SH |
486 | } |
487 | ||
488 | pltfm_host->clk = imx_data->clk_per; | |
489 | ||
490 | clk_prepare_enable(imx_data->clk_per); | |
491 | clk_prepare_enable(imx_data->clk_ipg); | |
492 | clk_prepare_enable(imx_data->clk_ahb); | |
95f25efe | 493 | |
e62d8b8f DA |
494 | imx_data->pinctrl = devm_pinctrl_get_select_default(&pdev->dev); |
495 | if (IS_ERR(imx_data->pinctrl)) { | |
496 | err = PTR_ERR(imx_data->pinctrl); | |
e3af31c6 | 497 | goto disable_clk; |
e62d8b8f DA |
498 | } |
499 | ||
b8915282 | 500 | host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; |
37865fe9 | 501 | |
57ed3314 | 502 | if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data)) |
0c6d49ce | 503 | /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ |
97e4ba6a RZ |
504 | host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK |
505 | | SDHCI_QUIRK_BROKEN_ADMA; | |
0c6d49ce | 506 | |
57ed3314 | 507 | if (is_imx53_esdhc(imx_data)) |
58ac8177 RZ |
508 | imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; |
509 | ||
f750ba9b SG |
510 | /* |
511 | * The imx6q ROM code will change the default watermark level setting | |
512 | * to something insane. Change it back here. | |
513 | */ | |
514 | if (is_imx6q_usdhc(imx_data)) | |
515 | writel(0x08100810, host->ioaddr + SDHCI_WTMK_LVL); | |
516 | ||
842afc02 | 517 | boarddata = &imx_data->boarddata; |
abfafc2d SG |
518 | if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { |
519 | if (!host->mmc->parent->platform_data) { | |
520 | dev_err(mmc_dev(host->mmc), "no board data!\n"); | |
521 | err = -EINVAL; | |
e3af31c6 | 522 | goto disable_clk; |
abfafc2d SG |
523 | } |
524 | imx_data->boarddata = *((struct esdhc_platform_data *) | |
525 | host->mmc->parent->platform_data); | |
526 | } | |
913413c3 SG |
527 | |
528 | /* write_protect */ | |
529 | if (boarddata->wp_type == ESDHC_WP_GPIO) { | |
e3af31c6 SG |
530 | err = devm_gpio_request_one(&pdev->dev, boarddata->wp_gpio, |
531 | GPIOF_IN, "ESDHC_WP"); | |
0c6d49ce WS |
532 | if (err) { |
533 | dev_warn(mmc_dev(host->mmc), | |
913413c3 SG |
534 | "no write-protect pin available!\n"); |
535 | boarddata->wp_gpio = -EINVAL; | |
0c6d49ce | 536 | } |
913413c3 SG |
537 | } else { |
538 | boarddata->wp_gpio = -EINVAL; | |
539 | } | |
540 | ||
541 | /* card_detect */ | |
542 | if (boarddata->cd_type != ESDHC_CD_GPIO) | |
543 | boarddata->cd_gpio = -EINVAL; | |
7e29c306 | 544 | |
913413c3 SG |
545 | switch (boarddata->cd_type) { |
546 | case ESDHC_CD_GPIO: | |
e3af31c6 SG |
547 | err = devm_gpio_request_one(&pdev->dev, boarddata->cd_gpio, |
548 | GPIOF_IN, "ESDHC_CD"); | |
7e29c306 | 549 | if (err) { |
913413c3 | 550 | dev_err(mmc_dev(host->mmc), |
7e29c306 | 551 | "no card-detect pin available!\n"); |
e3af31c6 | 552 | goto disable_clk; |
7e29c306 WS |
553 | } |
554 | ||
e3af31c6 SG |
555 | err = devm_request_irq(&pdev->dev, |
556 | gpio_to_irq(boarddata->cd_gpio), cd_irq, | |
7e29c306 WS |
557 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, |
558 | mmc_hostname(host->mmc), host); | |
559 | if (err) { | |
913413c3 | 560 | dev_err(mmc_dev(host->mmc), "request irq error\n"); |
e3af31c6 | 561 | goto disable_clk; |
7e29c306 | 562 | } |
913413c3 | 563 | /* fall through */ |
7e29c306 | 564 | |
913413c3 SG |
565 | case ESDHC_CD_CONTROLLER: |
566 | /* we have a working card_detect back */ | |
7e29c306 | 567 | host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; |
913413c3 SG |
568 | break; |
569 | ||
570 | case ESDHC_CD_PERMANENT: | |
571 | host->mmc->caps = MMC_CAP_NONREMOVABLE; | |
572 | break; | |
573 | ||
574 | case ESDHC_CD_NONE: | |
575 | break; | |
0c6d49ce | 576 | } |
16a790bc | 577 | |
85d6509d SG |
578 | err = sdhci_add_host(host); |
579 | if (err) | |
e3af31c6 | 580 | goto disable_clk; |
85d6509d | 581 | |
95f25efe | 582 | return 0; |
7e29c306 | 583 | |
e3af31c6 | 584 | disable_clk: |
52dac615 SH |
585 | clk_disable_unprepare(imx_data->clk_per); |
586 | clk_disable_unprepare(imx_data->clk_ipg); | |
587 | clk_disable_unprepare(imx_data->clk_ahb); | |
e3af31c6 | 588 | free_sdhci: |
85d6509d SG |
589 | sdhci_pltfm_free(pdev); |
590 | return err; | |
95f25efe WS |
591 | } |
592 | ||
6e0ee714 | 593 | static int sdhci_esdhc_imx_remove(struct platform_device *pdev) |
95f25efe | 594 | { |
85d6509d | 595 | struct sdhci_host *host = platform_get_drvdata(pdev); |
95f25efe | 596 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
e149860d | 597 | struct pltfm_imx_data *imx_data = pltfm_host->priv; |
85d6509d SG |
598 | int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); |
599 | ||
600 | sdhci_remove_host(host, dead); | |
0c6d49ce | 601 | |
52dac615 SH |
602 | clk_disable_unprepare(imx_data->clk_per); |
603 | clk_disable_unprepare(imx_data->clk_ipg); | |
604 | clk_disable_unprepare(imx_data->clk_ahb); | |
605 | ||
85d6509d SG |
606 | sdhci_pltfm_free(pdev); |
607 | ||
608 | return 0; | |
95f25efe WS |
609 | } |
610 | ||
85d6509d SG |
611 | static struct platform_driver sdhci_esdhc_imx_driver = { |
612 | .driver = { | |
613 | .name = "sdhci-esdhc-imx", | |
614 | .owner = THIS_MODULE, | |
abfafc2d | 615 | .of_match_table = imx_esdhc_dt_ids, |
29495aa0 | 616 | .pm = SDHCI_PLTFM_PMOPS, |
85d6509d | 617 | }, |
57ed3314 | 618 | .id_table = imx_esdhc_devtype, |
85d6509d | 619 | .probe = sdhci_esdhc_imx_probe, |
0433c143 | 620 | .remove = sdhci_esdhc_imx_remove, |
95f25efe | 621 | }; |
85d6509d | 622 | |
d1f81a64 | 623 | module_platform_driver(sdhci_esdhc_imx_driver); |
85d6509d SG |
624 | |
625 | MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC"); | |
626 | MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); | |
627 | MODULE_LICENSE("GPL v2"); |