Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6e633ad authored by Daniel Drake's avatar Daniel Drake Committed by Chris Ball
Browse files

mmc: sdio: reset card during power_restore



mmc_sdio_power_restore() skips some steps that are performed in other
power-related codepaths which are necessary to fully reset the card.
Without this, runtime PM fails for SD8686 SDIO wifi on OLPC XO-1.5.

Signed-off-by: default avatarDaniel Drake <dsd@laptop.org>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent e9e8bcb8
Loading
Loading
Loading
Loading
+39 −0
Original line number Original line Diff line number Diff line
@@ -691,15 +691,54 @@ static int mmc_sdio_resume(struct mmc_host *host)
static int mmc_sdio_power_restore(struct mmc_host *host)
static int mmc_sdio_power_restore(struct mmc_host *host)
{
{
	int ret;
	int ret;
	u32 ocr;


	BUG_ON(!host);
	BUG_ON(!host);
	BUG_ON(!host->card);
	BUG_ON(!host->card);


	mmc_claim_host(host);
	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.
	 *
	 * 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.
	 *
	 * With these steps taken, mmc_select_voltage() is also required to
	 * restore the correct voltage setting of the card.
	 */
	sdio_reset(host);
	mmc_go_idle(host);
	mmc_send_if_cond(host, host->ocr_avail);

	ret = mmc_send_io_op_cond(host, 0, &ocr);
	if (ret)
		goto out;

	if (host->ocr_avail_sdio)
		host->ocr_avail = host->ocr_avail_sdio;

	host->ocr = mmc_select_voltage(host, ocr & ~0x7F);
	if (!host->ocr) {
		ret = -EINVAL;
		goto out;
	}

	ret = mmc_sdio_init_card(host, host->ocr, host->card,
	ret = mmc_sdio_init_card(host, host->ocr, host->card,
				mmc_card_keep_power(host));
				mmc_card_keep_power(host));
	if (!ret && host->sdio_irqs)
	if (!ret && host->sdio_irqs)
		mmc_signal_sdio_irq(host);
		mmc_signal_sdio_irq(host);

out:
	mmc_release_host(host);
	mmc_release_host(host);


	return ret;
	return ret;