diff options
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 53 |
1 files changed, 46 insertions, 7 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c6d1bd8d4ac4..785512133b50 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/dma-mapping.h> | 19 | #include <linux/dma-mapping.h> |
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/scatterlist.h> | 21 | #include <linux/scatterlist.h> |
22 | #include <linux/regulator/consumer.h> | ||
22 | 23 | ||
23 | #include <linux/leds.h> | 24 | #include <linux/leds.h> |
24 | 25 | ||
@@ -817,8 +818,12 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, | |||
817 | WARN_ON(!host->data); | 818 | WARN_ON(!host->data); |
818 | 819 | ||
819 | mode = SDHCI_TRNS_BLK_CNT_EN; | 820 | mode = SDHCI_TRNS_BLK_CNT_EN; |
820 | if (data->blocks > 1) | 821 | if (data->blocks > 1) { |
821 | mode |= SDHCI_TRNS_MULTI; | 822 | if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) |
823 | mode |= SDHCI_TRNS_MULTI | SDHCI_TRNS_ACMD12; | ||
824 | else | ||
825 | mode |= SDHCI_TRNS_MULTI; | ||
826 | } | ||
822 | if (data->flags & MMC_DATA_READ) | 827 | if (data->flags & MMC_DATA_READ) |
823 | mode |= SDHCI_TRNS_READ; | 828 | mode |= SDHCI_TRNS_READ; |
824 | if (host->flags & SDHCI_REQ_USE_DMA) | 829 | if (host->flags & SDHCI_REQ_USE_DMA) |
@@ -1108,6 +1113,12 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
1108 | #ifndef SDHCI_USE_LEDS_CLASS | 1113 | #ifndef SDHCI_USE_LEDS_CLASS |
1109 | sdhci_activate_led(host); | 1114 | sdhci_activate_led(host); |
1110 | #endif | 1115 | #endif |
1116 | if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12) { | ||
1117 | if (mrq->stop) { | ||
1118 | mrq->data->stop = NULL; | ||
1119 | mrq->stop = NULL; | ||
1120 | } | ||
1121 | } | ||
1111 | 1122 | ||
1112 | host->mrq = mrq; | 1123 | host->mrq = mrq; |
1113 | 1124 | ||
@@ -1159,6 +1170,11 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
1159 | 1170 | ||
1160 | ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); | 1171 | ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL); |
1161 | 1172 | ||
1173 | if (ios->bus_width == MMC_BUS_WIDTH_8) | ||
1174 | ctrl |= SDHCI_CTRL_8BITBUS; | ||
1175 | else | ||
1176 | ctrl &= ~SDHCI_CTRL_8BITBUS; | ||
1177 | |||
1162 | if (ios->bus_width == MMC_BUS_WIDTH_4) | 1178 | if (ios->bus_width == MMC_BUS_WIDTH_4) |
1163 | ctrl |= SDHCI_CTRL_4BITBUS; | 1179 | ctrl |= SDHCI_CTRL_4BITBUS; |
1164 | else | 1180 | else |
@@ -1603,7 +1619,10 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state) | |||
1603 | 1619 | ||
1604 | free_irq(host->irq, host); | 1620 | free_irq(host->irq, host); |
1605 | 1621 | ||
1606 | return 0; | 1622 | if (host->vmmc) |
1623 | ret = regulator_disable(host->vmmc); | ||
1624 | |||
1625 | return ret; | ||
1607 | } | 1626 | } |
1608 | 1627 | ||
1609 | EXPORT_SYMBOL_GPL(sdhci_suspend_host); | 1628 | EXPORT_SYMBOL_GPL(sdhci_suspend_host); |
@@ -1612,6 +1631,13 @@ int sdhci_resume_host(struct sdhci_host *host) | |||
1612 | { | 1631 | { |
1613 | int ret; | 1632 | int ret; |
1614 | 1633 | ||
1634 | if (host->vmmc) { | ||
1635 | int ret = regulator_enable(host->vmmc); | ||
1636 | if (ret) | ||
1637 | return ret; | ||
1638 | } | ||
1639 | |||
1640 | |||
1615 | if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { | 1641 | if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { |
1616 | if (host->ops->enable_dma) | 1642 | if (host->ops->enable_dma) |
1617 | host->ops->enable_dma(host); | 1643 | host->ops->enable_dma(host); |
@@ -1687,7 +1713,8 @@ int sdhci_add_host(struct sdhci_host *host) | |||
1687 | host->version); | 1713 | host->version); |
1688 | } | 1714 | } |
1689 | 1715 | ||
1690 | caps = sdhci_readl(host, SDHCI_CAPABILITIES); | 1716 | caps = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps : |
1717 | sdhci_readl(host, SDHCI_CAPABILITIES); | ||
1691 | 1718 | ||
1692 | if (host->quirks & SDHCI_QUIRK_FORCE_DMA) | 1719 | if (host->quirks & SDHCI_QUIRK_FORCE_DMA) |
1693 | host->flags |= SDHCI_USE_SDMA; | 1720 | host->flags |= SDHCI_USE_SDMA; |
@@ -1785,13 +1812,12 @@ int sdhci_add_host(struct sdhci_host *host) | |||
1785 | * Set host parameters. | 1812 | * Set host parameters. |
1786 | */ | 1813 | */ |
1787 | mmc->ops = &sdhci_ops; | 1814 | mmc->ops = &sdhci_ops; |
1788 | if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK && | 1815 | if (host->ops->get_min_clock) |
1789 | host->ops->set_clock && host->ops->get_min_clock) | ||
1790 | mmc->f_min = host->ops->get_min_clock(host); | 1816 | mmc->f_min = host->ops->get_min_clock(host); |
1791 | else | 1817 | else |
1792 | mmc->f_min = host->max_clk / 256; | 1818 | mmc->f_min = host->max_clk / 256; |
1793 | mmc->f_max = host->max_clk; | 1819 | mmc->f_max = host->max_clk; |
1794 | mmc->caps = MMC_CAP_SDIO_IRQ; | 1820 | mmc->caps |= MMC_CAP_SDIO_IRQ; |
1795 | 1821 | ||
1796 | if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA)) | 1822 | if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA)) |
1797 | mmc->caps |= MMC_CAP_4_BIT_DATA; | 1823 | mmc->caps |= MMC_CAP_4_BIT_DATA; |
@@ -1884,6 +1910,14 @@ int sdhci_add_host(struct sdhci_host *host) | |||
1884 | if (ret) | 1910 | if (ret) |
1885 | goto untasklet; | 1911 | goto untasklet; |
1886 | 1912 | ||
1913 | host->vmmc = regulator_get(mmc_dev(mmc), "vmmc"); | ||
1914 | if (IS_ERR(host->vmmc)) { | ||
1915 | printk(KERN_INFO "%s: no vmmc regulator found\n", mmc_hostname(mmc)); | ||
1916 | host->vmmc = NULL; | ||
1917 | } else { | ||
1918 | regulator_enable(host->vmmc); | ||
1919 | } | ||
1920 | |||
1887 | sdhci_init(host, 0); | 1921 | sdhci_init(host, 0); |
1888 | 1922 | ||
1889 | #ifdef CONFIG_MMC_DEBUG | 1923 | #ifdef CONFIG_MMC_DEBUG |
@@ -1968,6 +2002,11 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) | |||
1968 | tasklet_kill(&host->card_tasklet); | 2002 | tasklet_kill(&host->card_tasklet); |
1969 | tasklet_kill(&host->finish_tasklet); | 2003 | tasklet_kill(&host->finish_tasklet); |
1970 | 2004 | ||
2005 | if (host->vmmc) { | ||
2006 | regulator_disable(host->vmmc); | ||
2007 | regulator_put(host->vmmc); | ||
2008 | } | ||
2009 | |||
1971 | kfree(host->adma_desc); | 2010 | kfree(host->adma_desc); |
1972 | kfree(host->align_buffer); | 2011 | kfree(host->align_buffer); |
1973 | 2012 | ||