diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2011-07-14 06:16:59 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-07-21 10:35:06 -0400 |
commit | 71d111cd34ee119c93d056ad9e84dc0e82367f82 (patch) | |
tree | 7bc21722ad1f8122b57ca5fe96b2298ded3fea40 /drivers/mmc | |
parent | b9269fdd4f61aa4d185c982b0f84a3e7b7ccb4d2 (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.h | 2 | ||||
-rw-r--r-- | drivers/mmc/host/tmio_mmc_pio.c | 64 |
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: | |||
546 | irqreturn_t tmio_mmc_irq(int irq, void *devid) | 546 | irqreturn_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 | } |