diff options
author | Nicolas Pitre <nico@fluxnic.net> | 2010-03-05 16:43:32 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-06 14:26:37 -0500 |
commit | 2f4cbb3d834922ffa0309b6a08fa42dac87ef9d2 (patch) | |
tree | 9c4b919b3851d3e0c066ba5c456bf0d2c150da4f | |
parent | da68c4eb258cd9f3f0b8aeb7e46b8118bb6358b6 (diff) |
sdio: sdhci support for suspend mode PM features
Tested with an XO v1.5 from OLPC.
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Cc: <linux-mmc@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/mmc/host/sdhci-pci.c | 17 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 26 |
2 files changed, 31 insertions, 12 deletions
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 5c3a1767770a..dbf054315fe2 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c | |||
@@ -501,6 +501,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state) | |||
501 | { | 501 | { |
502 | struct sdhci_pci_chip *chip; | 502 | struct sdhci_pci_chip *chip; |
503 | struct sdhci_pci_slot *slot; | 503 | struct sdhci_pci_slot *slot; |
504 | mmc_pm_flag_t pm_flags = 0; | ||
504 | int i, ret; | 505 | int i, ret; |
505 | 506 | ||
506 | chip = pci_get_drvdata(pdev); | 507 | chip = pci_get_drvdata(pdev); |
@@ -519,6 +520,8 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state) | |||
519 | sdhci_resume_host(chip->slots[i]->host); | 520 | sdhci_resume_host(chip->slots[i]->host); |
520 | return ret; | 521 | return ret; |
521 | } | 522 | } |
523 | |||
524 | pm_flags |= slot->host->mmc->pm_flags; | ||
522 | } | 525 | } |
523 | 526 | ||
524 | if (chip->fixes && chip->fixes->suspend) { | 527 | if (chip->fixes && chip->fixes->suspend) { |
@@ -531,9 +534,15 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state) | |||
531 | } | 534 | } |
532 | 535 | ||
533 | pci_save_state(pdev); | 536 | pci_save_state(pdev); |
534 | pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); | 537 | if (pm_flags & MMC_PM_KEEP_POWER) { |
535 | pci_disable_device(pdev); | 538 | if (pm_flags & MMC_PM_WAKE_SDIO_IRQ) |
536 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | 539 | pci_enable_wake(pdev, PCI_D3hot, 1); |
540 | pci_set_power_state(pdev, PCI_D3hot); | ||
541 | } else { | ||
542 | pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); | ||
543 | pci_disable_device(pdev); | ||
544 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | ||
545 | } | ||
537 | 546 | ||
538 | return 0; | 547 | return 0; |
539 | } | 548 | } |
@@ -653,6 +662,8 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot( | |||
653 | goto unmap; | 662 | goto unmap; |
654 | } | 663 | } |
655 | 664 | ||
665 | host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; | ||
666 | |||
656 | ret = sdhci_add_host(host); | 667 | ret = sdhci_add_host(host); |
657 | if (ret) | 668 | if (ret) |
658 | goto remove; | 669 | goto remove; |
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 6c866b43b03c..d6ab62d539fb 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
@@ -174,20 +174,31 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask) | |||
174 | sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier); | 174 | sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier); |
175 | } | 175 | } |
176 | 176 | ||
177 | static void sdhci_init(struct sdhci_host *host) | 177 | static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios); |
178 | |||
179 | static void sdhci_init(struct sdhci_host *host, int soft) | ||
178 | { | 180 | { |
179 | sdhci_reset(host, SDHCI_RESET_ALL); | 181 | if (soft) |
182 | sdhci_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA); | ||
183 | else | ||
184 | sdhci_reset(host, SDHCI_RESET_ALL); | ||
180 | 185 | ||
181 | sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, | 186 | sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, |
182 | SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | | 187 | SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | |
183 | SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | | 188 | SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | |
184 | SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | | 189 | SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | |
185 | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE); | 190 | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE); |
191 | |||
192 | if (soft) { | ||
193 | /* force clock reconfiguration */ | ||
194 | host->clock = 0; | ||
195 | sdhci_set_ios(host->mmc, &host->mmc->ios); | ||
196 | } | ||
186 | } | 197 | } |
187 | 198 | ||
188 | static void sdhci_reinit(struct sdhci_host *host) | 199 | static void sdhci_reinit(struct sdhci_host *host) |
189 | { | 200 | { |
190 | sdhci_init(host); | 201 | sdhci_init(host, 0); |
191 | sdhci_enable_card_detection(host); | 202 | sdhci_enable_card_detection(host); |
192 | } | 203 | } |
193 | 204 | ||
@@ -1600,16 +1611,13 @@ int sdhci_resume_host(struct sdhci_host *host) | |||
1600 | if (ret) | 1611 | if (ret) |
1601 | return ret; | 1612 | return ret; |
1602 | 1613 | ||
1603 | sdhci_init(host); | 1614 | sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); |
1604 | mmiowb(); | 1615 | mmiowb(); |
1605 | 1616 | ||
1606 | ret = mmc_resume_host(host->mmc); | 1617 | ret = mmc_resume_host(host->mmc); |
1607 | if (ret) | ||
1608 | return ret; | ||
1609 | |||
1610 | sdhci_enable_card_detection(host); | 1618 | sdhci_enable_card_detection(host); |
1611 | 1619 | ||
1612 | return 0; | 1620 | return ret; |
1613 | } | 1621 | } |
1614 | 1622 | ||
1615 | EXPORT_SYMBOL_GPL(sdhci_resume_host); | 1623 | EXPORT_SYMBOL_GPL(sdhci_resume_host); |
@@ -1864,7 +1872,7 @@ int sdhci_add_host(struct sdhci_host *host) | |||
1864 | if (ret) | 1872 | if (ret) |
1865 | goto untasklet; | 1873 | goto untasklet; |
1866 | 1874 | ||
1867 | sdhci_init(host); | 1875 | sdhci_init(host, 0); |
1868 | 1876 | ||
1869 | #ifdef CONFIG_MMC_DEBUG | 1877 | #ifdef CONFIG_MMC_DEBUG |
1870 | sdhci_dumpregs(host); | 1878 | sdhci_dumpregs(host); |