aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2009-02-17 17:49:01 -0500
committerPierre Ossman <drzeus@drzeus.cx>2009-02-18 16:09:56 -0500
commiteb25082657be3e7639e349fc926afdcbb0a4dc65 (patch)
treed311c5c0d95c9837e2a7b8b54bf0aa256df5bd7f /drivers/mmc
parent249d0fa9d59b6165ecc224720d9ce9b7267cf1b8 (diff)
omap_hsmmc: only MMC1 allows HCTL.SDVS != 1.8V
Based on a patch from Tony Lindgren ... after initialization, never change HCTL.SDVS except for MMC1. The other controller instances only support 1.8V in that field, although they can suport other card/SDIO/eMMC/... voltages with level shifting solutions such as external transceivers. MMC2 behavior sanity tested on Overo/WLAN, OMAP3430 SDP, and custom hardware. MMC1 also sanity tested on those platforms plus Beagle. This also fixes a bug preventing MMC2 (and also presumably MMC3) from powering down when requested. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Acked-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/omap_hsmmc.c43
1 files changed, 33 insertions, 10 deletions
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 4dba48642e60..3bfd0facb794 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
@@ -456,13 +457,20 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
456} 457}
457 458
458/* 459/*
459 * Switch MMC operating voltage 460 * Switch MMC interface voltage ... only relevant for MMC1.
461 *
462 * MMC2 and MMC3 use fixed 1.8V levels, and maybe a transceiver.
463 * The MMC2 transceiver controls are used instead of DAT4..DAT7.
464 * Some chips, like eMMC ones, use internal transceivers.
460 */ 465 */
461static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd) 466static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd)
462{ 467{
463 u32 reg_val = 0; 468 u32 reg_val = 0;
464 int ret; 469 int ret;
465 470
471 if (host->id != OMAP_MMC1_DEVID)
472 return 0;
473
466 /* Disable the clocks */ 474 /* Disable the clocks */
467 clk_disable(host->fclk); 475 clk_disable(host->fclk);
468 clk_disable(host->iclk); 476 clk_disable(host->iclk);
@@ -485,19 +493,26 @@ static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd)
485 OMAP_HSMMC_WRITE(host->base, HCTL, 493 OMAP_HSMMC_WRITE(host->base, HCTL,
486 OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR); 494 OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);
487 reg_val = OMAP_HSMMC_READ(host->base, HCTL); 495 reg_val = OMAP_HSMMC_READ(host->base, HCTL);
496
488 /* 497 /*
489 * If a MMC dual voltage card is detected, the set_ios fn calls 498 * 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 499 * 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. 500 * slot, omap_mmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF.
492 * 501 *
493 * Only MMC1 supports 3.0V. MMC2 will not function if SDVS30 is 502 * Cope with a bit of slop in the range ... per data sheets:
494 * set in HCTL. 503 * - "1.8V" for vdds_mmc1/vdds_mmc1a can be up to 2.45V max,
504 * but recommended values are 1.71V to 1.89V
505 * - "3.0V" for vdds_mmc1/vdds_mmc1a can be up to 3.5V max,
506 * but recommended values are 2.7V to 3.3V
507 *
508 * Board setup code shouldn't permit anything very out-of-range.
509 * TWL4030-family VMMC1 and VSIM regulators are fine (avoiding the
510 * middle range) but VSIM can't power DAT4..DAT7 at more than 3V.
495 */ 511 */
496 if (host->id == OMAP_MMC1_DEVID && (((1 << vdd) == MMC_VDD_32_33) || 512 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; 513 reg_val |= SDVS18;
514 else
515 reg_val |= SDVS30;
501 516
502 OMAP_HSMMC_WRITE(host->base, HCTL, reg_val); 517 OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
503 518
@@ -759,10 +774,14 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
759 case MMC_POWER_OFF: 774 case MMC_POWER_OFF:
760 mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0); 775 mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
761 /* 776 /*
762 * Reset bus voltage to 3V if it got set to 1.8V earlier. 777 * Reset interface voltage to 3V if it's 1.8V now;
778 * only relevant on MMC-1, the others always use 1.8V.
779 *
763 * REVISIT: If we are able to detect cards after unplugging 780 * REVISIT: If we are able to detect cards after unplugging
764 * a 1.8V card, this code should not be needed. 781 * a 1.8V card, this code should not be needed.
765 */ 782 */
783 if (host->id != OMAP_MMC1_DEVID)
784 break;
766 if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) { 785 if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
767 int vdd = fls(host->mmc->ocr_avail) - 1; 786 int vdd = fls(host->mmc->ocr_avail) - 1;
768 if (omap_mmc_switch_opcond(host, vdd) != 0) 787 if (omap_mmc_switch_opcond(host, vdd) != 0)
@@ -786,7 +805,9 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
786 } 805 }
787 806
788 if (host->id == OMAP_MMC1_DEVID) { 807 if (host->id == OMAP_MMC1_DEVID) {
789 /* Only MMC1 can operate at 3V/1.8V */ 808 /* Only MMC1 can interface at 3V without some flavor
809 * of external transceiver; but they all handle 1.8V.
810 */
790 if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) && 811 if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
791 (ios->vdd == DUAL_VOLT_OCR_BIT)) { 812 (ios->vdd == DUAL_VOLT_OCR_BIT)) {
792 /* 813 /*
@@ -1139,7 +1160,9 @@ static int omap_mmc_suspend(struct platform_device *pdev, pm_message_t state)
1139 " level suspend\n"); 1160 " level suspend\n");
1140 } 1161 }
1141 1162
1142 if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) { 1163 if (host->id == OMAP_MMC1_DEVID
1164 && !(OMAP_HSMMC_READ(host->base, HCTL)
1165 & SDVSDET)) {
1143 OMAP_HSMMC_WRITE(host->base, HCTL, 1166 OMAP_HSMMC_WRITE(host->base, HCTL,
1144 OMAP_HSMMC_READ(host->base, HCTL) 1167 OMAP_HSMMC_READ(host->base, HCTL)
1145 & SDVSCLR); 1168 & SDVSCLR);