diff options
author | Shawn Guo <shawn.guo@linaro.org> | 2011-05-27 11:48:12 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-07-20 17:16:06 -0400 |
commit | 85d6509dc8ca24b2b652863ef7a75622ddca17d6 (patch) | |
tree | e564c2d4f80478027abc96cb7d87da952b38409e /drivers/mmc/host/sdhci-pltfm.c | |
parent | 3a5c3743f15f27237ab025736a981e2d0c9fdfed (diff) |
mmc: sdhci: make sdhci-pltfm device drivers self registered
The patch turns the common stuff in sdhci-pltfm.c into functions, and
add device drivers their own .probe and .remove which in turn call
into the common functions, so that those sdhci-pltfm device drivers
register itself and keep all device specific things away from common
sdhci-pltfm file.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Grant Likely <grant.likely@secretlab.ca>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Anton Vorontsov <cbouatmailru@gmail.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/host/sdhci-pltfm.c')
-rw-r--r-- | drivers/mmc/host/sdhci-pltfm.c | 157 |
1 files changed, 37 insertions, 120 deletions
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index dbab0407f4b6..8ccf25666201 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c | |||
@@ -22,48 +22,22 @@ | |||
22 | * Inspired by sdhci-pci.c, by Pierre Ossman | 22 | * Inspired by sdhci-pci.c, by Pierre Ossman |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <linux/delay.h> | 25 | #include <linux/err.h> |
26 | #include <linux/highmem.h> | ||
27 | #include <linux/mod_devicetable.h> | ||
28 | #include <linux/platform_device.h> | ||
29 | |||
30 | #include <linux/mmc/host.h> | ||
31 | |||
32 | #include <linux/io.h> | ||
33 | #include <linux/mmc/sdhci-pltfm.h> | ||
34 | 26 | ||
35 | #include "sdhci.h" | 27 | #include "sdhci.h" |
36 | #include "sdhci-pltfm.h" | 28 | #include "sdhci-pltfm.h" |
37 | 29 | ||
38 | /*****************************************************************************\ | ||
39 | * * | ||
40 | * SDHCI core callbacks * | ||
41 | * * | ||
42 | \*****************************************************************************/ | ||
43 | |||
44 | static struct sdhci_ops sdhci_pltfm_ops = { | 30 | static struct sdhci_ops sdhci_pltfm_ops = { |
45 | }; | 31 | }; |
46 | 32 | ||
47 | /*****************************************************************************\ | 33 | struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev, |
48 | * * | 34 | struct sdhci_pltfm_data *pdata) |
49 | * Device probing/removal * | ||
50 | * * | ||
51 | \*****************************************************************************/ | ||
52 | |||
53 | static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) | ||
54 | { | 35 | { |
55 | const struct platform_device_id *platid = platform_get_device_id(pdev); | ||
56 | struct sdhci_pltfm_data *pdata; | ||
57 | struct sdhci_host *host; | 36 | struct sdhci_host *host; |
58 | struct sdhci_pltfm_host *pltfm_host; | 37 | struct sdhci_pltfm_host *pltfm_host; |
59 | struct resource *iomem; | 38 | struct resource *iomem; |
60 | int ret; | 39 | int ret; |
61 | 40 | ||
62 | if (platid && platid->driver_data) | ||
63 | pdata = (void *)platid->driver_data; | ||
64 | else | ||
65 | pdata = pdev->dev.platform_data; | ||
66 | |||
67 | iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 41 | iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
68 | if (!iomem) { | 42 | if (!iomem) { |
69 | ret = -ENOMEM; | 43 | ret = -ENOMEM; |
@@ -71,8 +45,7 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) | |||
71 | } | 45 | } |
72 | 46 | ||
73 | if (resource_size(iomem) < 0x100) | 47 | if (resource_size(iomem) < 0x100) |
74 | dev_err(&pdev->dev, "Invalid iomem size. You may " | 48 | dev_err(&pdev->dev, "Invalid iomem size!\n"); |
75 | "experience problems.\n"); | ||
76 | 49 | ||
77 | /* Some PCI-based MFD need the parent here */ | 50 | /* Some PCI-based MFD need the parent here */ |
78 | if (pdev->dev.parent != &platform_bus) | 51 | if (pdev->dev.parent != &platform_bus) |
@@ -87,7 +60,7 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) | |||
87 | 60 | ||
88 | pltfm_host = sdhci_priv(host); | 61 | pltfm_host = sdhci_priv(host); |
89 | 62 | ||
90 | host->hw_name = "platform"; | 63 | host->hw_name = dev_name(&pdev->dev); |
91 | if (pdata && pdata->ops) | 64 | if (pdata && pdata->ops) |
92 | host->ops = pdata->ops; | 65 | host->ops = pdata->ops; |
93 | else | 66 | else |
@@ -110,126 +83,70 @@ static int __devinit sdhci_pltfm_probe(struct platform_device *pdev) | |||
110 | goto err_remap; | 83 | goto err_remap; |
111 | } | 84 | } |
112 | 85 | ||
113 | if (pdata && pdata->init) { | ||
114 | ret = pdata->init(host, pdata); | ||
115 | if (ret) | ||
116 | goto err_plat_init; | ||
117 | } | ||
118 | |||
119 | ret = sdhci_add_host(host); | ||
120 | if (ret) | ||
121 | goto err_add_host; | ||
122 | |||
123 | platform_set_drvdata(pdev, host); | 86 | platform_set_drvdata(pdev, host); |
124 | 87 | ||
125 | return 0; | 88 | return host; |
126 | 89 | ||
127 | err_add_host: | ||
128 | if (pdata && pdata->exit) | ||
129 | pdata->exit(host); | ||
130 | err_plat_init: | ||
131 | iounmap(host->ioaddr); | ||
132 | err_remap: | 90 | err_remap: |
133 | release_mem_region(iomem->start, resource_size(iomem)); | 91 | release_mem_region(iomem->start, resource_size(iomem)); |
134 | err_request: | 92 | err_request: |
135 | sdhci_free_host(host); | 93 | sdhci_free_host(host); |
136 | err: | 94 | err: |
137 | printk(KERN_ERR"Probing of sdhci-pltfm failed: %d\n", ret); | 95 | dev_err(&pdev->dev, "%s failed %d\n", __func__, ret); |
138 | return ret; | 96 | return ERR_PTR(ret); |
139 | } | 97 | } |
140 | 98 | ||
141 | static int __devexit sdhci_pltfm_remove(struct platform_device *pdev) | 99 | void sdhci_pltfm_free(struct platform_device *pdev) |
142 | { | 100 | { |
143 | struct sdhci_pltfm_data *pdata = pdev->dev.platform_data; | ||
144 | struct sdhci_host *host = platform_get_drvdata(pdev); | 101 | struct sdhci_host *host = platform_get_drvdata(pdev); |
145 | struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 102 | struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
146 | int dead; | ||
147 | u32 scratch; | ||
148 | |||
149 | dead = 0; | ||
150 | scratch = readl(host->ioaddr + SDHCI_INT_STATUS); | ||
151 | if (scratch == (u32)-1) | ||
152 | dead = 1; | ||
153 | 103 | ||
154 | sdhci_remove_host(host, dead); | ||
155 | if (pdata && pdata->exit) | ||
156 | pdata->exit(host); | ||
157 | iounmap(host->ioaddr); | 104 | iounmap(host->ioaddr); |
158 | release_mem_region(iomem->start, resource_size(iomem)); | 105 | release_mem_region(iomem->start, resource_size(iomem)); |
159 | sdhci_free_host(host); | 106 | sdhci_free_host(host); |
160 | platform_set_drvdata(pdev, NULL); | 107 | platform_set_drvdata(pdev, NULL); |
108 | } | ||
161 | 109 | ||
162 | return 0; | 110 | int sdhci_pltfm_register(struct platform_device *pdev, |
111 | struct sdhci_pltfm_data *pdata) | ||
112 | { | ||
113 | struct sdhci_host *host; | ||
114 | int ret = 0; | ||
115 | |||
116 | host = sdhci_pltfm_init(pdev, pdata); | ||
117 | if (IS_ERR(host)) | ||
118 | return PTR_ERR(host); | ||
119 | |||
120 | ret = sdhci_add_host(host); | ||
121 | if (ret) | ||
122 | sdhci_pltfm_free(pdev); | ||
123 | |||
124 | return ret; | ||
163 | } | 125 | } |
164 | 126 | ||
165 | static const struct platform_device_id sdhci_pltfm_ids[] = { | 127 | int sdhci_pltfm_unregister(struct platform_device *pdev) |
166 | { "sdhci", }, | 128 | { |
167 | #ifdef CONFIG_MMC_SDHCI_CNS3XXX | 129 | struct sdhci_host *host = platform_get_drvdata(pdev); |
168 | { "sdhci-cns3xxx", (kernel_ulong_t)&sdhci_cns3xxx_pdata }, | 130 | int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); |
169 | #endif | 131 | |
170 | #ifdef CONFIG_MMC_SDHCI_ESDHC_IMX | 132 | sdhci_remove_host(host, dead); |
171 | { "sdhci-esdhc-imx", (kernel_ulong_t)&sdhci_esdhc_imx_pdata }, | 133 | sdhci_pltfm_free(pdev); |
172 | #endif | 134 | |
173 | #ifdef CONFIG_MMC_SDHCI_DOVE | 135 | return 0; |
174 | { "sdhci-dove", (kernel_ulong_t)&sdhci_dove_pdata }, | 136 | } |
175 | #endif | ||
176 | #ifdef CONFIG_MMC_SDHCI_TEGRA | ||
177 | { "sdhci-tegra", (kernel_ulong_t)&sdhci_tegra_pdata }, | ||
178 | #endif | ||
179 | { }, | ||
180 | }; | ||
181 | MODULE_DEVICE_TABLE(platform, sdhci_pltfm_ids); | ||
182 | 137 | ||
183 | #ifdef CONFIG_PM | 138 | #ifdef CONFIG_PM |
184 | static int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state) | 139 | int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state) |
185 | { | 140 | { |
186 | struct sdhci_host *host = platform_get_drvdata(dev); | 141 | struct sdhci_host *host = platform_get_drvdata(dev); |
187 | 142 | ||
188 | return sdhci_suspend_host(host, state); | 143 | return sdhci_suspend_host(host, state); |
189 | } | 144 | } |
190 | 145 | ||
191 | static int sdhci_pltfm_resume(struct platform_device *dev) | 146 | int sdhci_pltfm_resume(struct platform_device *dev) |
192 | { | 147 | { |
193 | struct sdhci_host *host = platform_get_drvdata(dev); | 148 | struct sdhci_host *host = platform_get_drvdata(dev); |
194 | 149 | ||
195 | return sdhci_resume_host(host); | 150 | return sdhci_resume_host(host); |
196 | } | 151 | } |
197 | #else | ||
198 | #define sdhci_pltfm_suspend NULL | ||
199 | #define sdhci_pltfm_resume NULL | ||
200 | #endif /* CONFIG_PM */ | 152 | #endif /* CONFIG_PM */ |
201 | |||
202 | static struct platform_driver sdhci_pltfm_driver = { | ||
203 | .driver = { | ||
204 | .name = "sdhci", | ||
205 | .owner = THIS_MODULE, | ||
206 | }, | ||
207 | .probe = sdhci_pltfm_probe, | ||
208 | .remove = __devexit_p(sdhci_pltfm_remove), | ||
209 | .id_table = sdhci_pltfm_ids, | ||
210 | .suspend = sdhci_pltfm_suspend, | ||
211 | .resume = sdhci_pltfm_resume, | ||
212 | }; | ||
213 | |||
214 | /*****************************************************************************\ | ||
215 | * * | ||
216 | * Driver init/exit * | ||
217 | * * | ||
218 | \*****************************************************************************/ | ||
219 | |||
220 | static int __init sdhci_drv_init(void) | ||
221 | { | ||
222 | return platform_driver_register(&sdhci_pltfm_driver); | ||
223 | } | ||
224 | |||
225 | static void __exit sdhci_drv_exit(void) | ||
226 | { | ||
227 | platform_driver_unregister(&sdhci_pltfm_driver); | ||
228 | } | ||
229 | |||
230 | module_init(sdhci_drv_init); | ||
231 | module_exit(sdhci_drv_exit); | ||
232 | |||
233 | MODULE_DESCRIPTION("Secure Digital Host Controller Interface platform driver"); | ||
234 | MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>"); | ||
235 | MODULE_LICENSE("GPL v2"); | ||