aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/sdhci-pci.c
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@intel.com>2011-10-03 08:33:34 -0400
committerChris Ball <cjb@laptop.org>2011-10-26 16:32:20 -0400
commit66fd8ad5100b5003046aa744a4f12fa31bb831f9 (patch)
treec71aa6ff8b5c4c2919b93630a2315017f4610986 /drivers/mmc/host/sdhci-pci.c
parent08a7e1dfaa63bf5132b5b7231fcf9a33473c78f5 (diff)
mmc: sdhci-pci: add runtime pm support
Ths patch allows runtime PM for sdhci-pci, runtime suspending after inactivity of 50ms and ensuring runtime resume before SDHC registers are accessed. During runtime suspend, interrupts are masked. The host controller state is restored at runtime resume. For Medfield, the host controller's card detect mechanism is supplanted by an always-on GPIO which provides for card detect wake-up. Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/host/sdhci-pci.c')
-rw-r--r--drivers/mmc/host/sdhci-pci.c182
1 files changed, 181 insertions, 1 deletions
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 4487b8430aaf..f49b184308c0 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -24,6 +24,7 @@
24#include <linux/io.h> 24#include <linux/io.h>
25#include <linux/gpio.h> 25#include <linux/gpio.h>
26#include <linux/sfi.h> 26#include <linux/sfi.h>
27#include <linux/pm_runtime.h>
27 28
28#include "sdhci.h" 29#include "sdhci.h"
29 30
@@ -63,6 +64,8 @@ struct sdhci_pci_slot {
63 64
64 int pci_bar; 65 int pci_bar;
65 int rst_n_gpio; 66 int rst_n_gpio;
67 int cd_gpio;
68 int cd_irq;
66}; 69};
67 70
68struct sdhci_pci_chip { 71struct sdhci_pci_chip {
@@ -190,6 +193,70 @@ static int mfd_emmc_gpio_parse(struct sfi_table_header *table)
190 return 0; 193 return 0;
191} 194}
192 195
196#ifdef CONFIG_PM_RUNTIME
197
198static irqreturn_t mfd_sd_cd(int irq, void *dev_id)
199{
200 struct sdhci_pci_slot *slot = dev_id;
201 struct sdhci_host *host = slot->host;
202
203 mmc_detect_change(host->mmc, msecs_to_jiffies(200));
204 return IRQ_HANDLED;
205}
206
207#define MFLD_SD_CD_PIN 69
208
209static int mfd_sd_probe_slot(struct sdhci_pci_slot *slot)
210{
211 int err, irq, gpio = MFLD_SD_CD_PIN;
212
213 slot->cd_gpio = -EINVAL;
214 slot->cd_irq = -EINVAL;
215
216 err = gpio_request(gpio, "sd_cd");
217 if (err < 0)
218 goto out;
219
220 err = gpio_direction_input(gpio);
221 if (err < 0)
222 goto out_free;
223
224 irq = gpio_to_irq(gpio);
225 if (irq < 0)
226 goto out_free;
227
228 err = request_irq(irq, mfd_sd_cd, IRQF_TRIGGER_RISING |
229 IRQF_TRIGGER_FALLING, "sd_cd", slot);
230 if (err)
231 goto out_free;
232
233 slot->cd_gpio = gpio;
234 slot->cd_irq = irq;
235 slot->host->quirks2 |= SDHCI_QUIRK2_OWN_CARD_DETECTION;
236
237 return 0;
238
239out_free:
240 gpio_free(gpio);
241out:
242 dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n");
243 return 0;
244}
245
246static void mfd_sd_remove_slot(struct sdhci_pci_slot *slot, int dead)
247{
248 if (slot->cd_irq >= 0)
249 free_irq(slot->cd_irq, slot);
250 gpio_free(slot->cd_gpio);
251}
252
253#else
254
255#define mfd_sd_probe_slot NULL
256#define mfd_sd_remove_slot NULL
257
258#endif
259
193static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) 260static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot)
194{ 261{
195 const char *name = NULL; 262 const char *name = NULL;
@@ -214,7 +281,7 @@ static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot)
214 slot->host->mmc->caps |= MMC_CAP_HW_RESET; 281 slot->host->mmc->caps |= MMC_CAP_HW_RESET;
215 } 282 }
216 283
217 slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA; 284 slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
218 285
219 slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC; 286 slot->host->mmc->caps2 = MMC_CAP2_BOOTPART_NOACC;
220 287
@@ -238,6 +305,8 @@ static const struct sdhci_pci_fixes sdhci_intel_mrst_hc1_hc2 = {
238 305
239static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = { 306static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = {
240 .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, 307 .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
308 .probe_slot = mfd_sd_probe_slot,
309 .remove_slot = mfd_sd_remove_slot,
241}; 310};
242 311
243static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = { 312static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = {
@@ -1018,6 +1087,95 @@ static int sdhci_pci_resume(struct pci_dev *pdev)
1018 1087
1019#endif /* CONFIG_PM */ 1088#endif /* CONFIG_PM */
1020 1089
1090#ifdef CONFIG_PM_RUNTIME
1091
1092static int sdhci_pci_runtime_suspend(struct device *dev)
1093{
1094 struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
1095 struct sdhci_pci_chip *chip;
1096 struct sdhci_pci_slot *slot;
1097 pm_message_t state = { .event = PM_EVENT_SUSPEND };
1098 int i, ret;
1099
1100 chip = pci_get_drvdata(pdev);
1101 if (!chip)
1102 return 0;
1103
1104 for (i = 0; i < chip->num_slots; i++) {
1105 slot = chip->slots[i];
1106 if (!slot)
1107 continue;
1108
1109 ret = sdhci_runtime_suspend_host(slot->host);
1110
1111 if (ret) {
1112 for (i--; i >= 0; i--)
1113 sdhci_runtime_resume_host(chip->slots[i]->host);
1114 return ret;
1115 }
1116 }
1117
1118 if (chip->fixes && chip->fixes->suspend) {
1119 ret = chip->fixes->suspend(chip, state);
1120 if (ret) {
1121 for (i = chip->num_slots - 1; i >= 0; i--)
1122 sdhci_runtime_resume_host(chip->slots[i]->host);
1123 return ret;
1124 }
1125 }
1126
1127 return 0;
1128}
1129
1130static int sdhci_pci_runtime_resume(struct device *dev)
1131{
1132 struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
1133 struct sdhci_pci_chip *chip;
1134 struct sdhci_pci_slot *slot;
1135 int i, ret;
1136
1137 chip = pci_get_drvdata(pdev);
1138 if (!chip)
1139 return 0;
1140
1141 if (chip->fixes && chip->fixes->resume) {
1142 ret = chip->fixes->resume(chip);
1143 if (ret)
1144 return ret;
1145 }
1146
1147 for (i = 0; i < chip->num_slots; i++) {
1148 slot = chip->slots[i];
1149 if (!slot)
1150 continue;
1151
1152 ret = sdhci_runtime_resume_host(slot->host);
1153 if (ret)
1154 return ret;
1155 }
1156
1157 return 0;
1158}
1159
1160static int sdhci_pci_runtime_idle(struct device *dev)
1161{
1162 return 0;
1163}
1164
1165#else
1166
1167#define sdhci_pci_runtime_suspend NULL
1168#define sdhci_pci_runtime_resume NULL
1169#define sdhci_pci_runtime_idle NULL
1170
1171#endif
1172
1173static const struct dev_pm_ops sdhci_pci_pm_ops = {
1174 .runtime_suspend = sdhci_pci_runtime_suspend,
1175 .runtime_resume = sdhci_pci_runtime_resume,
1176 .runtime_idle = sdhci_pci_runtime_idle,
1177};
1178
1021/*****************************************************************************\ 1179/*****************************************************************************\
1022 * * 1180 * *
1023 * Device probing/removal * 1181 * Device probing/removal *
@@ -1133,6 +1291,21 @@ static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
1133 sdhci_free_host(slot->host); 1291 sdhci_free_host(slot->host);
1134} 1292}
1135 1293
1294static void __devinit sdhci_pci_runtime_pm_allow(struct device *dev)
1295{
1296 pm_runtime_put_noidle(dev);
1297 pm_runtime_allow(dev);
1298 pm_runtime_set_autosuspend_delay(dev, 50);
1299 pm_runtime_use_autosuspend(dev);
1300 pm_suspend_ignore_children(dev, 1);
1301}
1302
1303static void __devexit sdhci_pci_runtime_pm_forbid(struct device *dev)
1304{
1305 pm_runtime_forbid(dev);
1306 pm_runtime_get_noresume(dev);
1307}
1308
1136static int __devinit sdhci_pci_probe(struct pci_dev *pdev, 1309static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
1137 const struct pci_device_id *ent) 1310 const struct pci_device_id *ent)
1138{ 1311{
@@ -1208,6 +1381,8 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
1208 chip->slots[i] = slot; 1381 chip->slots[i] = slot;
1209 } 1382 }
1210 1383
1384 sdhci_pci_runtime_pm_allow(&pdev->dev);
1385
1211 return 0; 1386 return 0;
1212 1387
1213free: 1388free:
@@ -1224,6 +1399,8 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev)
1224 int i; 1399 int i;
1225 struct sdhci_pci_chip *chip; 1400 struct sdhci_pci_chip *chip;
1226 1401
1402 sdhci_pci_runtime_pm_forbid(&pdev->dev);
1403
1227 chip = pci_get_drvdata(pdev); 1404 chip = pci_get_drvdata(pdev);
1228 1405
1229 if (chip) { 1406 if (chip) {
@@ -1244,6 +1421,9 @@ static struct pci_driver sdhci_driver = {
1244 .remove = __devexit_p(sdhci_pci_remove), 1421 .remove = __devexit_p(sdhci_pci_remove),
1245 .suspend = sdhci_pci_suspend, 1422 .suspend = sdhci_pci_suspend,
1246 .resume = sdhci_pci_resume, 1423 .resume = sdhci_pci_resume,
1424 .driver = {
1425 .pm = &sdhci_pci_pm_ops
1426 },
1247}; 1427};
1248 1428
1249/*****************************************************************************\ 1429/*****************************************************************************\