From 146ad66eac836c0b976c98f428d73e1f6a75270d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 30 Jun 2006 02:22:23 -0700 Subject: [MMC] sdhci: support for multiple voltages The sdhci controllers can support up to three voltage levels. Detect which and report back to the MMC layer. Signed-off-by: Pierre Ossman Signed-off-by: Andrew Morton Signed-off-by: Russell King --- drivers/mmc/sdhci.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) (limited to 'drivers/mmc/sdhci.c') diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 405b6158cb6c..74912dcac82f 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -530,6 +530,46 @@ out: host->clock = clock; } +static void sdhci_set_power(struct sdhci_host *host, unsigned short power) +{ + u8 pwr; + + if (host->power == power) + return; + + writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); + + if (power == (unsigned short)-1) + goto out; + + pwr = SDHCI_POWER_ON; + + switch (power) { + case MMC_VDD_170: + case MMC_VDD_180: + case MMC_VDD_190: + pwr |= SDHCI_POWER_180; + break; + case MMC_VDD_290: + case MMC_VDD_300: + case MMC_VDD_310: + pwr |= SDHCI_POWER_300; + break; + case MMC_VDD_320: + case MMC_VDD_330: + case MMC_VDD_340: + pwr |= SDHCI_POWER_330; + break; + default: + BUG(); + } + + writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL); + +out: + host->power = power; +} + /*****************************************************************************\ * * * MMC callbacks * @@ -584,9 +624,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) sdhci_set_clock(host, ios->clock); if (ios->power_mode == MMC_POWER_OFF) - writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); + sdhci_set_power(host, -1); else - writeb(0xFF, host->ioaddr + SDHCI_POWER_CONTROL); + sdhci_set_power(host, ios->vdd); ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); if (ios->bus_width == MMC_BUS_WIDTH_4) @@ -1046,9 +1086,23 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) mmc->ops = &sdhci_ops; mmc->f_min = host->max_clk / 256; mmc->f_max = host->max_clk; - mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; mmc->caps = MMC_CAP_4_BIT_DATA; + mmc->ocr_avail = 0; + if (caps & SDHCI_CAN_VDD_330) + mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34; + else if (caps & SDHCI_CAN_VDD_300) + mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31; + else if (caps & SDHCI_CAN_VDD_180) + mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19; + + if (mmc->ocr_avail == 0) { + printk(KERN_ERR "%s: Hardware doesn't report any " + "support voltages.\n", host->slot_descr); + ret = -ENODEV; + goto unmap; + } + spin_lock_init(&host->lock); /* -- cgit v1.2.3