Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Ludovic Desroches and committed by
Chris Ball
e919fd20 77dcb3f4

+151 -2
+68
Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
··· 1 + * Atmel High Speed MultiMedia Card Interface 2 + 3 + This controller on atmel products provides an interface for MMC, SD and SDIO 4 + types of memory cards. 5 + 6 + This file documents differences between the core properties described 7 + by mmc.txt and the properties used by the atmel-mci driver. 8 + 9 + 1) MCI node 10 + 11 + Required 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 + 17 + The node contains child nodes for each slot that the platform uses 18 + 19 + Example MCI node: 20 + 21 + mmc0: 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 + 31 + 2) slot nodes 32 + 33 + Required properties: 34 + - reg: should contain the slot id. 35 + - bus-width: number of data lines connected to the controller 36 + 37 + Optional 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 + 42 + Example slot node: 43 + 44 + slot@0 { 45 + reg = <0>; 46 + bus-width = <4>; 47 + cd-gpios = <&pioD 15 0> 48 + cd-inverted; 49 + }; 50 + 51 + Example full MCI node: 52 + mmc0: 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 + };
+83 -2
drivers/mmc/host/atmel-mci.c
··· 19 19 #include <linux/interrupt.h> 20 20 #include <linux/ioport.h> 21 21 #include <linux/module.h> 22 + #include <linux/of.h> 23 + #include <linux/of_device.h> 24 + #include <linux/of_gpio.h> 22 25 #include <linux/platform_device.h> 23 26 #include <linux/scatterlist.h> 24 27 #include <linux/seq_file.h> ··· 502 499 err: 503 500 dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); 504 501 } 502 + 503 + #if defined(CONFIG_OF) 504 + static const struct of_device_id atmci_dt_ids[] = { 505 + { .compatible = "atmel,hsmci" }, 506 + { /* sentinel */ } 507 + }; 508 + 509 + MODULE_DEVICE_TABLE(of, atmci_dt_ids); 510 + 511 + static struct mci_platform_data __devinit* 512 + atmci_of_init(struct platform_device *pdev) 513 + { 514 + struct device_node *np = pdev->dev.of_node; 515 + struct device_node *cnp; 516 + struct mci_platform_data *pdata; 517 + u32 slot_id; 518 + 519 + if (!np) { 520 + dev_err(&pdev->dev, "device node not found\n"); 521 + return ERR_PTR(-EINVAL); 522 + } 523 + 524 + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 525 + if (!pdata) { 526 + dev_err(&pdev->dev, "could not allocate memory for pdata\n"); 527 + return ERR_PTR(-ENOMEM); 528 + } 529 + 530 + for_each_child_of_node(np, cnp) { 531 + if (of_property_read_u32(cnp, "reg", &slot_id)) { 532 + dev_warn(&pdev->dev, "reg property is missing for %s\n", 533 + cnp->full_name); 534 + continue; 535 + } 536 + 537 + if (slot_id >= ATMCI_MAX_NR_SLOTS) { 538 + dev_warn(&pdev->dev, "can't have more than %d slots\n", 539 + ATMCI_MAX_NR_SLOTS); 540 + break; 541 + } 542 + 543 + if (of_property_read_u32(cnp, "bus-width", 544 + &pdata->slot[slot_id].bus_width)) 545 + pdata->slot[slot_id].bus_width = 1; 546 + 547 + pdata->slot[slot_id].detect_pin = 548 + of_get_named_gpio(cnp, "cd-gpios", 0); 549 + 550 + pdata->slot[slot_id].detect_is_active_high = 551 + of_property_read_bool(cnp, "cd-inverted"); 552 + 553 + pdata->slot[slot_id].wp_pin = 554 + of_get_named_gpio(cnp, "wp-gpios", 0); 555 + } 556 + 557 + return pdata; 558 + } 559 + #else /* CONFIG_OF */ 560 + static inline struct mci_platform_data* 561 + atmci_of_init(struct platform_device *dev) 562 + { 563 + return ERR_PTR(-EINVAL); 564 + } 565 + #endif 505 566 506 567 static inline unsigned int atmci_get_version(struct atmel_mci *host) 507 568 { ··· 2113 2046 slot->sdc_reg = sdc_reg; 2114 2047 slot->sdio_irq = sdio_irq; 2115 2048 2049 + dev_dbg(&mmc->class_dev, 2050 + "slot[%u]: bus_width=%u, detect_pin=%d, " 2051 + "detect_is_active_high=%s, wp_pin=%d\n", 2052 + id, slot_data->bus_width, slot_data->detect_pin, 2053 + slot_data->detect_is_active_high ? "true" : "false", 2054 + slot_data->wp_pin); 2055 + 2116 2056 mmc->ops = &atmci_ops; 2117 2057 mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); 2118 2058 mmc->f_max = host->bus_hz / 2; ··· 2342 2268 if (!regs) 2343 2269 return -ENXIO; 2344 2270 pdata = pdev->dev.platform_data; 2345 - if (!pdata) 2346 - return -ENXIO; 2271 + if (!pdata) { 2272 + pdata = atmci_of_init(pdev); 2273 + if (IS_ERR(pdata)) { 2274 + dev_err(&pdev->dev, "platform data not available\n"); 2275 + return PTR_ERR(pdata); 2276 + } 2277 + } 2278 + 2347 2279 irq = platform_get_irq(pdev, 0); 2348 2280 if (irq < 0) 2349 2281 return irq; ··· 2567 2487 .driver = { 2568 2488 .name = "atmel_mci", 2569 2489 .pm = ATMCI_PM_OPS, 2490 + .of_match_table = of_match_ptr(atmci_dt_ids), 2570 2491 }, 2571 2492 }; 2572 2493