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> 18 #include <linux/gpio.h> 19 #include <linux/module.h> 20 #include <linux/slab.h> 21 #include <linux/mmc/host.h> 22 #include <linux/mmc/mmc.h> 23 #include <linux/mmc/sdio.h> 24 #include <linux/of.h> 25 #include <linux/of_device.h> 26 #include <linux/of_gpio.h> 27 #include <mach/esdhc.h> 28 #include "sdhci-pltfm.h" 29 #include "sdhci-esdhc.h" 30 31 #define SDHCI_CTRL_D3CD 0x08 32 /* VENDOR SPEC register */ 33 #define SDHCI_VENDOR_SPEC 0xC0 34 #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 35 36 /* 37 * The CMDTYPE of the CMD register (offset 0xE) should be set to 38 * "11" when the STOP CMD12 is issued on imx53 to abort one 39 * open ended multi-blk IO. Otherwise the TC INT wouldn't 40 * be generated. 41 * In exact block transfer, the controller doesn't complete the 42 * operations automatically as required at the end of the 43 * transfer and remains on hold if the abort command is not sent. 44 * As a result, the TC flag is not asserted and SW received timeout 45 * exeception. Bit1 of Vendor Spec registor is used to fix it. 46 */ 47 #define ESDHC_FLAG_MULTIBLK_NO_INT (1 << 1) 48 49 enum imx_esdhc_type { 50 IMX25_ESDHC, 51 IMX35_ESDHC, 52 IMX51_ESDHC, 53 IMX53_ESDHC, 54 }; 55 56 struct pltfm_imx_data { 57 int flags; 58 u32 scratchpad; 59 enum imx_esdhc_type devtype; 60 struct esdhc_platform_data boarddata; 61 }; 62 63 static struct platform_device_id imx_esdhc_devtype[] = { 64 { 65 .name = "sdhci-esdhc-imx25", 66 .driver_data = IMX25_ESDHC, 67 }, { 68 .name = "sdhci-esdhc-imx35", 69 .driver_data = IMX35_ESDHC, 70 }, { 71 .name = "sdhci-esdhc-imx51", 72 .driver_data = IMX51_ESDHC, 73 }, { 74 .name = "sdhci-esdhc-imx53", 75 .driver_data = IMX53_ESDHC, 76 }, { 77 /* sentinel */ 78 } 79 }; 80 MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype); 81 82 static const struct of_device_id imx_esdhc_dt_ids[] = { 83 { .compatible = "fsl,imx25-esdhc", .data = &imx_esdhc_devtype[IMX25_ESDHC], }, 84 { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], }, 85 { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], }, 86 { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], }, 87 { /* sentinel */ } 88 }; 89 MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); 90 91 static inline int is_imx25_esdhc(struct pltfm_imx_data *data) 92 { 93 return data->devtype == IMX25_ESDHC; 94 } 95 96 static inline int is_imx35_esdhc(struct pltfm_imx_data *data) 97 { 98 return data->devtype == IMX35_ESDHC; 99 } 100 101 static inline int is_imx51_esdhc(struct pltfm_imx_data *data) 102 { 103 return data->devtype == IMX51_ESDHC; 104 } 105 106 static inline int is_imx53_esdhc(struct pltfm_imx_data *data) 107 { 108 return data->devtype == IMX53_ESDHC; 109 } 110 111 static inline void esdhc_clrset_le(struct sdhci_host *host, u32 mask, u32 val, int reg) 112 { 113 void __iomem *base = host->ioaddr + (reg & ~0x3); 114 u32 shift = (reg & 0x3) * 8; 115 116 writel(((readl(base) & ~(mask << shift)) | (val << shift)), base); 117 } 118 119 static u32 esdhc_readl_le(struct sdhci_host *host, int reg) 120 { 121 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 122 struct pltfm_imx_data *imx_data = pltfm_host->priv; 123 struct esdhc_platform_data *boarddata = &imx_data->boarddata; 124 125 /* fake CARD_PRESENT flag */ 126 u32 val = readl(host->ioaddr + reg); 127 128 if (unlikely((reg == SDHCI_PRESENT_STATE) 129 && gpio_is_valid(boarddata->cd_gpio))) { 130 if (gpio_get_value(boarddata->cd_gpio)) 131 /* no card, if a valid gpio says so... */ 132 val &= ~SDHCI_CARD_PRESENT; 133 else 134 /* ... in all other cases assume card is present */ 135 val |= SDHCI_CARD_PRESENT; 136 } 137 138 return val; 139 } 140 141 static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg) 142 { 143 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 144 struct pltfm_imx_data *imx_data = pltfm_host->priv; 145 struct esdhc_platform_data *boarddata = &imx_data->boarddata; 146 u32 data; 147 148 if (unlikely(reg == SDHCI_INT_ENABLE || reg == SDHCI_SIGNAL_ENABLE)) { 149 if (boarddata->cd_type == ESDHC_CD_GPIO) 150 /* 151 * These interrupts won't work with a custom 152 * card_detect gpio (only applied to mx25/35) 153 */ 154 val &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT); 155 156 if (val & SDHCI_INT_CARD_INT) { 157 /* 158 * Clear and then set D3CD bit to avoid missing the 159 * card interrupt. This is a eSDHC controller problem 160 * so we need to apply the following workaround: clear 161 * and set D3CD bit will make eSDHC re-sample the card 162 * interrupt. In case a card interrupt was lost, 163 * re-sample it by the following steps. 164 */ 165 data = readl(host->ioaddr + SDHCI_HOST_CONTROL); 166 data &= ~SDHCI_CTRL_D3CD; 167 writel(data, host->ioaddr + SDHCI_HOST_CONTROL); 168 data |= SDHCI_CTRL_D3CD; 169 writel(data, host->ioaddr + SDHCI_HOST_CONTROL); 170 } 171 } 172 173 if (unlikely((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) 174 && (reg == SDHCI_INT_STATUS) 175 && (val & SDHCI_INT_DATA_END))) { 176 u32 v; 177 v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); 178 v &= ~SDHCI_VENDOR_SPEC_SDIO_QUIRK; 179 writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); 180 } 181 182 writel(val, host->ioaddr + reg); 183 } 184 185 static u16 esdhc_readw_le(struct sdhci_host *host, int reg) 186 { 187 if (unlikely(reg == SDHCI_HOST_VERSION)) 188 reg ^= 2; 189 190 return readw(host->ioaddr + reg); 191 } 192 193 static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) 194 { 195 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 196 struct pltfm_imx_data *imx_data = pltfm_host->priv; 197 198 switch (reg) { 199 case SDHCI_TRANSFER_MODE: 200 /* 201 * Postpone this write, we must do it together with a 202 * command write that is down below. 203 */ 204 if ((imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT) 205 && (host->cmd->opcode == SD_IO_RW_EXTENDED) 206 && (host->cmd->data->blocks > 1) 207 && (host->cmd->data->flags & MMC_DATA_READ)) { 208 u32 v; 209 v = readl(host->ioaddr + SDHCI_VENDOR_SPEC); 210 v |= SDHCI_VENDOR_SPEC_SDIO_QUIRK; 211 writel(v, host->ioaddr + SDHCI_VENDOR_SPEC); 212 } 213 imx_data->scratchpad = val; 214 return; 215 case SDHCI_COMMAND: 216 if ((host->cmd->opcode == MMC_STOP_TRANSMISSION) 217 && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) 218 val |= SDHCI_CMD_ABORTCMD; 219 writel(val << 16 | imx_data->scratchpad, 220 host->ioaddr + SDHCI_TRANSFER_MODE); 221 return; 222 case SDHCI_BLOCK_SIZE: 223 val &= ~SDHCI_MAKE_BLKSZ(0x7, 0); 224 break; 225 } 226 esdhc_clrset_le(host, 0xffff, val, reg); 227 } 228 229 static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg) 230 { 231 u32 new_val; 232 233 switch (reg) { 234 case SDHCI_POWER_CONTROL: 235 /* 236 * FSL put some DMA bits here 237 * If your board has a regulator, code should be here 238 */ 239 return; 240 case SDHCI_HOST_CONTROL: 241 /* FSL messed up here, so we can just keep those three */ 242 new_val = val & (SDHCI_CTRL_LED | \ 243 SDHCI_CTRL_4BITBUS | \ 244 SDHCI_CTRL_D3CD); 245 /* ensure the endianess */ 246 new_val |= ESDHC_HOST_CONTROL_LE; 247 /* DMA mode bits are shifted */ 248 new_val |= (val & SDHCI_CTRL_DMA_MASK) << 5; 249 250 esdhc_clrset_le(host, 0xffff, new_val, reg); 251 return; 252 } 253 esdhc_clrset_le(host, 0xff, val, reg); 254 255 /* 256 * The esdhc has a design violation to SDHC spec which tells 257 * that software reset should not affect card detection circuit. 258 * But esdhc clears its SYSCTL register bits [0..2] during the 259 * software reset. This will stop those clocks that card detection 260 * circuit relies on. To work around it, we turn the clocks on back 261 * to keep card detection circuit functional. 262 */ 263 if ((reg == SDHCI_SOFTWARE_RESET) && (val & 1)) 264 esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL); 265 } 266 267 static unsigned int esdhc_pltfm_get_max_clock(struct sdhci_host *host) 268 { 269 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 270 271 return clk_get_rate(pltfm_host->clk); 272 } 273 274 static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host) 275 { 276 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 277 278 return clk_get_rate(pltfm_host->clk) / 256 / 16; 279 } 280 281 static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) 282 { 283 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 284 struct pltfm_imx_data *imx_data = pltfm_host->priv; 285 struct esdhc_platform_data *boarddata = &imx_data->boarddata; 286 287 switch (boarddata->wp_type) { 288 case ESDHC_WP_GPIO: 289 if (gpio_is_valid(boarddata->wp_gpio)) 290 return gpio_get_value(boarddata->wp_gpio); 291 case ESDHC_WP_CONTROLLER: 292 return !(readl(host->ioaddr + SDHCI_PRESENT_STATE) & 293 SDHCI_WRITE_PROTECT); 294 case ESDHC_WP_NONE: 295 break; 296 } 297 298 return -ENOSYS; 299 } 300 301 static struct sdhci_ops sdhci_esdhc_ops = { 302 .read_l = esdhc_readl_le, 303 .read_w = esdhc_readw_le, 304 .write_l = esdhc_writel_le, 305 .write_w = esdhc_writew_le, 306 .write_b = esdhc_writeb_le, 307 .set_clock = esdhc_set_clock, 308 .get_max_clock = esdhc_pltfm_get_max_clock, 309 .get_min_clock = esdhc_pltfm_get_min_clock, 310 .get_ro = esdhc_pltfm_get_ro, 311 }; 312 313 static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { 314 .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA 315 | SDHCI_QUIRK_BROKEN_CARD_DETECTION, 316 /* ADMA has issues. Might be fixable */ 317 .ops = &sdhci_esdhc_ops, 318 }; 319 320 static irqreturn_t cd_irq(int irq, void *data) 321 { 322 struct sdhci_host *sdhost = (struct sdhci_host *)data; 323 324 tasklet_schedule(&sdhost->card_tasklet); 325 return IRQ_HANDLED; 326 }; 327 328 #ifdef CONFIG_OF 329 static int __devinit 330 sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, 331 struct esdhc_platform_data *boarddata) 332 { 333 struct device_node *np = pdev->dev.of_node; 334 335 if (!np) 336 return -ENODEV; 337 338 if (of_get_property(np, "fsl,card-wired", NULL)) 339 boarddata->cd_type = ESDHC_CD_PERMANENT; 340 341 if (of_get_property(np, "fsl,cd-controller", NULL)) 342 boarddata->cd_type = ESDHC_CD_CONTROLLER; 343 344 if (of_get_property(np, "fsl,wp-controller", NULL)) 345 boarddata->wp_type = ESDHC_WP_CONTROLLER; 346 347 boarddata->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); 348 if (gpio_is_valid(boarddata->cd_gpio)) 349 boarddata->cd_type = ESDHC_CD_GPIO; 350 351 boarddata->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); 352 if (gpio_is_valid(boarddata->wp_gpio)) 353 boarddata->wp_type = ESDHC_WP_GPIO; 354 355 return 0; 356 } 357 #else 358 static inline int 359 sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, 360 struct esdhc_platform_data *boarddata) 361 { 362 return -ENODEV; 363 } 364 #endif 365 366 static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) 367 { 368 const struct of_device_id *of_id = 369 of_match_device(imx_esdhc_dt_ids, &pdev->dev); 370 struct sdhci_pltfm_host *pltfm_host; 371 struct sdhci_host *host; 372 struct esdhc_platform_data *boarddata; 373 struct clk *clk; 374 int err; 375 struct pltfm_imx_data *imx_data; 376 377 host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata); 378 if (IS_ERR(host)) 379 return PTR_ERR(host); 380 381 pltfm_host = sdhci_priv(host); 382 383 imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL); 384 if (!imx_data) { 385 err = -ENOMEM; 386 goto err_imx_data; 387 } 388 389 if (of_id) 390 pdev->id_entry = of_id->data; 391 imx_data->devtype = pdev->id_entry->driver_data; 392 pltfm_host->priv = imx_data; 393 394 clk = clk_get(mmc_dev(host->mmc), NULL); 395 if (IS_ERR(clk)) { 396 dev_err(mmc_dev(host->mmc), "clk err\n"); 397 err = PTR_ERR(clk); 398 goto err_clk_get; 399 } 400 clk_enable(clk); 401 pltfm_host->clk = clk; 402 403 if (!is_imx25_esdhc(imx_data)) 404 host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; 405 406 if (is_imx25_esdhc(imx_data) || is_imx35_esdhc(imx_data)) 407 /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */ 408 host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK; 409 410 if (is_imx53_esdhc(imx_data)) 411 imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; 412 413 boarddata = &imx_data->boarddata; 414 if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { 415 if (!host->mmc->parent->platform_data) { 416 dev_err(mmc_dev(host->mmc), "no board data!\n"); 417 err = -EINVAL; 418 goto no_board_data; 419 } 420 imx_data->boarddata = *((struct esdhc_platform_data *) 421 host->mmc->parent->platform_data); 422 } 423 424 /* write_protect */ 425 if (boarddata->wp_type == ESDHC_WP_GPIO) { 426 err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); 427 if (err) { 428 dev_warn(mmc_dev(host->mmc), 429 "no write-protect pin available!\n"); 430 boarddata->wp_gpio = -EINVAL; 431 } 432 } else { 433 boarddata->wp_gpio = -EINVAL; 434 } 435 436 /* card_detect */ 437 if (boarddata->cd_type != ESDHC_CD_GPIO) 438 boarddata->cd_gpio = -EINVAL; 439 440 switch (boarddata->cd_type) { 441 case ESDHC_CD_GPIO: 442 err = gpio_request_one(boarddata->cd_gpio, GPIOF_IN, "ESDHC_CD"); 443 if (err) { 444 dev_err(mmc_dev(host->mmc), 445 "no card-detect pin available!\n"); 446 goto no_card_detect_pin; 447 } 448 449 err = request_irq(gpio_to_irq(boarddata->cd_gpio), cd_irq, 450 IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 451 mmc_hostname(host->mmc), host); 452 if (err) { 453 dev_err(mmc_dev(host->mmc), "request irq error\n"); 454 goto no_card_detect_irq; 455 } 456 /* fall through */ 457 458 case ESDHC_CD_CONTROLLER: 459 /* we have a working card_detect back */ 460 host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; 461 break; 462 463 case ESDHC_CD_PERMANENT: 464 host->mmc->caps = MMC_CAP_NONREMOVABLE; 465 break; 466 467 case ESDHC_CD_NONE: 468 break; 469 } 470 471 err = sdhci_add_host(host); 472 if (err) 473 goto err_add_host; 474 475 return 0; 476 477 err_add_host: 478 if (gpio_is_valid(boarddata->cd_gpio)) 479 free_irq(gpio_to_irq(boarddata->cd_gpio), host); 480 no_card_detect_irq: 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: 492 sdhci_pltfm_free(pdev); 493 return err; 494 } 495 496 static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev) 497 { 498 struct sdhci_host *host = platform_get_drvdata(pdev); 499 struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); 500 struct pltfm_imx_data *imx_data = pltfm_host->priv; 501 struct esdhc_platform_data *boarddata = &imx_data->boarddata; 502 int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); 503 504 sdhci_remove_host(host, dead); 505 506 if (gpio_is_valid(boarddata->wp_gpio)) 507 gpio_free(boarddata->wp_gpio); 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); 517 518 sdhci_pltfm_free(pdev); 519 520 return 0; 521 } 522 523 static struct platform_driver sdhci_esdhc_imx_driver = { 524 .driver = { 525 .name = "sdhci-esdhc-imx", 526 .owner = THIS_MODULE, 527 .of_match_table = imx_esdhc_dt_ids, 528 }, 529 .id_table = imx_esdhc_devtype, 530 .probe = sdhci_esdhc_imx_probe, 531 .remove = __devexit_p(sdhci_esdhc_imx_remove), 532 #ifdef CONFIG_PM 533 .suspend = sdhci_pltfm_suspend, 534 .resume = sdhci_pltfm_resume, 535 #endif 536 }; 537 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); 549 550 MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC"); 551 MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); 552 MODULE_LICENSE("GPL v2"); 553