diff options
author | Philip Rakity <prakity@marvell.com> | 2012-07-23 18:56:23 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2012-09-04 13:58:13 -0400 |
commit | 6231f3de1332b2a8a90e0c598ab6acc8f1eff7c1 (patch) | |
tree | bf43eafe176d49684116b5454a81e67b5c12db90 /drivers/mmc | |
parent | 137ccd46c5efaed6a8118cce3db2cbb64350113b (diff) |
mmc: sdhci: Add regulator support for vccq (voltage regualor)
On some systems the host controller does not support vccq
signaling. This is supplied by a dedicated regulator (vqmmc).
Add support for this regulator.
Signed-off-by: Philip Rakity <prakity@marvell.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 181 |
1 files changed, 116 insertions, 65 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9a11dc39921c..828ac6c2990c 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
@@ -1597,57 +1597,65 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) | |||
1597 | spin_unlock_irqrestore(&host->lock, flags); | 1597 | spin_unlock_irqrestore(&host->lock, flags); |
1598 | } | 1598 | } |
1599 | 1599 | ||
1600 | static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, | 1600 | static int sdhci_do_3_3v_signal_voltage_switch(struct sdhci_host *host, |
1601 | struct mmc_ios *ios) | 1601 | u16 ctrl) |
1602 | { | 1602 | { |
1603 | u8 pwr; | 1603 | int ret; |
1604 | u16 clk, ctrl; | ||
1605 | u32 present_state; | ||
1606 | 1604 | ||
1607 | /* | 1605 | /* Set 1.8V Signal Enable in the Host Control2 register to 0 */ |
1608 | * Signal Voltage Switching is only applicable for Host Controllers | 1606 | ctrl &= ~SDHCI_CTRL_VDD_180; |
1609 | * v3.00 and above. | 1607 | sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); |
1610 | */ | ||
1611 | if (host->version < SDHCI_SPEC_300) | ||
1612 | return 0; | ||
1613 | 1608 | ||
1614 | /* | 1609 | if (host->vqmmc) { |
1615 | * We first check whether the request is to set signalling voltage | 1610 | ret = regulator_set_voltage(host->vqmmc, 3300000, 3300000); |
1616 | * to 3.3V. If so, we change the voltage to 3.3V and return quickly. | 1611 | if (ret) { |
1617 | */ | 1612 | pr_warning("%s: Switching to 3.3V signalling voltage " |
1613 | " failed\n", mmc_hostname(host->mmc)); | ||
1614 | return -EIO; | ||
1615 | } | ||
1616 | } | ||
1617 | /* Wait for 5ms */ | ||
1618 | usleep_range(5000, 5500); | ||
1619 | |||
1620 | /* 3.3V regulator output should be stable within 5 ms */ | ||
1618 | ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); | 1621 | ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); |
1619 | if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) { | 1622 | if (!(ctrl & SDHCI_CTRL_VDD_180)) |
1620 | /* Set 1.8V Signal Enable in the Host Control2 register to 0 */ | 1623 | return 0; |
1621 | ctrl &= ~SDHCI_CTRL_VDD_180; | ||
1622 | sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); | ||
1623 | 1624 | ||
1624 | /* Wait for 5ms */ | 1625 | pr_warning("%s: 3.3V regulator output did not became stable\n", |
1625 | usleep_range(5000, 5500); | 1626 | mmc_hostname(host->mmc)); |
1626 | 1627 | ||
1627 | /* 3.3V regulator output should be stable within 5 ms */ | 1628 | return -EIO; |
1628 | ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); | 1629 | } |
1629 | if (!(ctrl & SDHCI_CTRL_VDD_180)) | ||
1630 | return 0; | ||
1631 | else { | ||
1632 | pr_info(DRIVER_NAME ": Switching to 3.3V " | ||
1633 | "signalling voltage failed\n"); | ||
1634 | return -EIO; | ||
1635 | } | ||
1636 | } else if (!(ctrl & SDHCI_CTRL_VDD_180) && | ||
1637 | (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)) { | ||
1638 | /* Stop SDCLK */ | ||
1639 | clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); | ||
1640 | clk &= ~SDHCI_CLOCK_CARD_EN; | ||
1641 | sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); | ||
1642 | 1630 | ||
1643 | /* Check whether DAT[3:0] is 0000 */ | 1631 | static int sdhci_do_1_8v_signal_voltage_switch(struct sdhci_host *host, |
1644 | present_state = sdhci_readl(host, SDHCI_PRESENT_STATE); | 1632 | u16 ctrl) |
1645 | if (!((present_state & SDHCI_DATA_LVL_MASK) >> | 1633 | { |
1646 | SDHCI_DATA_LVL_SHIFT)) { | 1634 | u8 pwr; |
1647 | /* | 1635 | u16 clk; |
1648 | * Enable 1.8V Signal Enable in the Host Control2 | 1636 | u32 present_state; |
1649 | * register | 1637 | int ret; |
1650 | */ | 1638 | |
1639 | /* Stop SDCLK */ | ||
1640 | clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); | ||
1641 | clk &= ~SDHCI_CLOCK_CARD_EN; | ||
1642 | sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); | ||
1643 | |||
1644 | /* Check whether DAT[3:0] is 0000 */ | ||
1645 | present_state = sdhci_readl(host, SDHCI_PRESENT_STATE); | ||
1646 | if (!((present_state & SDHCI_DATA_LVL_MASK) >> | ||
1647 | SDHCI_DATA_LVL_SHIFT)) { | ||
1648 | /* | ||
1649 | * Enable 1.8V Signal Enable in the Host Control2 | ||
1650 | * register | ||
1651 | */ | ||
1652 | if (host->vqmmc) | ||
1653 | ret = regulator_set_voltage(host->vqmmc, | ||
1654 | 1800000, 1800000); | ||
1655 | else | ||
1656 | ret = 0; | ||
1657 | |||
1658 | if (!ret) { | ||
1651 | ctrl |= SDHCI_CTRL_VDD_180; | 1659 | ctrl |= SDHCI_CTRL_VDD_180; |
1652 | sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); | 1660 | sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); |
1653 | 1661 | ||
@@ -1656,7 +1664,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, | |||
1656 | 1664 | ||
1657 | ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); | 1665 | ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); |
1658 | if (ctrl & SDHCI_CTRL_VDD_180) { | 1666 | if (ctrl & SDHCI_CTRL_VDD_180) { |
1659 | /* Provide SDCLK again and wait for 1ms*/ | 1667 | /* Provide SDCLK again and wait for 1ms */ |
1660 | clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); | 1668 | clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); |
1661 | clk |= SDHCI_CLOCK_CARD_EN; | 1669 | clk |= SDHCI_CLOCK_CARD_EN; |
1662 | sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); | 1670 | sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); |
@@ -1673,29 +1681,55 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, | |||
1673 | return 0; | 1681 | return 0; |
1674 | } | 1682 | } |
1675 | } | 1683 | } |
1684 | } | ||
1676 | 1685 | ||
1677 | /* | 1686 | /* |
1678 | * If we are here, that means the switch to 1.8V signaling | 1687 | * If we are here, that means the switch to 1.8V signaling |
1679 | * failed. We power cycle the card, and retry initialization | 1688 | * failed. We power cycle the card, and retry initialization |
1680 | * sequence by setting S18R to 0. | 1689 | * sequence by setting S18R to 0. |
1681 | */ | 1690 | */ |
1682 | pwr = sdhci_readb(host, SDHCI_POWER_CONTROL); | 1691 | pwr = sdhci_readb(host, SDHCI_POWER_CONTROL); |
1683 | pwr &= ~SDHCI_POWER_ON; | 1692 | pwr &= ~SDHCI_POWER_ON; |
1684 | sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); | 1693 | sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); |
1685 | if (host->vmmc) | 1694 | if (host->vmmc) |
1686 | regulator_disable(host->vmmc); | 1695 | regulator_disable(host->vmmc); |
1687 | 1696 | ||
1688 | /* Wait for 1ms as per the spec */ | 1697 | /* Wait for 1ms as per the spec */ |
1689 | usleep_range(1000, 1500); | 1698 | usleep_range(1000, 1500); |
1690 | pwr |= SDHCI_POWER_ON; | 1699 | pwr |= SDHCI_POWER_ON; |
1691 | sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); | 1700 | sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL); |
1692 | if (host->vmmc) | 1701 | if (host->vmmc) |
1693 | regulator_enable(host->vmmc); | 1702 | regulator_enable(host->vmmc); |
1694 | 1703 | ||
1695 | pr_info(DRIVER_NAME ": Switching to 1.8V signalling " | 1704 | pr_warning("%s: Switching to 1.8V signalling voltage failed, " |
1696 | "voltage failed, retrying with S18R set to 0\n"); | 1705 | "retrying with S18R set to 0\n", mmc_hostname(host->mmc)); |
1697 | return -EAGAIN; | 1706 | |
1698 | } else | 1707 | return -EAGAIN; |
1708 | } | ||
1709 | |||
1710 | static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, | ||
1711 | struct mmc_ios *ios) | ||
1712 | { | ||
1713 | u16 ctrl; | ||
1714 | |||
1715 | /* | ||
1716 | * Signal Voltage Switching is only applicable for Host Controllers | ||
1717 | * v3.00 and above. | ||
1718 | */ | ||
1719 | if (host->version < SDHCI_SPEC_300) | ||
1720 | return 0; | ||
1721 | |||
1722 | /* | ||
1723 | * We first check whether the request is to set signalling voltage | ||
1724 | * to 3.3V. If so, we change the voltage to 3.3V and return quickly. | ||
1725 | */ | ||
1726 | ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2); | ||
1727 | if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) | ||
1728 | return sdhci_do_3_3v_signal_voltage_switch(host, ctrl); | ||
1729 | else if (!(ctrl & SDHCI_CTRL_VDD_180) && | ||
1730 | (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)) | ||
1731 | return sdhci_do_1_8v_signal_voltage_switch(host, ctrl); | ||
1732 | else | ||
1699 | /* No signal voltage switch required */ | 1733 | /* No signal voltage switch required */ |
1700 | return 0; | 1734 | return 0; |
1701 | } | 1735 | } |
@@ -2802,6 +2836,18 @@ int sdhci_add_host(struct sdhci_host *host) | |||
2802 | !(host->mmc->caps & MMC_CAP_NONREMOVABLE)) | 2836 | !(host->mmc->caps & MMC_CAP_NONREMOVABLE)) |
2803 | mmc->caps |= MMC_CAP_NEEDS_POLL; | 2837 | mmc->caps |= MMC_CAP_NEEDS_POLL; |
2804 | 2838 | ||
2839 | /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */ | ||
2840 | host->vqmmc = regulator_get(mmc_dev(mmc), "vqmmc"); | ||
2841 | if (IS_ERR(host->vqmmc)) { | ||
2842 | pr_info("%s: no vqmmc regulator found\n", mmc_hostname(mmc)); | ||
2843 | host->vqmmc = NULL; | ||
2844 | } | ||
2845 | else if (regulator_is_supported_voltage(host->vqmmc, 1800000, 1800000)) | ||
2846 | regulator_enable(host->vqmmc); | ||
2847 | else | ||
2848 | caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | | ||
2849 | SDHCI_SUPPORT_DDR50); | ||
2850 | |||
2805 | /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */ | 2851 | /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */ |
2806 | if (caps[1] & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | | 2852 | if (caps[1] & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | |
2807 | SDHCI_SUPPORT_DDR50)) | 2853 | SDHCI_SUPPORT_DDR50)) |
@@ -3122,6 +3168,11 @@ void sdhci_remove_host(struct sdhci_host *host, int dead) | |||
3122 | if (host->vmmc) | 3168 | if (host->vmmc) |
3123 | regulator_put(host->vmmc); | 3169 | regulator_put(host->vmmc); |
3124 | 3170 | ||
3171 | if (host->vqmmc) { | ||
3172 | regulator_disable(host->vqmmc); | ||
3173 | regulator_put(host->vqmmc); | ||
3174 | } | ||
3175 | |||
3125 | kfree(host->adma_desc); | 3176 | kfree(host->adma_desc); |
3126 | kfree(host->align_buffer); | 3177 | kfree(host->align_buffer); |
3127 | 3178 | ||