@@ -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,8 +1244,29 @@ 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) {
+ u32 clock = host->ios.clock;
+
mmc_host_clk_hold(host);
+ host->ios.clock = 0;
+ mmc_set_ios(host);
err = host->ops->start_signal_voltage_switch(host, &host->ios);
+
+ /* 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;
+ }
mmc_host_clk_release(host);
}
@@ -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);
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@stericsson.com> --- Changelog v2: - Keep calls to mmc_host_clk_hold / mmc_host_clk_release --- drivers/mmc/core/core.c | 22 ++++++++++++++++++++++ include/linux/mmc/host.h | 3 +++ 2 files changed, 25 insertions(+)