diff mbox

[RFC,5/8] mmc: sdhci: Add check_power_status host operation

Message ID 1467199233-20506-6-git-send-email-riteshh@codeaurora.org (mailing list archive)
State New, archived
Headers show

Commit Message

Ritesh Harjani June 29, 2016, 11:20 a.m. UTC
From: Sahitya Tummala <stummala@codeaurora.org>

MSM SDHCI doesn't control power as specified by the Standard
Host Controller 3.0 spec. Writing to power control register/
reset register/voltage bit of host control register would
trigger an IRQ with appropriate status bits set. Hence, use
host op check_power_status after writing to power control
register to check the status and wait until the IRQ is handled.

Signed-off-by: Sahitya Tummala <stummala@codeaurora.org>
Signed-off-by: Ritesh Harjani <riteshh@codeaurora.org>
---
 drivers/mmc/host/sdhci.c | 24 +++++++++++++++++++++---
 drivers/mmc/host/sdhci.h |  5 +++++
 2 files changed, 26 insertions(+), 3 deletions(-)

Comments

Adrian Hunter June 30, 2016, 6 a.m. UTC | #1
On 29/06/16 14:20, Ritesh Harjani wrote:
> From: Sahitya Tummala <stummala@codeaurora.org>
> 
> MSM SDHCI doesn't control power as specified by the Standard
> Host Controller 3.0 spec. Writing to power control register/
> reset register/voltage bit of host control register would
> trigger an IRQ with appropriate status bits set. Hence, use
> host op check_power_status after writing to power control
> register to check the status and wait until the IRQ is handled.

Did you consider using the SDHCI I/O Accessors for this? i.e.
CONFIG_MMC_SDHCI_IO_ACCESSORS

> 
> Signed-off-by: Sahitya Tummala <stummala@codeaurora.org>
> Signed-off-by: Ritesh Harjani <riteshh@codeaurora.org>
> ---
>  drivers/mmc/host/sdhci.c | 24 +++++++++++++++++++++---
>  drivers/mmc/host/sdhci.h |  5 +++++
>  2 files changed, 26 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 0e3d7c0..12f74bd 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -176,6 +176,10 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
>  	/* Wait max 100 ms */
>  	timeout = 100;
>  
> +	if (host->ops->check_power_status && host->pwr &&
> +	    (mask & SDHCI_RESET_ALL))
> +		host->ops->check_power_status(host, REQ_BUS_OFF);
> +
>  	/* hw clears the bit when it's done */
>  	while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
>  		if (timeout == 0) {
> @@ -1306,6 +1310,8 @@ void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
>  
>  	if (pwr == 0) {
>  		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
> +		if (host->ops->check_power_status)
> +			host->ops->check_power_status(host, REQ_BUS_OFF);
>  		if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
>  			sdhci_runtime_pm_bus_off(host);
>  	} else {
> @@ -1313,20 +1319,28 @@ void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
>  		 * Spec says that we should clear the power reg before setting
>  		 * a new value. Some controllers don't seem to like this though.
>  		 */
> -		if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
> +		if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) {
>  			sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
> -
> +			if (host->ops->check_power_status)
> +				host->ops->check_power_status(host,
> +							REQ_BUS_OFF);
> +		}
>  		/*
>  		 * At least the Marvell CaFe chip gets confused if we set the
>  		 * voltage and set turn on power at the same time, so set the
>  		 * voltage first.
>  		 */
> -		if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
> +		if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER) {
>  			sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
> +			if (host->ops->check_power_status)
> +				host->ops->check_power_status(host, REQ_BUS_ON);
> +		}
>  
>  		pwr |= SDHCI_POWER_ON;
>  
>  		sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
> +		if (host->ops->check_power_status)
> +			host->ops->check_power_status(host, REQ_BUS_ON);
>  
>  		if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
>  			sdhci_runtime_pm_bus_on(host);
> @@ -1736,6 +1750,8 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
>  		/* Set 1.8V Signal Enable in the Host Control2 register to 0 */
>  		ctrl &= ~SDHCI_CTRL_VDD_180;
>  		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
> +		if (host->ops->check_power_status)
> +			host->ops->check_power_status(host, REQ_IO_HIGH);
>  
>  		if (!IS_ERR(mmc->supply.vqmmc)) {
>  			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
> @@ -1775,6 +1791,8 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
>  		 */
>  		ctrl |= SDHCI_CTRL_VDD_180;
>  		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
> +		if (host->ops->check_power_status)
> +			host->ops->check_power_status(host, REQ_IO_LOW);
>  
>  		/* Some controller need to do more when switching */
>  		if (host->ops->voltage_switch)
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index 609f87c..5758cca 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -549,6 +549,11 @@ struct sdhci_ops {
>  					 struct mmc_card *card,
>  					 unsigned int max_dtr, int host_drv,
>  					 int card_drv, int *drv_type);
> +#define REQ_BUS_OFF	BIT(0)
> +#define REQ_BUS_ON	BIT(1)
> +#define REQ_IO_LOW	BIT(2)
> +#define REQ_IO_HIGH	BIT(3)
> +	void    (*check_power_status)(struct sdhci_host *host, u32 req_type);
>  };
>  
>  #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ritesh Harjani June 30, 2016, 1:32 p.m. UTC | #2
Hi Adrian,


On 6/30/2016 11:30 AM, Adrian Hunter wrote:
> On 29/06/16 14:20, Ritesh Harjani wrote:
>> From: Sahitya Tummala <stummala@codeaurora.org>
>>
>> MSM SDHCI doesn't control power as specified by the Standard
>> Host Controller 3.0 spec. Writing to power control register/
>> reset register/voltage bit of host control register would
>> trigger an IRQ with appropriate status bits set. Hence, use
>> host op check_power_status after writing to power control
>> register to check the status and wait until the IRQ is handled.
>
> Did you consider using the SDHCI I/O Accessors for this? i.e.
> CONFIG_MMC_SDHCI_IO_ACCESSORS
Thanks for the suggestion. I will check and get back.

>
>>
>> Signed-off-by: Sahitya Tummala <stummala@codeaurora.org>
>> Signed-off-by: Ritesh Harjani <riteshh@codeaurora.org>
>> ---
>>  drivers/mmc/host/sdhci.c | 24 +++++++++++++++++++++---
>>  drivers/mmc/host/sdhci.h |  5 +++++
>>  2 files changed, 26 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>> index 0e3d7c0..12f74bd 100644
>> --- a/drivers/mmc/host/sdhci.c
>> +++ b/drivers/mmc/host/sdhci.c
>> @@ -176,6 +176,10 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
>>  	/* Wait max 100 ms */
>>  	timeout = 100;
>>
>> +	if (host->ops->check_power_status && host->pwr &&
>> +	    (mask & SDHCI_RESET_ALL))
>> +		host->ops->check_power_status(host, REQ_BUS_OFF);
>> +
>>  	/* hw clears the bit when it's done */
>>  	while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
>>  		if (timeout == 0) {
>> @@ -1306,6 +1310,8 @@ void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
>>
>>  	if (pwr == 0) {
>>  		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
>> +		if (host->ops->check_power_status)
>> +			host->ops->check_power_status(host, REQ_BUS_OFF);
>>  		if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
>>  			sdhci_runtime_pm_bus_off(host);
>>  	} else {
>> @@ -1313,20 +1319,28 @@ void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
>>  		 * Spec says that we should clear the power reg before setting
>>  		 * a new value. Some controllers don't seem to like this though.
>>  		 */
>> -		if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
>> +		if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) {
>>  			sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
>> -
>> +			if (host->ops->check_power_status)
>> +				host->ops->check_power_status(host,
>> +							REQ_BUS_OFF);
>> +		}
>>  		/*
>>  		 * At least the Marvell CaFe chip gets confused if we set the
>>  		 * voltage and set turn on power at the same time, so set the
>>  		 * voltage first.
>>  		 */
>> -		if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
>> +		if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER) {
>>  			sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
>> +			if (host->ops->check_power_status)
>> +				host->ops->check_power_status(host, REQ_BUS_ON);
>> +		}
>>
>>  		pwr |= SDHCI_POWER_ON;
>>
>>  		sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
>> +		if (host->ops->check_power_status)
>> +			host->ops->check_power_status(host, REQ_BUS_ON);
>>
>>  		if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
>>  			sdhci_runtime_pm_bus_on(host);
>> @@ -1736,6 +1750,8 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
>>  		/* Set 1.8V Signal Enable in the Host Control2 register to 0 */
>>  		ctrl &= ~SDHCI_CTRL_VDD_180;
>>  		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
>> +		if (host->ops->check_power_status)
>> +			host->ops->check_power_status(host, REQ_IO_HIGH);
>>
>>  		if (!IS_ERR(mmc->supply.vqmmc)) {
>>  			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
>> @@ -1775,6 +1791,8 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
>>  		 */
>>  		ctrl |= SDHCI_CTRL_VDD_180;
>>  		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
>> +		if (host->ops->check_power_status)
>> +			host->ops->check_power_status(host, REQ_IO_LOW);
>>
>>  		/* Some controller need to do more when switching */
>>  		if (host->ops->voltage_switch)
>> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
>> index 609f87c..5758cca 100644
>> --- a/drivers/mmc/host/sdhci.h
>> +++ b/drivers/mmc/host/sdhci.h
>> @@ -549,6 +549,11 @@ struct sdhci_ops {
>>  					 struct mmc_card *card,
>>  					 unsigned int max_dtr, int host_drv,
>>  					 int card_drv, int *drv_type);
>> +#define REQ_BUS_OFF	BIT(0)
>> +#define REQ_BUS_ON	BIT(1)
>> +#define REQ_IO_LOW	BIT(2)
>> +#define REQ_IO_HIGH	BIT(3)
>> +	void    (*check_power_status)(struct sdhci_host *host, u32 req_type);
>>  };
>>
>>  #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
>>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ritesh Harjani Aug. 5, 2016, 4:48 a.m. UTC | #3
Hi,

Kindly drop this patch series, since recently there was another version 
of pwr_irq support added to upstream.

https://lkml.org/lkml/2016/6/24/416


Regards
Ritesh

On 6/30/2016 7:02 PM, Ritesh Harjani wrote:
> Hi Adrian,
>
>
> On 6/30/2016 11:30 AM, Adrian Hunter wrote:
>> On 29/06/16 14:20, Ritesh Harjani wrote:
>>> From: Sahitya Tummala <stummala@codeaurora.org>
>>>
>>> MSM SDHCI doesn't control power as specified by the Standard
>>> Host Controller 3.0 spec. Writing to power control register/
>>> reset register/voltage bit of host control register would
>>> trigger an IRQ with appropriate status bits set. Hence, use
>>> host op check_power_status after writing to power control
>>> register to check the status and wait until the IRQ is handled.
>>
>> Did you consider using the SDHCI I/O Accessors for this? i.e.
>> CONFIG_MMC_SDHCI_IO_ACCESSORS
> Thanks for the suggestion. I will check and get back.
>
>>
>>>
>>> Signed-off-by: Sahitya Tummala <stummala@codeaurora.org>
>>> Signed-off-by: Ritesh Harjani <riteshh@codeaurora.org>
>>> ---
>>>  drivers/mmc/host/sdhci.c | 24 +++++++++++++++++++++---
>>>  drivers/mmc/host/sdhci.h |  5 +++++
>>>  2 files changed, 26 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>>> index 0e3d7c0..12f74bd 100644
>>> --- a/drivers/mmc/host/sdhci.c
>>> +++ b/drivers/mmc/host/sdhci.c
>>> @@ -176,6 +176,10 @@ void sdhci_reset(struct sdhci_host *host, u8 mask)
>>>      /* Wait max 100 ms */
>>>      timeout = 100;
>>>
>>> +    if (host->ops->check_power_status && host->pwr &&
>>> +        (mask & SDHCI_RESET_ALL))
>>> +        host->ops->check_power_status(host, REQ_BUS_OFF);
>>> +
>>>      /* hw clears the bit when it's done */
>>>      while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
>>>          if (timeout == 0) {
>>> @@ -1306,6 +1310,8 @@ void sdhci_set_power(struct sdhci_host *host,
>>> unsigned char mode,
>>>
>>>      if (pwr == 0) {
>>>          sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
>>> +        if (host->ops->check_power_status)
>>> +            host->ops->check_power_status(host, REQ_BUS_OFF);
>>>          if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
>>>              sdhci_runtime_pm_bus_off(host);
>>>      } else {
>>> @@ -1313,20 +1319,28 @@ void sdhci_set_power(struct sdhci_host *host,
>>> unsigned char mode,
>>>           * Spec says that we should clear the power reg before setting
>>>           * a new value. Some controllers don't seem to like this
>>> though.
>>>           */
>>> -        if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
>>> +        if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) {
>>>              sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
>>> -
>>> +            if (host->ops->check_power_status)
>>> +                host->ops->check_power_status(host,
>>> +                            REQ_BUS_OFF);
>>> +        }
>>>          /*
>>>           * At least the Marvell CaFe chip gets confused if we set the
>>>           * voltage and set turn on power at the same time, so set the
>>>           * voltage first.
>>>           */
>>> -        if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
>>> +        if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER) {
>>>              sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
>>> +            if (host->ops->check_power_status)
>>> +                host->ops->check_power_status(host, REQ_BUS_ON);
>>> +        }
>>>
>>>          pwr |= SDHCI_POWER_ON;
>>>
>>>          sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
>>> +        if (host->ops->check_power_status)
>>> +            host->ops->check_power_status(host, REQ_BUS_ON);
>>>
>>>          if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
>>>              sdhci_runtime_pm_bus_on(host);
>>> @@ -1736,6 +1750,8 @@ static int
>>> sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
>>>          /* Set 1.8V Signal Enable in the Host Control2 register to 0 */
>>>          ctrl &= ~SDHCI_CTRL_VDD_180;
>>>          sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
>>> +        if (host->ops->check_power_status)
>>> +            host->ops->check_power_status(host, REQ_IO_HIGH);
>>>
>>>          if (!IS_ERR(mmc->supply.vqmmc)) {
>>>              ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
>>> @@ -1775,6 +1791,8 @@ static int
>>> sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
>>>           */
>>>          ctrl |= SDHCI_CTRL_VDD_180;
>>>          sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
>>> +        if (host->ops->check_power_status)
>>> +            host->ops->check_power_status(host, REQ_IO_LOW);
>>>
>>>          /* Some controller need to do more when switching */
>>>          if (host->ops->voltage_switch)
>>> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
>>> index 609f87c..5758cca 100644
>>> --- a/drivers/mmc/host/sdhci.h
>>> +++ b/drivers/mmc/host/sdhci.h
>>> @@ -549,6 +549,11 @@ struct sdhci_ops {
>>>                       struct mmc_card *card,
>>>                       unsigned int max_dtr, int host_drv,
>>>                       int card_drv, int *drv_type);
>>> +#define REQ_BUS_OFF    BIT(0)
>>> +#define REQ_BUS_ON    BIT(1)
>>> +#define REQ_IO_LOW    BIT(2)
>>> +#define REQ_IO_HIGH    BIT(3)
>>> +    void    (*check_power_status)(struct sdhci_host *host, u32
>>> req_type);
>>>  };
>>>
>>>  #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
>>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 0e3d7c0..12f74bd 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -176,6 +176,10 @@  void sdhci_reset(struct sdhci_host *host, u8 mask)
 	/* Wait max 100 ms */
 	timeout = 100;
 
+	if (host->ops->check_power_status && host->pwr &&
+	    (mask & SDHCI_RESET_ALL))
+		host->ops->check_power_status(host, REQ_BUS_OFF);
+
 	/* hw clears the bit when it's done */
 	while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
 		if (timeout == 0) {
@@ -1306,6 +1310,8 @@  void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
 
 	if (pwr == 0) {
 		sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+		if (host->ops->check_power_status)
+			host->ops->check_power_status(host, REQ_BUS_OFF);
 		if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
 			sdhci_runtime_pm_bus_off(host);
 	} else {
@@ -1313,20 +1319,28 @@  void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
 		 * Spec says that we should clear the power reg before setting
 		 * a new value. Some controllers don't seem to like this though.
 		 */
-		if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+		if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE)) {
 			sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
-
+			if (host->ops->check_power_status)
+				host->ops->check_power_status(host,
+							REQ_BUS_OFF);
+		}
 		/*
 		 * At least the Marvell CaFe chip gets confused if we set the
 		 * voltage and set turn on power at the same time, so set the
 		 * voltage first.
 		 */
-		if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
+		if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER) {
 			sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+			if (host->ops->check_power_status)
+				host->ops->check_power_status(host, REQ_BUS_ON);
+		}
 
 		pwr |= SDHCI_POWER_ON;
 
 		sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+		if (host->ops->check_power_status)
+			host->ops->check_power_status(host, REQ_BUS_ON);
 
 		if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
 			sdhci_runtime_pm_bus_on(host);
@@ -1736,6 +1750,8 @@  static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 		/* Set 1.8V Signal Enable in the Host Control2 register to 0 */
 		ctrl &= ~SDHCI_CTRL_VDD_180;
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+		if (host->ops->check_power_status)
+			host->ops->check_power_status(host, REQ_IO_HIGH);
 
 		if (!IS_ERR(mmc->supply.vqmmc)) {
 			ret = regulator_set_voltage(mmc->supply.vqmmc, 2700000,
@@ -1775,6 +1791,8 @@  static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
 		 */
 		ctrl |= SDHCI_CTRL_VDD_180;
 		sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+		if (host->ops->check_power_status)
+			host->ops->check_power_status(host, REQ_IO_LOW);
 
 		/* Some controller need to do more when switching */
 		if (host->ops->voltage_switch)
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 609f87c..5758cca 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -549,6 +549,11 @@  struct sdhci_ops {
 					 struct mmc_card *card,
 					 unsigned int max_dtr, int host_drv,
 					 int card_drv, int *drv_type);
+#define REQ_BUS_OFF	BIT(0)
+#define REQ_BUS_ON	BIT(1)
+#define REQ_IO_LOW	BIT(2)
+#define REQ_IO_HIGH	BIT(3)
+	void    (*check_power_status)(struct sdhci_host *host, u32 req_type);
 };
 
 #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS