Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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