aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/tmio_mmc_pio.c
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2011-05-05 12:13:12 -0400
committerChris Ball <cjb@laptop.org>2011-05-24 23:53:51 -0400
commite6ee7182c3b22afe0b983eac89dc020a93a13179 (patch)
treeed40843e6e306917818f00aa00dc0a3c37d98d31 /drivers/mmc/host/tmio_mmc_pio.c
parent3b0beafc92406b98cbc2749b8db736f313d390b1 (diff)
mmc: Add runtime and system-wide PM to the TMIO MMC driver
Add runtime and system-wide power management to the TMIO MMC driver in PIO and DMA modes, allowing it to properly save and restore its state during system suspend. Runtime PM is very crude ATM, because the controller has to be powered on all the time to detect card hotplug events. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/host/tmio_mmc_pio.c')
-rw-r--r--drivers/mmc/host/tmio_mmc_pio.c57
1 files changed, 54 insertions, 3 deletions
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index 710339a85c84..8b05d3ceb29c 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -39,6 +39,7 @@
39#include <linux/module.h> 39#include <linux/module.h>
40#include <linux/pagemap.h> 40#include <linux/pagemap.h>
41#include <linux/platform_device.h> 41#include <linux/platform_device.h>
42#include <linux/pm_runtime.h>
42#include <linux/scatterlist.h> 43#include <linux/scatterlist.h>
43#include <linux/workqueue.h> 44#include <linux/workqueue.h>
44#include <linux/spinlock.h> 45#include <linux/spinlock.h>
@@ -834,12 +835,17 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
834 else 835 else
835 mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; 836 mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
836 837
838 pm_runtime_enable(&pdev->dev);
839 ret = pm_runtime_resume(&pdev->dev);
840 if (ret < 0)
841 goto pm_disable;
842
837 tmio_mmc_clk_stop(_host); 843 tmio_mmc_clk_stop(_host);
838 tmio_mmc_reset(_host); 844 tmio_mmc_reset(_host);
839 845
840 ret = platform_get_irq(pdev, 0); 846 ret = platform_get_irq(pdev, 0);
841 if (ret < 0) 847 if (ret < 0)
842 goto unmap_ctl; 848 goto pm_suspend;
843 849
844 _host->irq = ret; 850 _host->irq = ret;
845 851
@@ -850,7 +856,7 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
850 ret = request_irq(_host->irq, tmio_mmc_irq, IRQF_DISABLED | 856 ret = request_irq(_host->irq, tmio_mmc_irq, IRQF_DISABLED |
851 IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), _host); 857 IRQF_TRIGGER_FALLING, dev_name(&pdev->dev), _host);
852 if (ret) 858 if (ret)
853 goto unmap_ctl; 859 goto pm_suspend;
854 860
855 spin_lock_init(&_host->lock); 861 spin_lock_init(&_host->lock);
856 862
@@ -860,6 +866,9 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
860 /* See if we also get DMA */ 866 /* See if we also get DMA */
861 tmio_mmc_request_dma(_host, pdata); 867 tmio_mmc_request_dma(_host, pdata);
862 868
869 /* We have to keep the device powered for its card detection to work */
870 pm_runtime_get_noresume(&pdev->dev);
871
863 mmc_add_host(mmc); 872 mmc_add_host(mmc);
864 873
865 /* Unmask the IRQs we want to know about */ 874 /* Unmask the IRQs we want to know about */
@@ -874,7 +883,10 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host,
874 883
875 return 0; 884 return 0;
876 885
877unmap_ctl: 886pm_suspend:
887 pm_runtime_suspend(&pdev->dev);
888pm_disable:
889 pm_runtime_disable(&pdev->dev);
878 iounmap(_host->ctl); 890 iounmap(_host->ctl);
879host_free: 891host_free:
880 mmc_free_host(mmc); 892 mmc_free_host(mmc);
@@ -885,13 +897,52 @@ EXPORT_SYMBOL(tmio_mmc_host_probe);
885 897
886void tmio_mmc_host_remove(struct tmio_mmc_host *host) 898void tmio_mmc_host_remove(struct tmio_mmc_host *host)
887{ 899{
900 struct platform_device *pdev = host->pdev;
901
888 mmc_remove_host(host->mmc); 902 mmc_remove_host(host->mmc);
889 cancel_delayed_work_sync(&host->delayed_reset_work); 903 cancel_delayed_work_sync(&host->delayed_reset_work);
890 tmio_mmc_release_dma(host); 904 tmio_mmc_release_dma(host);
891 free_irq(host->irq, host); 905 free_irq(host->irq, host);
892 iounmap(host->ctl); 906 iounmap(host->ctl);
893 mmc_free_host(host->mmc); 907 mmc_free_host(host->mmc);
908
909 /* Compensate for pm_runtime_get_sync() in probe() above */
910 pm_runtime_put_sync(&pdev->dev);
911 pm_runtime_disable(&pdev->dev);
894} 912}
895EXPORT_SYMBOL(tmio_mmc_host_remove); 913EXPORT_SYMBOL(tmio_mmc_host_remove);
896 914
915#ifdef CONFIG_PM
916int tmio_mmc_host_suspend(struct device *dev)
917{
918 struct mmc_host *mmc = dev_get_drvdata(dev);
919 struct tmio_mmc_host *host = mmc_priv(mmc);
920 int ret = mmc_suspend_host(mmc);
921
922 if (!ret)
923 tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL);
924
925 host->pm_error = pm_runtime_put_sync(dev);
926
927 return ret;
928}
929EXPORT_SYMBOL(tmio_mmc_host_suspend);
930
931int tmio_mmc_host_resume(struct device *dev)
932{
933 struct mmc_host *mmc = dev_get_drvdata(dev);
934 struct tmio_mmc_host *host = mmc_priv(mmc);
935
936 if (!host->pm_error)
937 pm_runtime_get_sync(dev);
938
939 tmio_mmc_reset(mmc_priv(mmc));
940 tmio_mmc_request_dma(host, host->pdata);
941
942 return mmc_resume_host(mmc);
943}
944EXPORT_SYMBOL(tmio_mmc_host_resume);
945
946#endif /* CONFIG_PM */
947
897MODULE_LICENSE("GPL v2"); 948MODULE_LICENSE("GPL v2");