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>
This commit is contained in:
Родитель
249d0fa9d5
Коммит
eb25082657
|
@ -55,6 +55,7 @@
|
|||
#define VS30 (1 << 25)
|
||||
#define SDVS18 (0x5 << 9)
|
||||
#define SDVS30 (0x6 << 9)
|
||||
#define SDVS33 (0x7 << 9)
|
||||
#define SDVSCLR 0xFFFFF1FF
|
||||
#define SDVSDET 0x00000400
|
||||
#define AUTOIDLE 0x1
|
||||
|
@ -456,13 +457,20 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
|
|||
}
|
||||
|
||||
/*
|
||||
* Switch MMC operating voltage
|
||||
* Switch MMC interface voltage ... only relevant for MMC1.
|
||||
*
|
||||
* MMC2 and MMC3 use fixed 1.8V levels, and maybe a transceiver.
|
||||
* The MMC2 transceiver controls are used instead of DAT4..DAT7.
|
||||
* Some chips, like eMMC ones, use internal transceivers.
|
||||
*/
|
||||
static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd)
|
||||
{
|
||||
u32 reg_val = 0;
|
||||
int ret;
|
||||
|
||||
if (host->id != OMAP_MMC1_DEVID)
|
||||
return 0;
|
||||
|
||||
/* Disable the clocks */
|
||||
clk_disable(host->fclk);
|
||||
clk_disable(host->iclk);
|
||||
|
@ -485,19 +493,26 @@ static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd)
|
|||
OMAP_HSMMC_WRITE(host->base, HCTL,
|
||||
OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);
|
||||
reg_val = OMAP_HSMMC_READ(host->base, HCTL);
|
||||
|
||||
/*
|
||||
* If a MMC dual voltage card is detected, the set_ios fn calls
|
||||
* this fn with VDD bit set for 1.8V. Upon card removal from the
|
||||
* slot, omap_mmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF.
|
||||
*
|
||||
* Only MMC1 supports 3.0V. MMC2 will not function if SDVS30 is
|
||||
* set in HCTL.
|
||||
* Cope with a bit of slop in the range ... per data sheets:
|
||||
* - "1.8V" for vdds_mmc1/vdds_mmc1a can be up to 2.45V max,
|
||||
* but recommended values are 1.71V to 1.89V
|
||||
* - "3.0V" for vdds_mmc1/vdds_mmc1a can be up to 3.5V max,
|
||||
* but recommended values are 2.7V to 3.3V
|
||||
*
|
||||
* Board setup code shouldn't permit anything very out-of-range.
|
||||
* TWL4030-family VMMC1 and VSIM regulators are fine (avoiding the
|
||||
* middle range) but VSIM can't power DAT4..DAT7 at more than 3V.
|
||||
*/
|
||||
if (host->id == OMAP_MMC1_DEVID && (((1 << vdd) == MMC_VDD_32_33) ||
|
||||
((1 << vdd) == MMC_VDD_33_34)))
|
||||
reg_val |= SDVS30;
|
||||
if ((1 << vdd) == MMC_VDD_165_195)
|
||||
if ((1 << vdd) <= MMC_VDD_23_24)
|
||||
reg_val |= SDVS18;
|
||||
else
|
||||
reg_val |= SDVS30;
|
||||
|
||||
OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
|
||||
|
||||
|
@ -759,10 +774,14 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
case MMC_POWER_OFF:
|
||||
mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
|
||||
/*
|
||||
* Reset bus voltage to 3V if it got set to 1.8V earlier.
|
||||
* Reset interface voltage to 3V if it's 1.8V now;
|
||||
* only relevant on MMC-1, the others always use 1.8V.
|
||||
*
|
||||
* REVISIT: If we are able to detect cards after unplugging
|
||||
* a 1.8V card, this code should not be needed.
|
||||
*/
|
||||
if (host->id != OMAP_MMC1_DEVID)
|
||||
break;
|
||||
if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
|
||||
int vdd = fls(host->mmc->ocr_avail) - 1;
|
||||
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)
|
|||
}
|
||||
|
||||
if (host->id == OMAP_MMC1_DEVID) {
|
||||
/* Only MMC1 can operate at 3V/1.8V */
|
||||
/* Only MMC1 can interface at 3V without some flavor
|
||||
* of external transceiver; but they all handle 1.8V.
|
||||
*/
|
||||
if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
|
||||
(ios->vdd == DUAL_VOLT_OCR_BIT)) {
|
||||
/*
|
||||
|
@ -1139,7 +1160,9 @@ static int omap_mmc_suspend(struct platform_device *pdev, pm_message_t state)
|
|||
" level suspend\n");
|
||||
}
|
||||
|
||||
if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
|
||||
if (host->id == OMAP_MMC1_DEVID
|
||||
&& !(OMAP_HSMMC_READ(host->base, HCTL)
|
||||
& SDVSDET)) {
|
||||
OMAP_HSMMC_WRITE(host->base, HCTL,
|
||||
OMAP_HSMMC_READ(host->base, HCTL)
|
||||
& SDVSCLR);
|
||||
|
|
Загрузка…
Ссылка в новой задаче