[PATCH 1/2] mmc: core: Proper signal voltage switch

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When switching SD and SDIO cards from 3.3V to 1.8V signal levels, the
clock should be gated for 5 ms during the step. Failure by the card to
switch is indicated by dat0 being pulled low. The host should check for
this condition and power-cycle the card if failure is indicated.

Signed-off-by: Johan Rudholm <johan.rudholm@xxxxxxxxxxxxxx>
---
 drivers/mmc/core/core.c  |   24 ++++++++++++++++++++++--
 include/linux/mmc/host.h |    3 +++
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 6612163..3779431 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1220,6 +1220,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11
 {
 	struct mmc_command cmd = {0};
 	int err = 0;
+	unsigned char old_voltage = host->ios.signal_voltage;
 
 	BUG_ON(!host);
 
@@ -1243,9 +1244,28 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11
 	host->ios.signal_voltage = signal_voltage;
 
 	if (host->ops->start_signal_voltage_switch) {
-		mmc_host_clk_hold(host);
+		u32 clock = host->ios.clock;
+
+		host->ios.clock = 0;
+		mmc_set_ios(host);
 		err = host->ops->start_signal_voltage_switch(host, &host->ios);
-		mmc_host_clk_release(host);
+
+		/* Hold clock for at least 5 ms according to spec */
+		mmc_delay(5);
+		host->ios.clock = clock;
+		mmc_set_ios(host);
+
+		/* Wait for at least 1 ms until we check if card is ready */
+		mmc_delay(1);
+
+		/* Check busy */
+		if (cmd11 && host->ops->card_busy &&
+						host->ops->card_busy(host)) {
+			host->ios.signal_voltage = old_voltage;
+			host->ops->start_signal_voltage_switch(host,
+							&host->ios);
+			err = -EAGAIN;
+		}
 	}
 
 	return err;
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index d5d9bd4..b58641a 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -131,6 +131,9 @@ struct mmc_host_ops {
 
 	int	(*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
 
+	/* Check if the card is pulling dat0 low */
+	int	(*card_busy)(struct mmc_host *host);
+
 	/* The tuning command opcode value is different for SD and eMMC cards */
 	int	(*execute_tuning)(struct mmc_host *host, u32 opcode);
 	void	(*enable_preset_value)(struct mmc_host *host, bool enable);
-- 
1.7.10

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux