summaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2018-06-04 02:30:24 -0400
committerUlf Hansson <ulf.hansson@linaro.org>2018-12-17 02:26:24 -0500
commit4dad599b8b5d1ffc5ef12a2edb13d15d537202ba (patch)
tree05f48c34b475d257494f4f4882549d3c53dd6750 /drivers/mmc
parentf275179f7bdcf08f4c74c2d1d19c4e8269be3454 (diff)
mmc: rtsx_usb_sdmmc: Re-work card detection/removal support
The rtsx USB parent device, has logic to detect when a card is inserted into the card slot. Although, the logic can't detect when a card is removed. This makes things a bit tricky, which is why the current method is simply to turn on MMC_CAP_NEEDS_POLL during probe. Using MMC_CAP_NEEDS_POLL means lots of energy being wasted, as the mmc host becomes runtime resumed frequently by the mmc core, while it polls for new cards being inserted. To address this problem, let's start relying on that the rtsx USB driver runtime resumes its child device, which is the rtsx_usb_sdmmc device, when it detects that a new card being inserted. This means dropping MMC_CAP_NEEDS_POLL from being set during probe. Instead let's implement a ->runtime_resume() callback to schedule a detect work and to set MMC_CAP_NEEDS_POLL. In this way, polling is enabled as long as there is card inserted, thus we can rely on the mmc core to detect also when the card becomes removed. Furthermore, to avoid polling forever after a card has been removed, let's implement a ->runtime_suspend() callback and make it clear MMC_CAP_NEEDS_POLL. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Tested-by: Kai-Heng Feng <kai.heng.feng@canonical.com> Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/rtsx_usb_sdmmc.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/drivers/mmc/host/rtsx_usb_sdmmc.c b/drivers/mmc/host/rtsx_usb_sdmmc.c
index ca0ab8eb30c3..669c6ab021c8 100644
--- a/drivers/mmc/host/rtsx_usb_sdmmc.c
+++ b/drivers/mmc/host/rtsx_usb_sdmmc.c
@@ -28,6 +28,7 @@
28#include <linux/mmc/sd.h> 28#include <linux/mmc/sd.h>
29#include <linux/mmc/card.h> 29#include <linux/mmc/card.h>
30#include <linux/scatterlist.h> 30#include <linux/scatterlist.h>
31#include <linux/pm.h>
31#include <linux/pm_runtime.h> 32#include <linux/pm_runtime.h>
32 33
33#include <linux/rtsx_usb.h> 34#include <linux/rtsx_usb.h>
@@ -1324,7 +1325,7 @@ static void rtsx_usb_init_host(struct rtsx_usb_sdmmc *host)
1324 mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED | 1325 mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED |
1325 MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST | 1326 MMC_CAP_MMC_HIGHSPEED | MMC_CAP_BUS_WIDTH_TEST |
1326 MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 | 1327 MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 | MMC_CAP_UHS_SDR50 |
1327 MMC_CAP_NEEDS_POLL | MMC_CAP_ERASE | MMC_CAP_SYNC_RUNTIME_PM; 1328 MMC_CAP_ERASE | MMC_CAP_SYNC_RUNTIME_PM;
1328 mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE | 1329 mmc->caps2 = MMC_CAP2_NO_PRESCAN_POWERUP | MMC_CAP2_FULL_PWR_CYCLE |
1329 MMC_CAP2_NO_SDIO; 1330 MMC_CAP2_NO_SDIO;
1330 1331
@@ -1429,6 +1430,31 @@ static int rtsx_usb_sdmmc_drv_remove(struct platform_device *pdev)
1429 return 0; 1430 return 0;
1430} 1431}
1431 1432
1433#ifdef CONFIG_PM
1434static int rtsx_usb_sdmmc_runtime_suspend(struct device *dev)
1435{
1436 struct rtsx_usb_sdmmc *host = dev_get_drvdata(dev);
1437
1438 host->mmc->caps &= ~MMC_CAP_NEEDS_POLL;
1439 return 0;
1440}
1441
1442static int rtsx_usb_sdmmc_runtime_resume(struct device *dev)
1443{
1444 struct rtsx_usb_sdmmc *host = dev_get_drvdata(dev);
1445
1446 host->mmc->caps |= MMC_CAP_NEEDS_POLL;
1447 if (sdmmc_get_cd(host->mmc) == 1)
1448 mmc_detect_change(host->mmc, 0);
1449 return 0;
1450}
1451#endif
1452
1453static const struct dev_pm_ops rtsx_usb_sdmmc_dev_pm_ops = {
1454 SET_RUNTIME_PM_OPS(rtsx_usb_sdmmc_runtime_suspend,
1455 rtsx_usb_sdmmc_runtime_resume, NULL)
1456};
1457
1432static const struct platform_device_id rtsx_usb_sdmmc_ids[] = { 1458static const struct platform_device_id rtsx_usb_sdmmc_ids[] = {
1433 { 1459 {
1434 .name = "rtsx_usb_sdmmc", 1460 .name = "rtsx_usb_sdmmc",
@@ -1444,6 +1470,7 @@ static struct platform_driver rtsx_usb_sdmmc_driver = {
1444 .id_table = rtsx_usb_sdmmc_ids, 1470 .id_table = rtsx_usb_sdmmc_ids,
1445 .driver = { 1471 .driver = {
1446 .name = "rtsx_usb_sdmmc", 1472 .name = "rtsx_usb_sdmmc",
1473 .pm = &rtsx_usb_sdmmc_dev_pm_ops,
1447 }, 1474 },
1448}; 1475};
1449module_platform_driver(rtsx_usb_sdmmc_driver); 1476module_platform_driver(rtsx_usb_sdmmc_driver);