diff options
author | Pierre Ossman <drzeus@drzeus.cx> | 2006-06-30 05:22:23 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2006-07-02 11:02:01 -0400 |
commit | 146ad66eac836c0b976c98f428d73e1f6a75270d (patch) | |
tree | 7f1dd2b34a6225360fab04abffa4c9dd2e124cd2 /drivers/mmc/sdhci.c | |
parent | 51f82bc07a9673d790c2a17de8e3fa8046543f04 (diff) |
[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 <drzeus@drzeus.cx>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/mmc/sdhci.c')
-rw-r--r-- | drivers/mmc/sdhci.c | 60 |
1 files changed, 57 insertions, 3 deletions
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: | |||
530 | host->clock = clock; | 530 | host->clock = clock; |
531 | } | 531 | } |
532 | 532 | ||
533 | static void sdhci_set_power(struct sdhci_host *host, unsigned short power) | ||
534 | { | ||
535 | u8 pwr; | ||
536 | |||
537 | if (host->power == power) | ||
538 | return; | ||
539 | |||
540 | writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); | ||
541 | |||
542 | if (power == (unsigned short)-1) | ||
543 | goto out; | ||
544 | |||
545 | pwr = SDHCI_POWER_ON; | ||
546 | |||
547 | switch (power) { | ||
548 | case MMC_VDD_170: | ||
549 | case MMC_VDD_180: | ||
550 | case MMC_VDD_190: | ||
551 | pwr |= SDHCI_POWER_180; | ||
552 | break; | ||
553 | case MMC_VDD_290: | ||
554 | case MMC_VDD_300: | ||
555 | case MMC_VDD_310: | ||
556 | pwr |= SDHCI_POWER_300; | ||
557 | break; | ||
558 | case MMC_VDD_320: | ||
559 | case MMC_VDD_330: | ||
560 | case MMC_VDD_340: | ||
561 | pwr |= SDHCI_POWER_330; | ||
562 | break; | ||
563 | default: | ||
564 | BUG(); | ||
565 | } | ||
566 | |||
567 | writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL); | ||
568 | |||
569 | out: | ||
570 | host->power = power; | ||
571 | } | ||
572 | |||
533 | /*****************************************************************************\ | 573 | /*****************************************************************************\ |
534 | * * | 574 | * * |
535 | * MMC callbacks * | 575 | * MMC callbacks * |
@@ -584,9 +624,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
584 | sdhci_set_clock(host, ios->clock); | 624 | sdhci_set_clock(host, ios->clock); |
585 | 625 | ||
586 | if (ios->power_mode == MMC_POWER_OFF) | 626 | if (ios->power_mode == MMC_POWER_OFF) |
587 | writeb(0, host->ioaddr + SDHCI_POWER_CONTROL); | 627 | sdhci_set_power(host, -1); |
588 | else | 628 | else |
589 | writeb(0xFF, host->ioaddr + SDHCI_POWER_CONTROL); | 629 | sdhci_set_power(host, ios->vdd); |
590 | 630 | ||
591 | ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); | 631 | ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL); |
592 | if (ios->bus_width == MMC_BUS_WIDTH_4) | 632 | if (ios->bus_width == MMC_BUS_WIDTH_4) |
@@ -1046,9 +1086,23 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) | |||
1046 | mmc->ops = &sdhci_ops; | 1086 | mmc->ops = &sdhci_ops; |
1047 | mmc->f_min = host->max_clk / 256; | 1087 | mmc->f_min = host->max_clk / 256; |
1048 | mmc->f_max = host->max_clk; | 1088 | mmc->f_max = host->max_clk; |
1049 | mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34; | ||
1050 | mmc->caps = MMC_CAP_4_BIT_DATA; | 1089 | mmc->caps = MMC_CAP_4_BIT_DATA; |
1051 | 1090 | ||
1091 | mmc->ocr_avail = 0; | ||
1092 | if (caps & SDHCI_CAN_VDD_330) | ||
1093 | mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34; | ||
1094 | else if (caps & SDHCI_CAN_VDD_300) | ||
1095 | mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31; | ||
1096 | else if (caps & SDHCI_CAN_VDD_180) | ||
1097 | mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19; | ||
1098 | |||
1099 | if (mmc->ocr_avail == 0) { | ||
1100 | printk(KERN_ERR "%s: Hardware doesn't report any " | ||
1101 | "support voltages.\n", host->slot_descr); | ||
1102 | ret = -ENODEV; | ||
1103 | goto unmap; | ||
1104 | } | ||
1105 | |||
1052 | spin_lock_init(&host->lock); | 1106 | spin_lock_init(&host->lock); |
1053 | 1107 | ||
1054 | /* | 1108 | /* |