mmc: atmel-mci: add suspend/resume support
authorNicolas Ferre <nicolas.ferre@atmel.com>
Wed, 6 Jul 2011 09:31:36 +0000 (11:31 +0200)
committerChris Ball <cjb@laptop.org>
Wed, 20 Jul 2011 21:21:08 +0000 (17:21 -0400)
Take care of slots while going to suspend state.

Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Reviewed-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
drivers/mmc/host/atmel-mci.c

index aa8039f..fa8cae1 100644 (file)
@@ -203,6 +203,7 @@ struct atmel_mci_slot {
 #define ATMCI_CARD_PRESENT     0
 #define ATMCI_CARD_NEED_INIT   1
 #define ATMCI_SHUTDOWN         2
+#define ATMCI_SUSPENDED                3
 
        int                     detect_pin;
        int                     wp_pin;
@@ -1878,10 +1879,72 @@ static int __exit atmci_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int atmci_suspend(struct device *dev)
+{
+       struct atmel_mci *host = dev_get_drvdata(dev);
+       int i;
+
+        for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+               struct atmel_mci_slot *slot = host->slot[i];
+               int ret;
+
+               if (!slot)
+                       continue;
+               ret = mmc_suspend_host(slot->mmc);
+               if (ret < 0) {
+                       while (--i >= 0) {
+                               slot = host->slot[i];
+                               if (slot
+                               && test_bit(ATMCI_SUSPENDED, &slot->flags)) {
+                                       mmc_resume_host(host->slot[i]->mmc);
+                                       clear_bit(ATMCI_SUSPENDED, &slot->flags);
+                               }
+                       }
+                       return ret;
+               } else {
+                       set_bit(ATMCI_SUSPENDED, &slot->flags);
+               }
+       }
+
+       return 0;
+}
+
+static int atmci_resume(struct device *dev)
+{
+       struct atmel_mci *host = dev_get_drvdata(dev);
+       int i;
+       int ret = 0;
+
+       for (i = 0; i < ATMEL_MCI_MAX_NR_SLOTS; i++) {
+               struct atmel_mci_slot *slot = host->slot[i];
+               int err;
+
+               slot = host->slot[i];
+               if (!slot)
+                       continue;
+               if (!test_bit(ATMCI_SUSPENDED, &slot->flags))
+                       continue;
+               err = mmc_resume_host(slot->mmc);
+               if (err < 0)
+                       ret = err;
+               else
+                       clear_bit(ATMCI_SUSPENDED, &slot->flags);
+       }
+
+       return ret;
+}
+static SIMPLE_DEV_PM_OPS(atmci_pm, atmci_suspend, atmci_resume);
+#define ATMCI_PM_OPS   (&atmci_pm)
+#else
+#define ATMCI_PM_OPS   NULL
+#endif
+
 static struct platform_driver atmci_driver = {
        .remove         = __exit_p(atmci_remove),
        .driver         = {
                .name           = "atmel_mci",
+               .pm             = ATMCI_PM_OPS,
        },
 };