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

Commit 7e63010c authored by Asutosh Das's avatar Asutosh Das Committed by Stephen Boyd
Browse files

mmc: core: add wakeup functionality to sdio cards



This patch initializes wakeup source if the detected card
is a sdio card and enables the wakeup capability.

Platform drivers would have to invoke:
 * pm_wakeup_event on this card device to signal a wakeup
 * corresponding pm_relax have to be invoked

Change-Id: Ic8d5c98073e8ed3f676eb42fc0ce1f13a11cb40f
Signed-off-by: default avatarAsutosh Das <asutoshd@codeaurora.org>
parent f43b712d
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -419,6 +419,12 @@ int mmc_add_card(struct mmc_card *card)
			pm_runtime_enable(&card->dev);
	}

	if (mmc_card_sdio(card)) {
		ret = device_init_wakeup(&card->dev, true);
		if (ret)
			pr_err("%s: %s: failed to init wakeup: %d\n",
			       mmc_hostname(card->host), __func__, ret);
	}
	ret = device_add(&card->dev);
	if (ret)
		return ret;
+25 −0
Original line number Diff line number Diff line
@@ -81,16 +81,40 @@ static int mmc_host_suspend(struct device *dev)
{
	struct mmc_host *host = cls_dev_to_mmc_host(dev);
	int ret = 0;
	unsigned long flags;

	if (!mmc_use_core_runtime_pm(host))
		return 0;

	spin_lock_irqsave(&host->clk_lock, flags);
	/*
	 * let the driver know that suspend is in progress and must
	 * be aborted on receiving a sdio card interrupt
	 */
	host->dev_status = DEV_SUSPENDING;
	spin_unlock_irqrestore(&host->clk_lock, flags);
	if (!pm_runtime_suspended(dev)) {
		ret = mmc_suspend_host(host);
		if (ret < 0)
			pr_err("%s: %s: failed: ret: %d\n", mmc_hostname(host),
			       __func__, ret);
	}
	/*
	 * If SDIO function driver doesn't want to power off the card,
	 * atleast turn off clocks to allow deep sleep.
	 */
	if (!ret && host->card && mmc_card_sdio(host->card) &&
	    host->ios.clock) {
		spin_lock_irqsave(&host->clk_lock, flags);
		host->clk_old = host->ios.clock;
		host->ios.clock = 0;
		host->clk_gated = true;
		spin_unlock_irqrestore(&host->clk_lock, flags);
		mmc_set_ios(host);
	}
	spin_lock_irqsave(&host->clk_lock, flags);
	host->dev_status = DEV_SUSPENDED;
	spin_unlock_irqrestore(&host->clk_lock, flags);
	return ret;
}

@@ -108,6 +132,7 @@ static int mmc_host_resume(struct device *dev)
			pr_err("%s: %s: failed: ret: %d\n", mmc_hostname(host),
			       __func__, ret);
	}
	host->dev_status = DEV_RESUMED;
	return ret;
}

+18 −0
Original line number Diff line number Diff line
@@ -85,6 +85,7 @@ static int sdio_irq_thread(void *_host)
	struct sched_param param = { .sched_priority = 1 };
	unsigned long period, idle_period;
	int ret;
	bool ws;

	sched_setscheduler(current, SCHED_FIFO, &param);

@@ -118,6 +119,17 @@ static int sdio_irq_thread(void *_host)
		ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
		if (ret)
			break;
		ws = false;
		/*
		 * prevent suspend if it has started when scheduled;
		 * 100 msec (approx. value) should be enough for the system to
		 * resume and attend to the card's request
		 */
		if ((host->dev_status == DEV_SUSPENDING) ||
		    (host->dev_status == DEV_SUSPENDED)) {
			pm_wakeup_event(&host->card->dev, 100);
			ws = true;
		}
		ret = process_sdio_pending_irqs(host);
		host->sdio_irq_pending = false;
		mmc_release_host(host);
@@ -154,6 +166,12 @@ static int sdio_irq_thread(void *_host)
			host->ops->enable_sdio_irq(host, 1);
			mmc_host_clk_release(host);
		}
		/*
		 * function drivers would have processed the event from card
		 * unless suspended, hence release wake source
		 */
		if (ws && (host->dev_status == DEV_RESUMED))
			pm_relax(&host->card->dev);
		if (!kthread_should_stop())
			schedule_timeout(period);
		set_current_state(TASK_RUNNING);
+7 −0
Original line number Diff line number Diff line
@@ -220,6 +220,12 @@ struct mmc_supply {
	struct regulator *vqmmc;	/* Optional Vccq supply */
};

enum dev_state {
	DEV_SUSPENDING = 1,
	DEV_SUSPENDED,
	DEV_RESUMED,
};

struct mmc_host {
	struct device		*parent;
	struct device		class_dev;
@@ -434,6 +440,7 @@ struct mmc_host {
		struct delayed_work work;
		enum mmc_load	state;
	} clk_scaling;
	enum dev_state dev_status;
	unsigned long		private[0] ____cacheline_aligned;
};