if (soft) {
                /* force clock reconfiguration */
                host->clock = 0;
+               host->reinit_uhs = true;
                mmc->ops->set_ios(mmc, &mmc->ios);
        }
 }
 }
 EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
 
+static bool sdhci_timing_has_preset(unsigned char timing)
+{
+       switch (timing) {
+       case MMC_TIMING_UHS_SDR12:
+       case MMC_TIMING_UHS_SDR25:
+       case MMC_TIMING_UHS_SDR50:
+       case MMC_TIMING_UHS_SDR104:
+       case MMC_TIMING_UHS_DDR50:
+       case MMC_TIMING_MMC_DDR52:
+               return true;
+       };
+       return false;
+}
+
+static bool sdhci_preset_needed(struct sdhci_host *host, unsigned char timing)
+{
+       return !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
+              sdhci_timing_has_preset(timing);
+}
+
+static bool sdhci_presetable_values_change(struct sdhci_host *host, struct mmc_ios *ios)
+{
+       /*
+        * Preset Values are: Driver Strength, Clock Generator and SDCLK/RCLK
+        * Frequency. Check if preset values need to be enabled, or the Driver
+        * Strength needs updating. Note, clock changes are handled separately.
+        */
+       return !host->preset_enabled &&
+              (sdhci_preset_needed(host, ios->timing) || host->drv_type != ios->drv_type);
+}
+
 void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct sdhci_host *host = mmc_priv(mmc);
+       bool reinit_uhs = host->reinit_uhs;
+       bool turning_on_clk = false;
        u8 ctrl;
 
+       host->reinit_uhs = false;
+
        if (ios->power_mode == MMC_POWER_UNDEFINED)
                return;
 
                sdhci_enable_preset_value(host, false);
 
        if (!ios->clock || ios->clock != host->clock) {
+               turning_on_clk = ios->clock && !host->clock;
+
                host->ops->set_clock(host, ios->clock);
                host->clock = ios->clock;
 
 
        host->ops->set_bus_width(host, ios->bus_width);
 
+       /*
+        * Special case to avoid multiple clock changes during voltage
+        * switching.
+        */
+       if (!reinit_uhs &&
+           turning_on_clk &&
+           host->timing == ios->timing &&
+           host->version >= SDHCI_SPEC_300 &&
+           !sdhci_presetable_values_change(host, ios))
+               return;
+
        ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
 
        if (!(host->quirks & SDHCI_QUIRK_NO_HISPD_BIT)) {
                        }
 
                        sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+                       host->drv_type = ios->drv_type;
                } else {
                        /*
                         * According to SDHC Spec v3.00, if the Preset Value
                host->ops->set_uhs_signaling(host, ios->timing);
                host->timing = ios->timing;
 
-               if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
-                               ((ios->timing == MMC_TIMING_UHS_SDR12) ||
-                                (ios->timing == MMC_TIMING_UHS_SDR25) ||
-                                (ios->timing == MMC_TIMING_UHS_SDR50) ||
-                                (ios->timing == MMC_TIMING_UHS_SDR104) ||
-                                (ios->timing == MMC_TIMING_UHS_DDR50) ||
-                                (ios->timing == MMC_TIMING_MMC_DDR52))) {
+               if (sdhci_preset_needed(host, ios->timing)) {
                        u16 preset;
 
                        sdhci_enable_preset_value(host, true);
                        preset = sdhci_get_preset_value(host);
                        ios->drv_type = FIELD_GET(SDHCI_PRESET_DRV_MASK,
                                                  preset);
+                       host->drv_type = ios->drv_type;
                }
 
                /* Re-enable SD Clock */
                sdhci_init(host, 0);
                host->pwr = 0;
                host->clock = 0;
+               host->reinit_uhs = true;
                mmc->ops->set_ios(mmc, &mmc->ios);
        } else {
                sdhci_init(host, (mmc->pm_flags & MMC_PM_KEEP_POWER));
                /* Force clock and power re-program */
                host->pwr = 0;
                host->clock = 0;
+               host->reinit_uhs = true;
                mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios);
                mmc->ops->set_ios(mmc, &mmc->ios);