aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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
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')
-rw-r--r--drivers/mmc/sdhci.c60
-rw-r--r--drivers/mmc/sdhci.h10
2 files changed, 66 insertions, 4 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 /*
diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/sdhci.h
index 3b270ef486b4..aed4abd37bfd 100644
--- a/drivers/mmc/sdhci.h
+++ b/drivers/mmc/sdhci.h
@@ -67,6 +67,10 @@
67#define SDHCI_CTRL_4BITBUS 0x02 67#define SDHCI_CTRL_4BITBUS 0x02
68 68
69#define SDHCI_POWER_CONTROL 0x29 69#define SDHCI_POWER_CONTROL 0x29
70#define SDHCI_POWER_ON 0x01
71#define SDHCI_POWER_180 0x0A
72#define SDHCI_POWER_300 0x0C
73#define SDHCI_POWER_330 0x0E
70 74
71#define SDHCI_BLOCK_GAP_CONTROL 0x2A 75#define SDHCI_BLOCK_GAP_CONTROL 0x2A
72 76
@@ -121,9 +125,12 @@
121/* 3E-3F reserved */ 125/* 3E-3F reserved */
122 126
123#define SDHCI_CAPABILITIES 0x40 127#define SDHCI_CAPABILITIES 0x40
124#define SDHCI_CAN_DO_DMA 0x00400000
125#define SDHCI_CLOCK_BASE_MASK 0x00003F00 128#define SDHCI_CLOCK_BASE_MASK 0x00003F00
126#define SDHCI_CLOCK_BASE_SHIFT 8 129#define SDHCI_CLOCK_BASE_SHIFT 8
130#define SDHCI_CAN_DO_DMA 0x00400000
131#define SDHCI_CAN_VDD_330 0x01000000
132#define SDHCI_CAN_VDD_300 0x02000000
133#define SDHCI_CAN_VDD_180 0x04000000
127 134
128/* 44-47 reserved for more caps */ 135/* 44-47 reserved for more caps */
129 136
@@ -151,6 +158,7 @@ struct sdhci_host {
151 unsigned int max_clk; /* Max possible freq (MHz) */ 158 unsigned int max_clk; /* Max possible freq (MHz) */
152 159
153 unsigned int clock; /* Current clock (MHz) */ 160 unsigned int clock; /* Current clock (MHz) */
161 unsigned short power; /* Current voltage */
154 162
155 struct mmc_request *mrq; /* Current request */ 163 struct mmc_request *mrq; /* Current request */
156 struct mmc_command *cmd; /* Current command */ 164 struct mmc_command *cmd; /* Current command */