greybus: SDIO: Add runtime pm support

Modify SDIO greybus driver to support runtime PM framework.
To enable SDIO runtime PM, it needs to remove MMC_CAP_NEEDS_POLL
and add MMC_CAP2_CORE_RUNTIME_PM in set_host_caps().
The suspend function and resume function have been tested
with micron-sdio image by sysfs. SDIO functions work well
on suspend/resume.

Testing Done: Compiled and verified on EVT2.0 + Micron ARA
              SD module with USB connector

Signed-off-by: Jackson Chang <chang_jackson@projectara.com>
Reviewed-by: Rui Miguel Silva <rui.silva@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Jackson Chang 2016-08-05 10:22:02 +08:00 committed by Greg Kroah-Hartman
parent 591c45227a
commit 8f3972f78f
2 changed files with 31 additions and 4 deletions

View File

@ -140,6 +140,10 @@ static inline void sysfs_remove_groups(struct kobject *kobj,
#define MMC_DDR52_DEFINED
#endif
#ifndef MMC_CAP2_CORE_RUNTIME_PM
#define MMC_CAP2_CORE_RUNTIME_PM 0
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
#define MMC_POWER_UNDEFINED_SUPPORTED
#endif

View File

@ -84,8 +84,8 @@ static void _gb_sdio_set_host_caps(struct gb_sdio_host *host, u32 r)
#endif
((r & GB_SDIO_CAP_HS200_1_8V) ? MMC_CAP2_HS200_1_8V_SDR : 0);
host->mmc->caps = caps | MMC_CAP_NEEDS_POLL;
host->mmc->caps2 = caps2;
host->mmc->caps = caps;
host->mmc->caps2 = caps2 | MMC_CAP2_CORE_RUNTIME_PM;
if (caps & MMC_CAP_NONREMOVABLE)
host->card_present = true;
@ -239,8 +239,18 @@ static int gb_sdio_request_handler(struct gb_operation *op)
static int gb_sdio_set_ios(struct gb_sdio_host *host,
struct gb_sdio_set_ios_request *request)
{
return gb_operation_sync(host->connection, GB_SDIO_TYPE_SET_IOS,
request, sizeof(*request), NULL, 0);
int ret;
ret = gbphy_runtime_get_sync(host->gbphy_dev);
if (ret)
return ret;
ret = gb_operation_sync(host->connection, GB_SDIO_TYPE_SET_IOS, request,
sizeof(*request), NULL, 0);
gbphy_runtime_put_autosuspend(host->gbphy_dev);
return ret;
}
static int _gb_sdio_send(struct gb_sdio_host *host, struct mmc_data *data,
@ -489,10 +499,15 @@ static void gb_sdio_mrq_work(struct work_struct *work)
host = container_of(work, struct gb_sdio_host, mrqwork);
ret = gbphy_runtime_get_sync(host->gbphy_dev);
if (ret)
return;
mutex_lock(&host->lock);
mrq = host->mrq;
if (!mrq) {
mutex_unlock(&host->lock);
gbphy_runtime_put_autosuspend(host->gbphy_dev);
dev_err(mmc_dev(host->mmc), "mmc request is NULL");
return;
}
@ -528,6 +543,7 @@ done:
host->mrq = NULL;
mutex_unlock(&host->lock);
mmc_request_done(host->mmc, mrq);
gbphy_runtime_put_autosuspend(host->gbphy_dev);
}
static void gb_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
@ -813,6 +829,8 @@ static int gb_sdio_probe(struct gbphy_device *gbphy_dev,
ret = _gb_sdio_process_events(host, host->queued_events);
host->queued_events = 0;
gbphy_runtime_put_autosuspend(gbphy_dev);
return ret;
exit_wq_destroy:
@ -832,6 +850,11 @@ static void gb_sdio_remove(struct gbphy_device *gbphy_dev)
struct gb_sdio_host *host = gb_gbphy_get_data(gbphy_dev);
struct gb_connection *connection = host->connection;
struct mmc_host *mmc;
int ret;
ret = gbphy_runtime_get_sync(gbphy_dev);
if (ret)
gbphy_runtime_get_noresume(gbphy_dev);
mutex_lock(&host->lock);
host->removed = true;