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

Commit ed919b01 authored by Ohad Ben-Cohen's avatar Ohad Ben-Cohen Committed by Chris Ball
Browse files

mmc: sdio: fix runtime PM anomalies by introducing MMC_CAP_POWER_OFF_CARD



Some board/card/host configurations are not capable of powering off the
card after boot.

To support such configurations, and to allow smoother transition to
runtime PM behavior, MMC_CAP_POWER_OFF_CARD is added, so hosts need to
explicitly indicate whether it's OK to power off their cards after boot.

SDIO core will enable runtime PM for a card only if that cap is set.
As a result, the card will be powered down after boot, and will only
be powered up again when a driver is loaded (and then it's up to the
driver to decide whether power will be kept or not).

This will prevent sdio_bus_probe() failures with setups that do not
support powering off the card.

Reported-and-tested-by: default avatarDaniel Drake <dsd@laptop.org>
Reported-and-tested-by: default avatarArnd Hannemann <arnd@arndnet.de>
Signed-off-by: default avatarOhad Ben-Cohen <ohad@wizery.com>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent 4d0812c3
Loading
Loading
Loading
Loading
+23 −14
Original line number Diff line number Diff line
@@ -547,9 +547,11 @@ static void mmc_sdio_detect(struct mmc_host *host)
	BUG_ON(!host->card);

	/* Make sure card is powered before detecting it */
	if (host->caps & MMC_CAP_POWER_OFF_CARD) {
		err = pm_runtime_get_sync(&host->card->dev);
		if (err < 0)
			goto out;
	}

	mmc_claim_host(host);

@@ -571,6 +573,7 @@ static void mmc_sdio_detect(struct mmc_host *host)
	 * 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:
@@ -727,6 +730,10 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
		goto err;
	card = host->card;

	/*
	 * Enable runtime PM only if supported by host+card+board
	 */
	if (host->caps & MMC_CAP_POWER_OFF_CARD) {
		/*
		 * Let runtime PM core know our card is active
		 */
@@ -738,6 +745,7 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
		 * Enable runtime PM for this card
		 */
		pm_runtime_enable(&card->dev);
	}

	/*
	 * The number of functions on the card is encoded inside
@@ -755,8 +763,9 @@ 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)
		 */
		if (host->caps & MMC_CAP_POWER_OFF_CARD)
			pm_runtime_enable(&card->sdio_func[i]->dev);
	}

+22 −11
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <linux/pm_runtime.h>

#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>

#include "sdio_cis.h"
@@ -132,9 +133,11 @@ static int sdio_bus_probe(struct device *dev)
	 * it should call pm_runtime_put_noidle() in its probe routine and
	 * pm_runtime_get_noresume() in its remove routine.
	 */
	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) {
		ret = pm_runtime_get_sync(dev);
		if (ret < 0)
			goto out;
	}

	/* Set the default block size so the driver is sure it's something
	 * sensible. */
@@ -151,6 +154,7 @@ static int sdio_bus_probe(struct device *dev)
	return 0;

disable_runtimepm:
	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
		pm_runtime_put_noidle(dev);
out:
	return ret;
@@ -160,12 +164,14 @@ static int sdio_bus_remove(struct device *dev)
{
	struct sdio_driver *drv = to_sdio_driver(dev->driver);
	struct sdio_func *func = dev_to_sdio_func(dev);
	int ret;
	int ret = 0;

	/* Make sure card is powered before invoking ->remove() */
	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) {
		ret = pm_runtime_get_sync(dev);
		if (ret < 0)
			goto out;
	}

	drv->remove(func);

@@ -178,9 +184,11 @@ static int sdio_bus_remove(struct device *dev)
	}

	/* First, undo the increment made directly above */
	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
		pm_runtime_put_noidle(dev);

	/* Then undo the runtime PM settings in sdio_bus_probe() */
	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
		pm_runtime_put_noidle(dev);

out:
@@ -191,6 +199,8 @@ out:

static int sdio_bus_pm_prepare(struct device *dev)
{
	struct sdio_func *func = dev_to_sdio_func(dev);

	/*
	 * Resume an SDIO device which was suspended at run time at this
	 * point, in order to allow standard SDIO suspend/resume paths
@@ -212,6 +222,7 @@ static int sdio_bus_pm_prepare(struct device *dev)
	 * since there is little point in failing system suspend if a
	 * device can't be resumed.
	 */
	if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
		pm_runtime_resume(dev);

	return 0;
+1 −0
Original line number Diff line number Diff line
@@ -168,6 +168,7 @@ struct mmc_host {
						/* DDR mode at 1.8V */
#define MMC_CAP_1_2V_DDR	(1 << 12)	/* can support */
						/* DDR mode at 1.2V */
#define MMC_CAP_POWER_OFF_CARD	(1 << 13)	/* Can power off after boot */

	mmc_pm_flag_t		pm_caps;	/* supported pm features */