diff options
author | Ludovic Desroches <ludovic.desroches@atmel.com> | 2012-07-24 09:30:03 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2012-09-04 13:58:14 -0400 |
commit | e919fd200033e80b26f152d22c00a8fae7f8d548 (patch) | |
tree | 09cf3583765d3acefe8a09b948c4827da928e9c6 /drivers/mmc/host/atmel-mci.c | |
parent | 77dcb3f4c344d4c9619803848f1aba4d271dac7b (diff) |
mmc: atmel-mci: add device tree support
Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc/host/atmel-mci.c')
-rw-r--r-- | drivers/mmc/host/atmel-mci.c | 85 |
1 files changed, 83 insertions, 2 deletions
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index a53c7c478e05..8c72828239b2 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c | |||
@@ -19,6 +19,9 @@ | |||
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/ioport.h> | 20 | #include <linux/ioport.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/of.h> | ||
23 | #include <linux/of_device.h> | ||
24 | #include <linux/of_gpio.h> | ||
22 | #include <linux/platform_device.h> | 25 | #include <linux/platform_device.h> |
23 | #include <linux/scatterlist.h> | 26 | #include <linux/scatterlist.h> |
24 | #include <linux/seq_file.h> | 27 | #include <linux/seq_file.h> |
@@ -500,6 +503,70 @@ err: | |||
500 | dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); | 503 | dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); |
501 | } | 504 | } |
502 | 505 | ||
506 | #if defined(CONFIG_OF) | ||
507 | static const struct of_device_id atmci_dt_ids[] = { | ||
508 | { .compatible = "atmel,hsmci" }, | ||
509 | { /* sentinel */ } | ||
510 | }; | ||
511 | |||
512 | MODULE_DEVICE_TABLE(of, atmci_dt_ids); | ||
513 | |||
514 | static struct mci_platform_data __devinit* | ||
515 | atmci_of_init(struct platform_device *pdev) | ||
516 | { | ||
517 | struct device_node *np = pdev->dev.of_node; | ||
518 | struct device_node *cnp; | ||
519 | struct mci_platform_data *pdata; | ||
520 | u32 slot_id; | ||
521 | |||
522 | if (!np) { | ||
523 | dev_err(&pdev->dev, "device node not found\n"); | ||
524 | return ERR_PTR(-EINVAL); | ||
525 | } | ||
526 | |||
527 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||
528 | if (!pdata) { | ||
529 | dev_err(&pdev->dev, "could not allocate memory for pdata\n"); | ||
530 | return ERR_PTR(-ENOMEM); | ||
531 | } | ||
532 | |||
533 | for_each_child_of_node(np, cnp) { | ||
534 | if (of_property_read_u32(cnp, "reg", &slot_id)) { | ||
535 | dev_warn(&pdev->dev, "reg property is missing for %s\n", | ||
536 | cnp->full_name); | ||
537 | continue; | ||
538 | } | ||
539 | |||
540 | if (slot_id >= ATMCI_MAX_NR_SLOTS) { | ||
541 | dev_warn(&pdev->dev, "can't have more than %d slots\n", | ||
542 | ATMCI_MAX_NR_SLOTS); | ||
543 | break; | ||
544 | } | ||
545 | |||
546 | if (of_property_read_u32(cnp, "bus-width", | ||
547 | &pdata->slot[slot_id].bus_width)) | ||
548 | pdata->slot[slot_id].bus_width = 1; | ||
549 | |||
550 | pdata->slot[slot_id].detect_pin = | ||
551 | of_get_named_gpio(cnp, "cd-gpios", 0); | ||
552 | |||
553 | pdata->slot[slot_id].detect_is_active_high = | ||
554 | of_property_read_bool(cnp, "cd-inverted"); | ||
555 | |||
556 | pdata->slot[slot_id].wp_pin = | ||
557 | of_get_named_gpio(cnp, "wp-gpios", 0); | ||
558 | } | ||
559 | |||
560 | return pdata; | ||
561 | } | ||
562 | #else /* CONFIG_OF */ | ||
563 | static inline struct mci_platform_data* | ||
564 | atmci_of_init(struct platform_device *dev) | ||
565 | { | ||
566 | return ERR_PTR(-EINVAL); | ||
567 | } | ||
568 | #endif | ||
569 | |||
503 | static inline unsigned int atmci_get_version(struct atmel_mci *host) | 570 | static inline unsigned int atmci_get_version(struct atmel_mci *host) |
504 | { | 571 | { |
505 | return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; | 572 | return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; |
@@ -2046,6 +2113,13 @@ static int __init atmci_init_slot(struct atmel_mci *host, | |||
2046 | slot->sdc_reg = sdc_reg; | 2113 | slot->sdc_reg = sdc_reg; |
2047 | slot->sdio_irq = sdio_irq; | 2114 | slot->sdio_irq = sdio_irq; |
2048 | 2115 | ||
2116 | dev_dbg(&mmc->class_dev, | ||
2117 | "slot[%u]: bus_width=%u, detect_pin=%d, " | ||
2118 | "detect_is_active_high=%s, wp_pin=%d\n", | ||
2119 | id, slot_data->bus_width, slot_data->detect_pin, | ||
2120 | slot_data->detect_is_active_high ? "true" : "false", | ||
2121 | slot_data->wp_pin); | ||
2122 | |||
2049 | mmc->ops = &atmci_ops; | 2123 | mmc->ops = &atmci_ops; |
2050 | mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); | 2124 | mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); |
2051 | mmc->f_max = host->bus_hz / 2; | 2125 | mmc->f_max = host->bus_hz / 2; |
@@ -2268,8 +2342,14 @@ static int __init atmci_probe(struct platform_device *pdev) | |||
2268 | if (!regs) | 2342 | if (!regs) |
2269 | return -ENXIO; | 2343 | return -ENXIO; |
2270 | pdata = pdev->dev.platform_data; | 2344 | pdata = pdev->dev.platform_data; |
2271 | if (!pdata) | 2345 | if (!pdata) { |
2272 | return -ENXIO; | 2346 | pdata = atmci_of_init(pdev); |
2347 | if (IS_ERR(pdata)) { | ||
2348 | dev_err(&pdev->dev, "platform data not available\n"); | ||
2349 | return PTR_ERR(pdata); | ||
2350 | } | ||
2351 | } | ||
2352 | |||
2273 | irq = platform_get_irq(pdev, 0); | 2353 | irq = platform_get_irq(pdev, 0); |
2274 | if (irq < 0) | 2354 | if (irq < 0) |
2275 | return irq; | 2355 | return irq; |
@@ -2487,6 +2567,7 @@ static struct platform_driver atmci_driver = { | |||
2487 | .driver = { | 2567 | .driver = { |
2488 | .name = "atmel_mci", | 2568 | .name = "atmel_mci", |
2489 | .pm = ATMCI_PM_OPS, | 2569 | .pm = ATMCI_PM_OPS, |
2570 | .of_match_table = of_match_ptr(atmci_dt_ids), | ||
2490 | }, | 2571 | }, |
2491 | }; | 2572 | }; |
2492 | 2573 | ||