diff --git a/arch/arm/include/asm/omap_mmc.h b/arch/arm/include/asm/omap_mmc.h
index 3073805..6871f54 100644
--- a/arch/arm/include/asm/omap_mmc.h
+++ b/arch/arm/include/asm/omap_mmc.h
@@ -172,10 +172,6 @@ struct omap_hsmmc_plat {
 #define VS30_3V0SUP			BIT(25)
 #define VS18_1V8SUP			BIT(26)
 
-#define IOV_3V3				3300000
-#define IOV_3V0				3000000
-#define IOV_1V8				1800000
-
 #define AC12_ET				(1 << 22)
 #define AC12_V1V8_SIGEN		(1 << 19)
 #define AC12_SCLK_SEL		(1 << 23)
@@ -224,6 +220,12 @@ struct omap_hsmmc_plat {
 		IE_DTO | IE_CIE | IE_CEB | IE_CCRC | IE_ADMAE | IE_CTO |\
 		IE_BRR | IE_BWR | IE_TC | IE_CC)
 
+#define CON_CLKEXTFREE		BIT(16)
+#define CON_PADEN		BIT(15)
+#define PSTATE_CLEV		BIT(24)
+#define PSTATE_DLEV		(0xF << 20)
+#define PSTATE_DLEV_DAT0	(0x1 << 20)
+
 int omap_mmc_init(int dev_index, uint host_caps_mask, uint f_max, int cd_gpio,
 		int wp_gpio);
 
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index f3da446..ecf5171 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -78,6 +78,7 @@ struct omap_hsmmc_data {
 #endif
 	uint bus_width;
 	uint clock;
+	ushort last_cmd;
 #ifdef OMAP_HSMMC_USE_GPIO
 #if CONFIG_IS_ENABLED(DM_MMC)
 	struct gpio_desc cd_gpio;	/* Change Detect GPIO */
@@ -89,7 +90,6 @@ struct omap_hsmmc_data {
 #endif
 #endif
 #if CONFIG_IS_ENABLED(DM_MMC)
-	uint iov;
 	enum bus_mode mode;
 #endif
 	u8 controller_flags;
@@ -98,6 +98,8 @@ struct omap_hsmmc_data {
 	uint desc_slot;
 #endif
 	const char *hw_rev;
+	struct udevice *pbias_supply;
+	uint signal_voltage;
 #ifdef CONFIG_IODELAY_RECALIBRATION
 	struct omap_hsmmc_pinctrl_state *default_pinctrl_state;
 	struct omap_hsmmc_pinctrl_state *hs_pinctrl_state;
@@ -254,7 +256,8 @@ static unsigned char mmc_board_init(struct mmc *mmc)
 		&prcm_base->iclken1_core);
 #endif
 
-#if defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX)
+#if (defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX)) &&\
+	!CONFIG_IS_ENABLED(DM_REGULATOR)
 	/* PBIAS config needed for MMC1 only */
 	if (mmc_get_blk_desc(mmc)->devnum == 0)
 		vmmc_pbias_config(LDO_VOLT_3V0);
@@ -398,7 +401,7 @@ static void omap_hsmmc_set_timing(struct mmc *mmc)
 	omap_hsmmc_start_clock(mmc_base);
 }
 
-static void omap_hsmmc_conf_bus_power(struct mmc *mmc)
+static void omap_hsmmc_conf_bus_power(struct mmc *mmc, uint signal_voltage)
 {
 	struct hsmmc *mmc_base;
 	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
@@ -408,14 +411,11 @@ static void omap_hsmmc_conf_bus_power(struct mmc *mmc)
 
 	val = readl(&mmc_base->hctl) & ~SDVS_MASK;
 
-	switch (priv->iov) {
-	case IOV_3V3:
-		val |= SDVS_3V3;
-		break;
-	case IOV_3V0:
+	switch (signal_voltage) {
+	case MMC_SIGNAL_VOLTAGE_330:
 		val |= SDVS_3V0;
 		break;
-	case IOV_1V8:
+	case MMC_SIGNAL_VOLTAGE_180:
 		val |= SDVS_1V8;
 		break;
 	}
@@ -423,7 +423,126 @@ static void omap_hsmmc_conf_bus_power(struct mmc *mmc)
 	writel(val, &mmc_base->hctl);
 }
 
-static void omap_hsmmc_set_capabilities(struct mmc *mmc)
+static int omap_hsmmc_wait_dat0(struct udevice *dev, int state, int timeout)
+{
+	int ret = -ETIMEDOUT;
+	u32 con;
+	bool dat0_high;
+	bool target_dat0_high = !!state;
+	struct omap_hsmmc_data *priv = dev_get_priv(dev);
+	struct hsmmc *mmc_base = priv->base_addr;
+
+	con = readl(&mmc_base->con);
+	writel(con | CON_CLKEXTFREE | CON_PADEN, &mmc_base->con);
+
+	timeout = DIV_ROUND_UP(timeout, 10); /* check every 10 us. */
+	while (timeout--)	{
+		dat0_high = !!(readl(&mmc_base->pstate) & PSTATE_DLEV_DAT0);
+		if (dat0_high == target_dat0_high) {
+			ret = 0;
+			break;
+		}
+		udelay(10);
+	}
+	writel(con, &mmc_base->con);
+
+	return ret;
+}
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+static int omap_hsmmc_set_io_regulator(struct mmc *mmc, int mV)
+{
+	int ret = 0;
+	int uV = mV * 1000;
+
+	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+
+	if (!mmc->vqmmc_supply)
+		return 0;
+
+	/* Disable PBIAS */
+	ret = regulator_set_enable(priv->pbias_supply, false);
+	if (ret && ret != -ENOSYS)
+		return ret;
+
+	/* Turn off IO voltage */
+	ret = regulator_set_enable(mmc->vqmmc_supply, false);
+	if (ret && ret != -ENOSYS)
+		return ret;
+	/* Program a new IO voltage value */
+	ret = regulator_set_value(mmc->vqmmc_supply, uV);
+	if (ret)
+		return ret;
+	/* Turn on IO voltage */
+	ret = regulator_set_enable(mmc->vqmmc_supply, true);
+	if (ret && ret != -ENOSYS)
+		return ret;
+
+	/* Program PBIAS voltage*/
+	ret = regulator_set_value(priv->pbias_supply, uV);
+	if (ret && ret != -ENOSYS)
+		return ret;
+	/* Enable PBIAS */
+	ret = regulator_set_enable(priv->pbias_supply, true);
+	if (ret && ret != -ENOSYS)
+		return ret;
+
+	return 0;
+}
+#endif
+
+static int omap_hsmmc_set_signal_voltage(struct mmc *mmc)
+{
+	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
+	struct hsmmc *mmc_base = priv->base_addr;
+	int mv = mmc_voltage_to_mv(mmc->signal_voltage);
+	u32 capa_mask;
+	u32 ac12_v1v8;
+	__maybe_unused u8 palmas_ldo_volt;
+	u32 val;
+
+	if (mv < 0)
+		return -EINVAL;
+
+	if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
+		/* Use 3.0V rather than 3.3V */
+		mv = 3000;
+		capa_mask = VS30_3V0SUP;
+		ac12_v1v8 = 0;
+		palmas_ldo_volt = LDO_VOLT_3V0;
+	} else if (mmc->signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
+		capa_mask = VS18_1V8SUP;
+		ac12_v1v8 = AC12_V1V8_SIGEN;
+		palmas_ldo_volt = LDO_VOLT_1V8;
+	} else {
+		return -EOPNOTSUPP;
+	}
+
+	val = readl(&mmc_base->capa);
+	if (!(val & capa_mask))
+		return -EOPNOTSUPP;
+
+	priv->signal_voltage = mmc->signal_voltage;
+
+	omap_hsmmc_conf_bus_power(mmc, mmc->signal_voltage);
+
+	val = readl(&mmc_base->ac12);
+	val = (val & ~AC12_V1V8_SIGEN) | ac12_v1v8;
+	writel(val, &mmc_base->ac12);
+
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+	return omap_hsmmc_set_io_regulator(mmc, mv);
+#elif (defined(CONFIG_OMAP54XX) || defined(CONFIG_OMAP44XX)) && \
+	defined(CONFIG_PALMAS_POWER)
+	if (mmc_get_blk_desc(mmc)->devnum == 0)
+		vmmc_pbias_config(palmas_ldo_volt);
+	return 0;
+#else
+	return 0;
+#endif
+}
+
+static uint32_t omap_hsmmc_set_capabilities(struct mmc *mmc)
 {
 	struct hsmmc *mmc_base;
 	struct omap_hsmmc_data *priv = omap_hsmmc_get_data(mmc);
@@ -434,18 +553,17 @@ static void omap_hsmmc_set_capabilities(struct mmc *mmc)
 
 	if (priv->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
 		val |= (VS30_3V0SUP | VS18_1V8SUP);
-		priv->iov = IOV_3V0;
 	} else if (priv->controller_flags & OMAP_HSMMC_NO_1_8_V) {
 		val |= VS30_3V0SUP;
 		val &= ~VS18_1V8SUP;
-		priv->iov = IOV_3V0;
 	} else {
 		val |= VS18_1V8SUP;
 		val &= ~VS30_3V0SUP;
-		priv->iov = IOV_1V8;
 	}
 
 	writel(val, &mmc_base->capa);
+
+	return val;
 }
 
 static void omap_hsmmc_disable_tuning(struct mmc *mmc)
@@ -628,8 +746,9 @@ static int omap_hsmmc_init_setup(struct mmc *mmc)
 #endif
 
 #if CONFIG_IS_ENABLED(DM_MMC)
-	omap_hsmmc_set_capabilities(mmc);
-	omap_hsmmc_conf_bus_power(mmc);
+	reg_val = omap_hsmmc_set_capabilities(mmc);
+	omap_hsmmc_conf_bus_power(mmc, (reg_val & VS30_3V0SUP) ?
+			  MMC_SIGNAL_VOLTAGE_330 : MMC_SIGNAL_VOLTAGE_180);
 #else
 	writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V0, &mmc_base->hctl);
 	writel(readl(&mmc_base->capa) | VS30_3V0SUP | VS18_1V8SUP,
@@ -840,6 +959,7 @@ static int omap_hsmmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
 	struct hsmmc *mmc_base;
 	unsigned int flags, mmc_stat;
 	ulong start;
+	priv->last_cmd = cmd->cmdidx;
 
 	mmc_base = priv->base_addr;
 
@@ -1204,6 +1324,7 @@ static int omap_hsmmc_set_ios(struct udevice *dev)
 	struct mmc *mmc = upriv->mmc;
 #endif
 	struct hsmmc *mmc_base = priv->base_addr;
+	int ret = 0;
 
 	if (priv->bus_width != mmc->bus_width)
 		omap_hsmmc_set_bus_width(mmc);
@@ -1219,8 +1340,11 @@ static int omap_hsmmc_set_ios(struct udevice *dev)
 #if CONFIG_IS_ENABLED(DM_MMC)
 	if (priv->mode != mmc->selected_mode)
 		omap_hsmmc_set_timing(mmc);
+
+	if (priv->signal_voltage != mmc->signal_voltage)
+		ret = omap_hsmmc_set_signal_voltage(mmc);
 #endif
-	return 0;
+	return ret;
 }
 
 #ifdef OMAP_HSMMC_USE_GPIO
@@ -1292,6 +1416,7 @@ static const struct dm_mmc_ops omap_hsmmc_ops = {
 #endif
 	.execute_tuning = omap_hsmmc_execute_tuning,
 	.send_init_stream	= omap_hsmmc_send_init_stream,
+	.wait_dat0	= omap_hsmmc_wait_dat0,
 };
 #else
 static const struct mmc_ops omap_hsmmc_ops = {
@@ -1753,7 +1878,10 @@ static int omap_hsmmc_probe(struct udevice *dev)
 	if (mmc == NULL)
 		return -1;
 #endif
-
+#if CONFIG_IS_ENABLED(DM_REGULATOR)
+	device_get_supply_regulator(dev, "pbias-supply",
+				    &priv->pbias_supply);
+#endif
 #if defined(OMAP_HSMMC_USE_GPIO) && CONFIG_IS_ENABLED(OF_CONTROL)
 	gpio_request_by_name(dev, "cd-gpios", 0, &priv->cd_gpio, GPIOD_IS_IN);
 	gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio, GPIOD_IS_IN);
