aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/sdhci.c
diff options
context:
space:
mode:
authorPierre Ossman <drzeus@drzeus.cx>2006-06-30 05:22:23 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-07-02 11:02:01 -0400
commit146ad66eac836c0b976c98f428d73e1f6a75270d (patch)
tree7f1dd2b34a6225360fab04abffa4c9dd2e124cd2 /drivers/mmc/sdhci.c
parent51f82bc07a9673d790c2a17de8e3fa8046543f04 (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.c60
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
533static 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
569out:
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 /*