diff options
-rw-r--r-- | drivers/mmc/host/sdhci-pci.c | 182 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 255 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 5 | ||||
-rw-r--r-- | include/linux/mmc/sdhci.h | 8 |
4 files changed, 405 insertions, 45 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 | ||
68 | struct sdhci_pci_chip { | 71 | struct 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 | |||
198 | static 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 | |||
209 | static 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 | |||
239 | out_free: | ||
240 | gpio_free(gpio); | ||
241 | out: | ||
242 | dev_warn(&slot->chip->pdev->dev, "failed to setup card detect wake up\n"); | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static 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 | |||
193 | static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot) | 260 | static 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 | ||
239 | static const struct sdhci_pci_fixes sdhci_intel_mfd_sd = { | 306 | static 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 | ||
243 | static const struct sdhci_pci_fixes sdhci_intel_mfd_sdio = { | 312 | static 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 | |||
1092 | static 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 | |||
1130 | static 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 | |||
1160 | static 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 | |||
1173 | static 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 | ||
1294 | static 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 | |||
1303 | static void __devexit sdhci_pci_runtime_pm_forbid(struct device *dev) | ||
1304 | { | ||
1305 | pm_runtime_forbid(dev); | ||
1306 | pm_runtime_get_noresume(dev); | ||
1307 | } | ||
1308 | |||
1136 | static int __devinit sdhci_pci_probe(struct pci_dev *pdev, | 1309 | static 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 | ||
1213 | free: | 1388 | free: |
@@ -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 | /*****************************************************************************\ |
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9394860602fe..155deb8629af 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | #include <linux/scatterlist.h> | 22 | #include <linux/scatterlist.h> |
23 | #include <linux/regulator/consumer.h> | 23 | #include <linux/regulator/consumer.h> |
24 | #include <linux/pm_runtime.h> | ||
24 | 25 | ||
25 | #include <linux/leds.h> | 26 | #include <linux/leds.h> |
26 | 27 | ||
@@ -42,6 +43,7 @@ | |||
42 | #define MAX_TUNING_LOOP 40 | 43 | #define MAX_TUNING_LOOP 40 |
43 | 44 | ||
44 | static unsigned int debug_quirks = 0; | 45 | static unsigned int debug_quirks = 0; |
46 | static unsigned int debug_quirks2; | ||
45 | 47 | ||
46 | static void sdhci_finish_data(struct sdhci_host *); | 48 | static void sdhci_finish_data(struct sdhci_host *); |
47 | 49 | ||
@@ -50,6 +52,20 @@ static void sdhci_finish_command(struct sdhci_host *); | |||
50 | static int sdhci_execute_tuning(struct mmc_host *mmc); | 52 | static int sdhci_execute_tuning(struct mmc_host *mmc); |
51 | static void sdhci_tuning_timer(unsigned long data); | 53 | static void sdhci_tuning_timer(unsigned long data); |
52 | 54 | ||
55 | #ifdef CONFIG_PM_RUNTIME | ||
56 | static int sdhci_runtime_pm_get(struct sdhci_host *host); | ||
57 | static int sdhci_runtime_pm_put(struct sdhci_host *host); | ||
58 | #else | ||
59 | static inline int sdhci_runtime_pm_get(struct sdhci_host *host) | ||
60 | { | ||
61 | return 0; | ||
62 | } | ||
63 | static inline int sdhci_runtime_pm_put(struct sdhci_host *host) | ||
64 | { | ||
65 | return 0; | ||
66 | } | ||
67 | #endif | ||
68 | |||
53 | static void sdhci_dumpregs(struct sdhci_host *host) | 69 | static void sdhci_dumpregs(struct sdhci_host *host) |
54 | { | 70 | { |
55 | printk(KERN_DEBUG DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", | 71 | printk(KERN_DEBUG DRIVER_NAME ": =========== REGISTER DUMP (%s)===========\n", |
@@ -133,6 +149,9 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) | |||
133 | if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) | 149 | if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) |
134 | return; | 150 | return; |
135 | 151 | ||
152 | if (host->quirks2 & SDHCI_QUIRK2_OWN_CARD_DETECTION) | ||
153 | return; | ||
154 | |||
136 | present = sdhci_readl(host, SDHCI_PRESENT_STATE) & | 155 | present = sdhci_readl(host, SDHCI_PRESENT_STATE) & |
137 | SDHCI_CARD_PRESENT; | 156 | SDHCI_CARD_PRESENT; |
138 | irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT; | 157 | irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT; |
@@ -252,11 +271,14 @@ static void sdhci_led_control(struct led_classdev *led, | |||
252 | 271 | ||
253 | spin_lock_irqsave(&host->lock, flags); | 272 | spin_lock_irqsave(&host->lock, flags); |
254 | 273 | ||
274 | if (host->runtime_suspended) | ||
275 | goto out; | ||
276 | |||
255 | if (brightness == LED_OFF) | 277 | if (brightness == LED_OFF) |
256 | sdhci_deactivate_led(host); | 278 | sdhci_deactivate_led(host); |
257 | else | 279 | else |
258 | sdhci_activate_led(host); | 280 | sdhci_activate_led(host); |
259 | 281 | out: | |
260 | spin_unlock_irqrestore(&host->lock, flags); | 282 | spin_unlock_irqrestore(&host->lock, flags); |
261 | } | 283 | } |
262 | #endif | 284 | #endif |
@@ -1210,6 +1232,8 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
1210 | 1232 | ||
1211 | host = mmc_priv(mmc); | 1233 | host = mmc_priv(mmc); |
1212 | 1234 | ||
1235 | sdhci_runtime_pm_get(host); | ||
1236 | |||
1213 | spin_lock_irqsave(&host->lock, flags); | 1237 | spin_lock_irqsave(&host->lock, flags); |
1214 | 1238 | ||
1215 | WARN_ON(host->mrq != NULL); | 1239 | WARN_ON(host->mrq != NULL); |
@@ -1270,14 +1294,11 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
1270 | spin_unlock_irqrestore(&host->lock, flags); | 1294 | spin_unlock_irqrestore(&host->lock, flags); |
1271 | } | 1295 | } |
1272 | 1296 | ||
1273 | static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | 1297 | static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) |
1274 | { | 1298 | { |
1275 | struct sdhci_host *host; | ||
1276 | unsigned long flags; | 1299 | unsigned long flags; |
1277 | u8 ctrl; | 1300 | u8 ctrl; |
1278 | 1301 | ||
1279 | host = mmc_priv(mmc); | ||
1280 | |||
1281 | spin_lock_irqsave(&host->lock, flags); | 1302 | spin_lock_irqsave(&host->lock, flags); |
1282 | 1303 | ||
1283 | if (host->flags & SDHCI_DEVICE_DEAD) | 1304 | if (host->flags & SDHCI_DEVICE_DEAD) |
@@ -1427,7 +1448,16 @@ out: | |||
1427 | spin_unlock_irqrestore(&host->lock, flags); | 1448 | spin_unlock_irqrestore(&host->lock, flags); |
1428 | } | 1449 | } |
1429 | 1450 | ||
1430 | static int check_ro(struct sdhci_host *host) | 1451 | static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) |
1452 | { | ||
1453 | struct sdhci_host *host = mmc_priv(mmc); | ||
1454 | |||
1455 | sdhci_runtime_pm_get(host); | ||
1456 | sdhci_do_set_ios(host, ios); | ||
1457 | sdhci_runtime_pm_put(host); | ||
1458 | } | ||
1459 | |||
1460 | static int sdhci_check_ro(struct sdhci_host *host) | ||
1431 | { | 1461 | { |
1432 | unsigned long flags; | 1462 | unsigned long flags; |
1433 | int is_readonly; | 1463 | int is_readonly; |
@@ -1451,19 +1481,16 @@ static int check_ro(struct sdhci_host *host) | |||
1451 | 1481 | ||
1452 | #define SAMPLE_COUNT 5 | 1482 | #define SAMPLE_COUNT 5 |
1453 | 1483 | ||
1454 | static int sdhci_get_ro(struct mmc_host *mmc) | 1484 | static int sdhci_do_get_ro(struct sdhci_host *host) |
1455 | { | 1485 | { |
1456 | struct sdhci_host *host; | ||
1457 | int i, ro_count; | 1486 | int i, ro_count; |
1458 | 1487 | ||
1459 | host = mmc_priv(mmc); | ||
1460 | |||
1461 | if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT)) | 1488 | if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT)) |
1462 | return check_ro(host); | 1489 | return sdhci_check_ro(host); |
1463 | 1490 | ||
1464 | ro_count = 0; | 1491 | ro_count = 0; |
1465 | for (i = 0; i < SAMPLE_COUNT; i++) { | 1492 | for (i = 0; i < SAMPLE_COUNT; i++) { |
1466 | if (check_ro(host)) { | 1493 | if (sdhci_check_ro(host)) { |
1467 | if (++ro_count > SAMPLE_COUNT / 2) | 1494 | if (++ro_count > SAMPLE_COUNT / 2) |
1468 | return 1; | 1495 | return 1; |
1469 | } | 1496 | } |
@@ -1480,38 +1507,56 @@ static void sdhci_hw_reset(struct mmc_host *mmc) | |||
1480 | host->ops->hw_reset(host); | 1507 | host->ops->hw_reset(host); |
1481 | } | 1508 | } |
1482 | 1509 | ||
1483 | static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) | 1510 | static int sdhci_get_ro(struct mmc_host *mmc) |
1484 | { | 1511 | { |
1485 | struct sdhci_host *host; | 1512 | struct sdhci_host *host = mmc_priv(mmc); |
1486 | unsigned long flags; | 1513 | int ret; |
1487 | |||
1488 | host = mmc_priv(mmc); | ||
1489 | 1514 | ||
1490 | spin_lock_irqsave(&host->lock, flags); | 1515 | sdhci_runtime_pm_get(host); |
1516 | ret = sdhci_do_get_ro(host); | ||
1517 | sdhci_runtime_pm_put(host); | ||
1518 | return ret; | ||
1519 | } | ||
1491 | 1520 | ||
1521 | static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable) | ||
1522 | { | ||
1492 | if (host->flags & SDHCI_DEVICE_DEAD) | 1523 | if (host->flags & SDHCI_DEVICE_DEAD) |
1493 | goto out; | 1524 | goto out; |
1494 | 1525 | ||
1495 | if (enable) | 1526 | if (enable) |
1527 | host->flags |= SDHCI_SDIO_IRQ_ENABLED; | ||
1528 | else | ||
1529 | host->flags &= ~SDHCI_SDIO_IRQ_ENABLED; | ||
1530 | |||
1531 | /* SDIO IRQ will be enabled as appropriate in runtime resume */ | ||
1532 | if (host->runtime_suspended) | ||
1533 | goto out; | ||
1534 | |||
1535 | if (enable) | ||
1496 | sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT); | 1536 | sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT); |
1497 | else | 1537 | else |
1498 | sdhci_mask_irqs(host, SDHCI_INT_CARD_INT); | 1538 | sdhci_mask_irqs(host, SDHCI_INT_CARD_INT); |
1499 | out: | 1539 | out: |
1500 | mmiowb(); | 1540 | mmiowb(); |
1541 | } | ||
1542 | |||
1543 | static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) | ||
1544 | { | ||
1545 | struct sdhci_host *host = mmc_priv(mmc); | ||
1546 | unsigned long flags; | ||
1501 | 1547 | ||
1548 | spin_lock_irqsave(&host->lock, flags); | ||
1549 | sdhci_enable_sdio_irq_nolock(host, enable); | ||
1502 | spin_unlock_irqrestore(&host->lock, flags); | 1550 | spin_unlock_irqrestore(&host->lock, flags); |
1503 | } | 1551 | } |
1504 | 1552 | ||
1505 | static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, | 1553 | static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host, |
1506 | struct mmc_ios *ios) | 1554 | struct mmc_ios *ios) |
1507 | { | 1555 | { |
1508 | struct sdhci_host *host; | ||
1509 | u8 pwr; | 1556 | u8 pwr; |
1510 | u16 clk, ctrl; | 1557 | u16 clk, ctrl; |
1511 | u32 present_state; | 1558 | u32 present_state; |
1512 | 1559 | ||
1513 | host = mmc_priv(mmc); | ||
1514 | |||
1515 | /* | 1560 | /* |
1516 | * Signal Voltage Switching is only applicable for Host Controllers | 1561 | * Signal Voltage Switching is only applicable for Host Controllers |
1517 | * v3.00 and above. | 1562 | * v3.00 and above. |
@@ -1604,6 +1649,20 @@ static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, | |||
1604 | return 0; | 1649 | return 0; |
1605 | } | 1650 | } |
1606 | 1651 | ||
1652 | static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc, | ||
1653 | struct mmc_ios *ios) | ||
1654 | { | ||
1655 | struct sdhci_host *host = mmc_priv(mmc); | ||
1656 | int err; | ||
1657 | |||
1658 | if (host->version < SDHCI_SPEC_300) | ||
1659 | return 0; | ||
1660 | sdhci_runtime_pm_get(host); | ||
1661 | err = sdhci_do_start_signal_voltage_switch(host, ios); | ||
1662 | sdhci_runtime_pm_put(host); | ||
1663 | return err; | ||
1664 | } | ||
1665 | |||
1607 | static int sdhci_execute_tuning(struct mmc_host *mmc) | 1666 | static int sdhci_execute_tuning(struct mmc_host *mmc) |
1608 | { | 1667 | { |
1609 | struct sdhci_host *host; | 1668 | struct sdhci_host *host; |
@@ -1615,6 +1674,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) | |||
1615 | 1674 | ||
1616 | host = mmc_priv(mmc); | 1675 | host = mmc_priv(mmc); |
1617 | 1676 | ||
1677 | sdhci_runtime_pm_get(host); | ||
1618 | disable_irq(host->irq); | 1678 | disable_irq(host->irq); |
1619 | spin_lock(&host->lock); | 1679 | spin_lock(&host->lock); |
1620 | 1680 | ||
@@ -1632,6 +1692,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) | |||
1632 | else { | 1692 | else { |
1633 | spin_unlock(&host->lock); | 1693 | spin_unlock(&host->lock); |
1634 | enable_irq(host->irq); | 1694 | enable_irq(host->irq); |
1695 | sdhci_runtime_pm_put(host); | ||
1635 | return 0; | 1696 | return 0; |
1636 | } | 1697 | } |
1637 | 1698 | ||
@@ -1657,7 +1718,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc) | |||
1657 | timeout = 150; | 1718 | timeout = 150; |
1658 | do { | 1719 | do { |
1659 | struct mmc_command cmd = {0}; | 1720 | struct mmc_command cmd = {0}; |
1660 | struct mmc_request mrq = {0}; | 1721 | struct mmc_request mrq = {NULL}; |
1661 | 1722 | ||
1662 | if (!tuning_loop_counter && !timeout) | 1723 | if (!tuning_loop_counter && !timeout) |
1663 | break; | 1724 | break; |
@@ -1775,18 +1836,16 @@ out: | |||
1775 | sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier); | 1836 | sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier); |
1776 | spin_unlock(&host->lock); | 1837 | spin_unlock(&host->lock); |
1777 | enable_irq(host->irq); | 1838 | enable_irq(host->irq); |
1839 | sdhci_runtime_pm_put(host); | ||
1778 | 1840 | ||
1779 | return err; | 1841 | return err; |
1780 | } | 1842 | } |
1781 | 1843 | ||
1782 | static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) | 1844 | static void sdhci_do_enable_preset_value(struct sdhci_host *host, bool enable) |
1783 | { | 1845 | { |
1784 | struct sdhci_host *host; | ||
1785 | u16 ctrl; | 1846 | u16 ctrl; |
1786 | unsigned long flags; | 1847 | unsigned long flags; |
1787 | 1848 | ||
1788 | host = mmc_priv(mmc); | ||
1789 | |||
1790 | /* Host Controller v3.00 defines preset value registers */ | 1849 | /* Host Controller v3.00 defines preset value registers */ |
1791 | if (host->version < SDHCI_SPEC_300) | 1850 | if (host->version < SDHCI_SPEC_300) |
1792 | return; | 1851 | return; |
@@ -1802,14 +1861,25 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) | |||
1802 | if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { | 1861 | if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { |
1803 | ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE; | 1862 | ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE; |
1804 | sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); | 1863 | sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); |
1864 | host->flags |= SDHCI_PV_ENABLED; | ||
1805 | } else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { | 1865 | } else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) { |
1806 | ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; | 1866 | ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; |
1807 | sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); | 1867 | sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); |
1868 | host->flags &= ~SDHCI_PV_ENABLED; | ||
1808 | } | 1869 | } |
1809 | 1870 | ||
1810 | spin_unlock_irqrestore(&host->lock, flags); | 1871 | spin_unlock_irqrestore(&host->lock, flags); |
1811 | } | 1872 | } |
1812 | 1873 | ||
1874 | static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) | ||
1875 | { | ||
1876 | struct sdhci_host *host = mmc_priv(mmc); | ||
1877 | |||
1878 | sdhci_runtime_pm_get(host); | ||
1879 | sdhci_do_enable_preset_value(host, enable); | ||
1880 | sdhci_runtime_pm_put(host); | ||
1881 | } | ||
1882 | |||
1813 | static const struct mmc_host_ops sdhci_ops = { | 1883 | static const struct mmc_host_ops sdhci_ops = { |
1814 | .request = sdhci_request, | 1884 | .request = sdhci_request, |
1815 | .set_ios = sdhci_set_ios, | 1885 | .set_ios = sdhci_set_ios, |
@@ -1836,19 +1906,19 @@ static void sdhci_tasklet_card(unsigned long param) | |||
1836 | 1906 | ||
1837 | spin_lock_irqsave(&host->lock, flags); | 1907 | spin_lock_irqsave(&host->lock, flags); |
1838 | 1908 | ||
1839 | if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { | 1909 | /* Check host->mrq first in case we are runtime suspended */ |
1840 | if (host->mrq) { | 1910 | if (host->mrq && |
1841 | printk(KERN_ERR "%s: Card removed during transfer!\n", | 1911 | !(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { |
1842 | mmc_hostname(host->mmc)); | 1912 | printk(KERN_ERR "%s: Card removed during transfer!\n", |
1843 | printk(KERN_ERR "%s: Resetting controller.\n", | 1913 | mmc_hostname(host->mmc)); |
1844 | mmc_hostname(host->mmc)); | 1914 | printk(KERN_ERR "%s: Resetting controller.\n", |
1915 | mmc_hostname(host->mmc)); | ||
1845 | 1916 | ||
1846 | sdhci_reset(host, SDHCI_RESET_CMD); | 1917 | sdhci_reset(host, SDHCI_RESET_CMD); |
1847 | sdhci_reset(host, SDHCI_RESET_DATA); | 1918 | sdhci_reset(host, SDHCI_RESET_DATA); |
1848 | 1919 | ||
1849 | host->mrq->cmd->error = -ENOMEDIUM; | 1920 | host->mrq->cmd->error = -ENOMEDIUM; |
1850 | tasklet_schedule(&host->finish_tasklet); | 1921 | tasklet_schedule(&host->finish_tasklet); |
1851 | } | ||
1852 | } | 1922 | } |
1853 | 1923 | ||
1854 | spin_unlock_irqrestore(&host->lock, flags); | 1924 | spin_unlock_irqrestore(&host->lock, flags); |
@@ -1864,14 +1934,16 @@ static void sdhci_tasklet_finish(unsigned long param) | |||
1864 | 1934 | ||
1865 | host = (struct sdhci_host*)param; | 1935 | host = (struct sdhci_host*)param; |
1866 | 1936 | ||
1937 | spin_lock_irqsave(&host->lock, flags); | ||
1938 | |||
1867 | /* | 1939 | /* |
1868 | * If this tasklet gets rescheduled while running, it will | 1940 | * If this tasklet gets rescheduled while running, it will |
1869 | * be run again afterwards but without any active request. | 1941 | * be run again afterwards but without any active request. |
1870 | */ | 1942 | */ |
1871 | if (!host->mrq) | 1943 | if (!host->mrq) { |
1944 | spin_unlock_irqrestore(&host->lock, flags); | ||
1872 | return; | 1945 | return; |
1873 | 1946 | } | |
1874 | spin_lock_irqsave(&host->lock, flags); | ||
1875 | 1947 | ||
1876 | del_timer(&host->timer); | 1948 | del_timer(&host->timer); |
1877 | 1949 | ||
@@ -1915,6 +1987,7 @@ static void sdhci_tasklet_finish(unsigned long param) | |||
1915 | spin_unlock_irqrestore(&host->lock, flags); | 1987 | spin_unlock_irqrestore(&host->lock, flags); |
1916 | 1988 | ||
1917 | mmc_request_done(host->mmc, mrq); | 1989 | mmc_request_done(host->mmc, mrq); |
1990 | sdhci_runtime_pm_put(host); | ||
1918 | } | 1991 | } |
1919 | 1992 | ||
1920 | static void sdhci_timeout_timer(unsigned long data) | 1993 | static void sdhci_timeout_timer(unsigned long data) |
@@ -2146,12 +2219,19 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) | |||
2146 | static irqreturn_t sdhci_irq(int irq, void *dev_id) | 2219 | static irqreturn_t sdhci_irq(int irq, void *dev_id) |
2147 | { | 2220 | { |
2148 | irqreturn_t result; | 2221 | irqreturn_t result; |
2149 | struct sdhci_host* host = dev_id; | 2222 | struct sdhci_host *host = dev_id; |
2150 | u32 intmask; | 2223 | u32 intmask; |
2151 | int cardint = 0; | 2224 | int cardint = 0; |
2152 | 2225 | ||
2153 | spin_lock(&host->lock); | 2226 | spin_lock(&host->lock); |
2154 | 2227 | ||
2228 | if (host->runtime_suspended) { | ||
2229 | spin_unlock(&host->lock); | ||
2230 | printk(KERN_WARNING "%s: got irq while runtime suspended\n", | ||
2231 | mmc_hostname(host->mmc)); | ||
2232 | return IRQ_HANDLED; | ||
2233 | } | ||
2234 | |||
2155 | intmask = sdhci_readl(host, SDHCI_INT_STATUS); | 2235 | intmask = sdhci_readl(host, SDHCI_INT_STATUS); |
2156 | 2236 | ||
2157 | if (!intmask || intmask == 0xffffffff) { | 2237 | if (!intmask || intmask == 0xffffffff) { |
@@ -2285,7 +2365,6 @@ int sdhci_resume_host(struct sdhci_host *host) | |||
2285 | return ret; | 2365 | return ret; |
2286 | } | 2366 | } |
2287 | 2367 | ||
2288 | |||
2289 | if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { | 2368 | if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { |
2290 | if (host->ops->enable_dma) | 2369 | if (host->ops->enable_dma) |
2291 | host->ops->enable_dma(host); | 2370 | host->ops->enable_dma(host); |
@@ -2324,6 +2403,90 @@ EXPORT_SYMBOL_GPL(sdhci_enable_irq_wakeups); | |||
2324 | 2403 | ||
2325 | #endif /* CONFIG_PM */ | 2404 | #endif /* CONFIG_PM */ |
2326 | 2405 | ||
2406 | #ifdef CONFIG_PM_RUNTIME | ||
2407 | |||
2408 | static int sdhci_runtime_pm_get(struct sdhci_host *host) | ||
2409 | { | ||
2410 | return pm_runtime_get_sync(host->mmc->parent); | ||
2411 | } | ||
2412 | |||
2413 | static int sdhci_runtime_pm_put(struct sdhci_host *host) | ||
2414 | { | ||
2415 | pm_runtime_mark_last_busy(host->mmc->parent); | ||
2416 | return pm_runtime_put_autosuspend(host->mmc->parent); | ||
2417 | } | ||
2418 | |||
2419 | int sdhci_runtime_suspend_host(struct sdhci_host *host) | ||
2420 | { | ||
2421 | unsigned long flags; | ||
2422 | int ret = 0; | ||
2423 | |||
2424 | /* Disable tuning since we are suspending */ | ||
2425 | if (host->version >= SDHCI_SPEC_300 && | ||
2426 | host->tuning_mode == SDHCI_TUNING_MODE_1) { | ||
2427 | del_timer_sync(&host->tuning_timer); | ||
2428 | host->flags &= ~SDHCI_NEEDS_RETUNING; | ||
2429 | } | ||
2430 | |||
2431 | spin_lock_irqsave(&host->lock, flags); | ||
2432 | sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); | ||
2433 | spin_unlock_irqrestore(&host->lock, flags); | ||
2434 | |||
2435 | synchronize_irq(host->irq); | ||
2436 | |||
2437 | spin_lock_irqsave(&host->lock, flags); | ||
2438 | host->runtime_suspended = true; | ||
2439 | spin_unlock_irqrestore(&host->lock, flags); | ||
2440 | |||
2441 | return ret; | ||
2442 | } | ||
2443 | EXPORT_SYMBOL_GPL(sdhci_runtime_suspend_host); | ||
2444 | |||
2445 | int sdhci_runtime_resume_host(struct sdhci_host *host) | ||
2446 | { | ||
2447 | unsigned long flags; | ||
2448 | int ret = 0, host_flags = host->flags; | ||
2449 | |||
2450 | if (host_flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { | ||
2451 | if (host->ops->enable_dma) | ||
2452 | host->ops->enable_dma(host); | ||
2453 | } | ||
2454 | |||
2455 | sdhci_init(host, 0); | ||
2456 | |||
2457 | /* Force clock and power re-program */ | ||
2458 | host->pwr = 0; | ||
2459 | host->clock = 0; | ||
2460 | sdhci_do_set_ios(host, &host->mmc->ios); | ||
2461 | |||
2462 | sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios); | ||
2463 | if (host_flags & SDHCI_PV_ENABLED) | ||
2464 | sdhci_do_enable_preset_value(host, true); | ||
2465 | |||
2466 | /* Set the re-tuning expiration flag */ | ||
2467 | if ((host->version >= SDHCI_SPEC_300) && host->tuning_count && | ||
2468 | (host->tuning_mode == SDHCI_TUNING_MODE_1)) | ||
2469 | host->flags |= SDHCI_NEEDS_RETUNING; | ||
2470 | |||
2471 | spin_lock_irqsave(&host->lock, flags); | ||
2472 | |||
2473 | host->runtime_suspended = false; | ||
2474 | |||
2475 | /* Enable SDIO IRQ */ | ||
2476 | if ((host->flags & SDHCI_SDIO_IRQ_ENABLED)) | ||
2477 | sdhci_enable_sdio_irq_nolock(host, true); | ||
2478 | |||
2479 | /* Enable Card Detection */ | ||
2480 | sdhci_enable_card_detection(host); | ||
2481 | |||
2482 | spin_unlock_irqrestore(&host->lock, flags); | ||
2483 | |||
2484 | return ret; | ||
2485 | } | ||
2486 | EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host); | ||
2487 | |||
2488 | #endif | ||
2489 | |||
2327 | /*****************************************************************************\ | 2490 | /*****************************************************************************\ |
2328 | * * | 2491 | * * |
2329 | * Device allocation/registration * | 2492 | * Device allocation/registration * |
@@ -2366,6 +2529,8 @@ int sdhci_add_host(struct sdhci_host *host) | |||
2366 | 2529 | ||
2367 | if (debug_quirks) | 2530 | if (debug_quirks) |
2368 | host->quirks = debug_quirks; | 2531 | host->quirks = debug_quirks; |
2532 | if (debug_quirks2) | ||
2533 | host->quirks2 = debug_quirks2; | ||
2369 | 2534 | ||
2370 | sdhci_reset(host, SDHCI_RESET_ALL); | 2535 | sdhci_reset(host, SDHCI_RESET_ALL); |
2371 | 2536 | ||
@@ -2888,9 +3053,11 @@ module_init(sdhci_drv_init); | |||
2888 | module_exit(sdhci_drv_exit); | 3053 | module_exit(sdhci_drv_exit); |
2889 | 3054 | ||
2890 | module_param(debug_quirks, uint, 0444); | 3055 | module_param(debug_quirks, uint, 0444); |
3056 | module_param(debug_quirks2, uint, 0444); | ||
2891 | 3057 | ||
2892 | MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>"); | 3058 | MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>"); |
2893 | MODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver"); | 3059 | MODULE_DESCRIPTION("Secure Digital Host Controller Interface core driver"); |
2894 | MODULE_LICENSE("GPL"); | 3060 | MODULE_LICENSE("GPL"); |
2895 | 3061 | ||
2896 | MODULE_PARM_DESC(debug_quirks, "Force certain quirks."); | 3062 | MODULE_PARM_DESC(debug_quirks, "Force certain quirks."); |
3063 | MODULE_PARM_DESC(debug_quirks2, "Force certain other quirks."); | ||
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 7bd919c33cc2..0a5b65460d8a 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h | |||
@@ -379,4 +379,9 @@ extern int sdhci_resume_host(struct sdhci_host *host); | |||
379 | extern void sdhci_enable_irq_wakeups(struct sdhci_host *host); | 379 | extern void sdhci_enable_irq_wakeups(struct sdhci_host *host); |
380 | #endif | 380 | #endif |
381 | 381 | ||
382 | #ifdef CONFIG_PM_RUNTIME | ||
383 | extern int sdhci_runtime_suspend_host(struct sdhci_host *host); | ||
384 | extern int sdhci_runtime_resume_host(struct sdhci_host *host); | ||
385 | #endif | ||
386 | |||
382 | #endif /* __SDHCI_HW_H */ | 387 | #endif /* __SDHCI_HW_H */ |
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 5666f3abfab7..e4b69353678d 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h | |||
@@ -88,6 +88,10 @@ struct sdhci_host { | |||
88 | /* The read-only detection via SDHCI_PRESENT_STATE register is unstable */ | 88 | /* The read-only detection via SDHCI_PRESENT_STATE register is unstable */ |
89 | #define SDHCI_QUIRK_UNSTABLE_RO_DETECT (1<<31) | 89 | #define SDHCI_QUIRK_UNSTABLE_RO_DETECT (1<<31) |
90 | 90 | ||
91 | unsigned int quirks2; /* More deviations from spec. */ | ||
92 | |||
93 | #define SDHCI_QUIRK2_OWN_CARD_DETECTION (1<<0) | ||
94 | |||
91 | int irq; /* Device IRQ */ | 95 | int irq; /* Device IRQ */ |
92 | void __iomem *ioaddr; /* Mapped address */ | 96 | void __iomem *ioaddr; /* Mapped address */ |
93 | 97 | ||
@@ -115,6 +119,8 @@ struct sdhci_host { | |||
115 | #define SDHCI_NEEDS_RETUNING (1<<5) /* Host needs retuning */ | 119 | #define SDHCI_NEEDS_RETUNING (1<<5) /* Host needs retuning */ |
116 | #define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */ | 120 | #define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */ |
117 | #define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */ | 121 | #define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */ |
122 | #define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */ | ||
123 | #define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */ | ||
118 | 124 | ||
119 | unsigned int version; /* SDHCI spec. version */ | 125 | unsigned int version; /* SDHCI spec. version */ |
120 | 126 | ||
@@ -125,6 +131,8 @@ struct sdhci_host { | |||
125 | unsigned int clock; /* Current clock (MHz) */ | 131 | unsigned int clock; /* Current clock (MHz) */ |
126 | u8 pwr; /* Current voltage */ | 132 | u8 pwr; /* Current voltage */ |
127 | 133 | ||
134 | bool runtime_suspended; /* Host is runtime suspended */ | ||
135 | |||
128 | struct mmc_request *mrq; /* Current request */ | 136 | struct mmc_request *mrq; /* Current request */ |
129 | struct mmc_command *cmd; /* Current command */ | 137 | struct mmc_command *cmd; /* Current command */ |
130 | struct mmc_data *data; /* Current data request */ | 138 | struct mmc_data *data; /* Current data request */ |