aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core
diff options
context:
space:
mode:
authorUlf Hansson <ulf.hansson@linaro.org>2013-05-02 08:02:39 -0400
committerChris Ball <cjb@laptop.org>2013-05-26 14:23:17 -0400
commitc4d770d72492df510077b277f21ac5f0dad9e5eb (patch)
tree60412abaad7c69267483d368afeff4d0a769a82b /drivers/mmc/core
parente94cfef698aae6b209d8918dd319312e4b02118d (diff)
mmc: core: Support aggressive power management for (e)MMC/SD
Aggressive power management is suitable when saving power is essential. At request inactivity timeout, aka pm runtime autosuspend timeout, the card will be suspended. Once a new request arrives, the card will be re-initalized and thus the first request will suffer from a latency. This latency is card-specific, experiments has shown in general that SD-cards has quite poor initialization time, around 300ms-1100ms. eMMC is not surprisingly far better but still a couple of hundreds of ms has been observed. Except for the request latency, it is important to know that suspending the card will also prevent the card from executing internal house-keeping operations in idle mode. This could mean degradation in performance. To use this feature make sure the request inactivity timeout is chosen carefully. This has not been done as a part of this patch. Enable this feature by using host cap MMC_CAP_AGGRESSIVE_PM and by setting CONFIG_MMC_UNSAFE_RESUME. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r--drivers/mmc/core/mmc.c50
-rw-r--r--drivers/mmc/core/sd.c49
2 files changed, 99 insertions, 0 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 903f38150180..506f4ee84e12 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1454,6 +1454,54 @@ static int mmc_resume(struct mmc_host *host)
1454 return err; 1454 return err;
1455} 1455}
1456 1456
1457
1458/*
1459 * Callback for runtime_suspend.
1460 */
1461static int mmc_runtime_suspend(struct mmc_host *host)
1462{
1463 int err;
1464
1465 if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
1466 return 0;
1467
1468 mmc_claim_host(host);
1469
1470 err = mmc_suspend(host);
1471 if (err) {
1472 pr_err("%s: error %d doing aggessive suspend\n",
1473 mmc_hostname(host), err);
1474 goto out;
1475 }
1476 mmc_power_off(host);
1477
1478out:
1479 mmc_release_host(host);
1480 return err;
1481}
1482
1483/*
1484 * Callback for runtime_resume.
1485 */
1486static int mmc_runtime_resume(struct mmc_host *host)
1487{
1488 int err;
1489
1490 if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
1491 return 0;
1492
1493 mmc_claim_host(host);
1494
1495 mmc_power_up(host);
1496 err = mmc_resume(host);
1497 if (err)
1498 pr_err("%s: error %d doing aggessive resume\n",
1499 mmc_hostname(host), err);
1500
1501 mmc_release_host(host);
1502 return 0;
1503}
1504
1457static int mmc_power_restore(struct mmc_host *host) 1505static int mmc_power_restore(struct mmc_host *host)
1458{ 1506{
1459 int ret; 1507 int ret;
@@ -1514,6 +1562,8 @@ static const struct mmc_bus_ops mmc_ops_unsafe = {
1514 .detect = mmc_detect, 1562 .detect = mmc_detect,
1515 .suspend = mmc_suspend, 1563 .suspend = mmc_suspend,
1516 .resume = mmc_resume, 1564 .resume = mmc_resume,
1565 .runtime_suspend = mmc_runtime_suspend,
1566 .runtime_resume = mmc_runtime_resume,
1517 .power_restore = mmc_power_restore, 1567 .power_restore = mmc_power_restore,
1518 .alive = mmc_alive, 1568 .alive = mmc_alive,
1519}; 1569};
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 17fa2d271dd4..aeaae7c3b22b 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1100,6 +1100,53 @@ static int mmc_sd_resume(struct mmc_host *host)
1100 return err; 1100 return err;
1101} 1101}
1102 1102
1103/*
1104 * Callback for runtime_suspend.
1105 */
1106static int mmc_sd_runtime_suspend(struct mmc_host *host)
1107{
1108 int err;
1109
1110 if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
1111 return 0;
1112
1113 mmc_claim_host(host);
1114
1115 err = mmc_sd_suspend(host);
1116 if (err) {
1117 pr_err("%s: error %d doing aggessive suspend\n",
1118 mmc_hostname(host), err);
1119 goto out;
1120 }
1121 mmc_power_off(host);
1122
1123out:
1124 mmc_release_host(host);
1125 return err;
1126}
1127
1128/*
1129 * Callback for runtime_resume.
1130 */
1131static int mmc_sd_runtime_resume(struct mmc_host *host)
1132{
1133 int err;
1134
1135 if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
1136 return 0;
1137
1138 mmc_claim_host(host);
1139
1140 mmc_power_up(host);
1141 err = mmc_sd_resume(host);
1142 if (err)
1143 pr_err("%s: error %d doing aggessive resume\n",
1144 mmc_hostname(host), err);
1145
1146 mmc_release_host(host);
1147 return 0;
1148}
1149
1103static int mmc_sd_power_restore(struct mmc_host *host) 1150static int mmc_sd_power_restore(struct mmc_host *host)
1104{ 1151{
1105 int ret; 1152 int ret;
@@ -1124,6 +1171,8 @@ static const struct mmc_bus_ops mmc_sd_ops = {
1124static const struct mmc_bus_ops mmc_sd_ops_unsafe = { 1171static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
1125 .remove = mmc_sd_remove, 1172 .remove = mmc_sd_remove,
1126 .detect = mmc_sd_detect, 1173 .detect = mmc_sd_detect,
1174 .runtime_suspend = mmc_sd_runtime_suspend,
1175 .runtime_resume = mmc_sd_runtime_resume,
1127 .suspend = mmc_sd_suspend, 1176 .suspend = mmc_sd_suspend,
1128 .resume = mmc_sd_resume, 1177 .resume = mmc_sd_resume,
1129 .power_restore = mmc_sd_power_restore, 1178 .power_restore = mmc_sd_power_restore,