diff options
author | Shawn Guo <shawn.guo@linaro.org> | 2011-06-30 03:44:44 -0400 |
---|---|---|
committer | Shawn Guo <shawn.guo@linaro.org> | 2011-07-26 21:31:39 -0400 |
commit | abfafc2d10ee2ad217be9ef06181819ca5dd6960 (patch) | |
tree | 7d05feaadbdebb8997c3ce292f899bc7bc15be6a | |
parent | a4d2177f00a5252d825236c5124bc1e9918bdb41 (diff) |
mmc: sdhci-esdhc-imx: add device tree probe support
The patch adds device tree probe support for sdhci-esdhc-imx driver.
Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Cc: Wolfram Sang <w.sang@pengutronix.de>
Cc: Chris Ball <cjb@laptop.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Acked-by: Chris Ball <cjb@laptop.org>
-rw-r--r-- | Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt | 34 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-esdhc-imx.c | 78 |
2 files changed, 103 insertions, 9 deletions
diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt new file mode 100644 index 000000000000..ab22fe6e73ab --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt | |||
@@ -0,0 +1,34 @@ | |||
1 | * Freescale Enhanced Secure Digital Host Controller (eSDHC) for i.MX | ||
2 | |||
3 | The Enhanced Secure Digital Host Controller on Freescale i.MX family | ||
4 | provides an interface for MMC, SD, and SDIO types of memory cards. | ||
5 | |||
6 | Required properties: | ||
7 | - compatible : Should be "fsl,<chip>-esdhc" | ||
8 | - reg : Should contain eSDHC registers location and length | ||
9 | - interrupts : Should contain eSDHC interrupt | ||
10 | |||
11 | Optional properties: | ||
12 | - fsl,card-wired : Indicate the card is wired to host permanently | ||
13 | - fsl,cd-internal : Indicate to use controller internal card detection | ||
14 | - fsl,wp-internal : Indicate to use controller internal write protection | ||
15 | - cd-gpios : Specify GPIOs for card detection | ||
16 | - wp-gpios : Specify GPIOs for write protection | ||
17 | |||
18 | Examples: | ||
19 | |||
20 | esdhc@70004000 { | ||
21 | compatible = "fsl,imx51-esdhc"; | ||
22 | reg = <0x70004000 0x4000>; | ||
23 | interrupts = <1>; | ||
24 | fsl,cd-internal; | ||
25 | fsl,wp-internal; | ||
26 | }; | ||
27 | |||
28 | esdhc@70008000 { | ||
29 | compatible = "fsl,imx51-esdhc"; | ||
30 | reg = <0x70008000 0x4000>; | ||
31 | interrupts = <2>; | ||
32 | cd-gpios = <&gpio0 6 0>; /* GPIO1_6 */ | ||
33 | wp-gpios = <&gpio0 5 0>; /* GPIO1_5 */ | ||
34 | }; | ||
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index a0d0da4d9bc8..9ebfb4b482f5 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c | |||
@@ -20,6 +20,9 @@ | |||
20 | #include <linux/mmc/host.h> | 20 | #include <linux/mmc/host.h> |
21 | #include <linux/mmc/mmc.h> | 21 | #include <linux/mmc/mmc.h> |
22 | #include <linux/mmc/sdio.h> | 22 | #include <linux/mmc/sdio.h> |
23 | #include <linux/of.h> | ||
24 | #include <linux/of_device.h> | ||
25 | #include <linux/of_gpio.h> | ||
23 | #include <mach/esdhc.h> | 26 | #include <mach/esdhc.h> |
24 | #include "sdhci-pltfm.h" | 27 | #include "sdhci-pltfm.h" |
25 | #include "sdhci-esdhc.h" | 28 | #include "sdhci-esdhc.h" |
@@ -74,6 +77,15 @@ static struct platform_device_id imx_esdhc_devtype[] = { | |||
74 | }; | 77 | }; |
75 | MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype); | 78 | MODULE_DEVICE_TABLE(platform, imx_esdhc_devtype); |
76 | 79 | ||
80 | static const struct of_device_id imx_esdhc_dt_ids[] = { | ||
81 | { .compatible = "fsl,imx25-esdhc", .data = &imx_esdhc_devtype[IMX25_ESDHC], }, | ||
82 | { .compatible = "fsl,imx35-esdhc", .data = &imx_esdhc_devtype[IMX35_ESDHC], }, | ||
83 | { .compatible = "fsl,imx51-esdhc", .data = &imx_esdhc_devtype[IMX51_ESDHC], }, | ||
84 | { .compatible = "fsl,imx53-esdhc", .data = &imx_esdhc_devtype[IMX53_ESDHC], }, | ||
85 | { /* sentinel */ } | ||
86 | }; | ||
87 | MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); | ||
88 | |||
77 | static inline int is_imx25_esdhc(struct pltfm_imx_data *data) | 89 | static inline int is_imx25_esdhc(struct pltfm_imx_data *data) |
78 | { | 90 | { |
79 | return data->devtype == IMX25_ESDHC; | 91 | return data->devtype == IMX25_ESDHC; |
@@ -290,8 +302,48 @@ static irqreturn_t cd_irq(int irq, void *data) | |||
290 | return IRQ_HANDLED; | 302 | return IRQ_HANDLED; |
291 | }; | 303 | }; |
292 | 304 | ||
305 | #ifdef CONFIG_OF | ||
306 | static int __devinit | ||
307 | sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, | ||
308 | struct esdhc_platform_data *boarddata) | ||
309 | { | ||
310 | struct device_node *np = pdev->dev.of_node; | ||
311 | |||
312 | if (!np) | ||
313 | return -ENODEV; | ||
314 | |||
315 | if (of_get_property(np, "fsl,card-wired", NULL)) | ||
316 | boarddata->cd_type = ESDHC_CD_PERMANENT; | ||
317 | |||
318 | if (of_get_property(np, "fsl,cd-controller", NULL)) | ||
319 | boarddata->cd_type = ESDHC_CD_CONTROLLER; | ||
320 | |||
321 | if (of_get_property(np, "fsl,wp-controller", NULL)) | ||
322 | boarddata->wp_type = ESDHC_WP_CONTROLLER; | ||
323 | |||
324 | boarddata->cd_gpio = of_get_named_gpio(np, "cd-gpios", 0); | ||
325 | if (gpio_is_valid(boarddata->cd_gpio)) | ||
326 | boarddata->cd_type = ESDHC_CD_GPIO; | ||
327 | |||
328 | boarddata->wp_gpio = of_get_named_gpio(np, "wp-gpios", 0); | ||
329 | if (gpio_is_valid(boarddata->wp_gpio)) | ||
330 | boarddata->wp_type = ESDHC_WP_GPIO; | ||
331 | |||
332 | return 0; | ||
333 | } | ||
334 | #else | ||
335 | static inline int | ||
336 | sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, | ||
337 | struct esdhc_platform_data *boarddata) | ||
338 | { | ||
339 | return -ENODEV; | ||
340 | } | ||
341 | #endif | ||
342 | |||
293 | static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) | 343 | static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) |
294 | { | 344 | { |
345 | const struct of_device_id *of_id = | ||
346 | of_match_device(imx_esdhc_dt_ids, &pdev->dev); | ||
295 | struct sdhci_pltfm_host *pltfm_host; | 347 | struct sdhci_pltfm_host *pltfm_host; |
296 | struct sdhci_host *host; | 348 | struct sdhci_host *host; |
297 | struct esdhc_platform_data *boarddata; | 349 | struct esdhc_platform_data *boarddata; |
@@ -306,9 +358,13 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) | |||
306 | pltfm_host = sdhci_priv(host); | 358 | pltfm_host = sdhci_priv(host); |
307 | 359 | ||
308 | imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL); | 360 | imx_data = kzalloc(sizeof(struct pltfm_imx_data), GFP_KERNEL); |
309 | if (!imx_data) | 361 | if (!imx_data) { |
310 | return -ENOMEM; | 362 | err = -ENOMEM; |
363 | goto err_imx_data; | ||
364 | } | ||
311 | 365 | ||
366 | if (of_id) | ||
367 | pdev->id_entry = of_id->data; | ||
312 | imx_data->devtype = pdev->id_entry->driver_data; | 368 | imx_data->devtype = pdev->id_entry->driver_data; |
313 | pltfm_host->priv = imx_data; | 369 | pltfm_host->priv = imx_data; |
314 | 370 | ||
@@ -331,14 +387,16 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) | |||
331 | if (is_imx53_esdhc(imx_data)) | 387 | if (is_imx53_esdhc(imx_data)) |
332 | imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; | 388 | imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; |
333 | 389 | ||
334 | if (!host->mmc->parent->platform_data) { | ||
335 | dev_err(mmc_dev(host->mmc), "no board data!\n"); | ||
336 | err = -EINVAL; | ||
337 | goto no_board_data; | ||
338 | } | ||
339 | imx_data->boarddata = *((struct esdhc_platform_data *) | ||
340 | host->mmc->parent->platform_data); | ||
341 | boarddata = &imx_data->boarddata; | 390 | boarddata = &imx_data->boarddata; |
391 | if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { | ||
392 | if (!host->mmc->parent->platform_data) { | ||
393 | dev_err(mmc_dev(host->mmc), "no board data!\n"); | ||
394 | err = -EINVAL; | ||
395 | goto no_board_data; | ||
396 | } | ||
397 | imx_data->boarddata = *((struct esdhc_platform_data *) | ||
398 | host->mmc->parent->platform_data); | ||
399 | } | ||
342 | 400 | ||
343 | /* write_protect */ | 401 | /* write_protect */ |
344 | if (boarddata->wp_type == ESDHC_WP_GPIO) { | 402 | if (boarddata->wp_type == ESDHC_WP_GPIO) { |
@@ -407,6 +465,7 @@ no_board_data: | |||
407 | clk_put(pltfm_host->clk); | 465 | clk_put(pltfm_host->clk); |
408 | err_clk_get: | 466 | err_clk_get: |
409 | kfree(imx_data); | 467 | kfree(imx_data); |
468 | err_imx_data: | ||
410 | sdhci_pltfm_free(pdev); | 469 | sdhci_pltfm_free(pdev); |
411 | return err; | 470 | return err; |
412 | } | 471 | } |
@@ -442,6 +501,7 @@ static struct platform_driver sdhci_esdhc_imx_driver = { | |||
442 | .driver = { | 501 | .driver = { |
443 | .name = "sdhci-esdhc-imx", | 502 | .name = "sdhci-esdhc-imx", |
444 | .owner = THIS_MODULE, | 503 | .owner = THIS_MODULE, |
504 | .of_match_table = imx_esdhc_dt_ids, | ||
445 | }, | 505 | }, |
446 | .id_table = imx_esdhc_devtype, | 506 | .id_table = imx_esdhc_devtype, |
447 | .probe = sdhci_esdhc_imx_probe, | 507 | .probe = sdhci_esdhc_imx_probe, |