diff options
Diffstat (limited to 'drivers/mmc/host/sdhci-esdhc-imx.c')
-rw-r--r-- | drivers/mmc/host/sdhci-esdhc-imx.c | 233 |
1 files changed, 79 insertions, 154 deletions
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index e07df812ff1..4dc0028086a 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c | |||
@@ -24,8 +24,7 @@ | |||
24 | #include <linux/of.h> | 24 | #include <linux/of.h> |
25 | #include <linux/of_device.h> | 25 | #include <linux/of_device.h> |
26 | #include <linux/of_gpio.h> | 26 | #include <linux/of_gpio.h> |
27 | #include <linux/pinctrl/consumer.h> | 27 | #include <mach/esdhc.h> |
28 | #include <linux/platform_data/mmc-esdhc-imx.h> | ||
29 | #include "sdhci-pltfm.h" | 28 | #include "sdhci-pltfm.h" |
30 | #include "sdhci-esdhc.h" | 29 | #include "sdhci-esdhc.h" |
31 | 30 | ||
@@ -33,16 +32,6 @@ | |||
33 | /* VENDOR SPEC register */ | 32 | /* VENDOR SPEC register */ |
34 | #define SDHCI_VENDOR_SPEC 0xC0 | 33 | #define SDHCI_VENDOR_SPEC 0xC0 |
35 | #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 | 34 | #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 |
36 | #define SDHCI_WTMK_LVL 0x44 | ||
37 | #define SDHCI_MIX_CTRL 0x48 | ||
38 | |||
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 | 35 | ||
47 | /* | 36 | /* |
48 | * The CMDTYPE of the CMD register (offset 0xE) should be set to | 37 | * The CMDTYPE of the CMD register (offset 0xE) should be set to |
@@ -62,18 +51,13 @@ enum imx_esdhc_type { | |||
62 | IMX35_ESDHC, | 51 | IMX35_ESDHC, |
63 | IMX51_ESDHC, | 52 | IMX51_ESDHC, |
64 | IMX53_ESDHC, | 53 | IMX53_ESDHC, |
65 | IMX6Q_USDHC, | ||
66 | }; | 54 | }; |
67 | 55 | ||
68 | struct pltfm_imx_data { | 56 | struct pltfm_imx_data { |
69 | int flags; | 57 | int flags; |
70 | u32 scratchpad; | 58 | u32 scratchpad; |
71 | enum imx_esdhc_type devtype; | 59 | enum imx_esdhc_type devtype; |
72 | struct pinctrl *pinctrl; | ||
73 | struct esdhc_platform_data boarddata; | 60 | struct esdhc_platform_data boarddata; |
74 | struct clk *clk_ipg; | ||
75 | struct clk *clk_ahb; | ||
76 | struct clk *clk_per; | ||
77 | }; | 61 | }; |
78 | 62 | ||
79 | static struct platform_device_id imx_esdhc_devtype[] = { | 63 | static struct platform_device_id imx_esdhc_devtype[] = { |
@@ -90,9 +74,6 @@ static struct platform_device_id imx_esdhc_devtype[] = { | |||
90 | .name = "sdhci-esdhc-imx53", | 74 | .name = "sdhci-esdhc-imx53", |
91 | .driver_data = IMX53_ESDHC, | 75 | .driver_data = IMX53_ESDHC, |
92 | }, { | 76 | }, { |
93 | .name = "sdhci-usdhc-imx6q", | ||
94 | .driver_data = IMX6Q_USDHC, | ||
95 | }, { | ||
96 | /* sentinel */ | 77 | /* sentinel */ |
97 | } | 78 | } |
98 | }; | 79 | }; |
@@ -103,7 +84,6 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { | |||
103 | { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], }, | 84 | { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], }, |
104 | { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], }, | 85 | { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], }, |
105 | { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], }, | 86 | { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], }, |
106 | { .compatible = "fsl,imx6q-usdhc", .data = &imx_esdhc_devtype[IMX6Q_USDHC], }, | ||
107 | { /* sentinel */ } | 87 | { /* sentinel */ } |
108 | }; | 88 | }; |
109 | MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); | 89 | MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); |
@@ -128,11 +108,6 @@ static inline int is_imx53_esdhc(struct pltfm_imx_data *data) | |||
128 | return data->devtype == IMX53_ESDHC; | 108 | return data->devtype == IMX53_ESDHC; |
129 | } | 109 | } |
130 | 110 | ||
131 | static inline int is_imx6q_usdhc(struct pltfm_imx_data *data) | ||
132 | { | ||
133 | return data->devtype == IMX6Q_USDHC; | ||
134 | } | ||
135 | |||
136 | static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) | 111 | static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) |
137 | { | 112 | { |
138 | void __iomem *base = host->ioaddr + (reg & ~0x3); | 113 | void __iomem *base = host->ioaddr + (reg & ~0x3); |
@@ -160,27 +135,6 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) | |||
160 | val |= SDHCI_CARD_PRESENT; | 135 | val |= SDHCI_CARD_PRESENT; |
161 | } | 136 | } |
162 | 137 | ||
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 | |||
184 | return val; | 138 | return val; |
185 | } | 139 | } |
186 | 140 | ||
@@ -225,28 +179,13 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) | |||
225 | writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); | 179 | writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); |
226 | } | 180 | } |
227 | 181 | ||
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 | |||
235 | writel(val, host->ioaddr + reg); | 182 | writel(val, host->ioaddr + reg); |
236 | } | 183 | } |
237 | 184 | ||
238 | static u16 esdhc_readw_le(struct sdhci_host *host, int reg) | 185 | static u16 esdhc_readw_le(struct sdhci_host *host, int reg) |
239 | { | 186 | { |
240 | if (unlikely(reg == SDHCI_HOST_VERSION)) { | 187 | if (unlikely(reg == SDHCI_HOST_VERSION)) |
241 | u16 val = readw(host->ioaddr + (reg ^ 2)); | 188 | 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 | } | ||
250 | 189 | ||
251 | return readw(host->ioaddr + reg); | 190 | return readw(host->ioaddr + reg); |
252 | } | 191 | } |
@@ -274,21 +213,11 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) | |||
274 | imx_data->scratchpad = val; | 213 | imx_data->scratchpad = val; |
275 | return; | 214 | return; |
276 | case SDHCI_COMMAND: | 215 | case SDHCI_COMMAND: |
277 | if ((host->cmd->opcode == MMC_STOP_TRANSMISSION || | 216 | if ((host->cmd->opcode == MMC_STOP_TRANSMISSION) |
278 | host->cmd->opcode == MMC_SET_BLOCK_COUNT) && | 217 | && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) |
279 | (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) | ||
280 | val |= SDHCI_CMD_ABORTCMD; | 218 | val |= SDHCI_CMD_ABORTCMD; |
281 | 219 | writel(val << 16 | imx_data->scratchpad, | |
282 | if (is_imx6q_usdhc(imx_data)) { | 220 | host->ioaddr + SDHCI_TRANSFER_MODE); |
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 | } | ||
292 | return; | 221 | return; |
293 | case SDHCI_BLOCK_SIZE: | 222 | case SDHCI_BLOCK_SIZE: |
294 | val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); | 223 | val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); |
@@ -299,8 +228,6 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) | |||
299 | 228 | ||
300 | static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) | 229 | static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) |
301 | { | 230 | { |
302 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | ||
303 | struct pltfm_imx_data *imx_data = pltfm_host->priv; | ||
304 | u32 new_val; | 231 | u32 new_val; |
305 | 232 | ||
306 | switch (reg) { | 233 | switch (reg) { |
@@ -315,13 +242,10 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) | |||
315 | new_val = val & (SDHCI_CTRL_LED | \ | 242 | new_val = val & (SDHCI_CTRL_LED | \ |
316 | SDHCI_CTRL_4BITBUS | \ | 243 | SDHCI_CTRL_4BITBUS | \ |
317 | SDHCI_CTRL_D3CD); | 244 | SDHCI_CTRL_D3CD); |
318 | /* ensure the endianness */ | 245 | /* ensure the endianess */ |
319 | new_val |= ESDHC_HOST_CONTROL_LE; | 246 | new_val |= ESDHC_HOST_CONTROL_LE; |
320 | /* bits 8&9 are reserved on mx25 */ | 247 | /* DMA mode bits are shifted */ |
321 | if (!is_imx25_esdhc(imx_data)) { | 248 | new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; |
322 | /* DMA mode bits are shifted */ | ||
323 | new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; | ||
324 | } | ||
325 | 249 | ||
326 | esdhc_clrset_le(host, 0xffff, new_val, reg); | 250 | esdhc_clrset_le(host, 0xffff, new_val, reg); |
327 | return; | 251 | return; |
@@ -387,10 +311,9 @@ static struct sdhci_ops sdhci_esdhc_ops = { | |||
387 | }; | 311 | }; |
388 | 312 | ||
389 | static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { | 313 | static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { |
390 | .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_NO_HISPD_BIT | 314 | .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA |
391 | | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC | ||
392 | | SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC | ||
393 | | SDHCI_QUIRK_BROKEN_CARD_DETECTION, | 315 | | SDHCI_QUIRK_BROKEN_CARD_DETECTION, |
316 | /* ADMA has issues. Might be fixable */ | ||
394 | .ops = &sdhci_esdhc_ops, | 317 | .ops = &sdhci_esdhc_ops, |
395 | }; | 318 | }; |
396 | 319 | ||
@@ -403,7 +326,7 @@ static irqreturn_t cd_irq(int irq, void *data) | |||
403 | }; | 326 | }; |
404 | 327 | ||
405 | #ifdef CONFIG_OF | 328 | #ifdef CONFIG_OF |
406 | static int | 329 | static int __devinit |
407 | sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, | 330 | sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, |
408 | struct esdhc_platform_data *boarddata) | 331 | struct esdhc_platform_data *boarddata) |
409 | { | 332 | { |
@@ -412,7 +335,7 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, | |||
412 | if (!np) | 335 | if (!np) |
413 | return -ENODEV; | 336 | return -ENODEV; |
414 | 337 | ||
415 | if (of_get_property(np, "non-removable", NULL)) | 338 | if (of_get_property(np, "fsl,card-wired", NULL)) |
416 | boarddata->cd_type = ESDHC_CD_PERMANENT; | 339 | boarddata->cd_type = ESDHC_CD_PERMANENT; |
417 | 340 | ||
418 | if (of_get_property(np, "fsl,cd-controller", NULL)) | 341 | if (of_get_property(np, "fsl,cd-controller", NULL)) |
@@ -440,13 +363,14 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, | |||
440 | } | 363 | } |
441 | #endif | 364 | #endif |
442 | 365 | ||
443 | static int sdhci_esdhc_imx_probe(struct platform_device *pdev) | 366 | static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) |
444 | { | 367 | { |
445 | const struct of_device_id *of_id = | 368 | const struct of_device_id *of_id = |
446 | of_match_device(imx_esdhc_dt_ids, &pdev->dev); | 369 | of_match_device(imx_esdhc_dt_ids, &pdev->dev); |
447 | struct sdhci_pltfm_host *pltfm_host; | 370 | struct sdhci_pltfm_host *pltfm_host; |
448 | struct sdhci_host *host; | 371 | struct sdhci_host *host; |
449 | struct esdhc_platform_data *boarddata; | 372 | struct esdhc_platform_data *boarddata; |
373 | struct clk *clk; | ||
450 | int err; | 374 | int err; |
451 | struct pltfm_imx_data *imx_data; | 375 | struct pltfm_imx_data *imx_data; |
452 | 376 | ||
@@ -456,10 +380,10 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) | |||
456 | 380 | ||
457 | pltfm_host = sdhci_priv(host); | 381 | pltfm_host = sdhci_priv(host); |
458 | 382 | ||
459 | imx_data = devm_kzalloc(&pdev->dev, sizeof(*imx_data), GFP_KERNEL); | 383 | imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL); |
460 | if (!imx_data) { | 384 | if (!imx_data) { |
461 | err = -ENOMEM; | 385 | err = -ENOMEM; |
462 | goto free_sdhci; | 386 | goto err_imx_data; |
463 | } | 387 | } |
464 | 388 | ||
465 | if (of_id) | 389 | if (of_id) |
@@ -467,59 +391,31 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) | |||
467 | imx_data->devtype = pdev->id_entry->driver_data; | 391 | imx_data->devtype = pdev->id_entry->driver_data; |
468 | pltfm_host->priv = imx_data; | 392 | pltfm_host->priv = imx_data; |
469 | 393 | ||
470 | imx_data->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); | 394 | clk = clk_get(mmc_dev(host->mmc), NULL); |
471 | if (IS_ERR(imx_data->clk_ipg)) { | 395 | if (IS_ERR(clk)) { |
472 | err = PTR_ERR(imx_data->clk_ipg); | 396 | dev_err(mmc_dev(host->mmc), "clk err\n"); |
473 | goto free_sdhci; | 397 | err = PTR_ERR(clk); |
474 | } | 398 | goto err_clk_get; |
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); | ||
479 | goto free_sdhci; | ||
480 | } | 399 | } |
400 | clk_enable(clk); | ||
401 | pltfm_host->clk = clk; | ||
481 | 402 | ||
482 | imx_data->clk_per = devm_clk_get(&pdev->dev, "per"); | 403 | if (!is_imx25_esdhc(imx_data)) |
483 | if (IS_ERR(imx_data->clk_per)) { | 404 | host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; |
484 | err = PTR_ERR(imx_data->clk_per); | ||
485 | goto free_sdhci; | ||
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); | ||
493 | |||
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); | ||
497 | goto disable_clk; | ||
498 | } | ||
499 | |||
500 | host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; | ||
501 | 405 | ||
502 | if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data)) | 406 | if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data)) |
503 | /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ | 407 | /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ |
504 | host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK | 408 | host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; |
505 | | SDHCI_QUIRK_BROKEN_ADMA; | ||
506 | 409 | ||
507 | if (is_imx53_esdhc(imx_data)) | 410 | if (is_imx53_esdhc(imx_data)) |
508 | imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; | 411 | imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; |
509 | 412 | ||
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 | |||
517 | boarddata = &imx_data->boarddata; | 413 | boarddata = &imx_data->boarddata; |
518 | if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { | 414 | if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { |
519 | if (!host->mmc->parent->platform_data) { | 415 | if (!host->mmc->parent->platform_data) { |
520 | dev_err(mmc_dev(host->mmc), "no board data!\n"); | 416 | dev_err(mmc_dev(host->mmc), "no board data!\n"); |
521 | err = -EINVAL; | 417 | err = -EINVAL; |
522 | goto disable_clk; | 418 | goto no_board_data; |
523 | } | 419 | } |
524 | imx_data->boarddata = *((struct esdhc_platform_data *) | 420 | imx_data->boarddata = *((struct esdhc_platform_data *) |
525 | host->mmc->parent->platform_data); | 421 | host->mmc->parent->platform_data); |
@@ -527,8 +423,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) | |||
527 | 423 | ||
528 | /* write_protect */ | 424 | /* write_protect */ |
529 | if (boarddata->wp_type == ESDHC_WP_GPIO) { | 425 | if (boarddata->wp_type == ESDHC_WP_GPIO) { |
530 | err = devm_gpio_request_one(&pdev->dev, boarddata->wp_gpio, | 426 | err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); |
531 | GPIOF_IN, "ESDHC_WP"); | ||
532 | if (err) { | 427 | if (err) { |
533 | dev_warn(mmc_dev(host->mmc), | 428 | dev_warn(mmc_dev(host->mmc), |
534 | "no write-protect pin available!\n"); | 429 | "no write-protect pin available!\n"); |
@@ -544,21 +439,19 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) | |||
544 | 439 | ||
545 | switch (boarddata->cd_type) { | 440 | switch (boarddata->cd_type) { |
546 | case ESDHC_CD_GPIO: | 441 | case ESDHC_CD_GPIO: |
547 | err = devm_gpio_request_one(&pdev->dev, boarddata->cd_gpio, | 442 | err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD"); |
548 | GPIOF_IN, "ESDHC_CD"); | ||
549 | if (err) { | 443 | if (err) { |
550 | dev_err(mmc_dev(host->mmc), | 444 | dev_err(mmc_dev(host->mmc), |
551 | "no card-detect pin available!\n"); | 445 | "no card-detect pin available!\n"); |
552 | goto disable_clk; | 446 | goto no_card_detect_pin; |
553 | } | 447 | } |
554 | 448 | ||
555 | err = devm_request_irq(&pdev->dev, | 449 | err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq, |
556 | gpio_to_irq(boarddata->cd_gpio), cd_irq, | ||
557 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, | 450 | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, |
558 | mmc_hostname(host->mmc), host); | 451 | mmc_hostname(host->mmc), host); |
559 | if (err) { | 452 | if (err) { |
560 | dev_err(mmc_dev(host->mmc), "request irq error\n"); | 453 | dev_err(mmc_dev(host->mmc), "request irq error\n"); |
561 | goto disable_clk; | 454 | goto no_card_detect_irq; |
562 | } | 455 | } |
563 | /* fall through */ | 456 | /* fall through */ |
564 | 457 | ||
@@ -577,31 +470,50 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) | |||
577 | 470 | ||
578 | err = sdhci_add_host(host); | 471 | err = sdhci_add_host(host); |
579 | if (err) | 472 | if (err) |
580 | goto disable_clk; | 473 | goto err_add_host; |
581 | 474 | ||
582 | return 0; | 475 | return 0; |
583 | 476 | ||
584 | disable_clk: | 477 | err_add_host: |
585 | clk_disable_unprepare(imx_data->clk_per); | 478 | if (gpio_is_valid(boarddata->cd_gpio)) |
586 | clk_disable_unprepare(imx_data->clk_ipg); | 479 | free_irq(gpio_to_irq(boarddata->cd_gpio), host); |
587 | clk_disable_unprepare(imx_data->clk_ahb); | 480 | no_card_detect_irq: |
588 | free_sdhci: | 481 | if (gpio_is_valid(boarddata->cd_gpio)) |
482 | gpio_free(boarddata->cd_gpio); | ||
483 | if (gpio_is_valid(boarddata->wp_gpio)) | ||
484 | gpio_free(boarddata->wp_gpio); | ||
485 | no_card_detect_pin: | ||
486 | no_board_data: | ||
487 | clk_disable(pltfm_host->clk); | ||
488 | clk_put(pltfm_host->clk); | ||
489 | err_clk_get: | ||
490 | kfree(imx_data); | ||
491 | err_imx_data: | ||
589 | sdhci_pltfm_free(pdev); | 492 | sdhci_pltfm_free(pdev); |
590 | return err; | 493 | return err; |
591 | } | 494 | } |
592 | 495 | ||
593 | static int sdhci_esdhc_imx_remove(struct platform_device *pdev) | 496 | static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev) |
594 | { | 497 | { |
595 | struct sdhci_host *host = platform_get_drvdata(pdev); | 498 | struct sdhci_host *host = platform_get_drvdata(pdev); |
596 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | 499 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
597 | struct pltfm_imx_data *imx_data = pltfm_host->priv; | 500 | struct pltfm_imx_data *imx_data = pltfm_host->priv; |
501 | struct esdhc_platform_data *boarddata = &imx_data->boarddata; | ||
598 | int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); | 502 | int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); |
599 | 503 | ||
600 | sdhci_remove_host(host, dead); | 504 | sdhci_remove_host(host, dead); |
601 | 505 | ||
602 | clk_disable_unprepare(imx_data->clk_per); | 506 | if (gpio_is_valid(boarddata->wp_gpio)) |
603 | clk_disable_unprepare(imx_data->clk_ipg); | 507 | gpio_free(boarddata->wp_gpio); |
604 | clk_disable_unprepare(imx_data->clk_ahb); | 508 | |
509 | if (gpio_is_valid(boarddata->cd_gpio)) { | ||
510 | free_irq(gpio_to_irq(boarddata->cd_gpio), host); | ||
511 | gpio_free(boarddata->cd_gpio); | ||
512 | } | ||
513 | |||
514 | clk_disable(pltfm_host->clk); | ||
515 | clk_put(pltfm_host->clk); | ||
516 | kfree(imx_data); | ||
605 | 517 | ||
606 | sdhci_pltfm_free(pdev); | 518 | sdhci_pltfm_free(pdev); |
607 | 519 | ||
@@ -613,14 +525,27 @@ static struct platform_driver sdhci_esdhc_imx_driver = { | |||
613 | .name = "sdhci-esdhc-imx", | 525 | .name = "sdhci-esdhc-imx", |
614 | .owner = THIS_MODULE, | 526 | .owner = THIS_MODULE, |
615 | .of_match_table = imx_esdhc_dt_ids, | 527 | .of_match_table = imx_esdhc_dt_ids, |
616 | .pm = SDHCI_PLTFM_PMOPS, | ||
617 | }, | 528 | }, |
618 | .id_table = imx_esdhc_devtype, | 529 | .id_table = imx_esdhc_devtype, |
619 | .probe = sdhci_esdhc_imx_probe, | 530 | .probe = sdhci_esdhc_imx_probe, |
620 | .remove = sdhci_esdhc_imx_remove, | 531 | .remove = __devexit_p(sdhci_esdhc_imx_remove), |
532 | #ifdef CONFIG_PM | ||
533 | .suspend = sdhci_pltfm_suspend, | ||
534 | .resume = sdhci_pltfm_resume, | ||
535 | #endif | ||
621 | }; | 536 | }; |
622 | 537 | ||
623 | module_platform_driver(sdhci_esdhc_imx_driver); | 538 | static int __init sdhci_esdhc_imx_init(void) |
539 | { | ||
540 | return platform_driver_register(&sdhci_esdhc_imx_driver); | ||
541 | } | ||
542 | module_init(sdhci_esdhc_imx_init); | ||
543 | |||
544 | static void __exit sdhci_esdhc_imx_exit(void) | ||
545 | { | ||
546 | platform_driver_unregister(&sdhci_esdhc_imx_driver); | ||
547 | } | ||
548 | module_exit(sdhci_esdhc_imx_exit); | ||
624 | 549 | ||
625 | MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC"); | 550 | MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC"); |
626 | MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); | 551 | MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); |