aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2011-07-14 06:16:59 -0400
committerChris Ball <cjb@laptop.org>2011-07-21 10:35:06 -0400
commit71d111cd34ee119c93d056ad9e84dc0e82367f82 (patch)
tree7bc21722ad1f8122b57ca5fe96b2298ded3fea40 /drivers/mmc
parentb9269fdd4f61aa4d185c982b0f84a3e7b7ccb4d2 (diff)
mmc: tmio: maximize power saving
This patch uses runtime PM to allow the system to power down the MMC controller, when the MMC closk is switched off. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/tmio_mmc.h2
-rw-r--r--drivers/mmc/host/tmio_mmc_pio.c64
2 files changed, 39 insertions, 27 deletions
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index f0d7c4349793..ba0d8e66001d 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -53,6 +53,8 @@ struct tmio_mmc_host {
53 void (*set_clk_div)(struct platform_device *host, int state); 53 void (*set_clk_div)(struct platform_device *host, int state);
54 54
55 int pm_error; 55 int pm_error;
56 /* recognise system-wide suspend in runtime PM methods */
57 bool pm_global;
56 58
57 /* pio related stuff */ 59 /* pio related stuff */
58 struct scatterlist *sg_ptr; 60 struct scatterlist *sg_ptr;
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index a2f76adbfd34..221ffb71c7a3 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -546,6 +546,7 @@ out:
546irqreturn_t tmio_mmc_irq(int irq, void *devid) 546irqreturn_t tmio_mmc_irq(int irq, void *devid)
547{ 547{
548 struct tmio_mmc_host *host = devid; 548 struct tmio_mmc_host *host = devid;
549 struct mmc_host *mmc = host->mmc;
549 struct tmio_mmc_data *pdata = host->pdata; 550 struct tmio_mmc_data *pdata = host->pdata;
550 unsigned int ireg, irq_mask, status; 551 unsigned int ireg, irq_mask, status;
551 unsigned int sdio_ireg, sdio_irq_mask, sdio_status; 552 unsigned int sdio_ireg, sdio_irq_mask, sdio_status;
@@ -567,13 +568,13 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid)
567 if (sdio_ireg && !host->sdio_irq_enabled) { 568 if (sdio_ireg && !host->sdio_irq_enabled) {
568 pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n", 569 pr_warning("tmio_mmc: Spurious SDIO IRQ, disabling! 0x%04x 0x%04x 0x%04x\n",
569 sdio_status, sdio_irq_mask, sdio_ireg); 570 sdio_status, sdio_irq_mask, sdio_ireg);
570 tmio_mmc_enable_sdio_irq(host->mmc, 0); 571 tmio_mmc_enable_sdio_irq(mmc, 0);
571 goto out; 572 goto out;
572 } 573 }
573 574
574 if (host->mmc->caps & MMC_CAP_SDIO_IRQ && 575 if (mmc->caps & MMC_CAP_SDIO_IRQ &&
575 sdio_ireg & TMIO_SDIO_STAT_IOIRQ) 576 sdio_ireg & TMIO_SDIO_STAT_IOIRQ)
576 mmc_signal_sdio_irq(host->mmc); 577 mmc_signal_sdio_irq(mmc);
577 578
578 if (sdio_ireg) 579 if (sdio_ireg)
579 goto out; 580 goto out;
@@ -586,7 +587,9 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid)
586 if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) { 587 if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)) {
587 tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT | 588 tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_CARD_INSERT |
588 TMIO_STAT_CARD_REMOVE); 589 TMIO_STAT_CARD_REMOVE);
589 if (!work_pending(&host->mmc->detect.work)) 590 if ((((ireg & TMIO_STAT_CARD_REMOVE) && mmc->card) ||
591 ((ireg & TMIO_STAT_CARD_INSERT) && !mmc->card)) &&
592 !work_pending(&mmc->detect.work))
590 mmc_detect_change(host->mmc, msecs_to_jiffies(100)); 593 mmc_detect_change(host->mmc, msecs_to_jiffies(100));
591 goto out; 594 goto out;
592 } 595 }
@@ -743,33 +746,30 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
743 746
744 spin_unlock_irqrestore(&host->lock, flags); 747 spin_unlock_irqrestore(&host->lock, flags);
745 748
746 if (ios->clock) 749 /*
747 tmio_mmc_set_clock(host, ios->clock); 750 * pdata->power == false only if COLD_CD is available, otherwise only
748 751 * in short time intervals during probing or resuming
749 /* Power sequence - OFF -> UP -> ON */ 752 */
750 if (ios->power_mode == MMC_POWER_UP) { 753 if (ios->power_mode == MMC_POWER_ON && ios->clock) {
751 if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) && !pdata->power) { 754 if (!pdata->power) {
752 pm_runtime_get_sync(&host->pdev->dev); 755 pm_runtime_get_sync(&host->pdev->dev);
753 pdata->power = true; 756 pdata->power = true;
754 } 757 }
758 tmio_mmc_set_clock(host, ios->clock);
755 /* power up SD bus */ 759 /* power up SD bus */
756 if (host->set_pwr) 760 if (host->set_pwr)
757 host->set_pwr(host->pdev, 1); 761 host->set_pwr(host->pdev, 1);
758 } else if (ios->power_mode == MMC_POWER_OFF || !ios->clock) {
759 /* power down SD bus */
760 if (ios->power_mode == MMC_POWER_OFF) {
761 if (host->set_pwr)
762 host->set_pwr(host->pdev, 0);
763 if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) &&
764 pdata->power) {
765 pdata->power = false;
766 pm_runtime_put(&host->pdev->dev);
767 }
768 }
769 tmio_mmc_clk_stop(host);
770 } else {
771 /* start bus clock */ 762 /* start bus clock */
772 tmio_mmc_clk_start(host); 763 tmio_mmc_clk_start(host);
764 } else if (ios->power_mode != MMC_POWER_UP) {
765 if (host->set_pwr)
766 host->set_pwr(host->pdev, 0);
767 if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) &&
768 pdata->power) {
769 pdata->power = false;
770 pm_runtime_put(&host->pdev->dev);
771 }
772 tmio_mmc_clk_stop(host);
773 } 773 }
774 774
775 switch (ios->bus_width) { 775 switch (ios->bus_width) {
@@ -897,8 +897,10 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
897 tmio_mmc_request_dma(_host, pdata); 897 tmio_mmc_request_dma(_host, pdata);
898 898
899 /* We have to keep the device powered for its card detection to work */ 899 /* We have to keep the device powered for its card detection to work */
900 if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD)) 900 if (!(pdata->flags & TMIO_MMC_HAS_COLD_CD)) {
901 pdata->power = true;
901 pm_runtime_get_noresume(&pdev->dev); 902 pm_runtime_get_noresume(&pdev->dev);
903 }
902 904
903 mmc_add_host(mmc); 905 mmc_add_host(mmc);
904 906
@@ -975,11 +977,16 @@ int tmio_mmc_host_resume(struct device *dev)
975 /* The MMC core will perform the complete set up */ 977 /* The MMC core will perform the complete set up */
976 host->pdata->power = false; 978 host->pdata->power = false;
977 979
980 host->pm_global = true;
978 if (!host->pm_error) 981 if (!host->pm_error)
979 pm_runtime_get_sync(dev); 982 pm_runtime_get_sync(dev);
980 983
981 tmio_mmc_reset(mmc_priv(mmc)); 984 if (host->pm_global) {
982 tmio_mmc_request_dma(host, host->pdata); 985 /* Runtime PM resume callback didn't run */
986 tmio_mmc_reset(host);
987 tmio_mmc_request_dma(host, host->pdata);
988 host->pm_global = false;
989 }
983 990
984 return mmc_resume_host(mmc); 991 return mmc_resume_host(mmc);
985} 992}
@@ -1000,12 +1007,15 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
1000 struct tmio_mmc_data *pdata = host->pdata; 1007 struct tmio_mmc_data *pdata = host->pdata;
1001 1008
1002 tmio_mmc_reset(host); 1009 tmio_mmc_reset(host);
1010 tmio_mmc_request_dma(host, host->pdata);
1003 1011
1004 if (pdata->power) { 1012 if (pdata->power) {
1005 /* Only entered after a card-insert interrupt */ 1013 /* Only entered after a card-insert interrupt */
1006 tmio_mmc_set_ios(mmc, &mmc->ios); 1014 if (!mmc->card)
1015 tmio_mmc_set_ios(mmc, &mmc->ios);
1007 mmc_detect_change(mmc, msecs_to_jiffies(100)); 1016 mmc_detect_change(mmc, msecs_to_jiffies(100));
1008 } 1017 }
1018 host->pm_global = false;
1009 1019
1010 return 0; 1020 return 0;
1011} 1021}