diff options
Diffstat (limited to 'drivers/mmc/host/omap_hsmmc.c')
-rw-r--r-- | drivers/mmc/host/omap_hsmmc.c | 98 |
1 files changed, 68 insertions, 30 deletions
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index db37490f67ec..a631c81dce12 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c | |||
@@ -55,6 +55,7 @@ | |||
55 | #define VS30 (1 << 25) | 55 | #define VS30 (1 << 25) |
56 | #define SDVS18 (0x5 << 9) | 56 | #define SDVS18 (0x5 << 9) |
57 | #define SDVS30 (0x6 << 9) | 57 | #define SDVS30 (0x6 << 9) |
58 | #define SDVS33 (0x7 << 9) | ||
58 | #define SDVSCLR 0xFFFFF1FF | 59 | #define SDVSCLR 0xFFFFF1FF |
59 | #define SDVSDET 0x00000400 | 60 | #define SDVSDET 0x00000400 |
60 | #define AUTOIDLE 0x1 | 61 | #define AUTOIDLE 0x1 |
@@ -375,6 +376,32 @@ static void mmc_omap_report_irq(struct mmc_omap_host *host, u32 status) | |||
375 | } | 376 | } |
376 | #endif /* CONFIG_MMC_DEBUG */ | 377 | #endif /* CONFIG_MMC_DEBUG */ |
377 | 378 | ||
379 | /* | ||
380 | * MMC controller internal state machines reset | ||
381 | * | ||
382 | * Used to reset command or data internal state machines, using respectively | ||
383 | * SRC or SRD bit of SYSCTL register | ||
384 | * Can be called from interrupt context | ||
385 | */ | ||
386 | static inline void mmc_omap_reset_controller_fsm(struct mmc_omap_host *host, | ||
387 | unsigned long bit) | ||
388 | { | ||
389 | unsigned long i = 0; | ||
390 | unsigned long limit = (loops_per_jiffy * | ||
391 | msecs_to_jiffies(MMC_TIMEOUT_MS)); | ||
392 | |||
393 | OMAP_HSMMC_WRITE(host->base, SYSCTL, | ||
394 | OMAP_HSMMC_READ(host->base, SYSCTL) | bit); | ||
395 | |||
396 | while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) && | ||
397 | (i++ < limit)) | ||
398 | cpu_relax(); | ||
399 | |||
400 | if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit) | ||
401 | dev_err(mmc_dev(host->mmc), | ||
402 | "Timeout waiting on controller reset in %s\n", | ||
403 | __func__); | ||
404 | } | ||
378 | 405 | ||
379 | /* | 406 | /* |
380 | * MMC controller IRQ handler | 407 | * MMC controller IRQ handler |
@@ -403,21 +430,17 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) | |||
403 | (status & CMD_CRC)) { | 430 | (status & CMD_CRC)) { |
404 | if (host->cmd) { | 431 | if (host->cmd) { |
405 | if (status & CMD_TIMEOUT) { | 432 | if (status & CMD_TIMEOUT) { |
406 | OMAP_HSMMC_WRITE(host->base, SYSCTL, | 433 | mmc_omap_reset_controller_fsm(host, SRC); |
407 | OMAP_HSMMC_READ(host->base, | ||
408 | SYSCTL) | SRC); | ||
409 | while (OMAP_HSMMC_READ(host->base, | ||
410 | SYSCTL) & SRC) | ||
411 | ; | ||
412 | |||
413 | host->cmd->error = -ETIMEDOUT; | 434 | host->cmd->error = -ETIMEDOUT; |
414 | } else { | 435 | } else { |
415 | host->cmd->error = -EILSEQ; | 436 | host->cmd->error = -EILSEQ; |
416 | } | 437 | } |
417 | end_cmd = 1; | 438 | end_cmd = 1; |
418 | } | 439 | } |
419 | if (host->data) | 440 | if (host->data) { |
420 | mmc_dma_cleanup(host); | 441 | mmc_dma_cleanup(host); |
442 | mmc_omap_reset_controller_fsm(host, SRD); | ||
443 | } | ||
421 | } | 444 | } |
422 | if ((status & DATA_TIMEOUT) || | 445 | if ((status & DATA_TIMEOUT) || |
423 | (status & DATA_CRC)) { | 446 | (status & DATA_CRC)) { |
@@ -426,12 +449,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) | |||
426 | mmc_dma_cleanup(host); | 449 | mmc_dma_cleanup(host); |
427 | else | 450 | else |
428 | host->data->error = -EILSEQ; | 451 | host->data->error = -EILSEQ; |
429 | OMAP_HSMMC_WRITE(host->base, SYSCTL, | 452 | mmc_omap_reset_controller_fsm(host, SRD); |
430 | OMAP_HSMMC_READ(host->base, | ||
431 | SYSCTL) | SRD); | ||
432 | while (OMAP_HSMMC_READ(host->base, | ||
433 | SYSCTL) & SRD) | ||
434 | ; | ||
435 | end_trans = 1; | 453 | end_trans = 1; |
436 | } | 454 | } |
437 | } | 455 | } |
@@ -456,13 +474,20 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id) | |||
456 | } | 474 | } |
457 | 475 | ||
458 | /* | 476 | /* |
459 | * Switch MMC operating voltage | 477 | * Switch MMC interface voltage ... only relevant for MMC1. |
478 | * | ||
479 | * MMC2 and MMC3 use fixed 1.8V levels, and maybe a transceiver. | ||
480 | * The MMC2 transceiver controls are used instead of DAT4..DAT7. | ||
481 | * Some chips, like eMMC ones, use internal transceivers. | ||
460 | */ | 482 | */ |
461 | static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd) | 483 | static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd) |
462 | { | 484 | { |
463 | u32 reg_val = 0; | 485 | u32 reg_val = 0; |
464 | int ret; | 486 | int ret; |
465 | 487 | ||
488 | if (host->id != OMAP_MMC1_DEVID) | ||
489 | return 0; | ||
490 | |||
466 | /* Disable the clocks */ | 491 | /* Disable the clocks */ |
467 | clk_disable(host->fclk); | 492 | clk_disable(host->fclk); |
468 | clk_disable(host->iclk); | 493 | clk_disable(host->iclk); |
@@ -485,19 +510,26 @@ static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd) | |||
485 | OMAP_HSMMC_WRITE(host->base, HCTL, | 510 | OMAP_HSMMC_WRITE(host->base, HCTL, |
486 | OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR); | 511 | OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR); |
487 | reg_val = OMAP_HSMMC_READ(host->base, HCTL); | 512 | reg_val = OMAP_HSMMC_READ(host->base, HCTL); |
513 | |||
488 | /* | 514 | /* |
489 | * If a MMC dual voltage card is detected, the set_ios fn calls | 515 | * If a MMC dual voltage card is detected, the set_ios fn calls |
490 | * this fn with VDD bit set for 1.8V. Upon card removal from the | 516 | * this fn with VDD bit set for 1.8V. Upon card removal from the |
491 | * slot, omap_mmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF. | 517 | * slot, omap_mmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF. |
492 | * | 518 | * |
493 | * Only MMC1 supports 3.0V. MMC2 will not function if SDVS30 is | 519 | * Cope with a bit of slop in the range ... per data sheets: |
494 | * set in HCTL. | 520 | * - "1.8V" for vdds_mmc1/vdds_mmc1a can be up to 2.45V max, |
521 | * but recommended values are 1.71V to 1.89V | ||
522 | * - "3.0V" for vdds_mmc1/vdds_mmc1a can be up to 3.5V max, | ||
523 | * but recommended values are 2.7V to 3.3V | ||
524 | * | ||
525 | * Board setup code shouldn't permit anything very out-of-range. | ||
526 | * TWL4030-family VMMC1 and VSIM regulators are fine (avoiding the | ||
527 | * middle range) but VSIM can't power DAT4..DAT7 at more than 3V. | ||
495 | */ | 528 | */ |
496 | if (host->id == OMAP_MMC1_DEVID && (((1 << vdd) == MMC_VDD_32_33) || | 529 | if ((1 << vdd) <= MMC_VDD_23_24) |
497 | ((1 << vdd) == MMC_VDD_33_34))) | ||
498 | reg_val |= SDVS30; | ||
499 | if ((1 << vdd) == MMC_VDD_165_195) | ||
500 | reg_val |= SDVS18; | 530 | reg_val |= SDVS18; |
531 | else | ||
532 | reg_val |= SDVS30; | ||
501 | 533 | ||
502 | OMAP_HSMMC_WRITE(host->base, HCTL, reg_val); | 534 | OMAP_HSMMC_WRITE(host->base, HCTL, reg_val); |
503 | 535 | ||
@@ -517,16 +549,15 @@ static void mmc_omap_detect(struct work_struct *work) | |||
517 | { | 549 | { |
518 | struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, | 550 | struct mmc_omap_host *host = container_of(work, struct mmc_omap_host, |
519 | mmc_carddetect_work); | 551 | mmc_carddetect_work); |
552 | struct omap_mmc_slot_data *slot = &mmc_slot(host); | ||
553 | |||
554 | host->carddetect = slot->card_detect(slot->card_detect_irq); | ||
520 | 555 | ||
521 | sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); | 556 | sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); |
522 | if (host->carddetect) { | 557 | if (host->carddetect) { |
523 | mmc_detect_change(host->mmc, (HZ * 200) / 1000); | 558 | mmc_detect_change(host->mmc, (HZ * 200) / 1000); |
524 | } else { | 559 | } else { |
525 | OMAP_HSMMC_WRITE(host->base, SYSCTL, | 560 | mmc_omap_reset_controller_fsm(host, SRD); |
526 | OMAP_HSMMC_READ(host->base, SYSCTL) | SRD); | ||
527 | while (OMAP_HSMMC_READ(host->base, SYSCTL) & SRD) | ||
528 | ; | ||
529 | |||
530 | mmc_detect_change(host->mmc, (HZ * 50) / 1000); | 561 | mmc_detect_change(host->mmc, (HZ * 50) / 1000); |
531 | } | 562 | } |
532 | } | 563 | } |
@@ -538,7 +569,6 @@ static irqreturn_t omap_mmc_cd_handler(int irq, void *dev_id) | |||
538 | { | 569 | { |
539 | struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id; | 570 | struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id; |
540 | 571 | ||
541 | host->carddetect = mmc_slot(host).card_detect(irq); | ||
542 | schedule_work(&host->mmc_carddetect_work); | 572 | schedule_work(&host->mmc_carddetect_work); |
543 | 573 | ||
544 | return IRQ_HANDLED; | 574 | return IRQ_HANDLED; |
@@ -757,10 +787,14 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
757 | case MMC_POWER_OFF: | 787 | case MMC_POWER_OFF: |
758 | mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); | 788 | mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); |
759 | /* | 789 | /* |
760 | * Reset bus voltage to 3V if it got set to 1.8V earlier. | 790 | * Reset interface voltage to 3V if it's 1.8V now; |
791 | * only relevant on MMC-1, the others always use 1.8V. | ||
792 | * | ||
761 | * REVISIT: If we are able to detect cards after unplugging | 793 | * REVISIT: If we are able to detect cards after unplugging |
762 | * a 1.8V card, this code should not be needed. | 794 | * a 1.8V card, this code should not be needed. |
763 | */ | 795 | */ |
796 | if (host->id != OMAP_MMC1_DEVID) | ||
797 | break; | ||
764 | if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) { | 798 | if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) { |
765 | int vdd = fls(host->mmc->ocr_avail) - 1; | 799 | int vdd = fls(host->mmc->ocr_avail) - 1; |
766 | if (omap_mmc_switch_opcond(host, vdd) != 0) | 800 | if (omap_mmc_switch_opcond(host, vdd) != 0) |
@@ -784,7 +818,9 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
784 | } | 818 | } |
785 | 819 | ||
786 | if (host->id == OMAP_MMC1_DEVID) { | 820 | if (host->id == OMAP_MMC1_DEVID) { |
787 | /* Only MMC1 can operate at 3V/1.8V */ | 821 | /* Only MMC1 can interface at 3V without some flavor |
822 | * of external transceiver; but they all handle 1.8V. | ||
823 | */ | ||
788 | if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) && | 824 | if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) && |
789 | (ios->vdd == DUAL_VOLT_OCR_BIT)) { | 825 | (ios->vdd == DUAL_VOLT_OCR_BIT)) { |
790 | /* | 826 | /* |
@@ -1137,7 +1173,9 @@ static int omap_mmc_suspend(struct platform_device *pdev, pm_message_t state) | |||
1137 | " level suspend\n"); | 1173 | " level suspend\n"); |
1138 | } | 1174 | } |
1139 | 1175 | ||
1140 | if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) { | 1176 | if (host->id == OMAP_MMC1_DEVID |
1177 | && !(OMAP_HSMMC_READ(host->base, HCTL) | ||
1178 | & SDVSDET)) { | ||
1141 | OMAP_HSMMC_WRITE(host->base, HCTL, | 1179 | OMAP_HSMMC_WRITE(host->base, HCTL, |
1142 | OMAP_HSMMC_READ(host->base, HCTL) | 1180 | OMAP_HSMMC_READ(host->base, HCTL) |
1143 | & SDVSCLR); | 1181 | & SDVSCLR); |