diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2012-02-09 16:57:09 -0500 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2012-03-27 12:20:15 -0400 |
commit | c8be24c2afd3ed2445bbf8f542af35a9787fc0e8 (patch) | |
tree | e0e757bb3b6a45f55eef145484ca5707d9e45fa8 | |
parent | 2b1ac5c2caccbfd43bd616321cbbe21eb33c7879 (diff) |
mmc: tmio_mmc: support the generic MMC GPIO card hotplug helper
If the platform specifies the TMIO_MMC_HAS_COLD_CD flag, use the generic
MMC GPIO card hotplug helper.
Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r-- | drivers/mmc/host/tmio_mmc.h | 4 | ||||
-rw-r--r-- | drivers/mmc/host/tmio_mmc_pio.c | 69 | ||||
-rw-r--r-- | include/linux/mfd/tmio.h | 25 |
3 files changed, 50 insertions, 48 deletions
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index 8531d8d44fc1..ede2f4e5b952 100644 --- a/drivers/mmc/host/tmio_mmc.h +++ b/drivers/mmc/host/tmio_mmc.h | |||
@@ -53,10 +53,6 @@ struct tmio_mmc_host { | |||
53 | void (*set_pwr)(struct platform_device *host, int state); | 53 | void (*set_pwr)(struct platform_device *host, int state); |
54 | void (*set_clk_div)(struct platform_device *host, int state); | 54 | void (*set_clk_div)(struct platform_device *host, int state); |
55 | 55 | ||
56 | int pm_error; | ||
57 | /* recognise system-wide suspend in runtime PM methods */ | ||
58 | bool pm_global; | ||
59 | |||
60 | /* pio related stuff */ | 56 | /* pio related stuff */ |
61 | struct scatterlist *sg_ptr; | 57 | struct scatterlist *sg_ptr; |
62 | struct scatterlist *sg_orig; | 58 | struct scatterlist *sg_orig; |
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index 49f7f218cee1..42970ab6e803 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/io.h> | 34 | #include <linux/io.h> |
35 | #include <linux/irq.h> | 35 | #include <linux/irq.h> |
36 | #include <linux/mfd/tmio.h> | 36 | #include <linux/mfd/tmio.h> |
37 | #include <linux/mmc/cd-gpio.h> | ||
37 | #include <linux/mmc/host.h> | 38 | #include <linux/mmc/host.h> |
38 | #include <linux/mmc/tmio.h> | 39 | #include <linux/mmc/tmio.h> |
39 | #include <linux/module.h> | 40 | #include <linux/module.h> |
@@ -791,8 +792,10 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
791 | spin_unlock_irqrestore(&host->lock, flags); | 792 | spin_unlock_irqrestore(&host->lock, flags); |
792 | 793 | ||
793 | /* | 794 | /* |
794 | * pdata->power == false only if COLD_CD is available, otherwise only | 795 | * pdata->power toggles between false and true in both cases - either |
795 | * in short time intervals during probing or resuming | 796 | * or not the controller can be runtime-suspended during inactivity. |
797 | * But if the controller has to be kept on, the runtime-pm usage_count | ||
798 | * is kept positive, so no suspending actually takes place. | ||
796 | */ | 799 | */ |
797 | if (ios->power_mode == MMC_POWER_ON && ios->clock) { | 800 | if (ios->power_mode == MMC_POWER_ON && ios->clock) { |
798 | if (!pdata->power) { | 801 | if (!pdata->power) { |
@@ -916,7 +919,7 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, | |||
916 | else | 919 | else |
917 | mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; | 920 | mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; |
918 | 921 | ||
919 | _host->native_hotplug = !(pdata->flags & TMIO_MMC_HAS_COLD_CD || | 922 | _host->native_hotplug = !(pdata->flags & TMIO_MMC_USE_GPIO_CD || |
920 | mmc->caps & MMC_CAP_NEEDS_POLL || | 923 | mmc->caps & MMC_CAP_NEEDS_POLL || |
921 | mmc->caps & MMC_CAP_NONREMOVABLE); | 924 | mmc->caps & MMC_CAP_NONREMOVABLE); |
922 | 925 | ||
@@ -933,8 +936,9 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, | |||
933 | * 3) a worker thread polls the sdhi - indicated by MMC_CAP_NEEDS_POLL | 936 | * 3) a worker thread polls the sdhi - indicated by MMC_CAP_NEEDS_POLL |
934 | * 4) the medium is non-removable - indicated by MMC_CAP_NONREMOVABLE | 937 | * 4) the medium is non-removable - indicated by MMC_CAP_NONREMOVABLE |
935 | * | 938 | * |
936 | * While we increment the rtpm counter for all scenarios when the mmc | 939 | * While we increment the runtime PM counter for all scenarios when |
937 | * core activates us by calling an appropriate set_ios(), we must | 940 | * the mmc core activates us by calling an appropriate set_ios(), we |
941 | * must additionally ensure that in case 2) the tmio mmc hardware stays | ||
938 | * additionally ensure that in case 2) the tmio mmc hardware stays | 942 | * additionally ensure that in case 2) the tmio mmc hardware stays |
939 | * powered on during runtime for the card detection to work. | 943 | * powered on during runtime for the card detection to work. |
940 | */ | 944 | */ |
@@ -973,6 +977,14 @@ int __devinit tmio_mmc_host_probe(struct tmio_mmc_host **host, | |||
973 | 977 | ||
974 | tmio_mmc_enable_mmc_irqs(_host, irq_mask); | 978 | tmio_mmc_enable_mmc_irqs(_host, irq_mask); |
975 | 979 | ||
980 | if (pdata->flags & TMIO_MMC_USE_GPIO_CD) { | ||
981 | ret = mmc_cd_gpio_request(mmc, pdata->cd_gpio); | ||
982 | if (ret < 0) { | ||
983 | tmio_mmc_host_remove(_host); | ||
984 | return ret; | ||
985 | } | ||
986 | } | ||
987 | |||
976 | *host = _host; | 988 | *host = _host; |
977 | 989 | ||
978 | return 0; | 990 | return 0; |
@@ -990,20 +1002,22 @@ EXPORT_SYMBOL(tmio_mmc_host_probe); | |||
990 | void tmio_mmc_host_remove(struct tmio_mmc_host *host) | 1002 | void tmio_mmc_host_remove(struct tmio_mmc_host *host) |
991 | { | 1003 | { |
992 | struct platform_device *pdev = host->pdev; | 1004 | struct platform_device *pdev = host->pdev; |
1005 | struct tmio_mmc_data *pdata = host->pdata; | ||
1006 | struct mmc_host *mmc = host->mmc; | ||
1007 | |||
1008 | if (pdata->flags & TMIO_MMC_USE_GPIO_CD) | ||
1009 | /* | ||
1010 | * This means we can miss a card-eject, but this is anyway | ||
1011 | * possible, because of delayed processing of hotplug events. | ||
1012 | */ | ||
1013 | mmc_cd_gpio_free(mmc); | ||
993 | 1014 | ||
994 | /* | ||
995 | * We don't have to manipulate pdata->power here: if there is a card in | ||
996 | * the slot, the runtime PM is active and our .runtime_resume() will not | ||
997 | * be run. If there is no card in the slot and the platform can suspend | ||
998 | * the controller, the runtime PM is suspended and pdata->power == false, | ||
999 | * so, our .runtime_resume() will not try to detect a card in the slot. | ||
1000 | */ | ||
1001 | if (!host->native_hotplug) | 1015 | if (!host->native_hotplug) |
1002 | pm_runtime_get_sync(&pdev->dev); | 1016 | pm_runtime_get_sync(&pdev->dev); |
1003 | 1017 | ||
1004 | dev_pm_qos_hide_latency_limit(&pdev->dev); | 1018 | dev_pm_qos_hide_latency_limit(&pdev->dev); |
1005 | 1019 | ||
1006 | mmc_remove_host(host->mmc); | 1020 | mmc_remove_host(mmc); |
1007 | cancel_work_sync(&host->done); | 1021 | cancel_work_sync(&host->done); |
1008 | cancel_delayed_work_sync(&host->delayed_reset_work); | 1022 | cancel_delayed_work_sync(&host->delayed_reset_work); |
1009 | tmio_mmc_release_dma(host); | 1023 | tmio_mmc_release_dma(host); |
@@ -1012,7 +1026,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host) | |||
1012 | pm_runtime_disable(&pdev->dev); | 1026 | pm_runtime_disable(&pdev->dev); |
1013 | 1027 | ||
1014 | iounmap(host->ctl); | 1028 | iounmap(host->ctl); |
1015 | mmc_free_host(host->mmc); | 1029 | mmc_free_host(mmc); |
1016 | } | 1030 | } |
1017 | EXPORT_SYMBOL(tmio_mmc_host_remove); | 1031 | EXPORT_SYMBOL(tmio_mmc_host_remove); |
1018 | 1032 | ||
@@ -1026,8 +1040,6 @@ int tmio_mmc_host_suspend(struct device *dev) | |||
1026 | if (!ret) | 1040 | if (!ret) |
1027 | tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL); | 1041 | tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL); |
1028 | 1042 | ||
1029 | host->pm_error = pm_runtime_put_sync(dev); | ||
1030 | |||
1031 | return ret; | 1043 | return ret; |
1032 | } | 1044 | } |
1033 | EXPORT_SYMBOL(tmio_mmc_host_suspend); | 1045 | EXPORT_SYMBOL(tmio_mmc_host_suspend); |
@@ -1037,20 +1049,10 @@ int tmio_mmc_host_resume(struct device *dev) | |||
1037 | struct mmc_host *mmc = dev_get_drvdata(dev); | 1049 | struct mmc_host *mmc = dev_get_drvdata(dev); |
1038 | struct tmio_mmc_host *host = mmc_priv(mmc); | 1050 | struct tmio_mmc_host *host = mmc_priv(mmc); |
1039 | 1051 | ||
1040 | /* The MMC core will perform the complete set up */ | 1052 | tmio_mmc_reset(host); |
1041 | host->pdata->power = false; | 1053 | tmio_mmc_enable_dma(host, true); |
1042 | |||
1043 | host->pm_global = true; | ||
1044 | if (!host->pm_error) | ||
1045 | pm_runtime_get_sync(dev); | ||
1046 | |||
1047 | if (host->pm_global) { | ||
1048 | /* Runtime PM resume callback didn't run */ | ||
1049 | tmio_mmc_reset(host); | ||
1050 | tmio_mmc_enable_dma(host, true); | ||
1051 | host->pm_global = false; | ||
1052 | } | ||
1053 | 1054 | ||
1055 | /* The MMC core will perform the complete set up */ | ||
1054 | return mmc_resume_host(mmc); | 1056 | return mmc_resume_host(mmc); |
1055 | } | 1057 | } |
1056 | EXPORT_SYMBOL(tmio_mmc_host_resume); | 1058 | EXPORT_SYMBOL(tmio_mmc_host_resume); |
@@ -1067,19 +1069,10 @@ int tmio_mmc_host_runtime_resume(struct device *dev) | |||
1067 | { | 1069 | { |
1068 | struct mmc_host *mmc = dev_get_drvdata(dev); | 1070 | struct mmc_host *mmc = dev_get_drvdata(dev); |
1069 | struct tmio_mmc_host *host = mmc_priv(mmc); | 1071 | struct tmio_mmc_host *host = mmc_priv(mmc); |
1070 | struct tmio_mmc_data *pdata = host->pdata; | ||
1071 | 1072 | ||
1072 | tmio_mmc_reset(host); | 1073 | tmio_mmc_reset(host); |
1073 | tmio_mmc_enable_dma(host, true); | 1074 | tmio_mmc_enable_dma(host, true); |
1074 | 1075 | ||
1075 | if (pdata->power) { | ||
1076 | /* Only entered after a card-insert interrupt */ | ||
1077 | if (!mmc->card) | ||
1078 | tmio_mmc_set_ios(mmc, &mmc->ios); | ||
1079 | mmc_detect_change(mmc, msecs_to_jiffies(100)); | ||
1080 | } | ||
1081 | host->pm_global = false; | ||
1082 | |||
1083 | return 0; | 1076 | return 0; |
1084 | } | 1077 | } |
1085 | EXPORT_SYMBOL(tmio_mmc_host_runtime_resume); | 1078 | EXPORT_SYMBOL(tmio_mmc_host_runtime_resume); |
diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h index 0dc98044d8b7..5a197de4aac9 100644 --- a/include/linux/mfd/tmio.h +++ b/include/linux/mfd/tmio.h | |||
@@ -1,8 +1,10 @@ | |||
1 | #ifndef MFD_TMIO_H | 1 | #ifndef MFD_TMIO_H |
2 | #define MFD_TMIO_H | 2 | #define MFD_TMIO_H |
3 | 3 | ||
4 | #include <linux/device.h> | ||
4 | #include <linux/fb.h> | 5 | #include <linux/fb.h> |
5 | #include <linux/io.h> | 6 | #include <linux/io.h> |
7 | #include <linux/jiffies.h> | ||
6 | #include <linux/platform_device.h> | 8 | #include <linux/platform_device.h> |
7 | #include <linux/pm_runtime.h> | 9 | #include <linux/pm_runtime.h> |
8 | 10 | ||
@@ -64,8 +66,8 @@ | |||
64 | #define TMIO_MMC_SDIO_IRQ (1 << 2) | 66 | #define TMIO_MMC_SDIO_IRQ (1 << 2) |
65 | /* | 67 | /* |
66 | * Some platforms can detect card insertion events with controller powered | 68 | * Some platforms can detect card insertion events with controller powered |
67 | * down, in which case they have to call tmio_mmc_cd_wakeup() to power up the | 69 | * down, using a GPIO IRQ, in which case they have to fill in cd_irq, cd_gpio, |
68 | * controller and report the event to the driver. | 70 | * and cd_flags fields of struct tmio_mmc_data. |
69 | */ | 71 | */ |
70 | #define TMIO_MMC_HAS_COLD_CD (1 << 3) | 72 | #define TMIO_MMC_HAS_COLD_CD (1 << 3) |
71 | /* | 73 | /* |
@@ -73,6 +75,12 @@ | |||
73 | * idle before writing to some registers. | 75 | * idle before writing to some registers. |
74 | */ | 76 | */ |
75 | #define TMIO_MMC_HAS_IDLE_WAIT (1 << 4) | 77 | #define TMIO_MMC_HAS_IDLE_WAIT (1 << 4) |
78 | /* | ||
79 | * A GPIO is used for card hotplug detection. We need an extra flag for this, | ||
80 | * because 0 is a valid GPIO number too, and requiring users to specify | ||
81 | * cd_gpio < 0 to disable GPIO hotplug would break backwards compatibility. | ||
82 | */ | ||
83 | #define TMIO_MMC_USE_GPIO_CD (1 << 5) | ||
76 | 84 | ||
77 | int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base); | 85 | int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base); |
78 | int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base); | 86 | int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base); |
@@ -98,18 +106,23 @@ struct tmio_mmc_data { | |||
98 | struct tmio_mmc_dma *dma; | 106 | struct tmio_mmc_dma *dma; |
99 | struct device *dev; | 107 | struct device *dev; |
100 | bool power; | 108 | bool power; |
109 | unsigned int cd_gpio; | ||
101 | void (*set_pwr)(struct platform_device *host, int state); | 110 | void (*set_pwr)(struct platform_device *host, int state); |
102 | void (*set_clk_div)(struct platform_device *host, int state); | 111 | void (*set_clk_div)(struct platform_device *host, int state); |
103 | int (*get_cd)(struct platform_device *host); | 112 | int (*get_cd)(struct platform_device *host); |
104 | int (*write16_hook)(struct tmio_mmc_host *host, int addr); | 113 | int (*write16_hook)(struct tmio_mmc_host *host, int addr); |
105 | }; | 114 | }; |
106 | 115 | ||
116 | /* | ||
117 | * This function is deprecated and will be removed soon. Please, convert your | ||
118 | * platform to use drivers/mmc/core/cd-gpio.c | ||
119 | */ | ||
120 | #include <linux/mmc/host.h> | ||
107 | static inline void tmio_mmc_cd_wakeup(struct tmio_mmc_data *pdata) | 121 | static inline void tmio_mmc_cd_wakeup(struct tmio_mmc_data *pdata) |
108 | { | 122 | { |
109 | if (pdata && !pdata->power) { | 123 | if (pdata) |
110 | pdata->power = true; | 124 | mmc_detect_change(dev_get_drvdata(pdata->dev), |
111 | pm_runtime_get(pdata->dev); | 125 | msecs_to_jiffies(100)); |
112 | } | ||
113 | } | 126 | } |
114 | 127 | ||
115 | /* | 128 | /* |