diff options
| author | Asutosh Das <asutoshd@codeaurora.org> | 2014-12-04 23:05:50 +0200 |
|---|---|---|
| committer | Subhash Jadavani <subhashj@codeaurora.org> | 2016-05-31 15:25:51 -0700 |
| commit | 3c0c23354a0c200f2f52c4be8de85f8949daa0c4 (patch) | |
| tree | ea146fdf51dbfc5fdc446c06728e12b49d19d56d | |
| parent | 358ac29e04226897063b5f3be85d9eb636b99820 (diff) | |
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: Asutosh Das <asutoshd@codeaurora.org>
[merez@codeaurora.org: fix conflicts due to different PM in 3.14]
Signed-off-by: Maya Erez <merez@codeaurora.org>
[subhashj@codeaurora.org: fixed trivial merge conflicts]
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
| -rw-r--r-- | drivers/mmc/core/bus.c | 6 | ||||
| -rw-r--r-- | drivers/mmc/core/sdio_irq.c | 18 | ||||
| -rw-r--r-- | include/linux/mmc/host.h | 7 |
3 files changed, 31 insertions, 0 deletions
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 15e94c25b06e..4a542d6bf509 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -361,6 +361,12 @@ int mmc_add_card(struct mmc_card *card) card->dev.of_node = mmc_of_find_child_device(card->host, 0); + 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; diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 09cc67d028f0..b95f942aea0e 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -104,6 +104,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, ¶m); @@ -137,6 +138,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); @@ -173,6 +185,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); diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 8b459bdcc797..82cb8b901e8b 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -218,6 +218,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; @@ -447,6 +453,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; }; |
