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-esdhc-imx.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-esdhc-imx.c')
-rw-r--r-- | drivers/mmc/host/sdhci-esdhc-imx.c | 113 |
1 files changed, 82 insertions, 31 deletions
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index a19967d0bfc4..e27ccbb5285b 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c | |||
@@ -191,16 +191,6 @@ static unsigned int esdhc_pltfm_get_min_clock(struct sdhci_host *host) | |||
191 | return clk_get_rate(pltfm_host->clk) / 256 / 16; | 191 | return clk_get_rate(pltfm_host->clk) / 256 / 16; |
192 | } | 192 | } |
193 | 193 | ||
194 | static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) | ||
195 | { | ||
196 | struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; | ||
197 | |||
198 | if (boarddata && gpio_is_valid(boarddata->wp_gpio)) | ||
199 | return gpio_get_value(boarddata->wp_gpio); | ||
200 | else | ||
201 | return -ENOSYS; | ||
202 | } | ||
203 | |||
204 | static struct sdhci_ops sdhci_esdhc_ops = { | 194 | static struct sdhci_ops sdhci_esdhc_ops = { |
205 | .read_l = esdhc_readl_le, | 195 | .read_l = esdhc_readl_le, |
206 | .read_w = esdhc_readw_le, | 196 | .read_w = esdhc_readw_le, |
@@ -212,6 +202,24 @@ static struct sdhci_ops sdhci_esdhc_ops = { | |||
212 | .get_min_clock = esdhc_pltfm_get_min_clock, | 202 | .get_min_clock = esdhc_pltfm_get_min_clock, |
213 | }; | 203 | }; |
214 | 204 | ||
205 | static struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { | ||
206 | .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA | ||
207 | | SDHCI_QUIRK_BROKEN_CARD_DETECTION, | ||
208 | /* ADMA has issues. Might be fixable */ | ||
209 | .ops = &sdhci_esdhc_ops, | ||
210 | }; | ||
211 | |||
212 | static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) | ||
213 | { | ||
214 | struct esdhc_platform_data *boarddata = | ||
215 | host->mmc->parent->platform_data; | ||
216 | |||
217 | if (boarddata && gpio_is_valid(boarddata->wp_gpio)) | ||
218 | return gpio_get_value(boarddata->wp_gpio); | ||
219 | else | ||
220 | return -ENOSYS; | ||
221 | } | ||
222 | |||
215 | static irqreturn_t cd_irq(int irq, void *data) | 223 | static irqreturn_t cd_irq(int irq, void *data) |
216 | { | 224 | { |
217 | struct sdhci_host *sdhost = (struct sdhci_host *)data; | 225 | struct sdhci_host *sdhost = (struct sdhci_host *)data; |
@@ -220,30 +228,35 @@ static irqreturn_t cd_irq(int irq, void *data) | |||
220 | return IRQ_HANDLED; | 228 | return IRQ_HANDLED; |
221 | }; | 229 | }; |
222 | 230 | ||
223 | static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pdata) | 231 | static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) |
224 | { | 232 | { |
225 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | 233 | struct sdhci_pltfm_host *pltfm_host; |
226 | struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; | 234 | struct sdhci_host *host; |
235 | struct esdhc_platform_data *boarddata; | ||
227 | struct clk *clk; | 236 | struct clk *clk; |
228 | int err; | 237 | int err; |
229 | struct pltfm_imx_data *imx_data; | 238 | struct pltfm_imx_data *imx_data; |
230 | 239 | ||
240 | host = sdhci_pltfm_init(pdev, &sdhci_esdhc_imx_pdata); | ||
241 | if (IS_ERR(host)) | ||
242 | return PTR_ERR(host); | ||
243 | |||
244 | pltfm_host = sdhci_priv(host); | ||
245 | |||
246 | imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL); | ||
247 | if (!imx_data) | ||
248 | return -ENOMEM; | ||
249 | pltfm_host->priv = imx_data; | ||
250 | |||
231 | clk = clk_get(mmc_dev(host->mmc), NULL); | 251 | clk = clk_get(mmc_dev(host->mmc), NULL); |
232 | if (IS_ERR(clk)) { | 252 | if (IS_ERR(clk)) { |
233 | dev_err(mmc_dev(host->mmc), "clk err\n"); | 253 | dev_err(mmc_dev(host->mmc), "clk err\n"); |
234 | return PTR_ERR(clk); | 254 | err = PTR_ERR(clk); |
255 | goto err_clk_get; | ||
235 | } | 256 | } |
236 | clk_enable(clk); | 257 | clk_enable(clk); |
237 | pltfm_host->clk = clk; | 258 | pltfm_host->clk = clk; |
238 | 259 | ||
239 | imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL); | ||
240 | if (!imx_data) { | ||
241 | clk_disable(pltfm_host->clk); | ||
242 | clk_put(pltfm_host->clk); | ||
243 | return -ENOMEM; | ||
244 | } | ||
245 | pltfm_host->priv = imx_data; | ||
246 | |||
247 | if (!cpu_is_mx25()) | 260 | if (!cpu_is_mx25()) |
248 | host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; | 261 | host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL; |
249 | 262 | ||
@@ -257,6 +270,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd | |||
257 | if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51())) | 270 | if (!(cpu_is_mx25() || cpu_is_mx35() || cpu_is_mx51())) |
258 | imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; | 271 | imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; |
259 | 272 | ||
273 | boarddata = host->mmc->parent->platform_data; | ||
260 | if (boarddata) { | 274 | if (boarddata) { |
261 | err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); | 275 | err = gpio_request_one(boarddata->wp_gpio, GPIOF_IN, "ESDHC_WP"); |
262 | if (err) { | 276 | if (err) { |
@@ -289,6 +303,10 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd | |||
289 | host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; | 303 | host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION; |
290 | } | 304 | } |
291 | 305 | ||
306 | err = sdhci_add_host(host); | ||
307 | if (err) | ||
308 | goto err_add_host; | ||
309 | |||
292 | return 0; | 310 | return 0; |
293 | 311 | ||
294 | no_card_detect_irq: | 312 | no_card_detect_irq: |
@@ -297,14 +315,23 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd | |||
297 | boarddata->cd_gpio = err; | 315 | boarddata->cd_gpio = err; |
298 | not_supported: | 316 | not_supported: |
299 | kfree(imx_data); | 317 | kfree(imx_data); |
300 | return 0; | 318 | err_add_host: |
319 | clk_disable(pltfm_host->clk); | ||
320 | clk_put(pltfm_host->clk); | ||
321 | err_clk_get: | ||
322 | sdhci_pltfm_free(pdev); | ||
323 | return err; | ||
301 | } | 324 | } |
302 | 325 | ||
303 | static void esdhc_pltfm_exit(struct sdhci_host *host) | 326 | static int __devexit sdhci_esdhc_imx_remove(struct platform_device *pdev) |
304 | { | 327 | { |
328 | struct sdhci_host *host = platform_get_drvdata(pdev); | ||
305 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | 329 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
306 | struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; | 330 | struct esdhc_platform_data *boarddata = host->mmc->parent->platform_data; |
307 | struct pltfm_imx_data *imx_data = pltfm_host->priv; | 331 | struct pltfm_imx_data *imx_data = pltfm_host->priv; |
332 | int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); | ||
333 | |||
334 | sdhci_remove_host(host, dead); | ||
308 | 335 | ||
309 | if (boarddata && gpio_is_valid(boarddata->wp_gpio)) | 336 | if (boarddata && gpio_is_valid(boarddata->wp_gpio)) |
310 | gpio_free(boarddata->wp_gpio); | 337 | gpio_free(boarddata->wp_gpio); |
@@ -319,13 +346,37 @@ static void esdhc_pltfm_exit(struct sdhci_host *host) | |||
319 | clk_disable(pltfm_host->clk); | 346 | clk_disable(pltfm_host->clk); |
320 | clk_put(pltfm_host->clk); | 347 | clk_put(pltfm_host->clk); |
321 | kfree(imx_data); | 348 | kfree(imx_data); |
349 | |||
350 | sdhci_pltfm_free(pdev); | ||
351 | |||
352 | return 0; | ||
322 | } | 353 | } |
323 | 354 | ||
324 | struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { | 355 | static struct platform_driver sdhci_esdhc_imx_driver = { |
325 | .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_ADMA | 356 | .driver = { |
326 | | SDHCI_QUIRK_BROKEN_CARD_DETECTION, | 357 | .name = "sdhci-esdhc-imx", |
327 | /* ADMA has issues. Might be fixable */ | 358 | .owner = THIS_MODULE, |
328 | .ops = &sdhci_esdhc_ops, | 359 | }, |
329 | .init = esdhc_pltfm_init, | 360 | .probe = sdhci_esdhc_imx_probe, |
330 | .exit = esdhc_pltfm_exit, | 361 | .remove = __devexit_p(sdhci_esdhc_imx_remove), |
362 | #ifdef CONFIG_PM | ||
363 | .suspend = sdhci_pltfm_suspend, | ||
364 | .resume = sdhci_pltfm_resume, | ||
365 | #endif | ||
331 | }; | 366 | }; |
367 | |||
368 | static int __init sdhci_esdhc_imx_init(void) | ||
369 | { | ||
370 | return platform_driver_register(&sdhci_esdhc_imx_driver); | ||
371 | } | ||
372 | module_init(sdhci_esdhc_imx_init); | ||
373 | |||
374 | static void __exit sdhci_esdhc_imx_exit(void) | ||
375 | { | ||
376 | platform_driver_unregister(&sdhci_esdhc_imx_driver); | ||
377 | } | ||
378 | module_exit(sdhci_esdhc_imx_exit); | ||
379 | |||
380 | MODULE_DESCRIPTION("SDHCI driver for Freescale i.MX eSDHC"); | ||
381 | MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>"); | ||
382 | MODULE_LICENSE("GPL v2"); | ||