From patchwork Tue Jul 24 13:30:03 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ludovic Desroches X-Patchwork-Id: 1231181 Return-Path: X-Original-To: patchwork-linux-mmc@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 59CA84025E for ; Tue, 24 Jul 2012 13:31:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751801Ab2GXNbO (ORCPT ); Tue, 24 Jul 2012 09:31:14 -0400 Received: from eusmtp01.atmel.com ([212.144.249.242]:65158 "EHLO eusmtp01.atmel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751378Ab2GXNbO (ORCPT ); Tue, 24 Jul 2012 09:31:14 -0400 Received: from HNOCHT01.corp.atmel.com (10.161.30.161) by eusmtp01.atmel.com (10.161.101.30) with Microsoft SMTP Server (TLS) id 14.2.247.3; Tue, 24 Jul 2012 15:31:59 +0200 Received: from localhost.localdomain (10.159.245.197) by HNOCHT01.corp.atmel.com (10.161.30.160) with Microsoft SMTP Server (TLS) id 14.2.247.3; Tue, 24 Jul 2012 15:31:12 +0200 From: To: , CC: , , Subject: [PATCH 1/4] mmc: atmel-mci: add device tree support Date: Tue, 24 Jul 2012 15:30:03 +0200 Message-ID: <1343136606-8874-2-git-send-email-ludovic.desroches@atmel.com> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1343136606-8874-1-git-send-email-ludovic.desroches@atmel.com> References: <1343136606-8874-1-git-send-email-ludovic.desroches@atmel.com> MIME-Version: 1.0 X-Originating-IP: [10.159.245.197] Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org From: Ludovic Desroches Signed-off-by: Ludovic Desroches --- .../devicetree/bindings/mmc/atmel-hsmci.txt | 68 ++++++++++++++++ drivers/mmc/host/atmel-mci.c | 85 +++++++++++++++++++- 2 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/mmc/atmel-hsmci.txt diff --git a/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt new file mode 100644 index 0000000..0a85c70 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt @@ -0,0 +1,68 @@ +* Atmel High Speed MultiMedia Card Interface + +This controller on atmel products provides an interface for MMC, SD and SDIO +types of memory cards. + +This file documents differences between the core properties described +by mmc.txt and the properties used by the atmel-mci driver. + +1) MCI node + +Required properties: +- compatible: should be "atmel,hsmci" +- #address-cells: should be one. The cell is the slot id. +- #size-cells: should be zero. +- at least one slot node + +The node contains child nodes for each slot that the platform uses + +Example MCI node: + +mmc0: mmc@f0008000 { + compatible = "atmel,hsmci"; + reg = <0xf0008000 0x600>; + interrupts = <12 4>; + #address-cells = <1>; + #size-cells = <0>; + + [ child node definitions...] +}; + +2) slot nodes + +Required properties: +- reg: should contain the slot id. +- bus-width: number of data lines connected to the controller + +Optional properties: +- cd-gpios: specify GPIOs for card detection +- cd-inverted: invert the value of external card detect gpio line +- wp-gpios: specify GPIOs for write protection + +Example slot node: + +slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioD 15 0> + cd-inverted; +}; + +Example full MCI node: +mmc0: mmc@f0008000 { + compatible = "atmel,hsmci"; + reg = <0xf0008000 0x600>; + interrupts = <12 4>; + #address-cells = <1>; + #size-cells = <0>; + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioD 15 0> + cd-inverted; + }; + slot@1 { + reg = <1>; + bus-width = <4>; + }; +}; diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index f2c115e..47421fc 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -493,6 +496,70 @@ err: dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n"); } +#if defined(CONFIG_OF) +static const struct of_device_id atmci_dt_ids[] = { + { .compatible = "atmel,hsmci" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, atmci_dt_ids); + +static struct mci_platform_data __devinit* +atmci_of_init(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *cnp; + struct mci_platform_data *pdata; + u32 slot_id; + + if (!np) { + dev_err(&pdev->dev, "device node not found\n"); + return ERR_PTR(-EINVAL); + } + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "could not allocate memory for pdata\n"); + return ERR_PTR(-ENOMEM); + } + + for_each_child_of_node(np, cnp) { + if (of_property_read_u32(cnp, "reg", &slot_id)) { + dev_warn(&pdev->dev, "reg property is missing for %s\n", + cnp->full_name); + continue; + } + + if (slot_id >= ATMCI_MAX_NR_SLOTS) { + dev_warn(&pdev->dev, "can't have more than %d slots\n", + ATMCI_MAX_NR_SLOTS); + break; + } + + if (of_property_read_u32(cnp, "bus-width", + &pdata->slot[slot_id].bus_width)) + pdata->slot[slot_id].bus_width = 1; + + pdata->slot[slot_id].detect_pin = + of_get_named_gpio(cnp, "cd-gpios", 0); + + pdata->slot[slot_id].detect_is_active_high = + of_property_read_bool(cnp, "cd-inverted"); + + pdata->slot[slot_id].wp_pin = + of_get_named_gpio(cnp, "wp-gpios", 0); + } + + return pdata; +} +#else /* CONFIG_OF */ +static inline struct mci_platform_data* +atmci_of_init(struct platform_device *dev) +{ + return ERR_PTR(-EINVAL); +} +#endif + static inline unsigned int atmci_get_version(struct atmel_mci *host) { return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; @@ -2038,6 +2105,13 @@ static int __init atmci_init_slot(struct atmel_mci *host, slot->sdc_reg = sdc_reg; slot->sdio_irq = sdio_irq; + dev_dbg(&mmc->class_dev, + "slot[%u]: bus_width=%u, detect_pin=%d, " + "detect_is_active_high=%s, wp_pin=%d\n", + id, slot_data->bus_width, slot_data->detect_pin, + slot_data->detect_is_active_high ? "true" : "false", + slot_data->wp_pin); + mmc->ops = &atmci_ops; mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512); mmc->f_max = host->bus_hz / 2; @@ -2258,8 +2332,14 @@ static int __init atmci_probe(struct platform_device *pdev) if (!regs) return -ENXIO; pdata = pdev->dev.platform_data; - if (!pdata) - return -ENXIO; + if (!pdata) { + pdata = atmci_of_init(pdev); + if (IS_ERR(pdata)) { + dev_err(&pdev->dev, "platform data not available\n"); + return PTR_ERR(pdata); + } + } + irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -2477,6 +2557,7 @@ static struct platform_driver atmci_driver = { .driver = { .name = "atmel_mci", .pm = ATMCI_PM_OPS, + .of_match_table = of_match_ptr(atmci_dt_ids), }, };