diff options
Diffstat (limited to 'drivers/mmc/core/sdio.c')
| -rw-r--r-- | drivers/mmc/core/sdio.c | 70 | 
1 files changed, 47 insertions, 23 deletions
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index c599a628a387..a86490dbca70 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -444,6 +444,7 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)  	unsigned int bus_speed, timing;  	int err;  	unsigned char speed; +	unsigned int max_rate;  	/*  	 * If the host doesn't support any of the UHS-I modes, fallback on @@ -500,9 +501,12 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)  	if (err)  		return err; +	max_rate = min_not_zero(card->quirk_max_rate, +				card->sw_caps.uhs_max_dtr); +  	if (bus_speed) {  		mmc_set_timing(card->host, timing); -		mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr); +		mmc_set_clock(card->host, max_rate);  	}  	return 0; @@ -788,6 +792,14 @@ try_again:  		if (err)  			goto remove;  	} + +	if (host->caps2 & MMC_CAP2_AVOID_3_3V && +	    host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) { +		pr_err("%s: Host failed to negotiate down from 3.3V\n", +			mmc_hostname(host)); +		err = -EINVAL; +		goto remove; +	}  finish:  	if (!oldcard)  		host->card = card; @@ -801,6 +813,22 @@ err:  	return err;  } +static int mmc_sdio_reinit_card(struct mmc_host *host, bool powered_resume) +{ +	int ret; + +	sdio_reset(host); +	mmc_go_idle(host); +	mmc_send_if_cond(host, host->card->ocr); + +	ret = mmc_send_io_op_cond(host, 0, NULL); +	if (ret) +		return ret; + +	return mmc_sdio_init_card(host, host->card->ocr, host->card, +				  powered_resume); +} +  /*   * Host is being removed. Free up the current card.   */ @@ -948,14 +976,7 @@ static int mmc_sdio_resume(struct mmc_host *host)  	/* No need to reinitialize powered-resumed nonremovable cards */  	if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) { -		sdio_reset(host); -		mmc_go_idle(host); -		mmc_send_if_cond(host, host->card->ocr); -		err = mmc_send_io_op_cond(host, 0, NULL); -		if (!err) -			err = mmc_sdio_init_card(host, host->card->ocr, -						 host->card, -						 mmc_card_keep_power(host)); +		err = mmc_sdio_reinit_card(host, mmc_card_keep_power(host));  	} else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {  		/* We may have switched to 1-bit mode during suspend */  		err = sdio_enable_4bit_bus(host->card); @@ -978,8 +999,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host)  {  	int ret; -	mmc_claim_host(host); -  	/*  	 * Reset the card by performing the same steps that are taken by  	 * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe. @@ -997,20 +1016,12 @@ static int mmc_sdio_power_restore(struct mmc_host *host)  	 *  	 */ -	sdio_reset(host); -	mmc_go_idle(host); -	mmc_send_if_cond(host, host->card->ocr); - -	ret = mmc_send_io_op_cond(host, 0, NULL); -	if (ret) -		goto out; +	mmc_claim_host(host); -	ret = mmc_sdio_init_card(host, host->card->ocr, host->card, -				mmc_card_keep_power(host)); +	ret = mmc_sdio_reinit_card(host, mmc_card_keep_power(host));  	if (!ret && host->sdio_irqs)  		mmc_signal_sdio_irq(host); -out:  	mmc_release_host(host);  	return ret; @@ -1039,12 +1050,24 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host)  	return ret;  } -static int mmc_sdio_reset(struct mmc_host *host) +static int mmc_sdio_hw_reset(struct mmc_host *host)  {  	mmc_power_cycle(host, host->card->ocr);  	return mmc_sdio_power_restore(host);  } +static int mmc_sdio_sw_reset(struct mmc_host *host) +{ +	mmc_set_clock(host, host->f_init); +	sdio_reset(host); +	mmc_go_idle(host); + +	mmc_set_initial_state(host); +	mmc_set_initial_signal_voltage(host); + +	return mmc_sdio_reinit_card(host, 0); +} +  static const struct mmc_bus_ops mmc_sdio_ops = {  	.remove = mmc_sdio_remove,  	.detect = mmc_sdio_detect, @@ -1055,7 +1078,8 @@ static const struct mmc_bus_ops mmc_sdio_ops = {  	.runtime_resume = mmc_sdio_runtime_resume,  	.power_restore = mmc_sdio_power_restore,  	.alive = mmc_sdio_alive, -	.reset = mmc_sdio_reset, +	.hw_reset = mmc_sdio_hw_reset, +	.sw_reset = mmc_sdio_sw_reset,  };  | 
