aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLudovic Desroches <ludovic.desroches@atmel.com>2012-07-24 09:30:03 -0400
committerChris Ball <cjb@laptop.org>2012-09-04 13:58:14 -0400
commite919fd200033e80b26f152d22c00a8fae7f8d548 (patch)
tree09cf3583765d3acefe8a09b948c4827da928e9c6
parent77dcb3f4c344d4c9619803848f1aba4d271dac7b (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>
-rw-r--r--Documentation/devicetree/bindings/mmc/atmel-hsmci.txt68
-rw-r--r--drivers/mmc/host/atmel-mci.c85
2 files changed, 151 insertions, 2 deletions
diff --git a/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
new file mode 100644
index 000000000000..0a85c70cd30a
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
@@ -0,0 +1,68 @@
1* Atmel High Speed MultiMedia Card Interface
2
3This controller on atmel products provides an interface for MMC, SD and SDIO
4types of memory cards.
5
6This file documents differences between the core properties described
7by mmc.txt and the properties used by the atmel-mci driver.
8
91) MCI node
10
11Required properties:
12- compatible: should be "atmel,hsmci"
13- #address-cells: should be one. The cell is the slot id.
14- #size-cells: should be zero.
15- at least one slot node
16
17The node contains child nodes for each slot that the platform uses
18
19Example MCI node:
20
21mmc0: mmc@f0008000 {
22 compatible = "atmel,hsmci";
23 reg = <0xf0008000 0x600>;
24 interrupts = <12 4>;
25 #address-cells = <1>;
26 #size-cells = <0>;
27
28 [ child node definitions...]
29};
30
312) slot nodes
32
33Required properties:
34- reg: should contain the slot id.
35- bus-width: number of data lines connected to the controller
36
37Optional properties:
38- cd-gpios: specify GPIOs for card detection
39- cd-inverted: invert the value of external card detect gpio line
40- wp-gpios: specify GPIOs for write protection
41
42Example slot node:
43
44slot@0 {
45 reg = <0>;
46 bus-width = <4>;
47 cd-gpios = <&pioD 15 0>
48 cd-inverted;
49};
50
51Example full MCI node:
52mmc0: mmc@f0008000 {
53 compatible = "atmel,hsmci";
54 reg = <0xf0008000 0x600>;
55 interrupts = <12 4>;
56 #address-cells = <1>;
57 #size-cells = <0>;
58 slot@0 {
59 reg = <0>;
60 bus-width = <4>;
61 cd-gpios = <&pioD 15 0>
62 cd-inverted;
63 };
64 slot@1 {
65 reg = <1>;
66 bus-width = <4>;
67 };
68};
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)
507static const struct of_device_id atmci_dt_ids[] = {
508 { .compatible = "atmel,hsmci" },
509 { /* sentinel */ }
510};
511
512MODULE_DEVICE_TABLE(of, atmci_dt_ids);
513
514static struct mci_platform_data __devinit*
515atmci_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 */
563static inline struct mci_platform_data*
564atmci_of_init(struct platform_device *dev)
565{
566 return ERR_PTR(-EINVAL);
567}
568#endif
569
503static inline unsigned int atmci_get_version(struct atmel_mci *host) 570static 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