Merge tag 'docs-5.0-fixes' of git://git.lwn.net/linux
[linux-2.6-microblaze.git] / drivers / mmc / host / rtsx_usb_sdmmc.c
index 9a3ff22..669c6ab 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/mmc/sd.h>
 #include <linux/mmc/card.h>
 #include <linux/scatterlist.h>
+#include <linux/pm.h>
 #include <linux/pm_runtime.h>
 
 #include <linux/rtsx_usb.h>
@@ -1042,9 +1043,9 @@ static int sd_set_power_mode(struct rtsx_usb_sdmmc *host,
 
        if (power_mode == MMC_POWER_OFF) {
                err = sd_power_off(host);
-               pm_runtime_put(sdmmc_dev(host));
+               pm_runtime_put_noidle(sdmmc_dev(host));
        } else {
-               pm_runtime_get_sync(sdmmc_dev(host));
+               pm_runtime_get_noresume(sdmmc_dev(host));
                err = sd_power_on(host);
        }
 
@@ -1297,16 +1298,20 @@ static void rtsx_usb_update_led(struct work_struct *work)
                container_of(work, struct rtsx_usb_sdmmc, led_work);
        struct rtsx_ucr *ucr = host->ucr;
 
-       pm_runtime_get_sync(sdmmc_dev(host));
+       pm_runtime_get_noresume(sdmmc_dev(host));
        mutex_lock(&ucr->dev_mutex);
 
+       if (host->power_mode == MMC_POWER_OFF)
+               goto out;
+
        if (host->led.brightness == LED_OFF)
                rtsx_usb_turn_off_led(ucr);
        else
                rtsx_usb_turn_on_led(ucr);
 
+out:
        mutex_unlock(&ucr->dev_mutex);
-       pm_runtime_put(sdmmc_dev(host));
+       pm_runtime_put_sync_suspend(sdmmc_dev(host));
 }
 #endif
 
@@ -1320,7 +1325,7 @@ static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host)
        mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED |
                MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST |
                MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 |
-               MMC_CAP_NEEDS_POLL | MMC_CAP_ERASE;
+               MMC_CAP_ERASE | MMC_CAP_SYNC_RUNTIME_PM;
        mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE |
                MMC_CAP2_NO_SDIO;
 
@@ -1363,8 +1368,6 @@ static int rtsx_usb_sdmmc_drv_probe(struct platform_device *pdev)
 
        mutex_init(&host->host_mutex);
        rtsx_usb_init_host(host);
-       pm_runtime_use_autosuspend(&pdev->dev);
-       pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
        pm_runtime_enable(&pdev->dev);
 
 #ifdef RTSX_USB_USE_LEDS_CLASS
@@ -1419,7 +1422,6 @@ static int rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev)
 
        mmc_free_host(mmc);
        pm_runtime_disable(&pdev->dev);
-       pm_runtime_dont_use_autosuspend(&pdev->dev);
        platform_set_drvdata(pdev, NULL);
 
        dev_dbg(&(pdev->dev),
@@ -1428,6 +1430,31 @@ static int rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int rtsx_usb_sdmmc_runtime_suspend(struct device *dev)
+{
+       struct rtsx_usb_sdmmc *host = dev_get_drvdata(dev);
+
+       host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
+       return 0;
+}
+
+static int rtsx_usb_sdmmc_runtime_resume(struct device *dev)
+{
+       struct rtsx_usb_sdmmc *host = dev_get_drvdata(dev);
+
+       host->mmc->caps |= MMC_CAP_NEEDS_POLL;
+       if (sdmmc_get_cd(host->mmc) == 1)
+               mmc_detect_change(host->mmc, 0);
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops rtsx_usb_sdmmc_dev_pm_ops = {
+       SET_RUNTIME_PM_OPS(rtsx_usb_sdmmc_runtime_suspend,
+                          rtsx_usb_sdmmc_runtime_resume, NULL)
+};
+
 static const struct platform_device_id rtsx_usb_sdmmc_ids[] = {
        {
                .name = "rtsx_usb_sdmmc",
@@ -1443,6 +1470,7 @@ static struct platform_driver rtsx_usb_sdmmc_driver = {
        .id_table       = rtsx_usb_sdmmc_ids,
        .driver         = {
                .name   = "rtsx_usb_sdmmc",
+               .pm     = &rtsx_usb_sdmmc_dev_pm_ops,
        },
 };
 module_platform_driver(rtsx_usb_sdmmc_driver);