From 8f3972f78f3ac52833fb781cbb689af39fc8b0f1 Mon Sep 17 00:00:00 2001 From: Jackson Chang Date: Fri, 5 Aug 2016 10:22:02 +0800 Subject: [PATCH] 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 Reviewed-by: Rui Miguel Silva Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/kernel_ver.h | 4 ++++ drivers/staging/greybus/sdio.c | 31 ++++++++++++++++++++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/drivers/staging/greybus/kernel_ver.h b/drivers/staging/greybus/kernel_ver.h index 5d13e36008d3..62d640013035 100644 --- a/drivers/staging/greybus/kernel_ver.h +++ b/drivers/staging/greybus/kernel_ver.h @@ -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 diff --git a/drivers/staging/greybus/sdio.c b/drivers/staging/greybus/sdio.c index ad448c6388bb..3d3599a8b077 100644 --- a/drivers/staging/greybus/sdio.c +++ b/drivers/staging/greybus/sdio.c @@ -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;