diff options
Diffstat (limited to 'drivers/mmc/core/sdio.c')
| -rw-r--r-- | drivers/mmc/core/sdio.c | 620 | 
1 files changed, 511 insertions, 109 deletions
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index c3ad1058cd3..e636d9e99e4 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -14,8 +14,10 @@  #include <linux/mmc/host.h>  #include <linux/mmc/card.h> +#include <linux/mmc/mmc.h>  #include <linux/mmc/sdio.h>  #include <linux/mmc/sdio_func.h> +#include <linux/mmc/sdio_ids.h>  #include "core.h"  #include "bus.h" @@ -31,6 +33,11 @@ static int sdio_read_fbr(struct sdio_func *func)  	int ret;  	unsigned char data; +	if (mmc_card_nonstd_func_interface(func->card)) { +		func->class = SDIO_CLASS_NONE; +		return 0; +	} +  	ret = mmc_io_rw_direct(func->card, 0, 0,  		SDIO_FBR_BASE(func->num) + SDIO_FBR_STD_IF, 0, &data);  	if (ret) @@ -91,11 +98,13 @@ fail:  	return ret;  } -static int sdio_read_cccr(struct mmc_card *card) +static int sdio_read_cccr(struct mmc_card *card, u32 ocr)  {  	int ret;  	int cccr_vsn; +	int uhs = ocr & R4_18V_PRESENT;  	unsigned char data; +	unsigned char speed;  	memset(&card->cccr, 0, sizeof(struct sdio_cccr)); @@ -105,8 +114,8 @@ static int sdio_read_cccr(struct mmc_card *card)  	cccr_vsn = data & 0x0f; -	if (cccr_vsn > SDIO_CCCR_REV_1_20) { -		printk(KERN_ERR "%s: unrecognised CCCR structure version %d\n", +	if (cccr_vsn > SDIO_CCCR_REV_3_00) { +		pr_err("%s: unrecognised CCCR structure version %d\n",  			mmc_hostname(card->host), cccr_vsn);  		return -EINVAL;  	} @@ -134,12 +143,57 @@ static int sdio_read_cccr(struct mmc_card *card)  	}  	if (cccr_vsn >= SDIO_CCCR_REV_1_20) { -		ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &data); +		ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed);  		if (ret)  			goto out; -		if (data & SDIO_SPEED_SHS) -			card->cccr.high_speed = 1; +		card->scr.sda_spec3 = 0; +		card->sw_caps.sd3_bus_mode = 0; +		card->sw_caps.sd3_drv_type = 0; +		if (cccr_vsn >= SDIO_CCCR_REV_3_00 && uhs) { +			card->scr.sda_spec3 = 1; +			ret = mmc_io_rw_direct(card, 0, 0, +				SDIO_CCCR_UHS, 0, &data); +			if (ret) +				goto out; + +			if (mmc_host_uhs(card->host)) { +				if (data & SDIO_UHS_DDR50) +					card->sw_caps.sd3_bus_mode +						|= SD_MODE_UHS_DDR50; + +				if (data & SDIO_UHS_SDR50) +					card->sw_caps.sd3_bus_mode +						|= SD_MODE_UHS_SDR50; + +				if (data & SDIO_UHS_SDR104) +					card->sw_caps.sd3_bus_mode +						|= SD_MODE_UHS_SDR104; +			} + +			ret = mmc_io_rw_direct(card, 0, 0, +				SDIO_CCCR_DRIVE_STRENGTH, 0, &data); +			if (ret) +				goto out; + +			if (data & SDIO_DRIVE_SDTA) +				card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_A; +			if (data & SDIO_DRIVE_SDTC) +				card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_C; +			if (data & SDIO_DRIVE_SDTD) +				card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_D; +		} + +		/* if no uhs mode ensure we check for high speed */ +		if (!card->sw_caps.sd3_bus_mode) { +			if (speed & SDIO_SPEED_SHS) { +				card->cccr.high_speed = 1; +				card->sw_caps.hs_max_dtr = 50000000; +			} else { +				card->cccr.high_speed = 0; +				card->sw_caps.hs_max_dtr = 25000000; +			} +		}  	}  out: @@ -161,6 +215,12 @@ static int sdio_enable_wide(struct mmc_card *card)  	if (ret)  		return ret; +	if ((ctrl & SDIO_BUS_WIDTH_MASK) == SDIO_BUS_WIDTH_RESERVED) +		pr_warning("%s: SDIO_CCCR_IF is invalid: 0x%02x\n", +			   mmc_hostname(card->host), ctrl); + +	/* set as 4-bit bus width */ +	ctrl &= ~SDIO_BUS_WIDTH_MASK;  	ctrl |= SDIO_BUS_WIDTH_4BIT;  	ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL); @@ -181,7 +241,7 @@ static int sdio_disable_cd(struct mmc_card *card)  	int ret;  	u8 ctrl; -	if (!card->cccr.disable_cd) +	if (!mmc_card_disable_cd(card))  		return 0;  	ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_IF, 0, &ctrl); @@ -303,7 +363,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)  {  	unsigned max_dtr; -	if (mmc_card_highspeed(card)) { +	if (mmc_card_hs(card)) {  		/*  		 * The SDIO specification doesn't mention how  		 * the CIS transfer speed register relates to @@ -321,6 +381,206 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)  	return max_dtr;  } +static unsigned char host_drive_to_sdio_drive(int host_strength) +{ +	switch (host_strength) { +	case MMC_SET_DRIVER_TYPE_A: +		return SDIO_DTSx_SET_TYPE_A; +	case MMC_SET_DRIVER_TYPE_B: +		return SDIO_DTSx_SET_TYPE_B; +	case MMC_SET_DRIVER_TYPE_C: +		return SDIO_DTSx_SET_TYPE_C; +	case MMC_SET_DRIVER_TYPE_D: +		return SDIO_DTSx_SET_TYPE_D; +	default: +		return SDIO_DTSx_SET_TYPE_B; +	} +} + +static void sdio_select_driver_type(struct mmc_card *card) +{ +	int host_drv_type = SD_DRIVER_TYPE_B; +	int card_drv_type = SD_DRIVER_TYPE_B; +	int drive_strength; +	unsigned char card_strength; +	int err; + +	/* +	 * If the host doesn't support any of the Driver Types A,C or D, +	 * or there is no board specific handler then default Driver +	 * Type B is used. +	 */ +	if (!(card->host->caps & +		(MMC_CAP_DRIVER_TYPE_A | +		 MMC_CAP_DRIVER_TYPE_C | +		 MMC_CAP_DRIVER_TYPE_D))) +		return; + +	if (!card->host->ops->select_drive_strength) +		return; + +	if (card->host->caps & MMC_CAP_DRIVER_TYPE_A) +		host_drv_type |= SD_DRIVER_TYPE_A; + +	if (card->host->caps & MMC_CAP_DRIVER_TYPE_C) +		host_drv_type |= SD_DRIVER_TYPE_C; + +	if (card->host->caps & MMC_CAP_DRIVER_TYPE_D) +		host_drv_type |= SD_DRIVER_TYPE_D; + +	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_A) +		card_drv_type |= SD_DRIVER_TYPE_A; + +	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_C) +		card_drv_type |= SD_DRIVER_TYPE_C; + +	if (card->sw_caps.sd3_drv_type & SD_DRIVER_TYPE_D) +		card_drv_type |= SD_DRIVER_TYPE_D; + +	/* +	 * The drive strength that the hardware can support +	 * depends on the board design.  Pass the appropriate +	 * information and let the hardware specific code +	 * return what is possible given the options +	 */ +	drive_strength = card->host->ops->select_drive_strength( +		card->sw_caps.uhs_max_dtr, +		host_drv_type, card_drv_type); + +	/* if error just use default for drive strength B */ +	err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_DRIVE_STRENGTH, 0, +		&card_strength); +	if (err) +		return; + +	card_strength &= ~(SDIO_DRIVE_DTSx_MASK<<SDIO_DRIVE_DTSx_SHIFT); +	card_strength |= host_drive_to_sdio_drive(drive_strength); + +	err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_DRIVE_STRENGTH, +		card_strength, NULL); + +	/* if error default to drive strength B */ +	if (!err) +		mmc_set_driver_type(card->host, drive_strength); +} + + +static int sdio_set_bus_speed_mode(struct mmc_card *card) +{ +	unsigned int bus_speed, timing; +	int err; +	unsigned char speed; + +	/* +	 * If the host doesn't support any of the UHS-I modes, fallback on +	 * default speed. +	 */ +	if (!mmc_host_uhs(card->host)) +		return 0; + +	bus_speed = SDIO_SPEED_SDR12; +	timing = MMC_TIMING_UHS_SDR12; +	if ((card->host->caps & MMC_CAP_UHS_SDR104) && +	    (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) { +			bus_speed = SDIO_SPEED_SDR104; +			timing = MMC_TIMING_UHS_SDR104; +			card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR; +			card->sd_bus_speed = UHS_SDR104_BUS_SPEED; +	} else if ((card->host->caps & MMC_CAP_UHS_DDR50) && +		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) { +			bus_speed = SDIO_SPEED_DDR50; +			timing = MMC_TIMING_UHS_DDR50; +			card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR; +			card->sd_bus_speed = UHS_DDR50_BUS_SPEED; +	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | +		    MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode & +		    SD_MODE_UHS_SDR50)) { +			bus_speed = SDIO_SPEED_SDR50; +			timing = MMC_TIMING_UHS_SDR50; +			card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR; +			card->sd_bus_speed = UHS_SDR50_BUS_SPEED; +	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | +		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) && +		   (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) { +			bus_speed = SDIO_SPEED_SDR25; +			timing = MMC_TIMING_UHS_SDR25; +			card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR; +			card->sd_bus_speed = UHS_SDR25_BUS_SPEED; +	} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 | +		    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 | +		    MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode & +		    SD_MODE_UHS_SDR12)) { +			bus_speed = SDIO_SPEED_SDR12; +			timing = MMC_TIMING_UHS_SDR12; +			card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR; +			card->sd_bus_speed = UHS_SDR12_BUS_SPEED; +	} + +	err = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_SPEED, 0, &speed); +	if (err) +		return err; + +	speed &= ~SDIO_SPEED_BSS_MASK; +	speed |= bus_speed; +	err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL); +	if (err) +		return err; + +	if (bus_speed) { +		mmc_set_timing(card->host, timing); +		mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr); +	} + +	return 0; +} + +/* + * UHS-I specific initialization procedure + */ +static int mmc_sdio_init_uhs_card(struct mmc_card *card) +{ +	int err; + +	if (!card->scr.sda_spec3) +		return 0; + +	/* +	 * Switch to wider bus (if supported). +	 */ +	if (card->host->caps & MMC_CAP_4_BIT_DATA) { +		err = sdio_enable_4bit_bus(card); +		if (err > 0) { +			mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); +			err = 0; +		} +	} + +	/* Set the driver strength for the card */ +	sdio_select_driver_type(card); + +	/* Set bus speed mode of the card */ +	err = sdio_set_bus_speed_mode(card); +	if (err) +		goto out; + +	/* +	 * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and +	 * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104. +	 */ +	if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning && +			((card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50) || +			 (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104))) { +		mmc_host_clk_hold(card->host); +		err = card->host->ops->execute_tuning(card->host, +						      MMC_SEND_TUNING_BLOCK); +		mmc_host_clk_release(card->host); +	} + +out: + +	return err; +} +  /*   * Handle the detection and initialisation of a card.   * @@ -332,15 +592,29 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,  {  	struct mmc_card *card;  	int err; +	int retries = 10; +	u32 rocr = 0; +	u32 ocr_card = ocr;  	BUG_ON(!host);  	WARN_ON(!host->claimed); +	/* to query card if 1.8V signalling is supported */ +	if (mmc_host_uhs(host)) +		ocr |= R4_18V_PRESENT; + +try_again: +	if (!retries) { +		pr_warning("%s: Skipping voltage switch\n", +				mmc_hostname(host)); +		ocr &= ~R4_18V_PRESENT; +	} +  	/*  	 * Inform the card of the voltage  	 */  	if (!powered_resume) { -		err = mmc_send_io_op_cond(host, host->ocr, &ocr); +		err = mmc_send_io_op_cond(host, ocr, &rocr);  		if (err)  			goto err;  	} @@ -363,8 +637,8 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,  		goto err;  	} -	if (ocr & R4_MEMORY_PRESENT -	    && mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid) == 0) { +	if ((rocr & R4_MEMORY_PRESENT) && +	    mmc_sd_get_cid(host, ocr & rocr, card->raw_cid, NULL) == 0) {  		card->type = MMC_TYPE_SD_COMBO;  		if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO || @@ -388,6 +662,31 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,  		host->ops->init_card(host, card);  	/* +	 * If the host and card support UHS-I mode request the card +	 * to switch to 1.8V signaling level.  No 1.8v signalling if +	 * UHS mode is not enabled to maintain compatibility and some +	 * systems that claim 1.8v signalling in fact do not support +	 * it. +	 */ +	if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) { +		err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180, +					ocr); +		if (err == -EAGAIN) { +			sdio_reset(host); +			mmc_go_idle(host); +			mmc_send_if_cond(host, host->ocr_avail); +			mmc_remove_card(card); +			retries--; +			goto try_again; +		} else if (err) { +			ocr &= ~R4_18V_PRESENT; +		} +		err = 0; +	} else { +		ocr &= ~R4_18V_PRESENT; +	} + +	/*  	 * For native busses:  set card RCA and quit open drain mode.  	 */  	if (!powered_resume && !mmc_host_is_spi(host)) { @@ -395,7 +694,13 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,  		if (err)  			goto remove; -		mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL); +		/* +		 * Update oldcard with the new RCA received from the SDIO +		 * device -- we're doing this so that it's updated in the +		 * "card" struct when oldcard overwrites that later. +		 */ +		if (oldcard) +			oldcard->rca = card->rca;  	}  	/* @@ -428,7 +733,6 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,  		mmc_set_clock(host, card->cis.max_dtr);  		if (card->cccr.high_speed) { -			mmc_card_set_highspeed(card);  			mmc_set_timing(card->host, MMC_TIMING_SD_HS);  		} @@ -438,7 +742,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,  	/*  	 * Read the common registers.  	 */ -	err = sdio_read_cccr(card); +	err = sdio_read_cccr(card, ocr);  	if (err)  		goto remove; @@ -458,6 +762,8 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,  		card = oldcard;  	} +	card->ocr = ocr_card; +	mmc_fixup_device(card, NULL);  	if (card->type == MMC_TYPE_SD_COMBO) {  		err = mmc_sd_setup_card(host, card, oldcard != NULL); @@ -479,29 +785,36 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,  	if (err)  		goto remove; -	/* -	 * Switch to high-speed (if supported). -	 */ -	err = sdio_enable_hs(card); -	if (err > 0) -		mmc_sd_go_highspeed(card); -	else if (err) -		goto remove; - -	/* -	 * Change to the card's maximum speed. -	 */ -	mmc_set_clock(host, mmc_sdio_get_max_clock(card)); +	/* Initialization sequence for UHS-I cards */ +	/* Only if card supports 1.8v and UHS signaling */ +	if ((ocr & R4_18V_PRESENT) && card->sw_caps.sd3_bus_mode) { +		err = mmc_sdio_init_uhs_card(card); +		if (err) +			goto remove; +	} else { +		/* +		 * Switch to high-speed (if supported). +		 */ +		err = sdio_enable_hs(card); +		if (err > 0) +			mmc_set_timing(card->host, MMC_TIMING_SD_HS); +		else if (err) +			goto remove; -	/* -	 * Switch to wider bus (if supported). -	 */ -	err = sdio_enable_4bit_bus(card); -	if (err > 0) -		mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); -	else if (err) -		goto remove; +		/* +		 * Change to the card's maximum speed. +		 */ +		mmc_set_clock(host, mmc_sdio_get_max_clock(card)); +		/* +		 * Switch to wider bus (if supported). +		 */ +		err = sdio_enable_4bit_bus(card); +		if (err > 0) +			mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); +		else if (err) +			goto remove; +	}  finish:  	if (!oldcard)  		host->card = card; @@ -537,6 +850,14 @@ static void mmc_sdio_remove(struct mmc_host *host)  }  /* + * Card detection - card is alive. + */ +static int mmc_sdio_alive(struct mmc_host *host) +{ +	return mmc_select_card(host->card); +} + +/*   * Card detection callback from host.   */  static void mmc_sdio_detect(struct mmc_host *host) @@ -547,38 +868,54 @@ static void mmc_sdio_detect(struct mmc_host *host)  	BUG_ON(!host->card);  	/* Make sure card is powered before detecting it */ -	err = pm_runtime_get_sync(&host->card->dev); -	if (err < 0) -		goto out; +	if (host->caps & MMC_CAP_POWER_OFF_CARD) { +		err = pm_runtime_get_sync(&host->card->dev); +		if (err < 0) { +			pm_runtime_put_noidle(&host->card->dev); +			goto out; +		} +	}  	mmc_claim_host(host);  	/*  	 * Just check if our card has been removed.  	 */ -	err = mmc_select_card(host->card); +	err = _mmc_detect_card_removed(host);  	mmc_release_host(host); +	/* +	 * Tell PM core it's OK to power off the card now. +	 * +	 * The _sync variant is used in order to ensure that the card +	 * is left powered off in case an error occurred, and the card +	 * is going to be removed. +	 * +	 * Since there is no specific reason to believe a new user +	 * is about to show up at this point, the _sync variant is +	 * desirable anyway. +	 */ +	if (host->caps & MMC_CAP_POWER_OFF_CARD) +		pm_runtime_put_sync(&host->card->dev); +  out:  	if (err) {  		mmc_sdio_remove(host);  		mmc_claim_host(host);  		mmc_detach_bus(host); +		mmc_power_off(host);  		mmc_release_host(host);  	} - -	/* Tell PM core that we're done */ -	pm_runtime_put(&host->card->dev);  }  /* - * SDIO suspend.  We need to suspend all functions separately. + * SDIO pre_suspend.  We need to suspend all functions separately.   * Therefore all registered functions must have drivers with suspend   * and resume methods.  Failing that we simply remove the whole card.   */ -static int mmc_sdio_suspend(struct mmc_host *host) +static int mmc_sdio_pre_suspend(struct mmc_host *host)  {  	int i, err = 0; @@ -589,62 +926,77 @@ static int mmc_sdio_suspend(struct mmc_host *host)  			if (!pmops || !pmops->suspend || !pmops->resume) {  				/* force removal of entire card in that case */  				err = -ENOSYS; -			} else -				err = pmops->suspend(&func->dev); -			if (err)  				break; -		} -	} -	while (err && --i >= 0) { -		struct sdio_func *func = host->card->sdio_func[i]; -		if (func && sdio_func_present(func) && func->dev.driver) { -			const struct dev_pm_ops *pmops = func->dev.driver->pm; -			pmops->resume(&func->dev); +			}  		}  	} -	if (!err && host->pm_flags & MMC_PM_KEEP_POWER) { +	return err; +} + +/* + * SDIO suspend.  Suspend all functions separately. + */ +static int mmc_sdio_suspend(struct mmc_host *host) +{ +	if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {  		mmc_claim_host(host);  		sdio_disable_wide(host->card);  		mmc_release_host(host);  	} -	return err; +	if (!mmc_card_keep_power(host)) +		mmc_power_off(host); + +	return 0;  }  static int mmc_sdio_resume(struct mmc_host *host)  { -	int i, err; +	int err = 0;  	BUG_ON(!host);  	BUG_ON(!host->card);  	/* Basic card reinitialization. */  	mmc_claim_host(host); -	err = mmc_sdio_init_card(host, host->ocr, host->card, -				 (host->pm_flags & MMC_PM_KEEP_POWER)); -	if (!err && host->sdio_irqs) -		mmc_signal_sdio_irq(host); -	mmc_release_host(host); -	/* -	 * If the card looked to be the same as before suspending, then -	 * we proceed to resume all card functions.  If one of them returns -	 * an error then we simply return that error to the core and the -	 * card will be redetected as new.  It is the responsibility of -	 * the function driver to perform further tests with the extra -	 * knowledge it has of the card to confirm the card is indeed the -	 * same as before suspending (same MAC address for network cards, -	 * etc.) and return an error otherwise. -	 */ -	for (i = 0; !err && i < host->card->sdio_funcs; i++) { -		struct sdio_func *func = host->card->sdio_func[i]; -		if (func && sdio_func_present(func) && func->dev.driver) { -			const struct dev_pm_ops *pmops = func->dev.driver->pm; -			err = pmops->resume(&func->dev); +	/* Restore power if needed */ +	if (!mmc_card_keep_power(host)) { +		mmc_power_up(host, host->card->ocr); +		/* +		 * Tell runtime PM core we just powered up the card, +		 * since it still believes the card is powered off. +		 * Note that currently runtime PM is only enabled +		 * for SDIO cards that are MMC_CAP_POWER_OFF_CARD +		 */ +		if (host->caps & MMC_CAP_POWER_OFF_CARD) { +			pm_runtime_disable(&host->card->dev); +			pm_runtime_set_active(&host->card->dev); +			pm_runtime_enable(&host->card->dev);  		}  	} +	/* 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); +		err = mmc_sdio_init_card(host, host->card->ocr, host->card, +					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); +		if (err > 0) { +			mmc_set_bus_width(host, MMC_BUS_WIDTH_4); +			err = 0; +		} +	} + +	if (!err && host->sdio_irqs) +		wake_up_process(host->sdio_irq_thread); +	mmc_release_host(host); + +	host->pm_flags &= ~MMC_PM_KEEP_POWER;  	return err;  } @@ -656,55 +1008,97 @@ static int mmc_sdio_power_restore(struct mmc_host *host)  	BUG_ON(!host->card);  	mmc_claim_host(host); -	ret = mmc_sdio_init_card(host, host->ocr, host->card, -			(host->pm_flags & MMC_PM_KEEP_POWER)); + +	/* +	 * Reset the card by performing the same steps that are taken by +	 * mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe. +	 * +	 * sdio_reset() is technically not needed. Having just powered up the +	 * hardware, it should already be in reset state. However, some +	 * platforms (such as SD8686 on OLPC) do not instantly cut power, +	 * meaning that a reset is required when restoring power soon after +	 * powering off. It is harmless in other cases. +	 * +	 * The CMD5 reset (mmc_send_io_op_cond()), according to the SDIO spec, +	 * is not necessary for non-removable cards. However, it is required +	 * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and +	 * harmless in other situations. +	 * +	 */ + +	sdio_reset(host); +	mmc_go_idle(host); +	mmc_send_if_cond(host, host->ocr_avail); + +	ret = mmc_send_io_op_cond(host, 0, NULL); +	if (ret) +		goto out; + +	ret = mmc_sdio_init_card(host, host->card->ocr, host->card, +				mmc_card_keep_power(host));  	if (!ret && host->sdio_irqs)  		mmc_signal_sdio_irq(host); + +out:  	mmc_release_host(host);  	return ret;  } +static int mmc_sdio_runtime_suspend(struct mmc_host *host) +{ +	/* No references to the card, cut the power to it. */ +	mmc_power_off(host); +	return 0; +} + +static int mmc_sdio_runtime_resume(struct mmc_host *host) +{ +	/* Restore power and re-initialize. */ +	mmc_power_up(host, host->card->ocr); +	return mmc_sdio_power_restore(host); +} +  static const struct mmc_bus_ops mmc_sdio_ops = {  	.remove = mmc_sdio_remove,  	.detect = mmc_sdio_detect, +	.pre_suspend = mmc_sdio_pre_suspend,  	.suspend = mmc_sdio_suspend,  	.resume = mmc_sdio_resume, +	.runtime_suspend = mmc_sdio_runtime_suspend, +	.runtime_resume = mmc_sdio_runtime_resume,  	.power_restore = mmc_sdio_power_restore, +	.alive = mmc_sdio_alive,  };  /*   * Starting point for SDIO card init.   */ -int mmc_attach_sdio(struct mmc_host *host, u32 ocr) +int mmc_attach_sdio(struct mmc_host *host)  { -	int err; -	int i, funcs; +	int err, i, funcs; +	u32 ocr, rocr;  	struct mmc_card *card;  	BUG_ON(!host);  	WARN_ON(!host->claimed); +	err = mmc_send_io_op_cond(host, 0, &ocr); +	if (err) +		return err; +  	mmc_attach_bus(host, &mmc_sdio_ops); +	if (host->ocr_avail_sdio) +		host->ocr_avail = host->ocr_avail_sdio; -	/* -	 * Sanity check the voltages that the card claims to -	 * support. -	 */ -	if (ocr & 0x7F) { -		printk(KERN_WARNING "%s: card claims to support voltages " -		       "below the defined range. These will be ignored.\n", -		       mmc_hostname(host)); -		ocr &= ~0x7F; -	} -	host->ocr = mmc_select_voltage(host, ocr); +	rocr = mmc_select_voltage(host, ocr);  	/*  	 * Can we support the voltage(s) of the card(s)?  	 */ -	if (!host->ocr) { +	if (!rocr) {  		err = -EINVAL;  		goto err;  	} @@ -712,22 +1106,28 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)  	/*  	 * Detect and init the card.  	 */ -	err = mmc_sdio_init_card(host, host->ocr, NULL, 0); +	err = mmc_sdio_init_card(host, rocr, NULL, 0);  	if (err)  		goto err; +  	card = host->card;  	/* -	 * Let runtime PM core know our card is active +	 * Enable runtime PM only if supported by host+card+board  	 */ -	err = pm_runtime_set_active(&card->dev); -	if (err) -		goto remove; +	if (host->caps & MMC_CAP_POWER_OFF_CARD) { +		/* +		 * Let runtime PM core know our card is active +		 */ +		err = pm_runtime_set_active(&card->dev); +		if (err) +			goto remove; -	/* -	 * Enable runtime PM for this card -	 */ -	pm_runtime_enable(&card->dev); +		/* +		 * Enable runtime PM for this card +		 */ +		pm_runtime_enable(&card->dev); +	}  	/*  	 * The number of functions on the card is encoded inside @@ -745,16 +1145,16 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)  			goto remove;  		/* -		 * Enable Runtime PM for this func +		 * Enable Runtime PM for this func (if supported)  		 */ -		pm_runtime_enable(&card->sdio_func[i]->dev); +		if (host->caps & MMC_CAP_POWER_OFF_CARD) +			pm_runtime_enable(&card->sdio_func[i]->dev);  	} -	mmc_release_host(host); -  	/*  	 * First add the card to the driver model...  	 */ +	mmc_release_host(host);  	err = mmc_add_card(host->card);  	if (err)  		goto remove_added; @@ -768,6 +1168,7 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)  			goto remove_added;  	} +	mmc_claim_host(host);  	return 0; @@ -777,13 +1178,14 @@ remove_added:  	mmc_claim_host(host);  remove:  	/* And with lock if it hasn't been added. */ +	mmc_release_host(host);  	if (host->card)  		mmc_sdio_remove(host); +	mmc_claim_host(host);  err:  	mmc_detach_bus(host); -	mmc_release_host(host); -	printk(KERN_ERR "%s: error %d whilst initialising SDIO card\n", +	pr_err("%s: error %d whilst initialising SDIO card\n",  		mmc_hostname(host), err);  	return err;  | 
