@@ -1639,80 +1639,32 @@ static int sdhci_do_3_3v_signal_voltage_switch(struct sdhci_host *host,
static int sdhci_do_1_8v_signal_voltage_switch(struct sdhci_host *host,
u16 ctrl)
{
- u8 pwr;
- u16 clk;
- u32 present_state;
int ret;
- /* Stop SDCLK */
- clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- clk &= ~SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
- /* Check whether DAT[3:0] is 0000 */
- present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
- if (!((present_state & SDHCI_DATA_LVL_MASK) >>
- SDHCI_DATA_LVL_SHIFT)) {
- /*
- * Enable 1.8V Signal Enable in the Host Control2
- * register
- */
- if (host->vqmmc)
- ret = regulator_set_voltage(host->vqmmc,
- 1800000, 1800000);
- else
- ret = 0;
-
- if (!ret) {
- ctrl |= SDHCI_CTRL_VDD_180;
- sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-
- /* Wait for 5ms */
- usleep_range(5000, 5500);
-
- ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
- if (ctrl & SDHCI_CTRL_VDD_180) {
- /* Provide SDCLK again and wait for 1ms */
- clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
- clk |= SDHCI_CLOCK_CARD_EN;
- sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
- usleep_range(1000, 1500);
-
- /*
- * If DAT[3:0] level is 1111b, then the card
- * was successfully switched to 1.8V signaling.
- */
- present_state = sdhci_readl(host,
- SDHCI_PRESENT_STATE);
- if ((present_state & SDHCI_DATA_LVL_MASK) ==
- SDHCI_DATA_LVL_MASK)
- return 0;
- }
+ if (host->vqmmc) {
+ ret = regulator_set_voltage(host->vqmmc, 1800000, 1800000);
+ if (ret) {
+ pr_warning("%s: Switching to 1.8V signalling voltage "
+ " failed\n", mmc_hostname(host->mmc));
+ return -EIO;
}
}
- /*
- * If we are here, that means the switch to 1.8V signaling
- * failed. We power cycle the card, and retry initialization
- * sequence by setting S18R to 0.
- */
- pwr = sdhci_readb(host, SDHCI_POWER_CONTROL);
- pwr &= ~SDHCI_POWER_ON;
- sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
- if (host->vmmc)
- regulator_disable(host->vmmc);
+ /* Enable 1.8V Signal Enable in the Host Control2 register */
+ ctrl |= SDHCI_CTRL_VDD_180;
+ sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
- /* Wait for 1ms as per the spec */
- usleep_range(1000, 1500);
- pwr |= SDHCI_POWER_ON;
- sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
- if (host->vmmc)
- regulator_enable(host->vmmc);
+ /* Wait for 5ms */
+ usleep_range(5000, 5500);
- pr_warning("%s: Switching to 1.8V signalling voltage failed, "
- "retrying with S18R set to 0\n", mmc_hostname(host->mmc));
+ ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+ if (ctrl & SDHCI_CTRL_VDD_180)
+ return 0;
+
+ pr_warning("%s: 1.8V regulator output did not become stable\n",
+ mmc_hostname(host->mmc));
- return -EAGAIN;
+ return -EIO;
}
static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
@@ -1991,6 +1943,23 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable)
sdhci_runtime_pm_put(host);
}
+static void sdhci_card_busy(struct mmc_host *mmc, bool keep_busy)
+{
+ u32 present_state;
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ /* Check whether DAT[3:0] is 0000 */
+ sdhci_runtime_pm_get(host);
+ present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
+ sdhci_runtime_pm_put(host);
+
+ if (!((present_state & SDHCI_DATA_LVL_MASK) >> SDHCI_DATA_LVL_SHIFT))
+ return 1;
+ else
+ return 0;
+
+}
+
static const struct mmc_host_ops sdhci_ops = {
.request = sdhci_request,
.set_ios = sdhci_set_ios,
@@ -2000,6 +1969,7 @@ static const struct mmc_host_ops sdhci_ops = {
.start_signal_voltage_switch = sdhci_start_signal_voltage_switch,
.execute_tuning = sdhci_execute_tuning,
.enable_preset_value = sdhci_enable_preset_value,
+ .card_busy = sdhci_card_busy,
};
/*****************************************************************************\
Let the upper layers handle the details of the UHS signal voltage switch, such as timings and detection and handling of failure states. Implement the card_busy host_ops function to let the upper layers check if the card is signaling busy. Signed-off-by: Johan Rudholm <johan.rudholm@stericsson.com> --- This is a humble attempt to adapt the sdhci driver so it will work with [RFC/PATCH] mmc: core: Fixup signal voltage switch The patch is untested as I don't have the proper hardware. Furthermore, I don't have any particular insight into how the sdhci controller works, so quite possibly mistakes have been made, but the idea should hopefully be clear. I hope I can get some help at testing this, and I'm grateful for any comments. --- drivers/mmc/host/sdhci.c | 102 ++++++++++++++++------------------------------ 1 file changed, 36 insertions(+), 66 deletions(-)