]> git.karo-electronics.de Git - linux-beck.git/commitdiff
greybus: SDIO: Add runtime pm support
authorJackson Chang <chang_jackson@projectara.com>
Fri, 5 Aug 2016 02:22:02 +0000 (10:22 +0800)
committerGreg Kroah-Hartman <gregkh@google.com>
Fri, 5 Aug 2016 18:14:48 +0000 (20:14 +0200)
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>
drivers/staging/greybus/kernel_ver.h
drivers/staging/greybus/sdio.c

index 5d13e36008d3a6117ddbffddff53e3109b0bd64f..62d64001303565daeca28180f17cbd865d6f50d3 100644 (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
index ad448c6388bbf5ae29d214aca7734d8b9ca3a42b..3d3599a8b077fb66511d0285fa4274b8d8437263 100644 (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;