From patchwork Wed Jul 27 14:03:30 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jamie Iles X-Patchwork-Id: 107082 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from merlin.infradead.org (merlin.infradead.org [IPv6:2001:4978:20e::2]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id AFA42B6F69 for ; Thu, 28 Jul 2011 00:04:05 +1000 (EST) Received: from canuck.infradead.org ([2001:4978:20e::1]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1Qm4iD-00062D-5v; Wed, 27 Jul 2011 14:03:49 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Qm4iC-0006yd-Nc; Wed, 27 Jul 2011 14:03:48 +0000 Received: from mail-wy0-f177.google.com ([74.125.82.177]) by canuck.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1Qm4i7-0006yK-Bo for linux-mtd@lists.infradead.org; Wed, 27 Jul 2011 14:03:44 +0000 Received: by wyf23 with SMTP id 23so1178784wyf.36 for ; Wed, 27 Jul 2011 07:03:40 -0700 (PDT) Received: by 10.227.200.205 with SMTP id ex13mr5333610wbb.24.1311775419858; Wed, 27 Jul 2011 07:03:39 -0700 (PDT) Received: from localhost (gw-ba1.picochip.com [94.175.234.108]) by mx.google.com with ESMTPS id em16sm128203wbb.33.2011.07.27.07.03.38 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 27 Jul 2011 07:03:38 -0700 (PDT) From: Jamie Iles To: linux-mtd@lists.infradead.org Subject: [PATCH] mtd: gpio-nand: add device tree bindings Date: Wed, 27 Jul 2011 15:03:30 +0100 Message-Id: <1311775410-5158-1-git-send-email-jamie@jamieiles.com> X-Mailer: git-send-email 1.7.4.1 X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110727_100343_677797_B06E1E20 X-CRM114-Status: GOOD ( 28.90 ) X-Spam-Score: -0.7 (/) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (-0.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [74.125.82.177 listed in list.dnswl.org] Cc: Jamie Iles , devicetree-discuss@lists.ozlabs.org, David Woodhouse , Artem Bityutskiy X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-mtd-bounces@lists.infradead.org Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org Add device tree bindings so that the gpio-nand driver may be instantiated from the device tree. This also allows the partitions to be specified in the device tree. Cc: David Woodhouse Cc: Artem Bityutskiy Signed-off-by: Jamie Iles --- I have this working on our platform using the following DT section: ebi { compatible = "simple-bus"; #address-cells = <2>; #size-cells = <1>; ranges = <0 0 0x40000000 0x08000000 1 0 0x48000000 0x08000000 2 0 0x50000000 0x08000000 3 0 0x58000000 0x08000000>; nand: gpio-nand@2,0 { compatible = "gpio-nand"; #address-cells = <0>; #size-cells = <0>; reg = <2 0x0000 0x1000 0 0x2000 0x0004>; gpios = <&banka 1 0 /* rdy */ &banka 2 0 /* nce */ &banka 3 0 /* ale */ &banka 4 0 /* cle */ 0 /* nwp */>; boot@100000 { label = "Boot"; reg = <0x100000 0x80000>; }; ... }; }; }; but to provide synchronisation with regards to the bus reordering, we actually need to perform a read from the GPIO controller rather than the EBI, but I'm not sure how to express this in the DT when using ranges like this, so any suggestions would be welcome! Jamie .../devicetree/bindings/mtd/gpio-nand.txt | 43 +++++++++ drivers/mtd/nand/gpio.c | 91 ++++++++++++++++++-- 2 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 Documentation/devicetree/bindings/mtd/gpio-nand.txt diff --git a/Documentation/devicetree/bindings/mtd/gpio-nand.txt b/Documentation/devicetree/bindings/mtd/gpio-nand.txt new file mode 100644 index 0000000..98cb152 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/gpio-nand.txt @@ -0,0 +1,43 @@ +GPIO assisted NAND flash + +Required properties: +- compatible : "gpio-nand" +- reg : should specify localbus chip select and size used for the chip. For + ARM platforms where a dummy read is needed to provide synchronisation with + regards to bus reordering, an optional second resource describes the + location to read from. +- #address-cells, #size-cells : Must be present if the device has sub-nodes + representing partitions. In this case, both #address-cells and #size-cells + must be equal to 1. +- gpios : specifies the gpio pins to control the NAND device. nwp is an + optional gpio and may be set to 0 if not present. + +Optional properties: +- bank-width : Width (in bytes) of the bank. Equal to the device width times + the number of interleaved chips. +- chip-delay : chip dependent delay for transferring data from array to + read registers (tR). + +Examples: + +gpio-nand@1,0 { + compatible = "gpio-nand"; + reg = <1 0x0000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + gpios = <&banka 1 0 /* rdy */ + &banka 2 0 /* nce */ + &banka 3 0 /* ale */ + &banka 4 0 /* cle */ + 0 /* nwp */>; + + flash { + #address-cells = <1>; + #size-cells = <1>; + compatible = "..."; + + partition@0 { + ... + }; + }; +}; diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index 2c2060b..ee74593 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -27,6 +27,9 @@ #include #include #include +#include +#include +#include struct gpiomtd { void __iomem *io_sync; @@ -221,14 +224,70 @@ static void __iomem *request_and_remap(struct resource *res, size_t size, return ptr; } +static const struct of_device_id gpio_nand_id_table[] = { + { .compatible = "gpio-nand" }, + {} +}; +MODULE_DEVICE_TABLE(of, gpio_nand_id_table); + +static int gpio_nand_of_get_options(struct device *dev, + struct gpio_nand_platdata *plat) +{ + u32 width; + + if (!of_property_read_u32(dev->of_node, "bank-width", &width)) { + if (width == 2) { + plat->options |= NAND_BUSWIDTH_16; + } else if (width != 1) { + dev_err(dev, "invalid bank-width %u\n", width); + return -EINVAL; + } + } + + return 0; +} + +static void gpio_nand_of_get_gpio(struct device *dev, + struct gpio_nand_platdata *plat) +{ + plat->gpio_rdy = of_get_gpio(dev->of_node, 0); + plat->gpio_nce = of_get_gpio(dev->of_node, 1); + plat->gpio_ale = of_get_gpio(dev->of_node, 2); + plat->gpio_cle = of_get_gpio(dev->of_node, 3); + plat->gpio_nwp = of_get_gpio(dev->of_node, 4); +} + +static void gpio_nand_of_get_chip_delay(struct device *dev, + struct gpio_nand_platdata *plat) +{ + u32 chip_delay; + + if (!of_property_read_u32(dev->of_node, "chip-delay", &chip_delay)) + plat->chip_delay = (int)chip_delay; +} + +static int gpio_nand_of_get_config(struct device *dev, + struct gpio_nand_platdata *plat) +{ + int ret = gpio_nand_of_get_options(dev, plat); + + if (ret < 0) + return ret; + + gpio_nand_of_get_gpio(dev, plat); + gpio_nand_of_get_chip_delay(dev, plat); + + return 0; +} + static int __devinit gpio_nand_probe(struct platform_device *dev) { struct gpiomtd *gpiomtd; struct nand_chip *this; struct resource *res0, *res1; - int ret; + int ret = 0; - if (!dev->dev.platform_data) + if (!dev->dev.of_node && !dev->dev.platform_data) return -EINVAL; res0 = platform_get_resource(dev, IORESOURCE_MEM, 0); @@ -257,11 +316,17 @@ static int __devinit gpio_nand_probe(struct platform_device *dev) } } - memcpy(&gpiomtd->plat, dev->dev.platform_data, sizeof(gpiomtd->plat)); + if (dev->dev.platform_data) + memcpy(&gpiomtd->plat, dev->dev.platform_data, + sizeof(gpiomtd->plat)); + else + ret = gpio_nand_of_get_config(&dev->dev, &gpiomtd->plat); + if (ret) + goto err_config; ret = gpio_request(gpiomtd->plat.gpio_nce, "NAND NCE"); if (ret) - goto err_nce; + goto err_config; gpio_direction_output(gpiomtd->plat.gpio_nce, 1); if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) { ret = gpio_request(gpiomtd->plat.gpio_nwp, "NAND NWP"); @@ -312,12 +377,21 @@ static int __devinit gpio_nand_probe(struct platform_device *dev) goto err_wp; } - if (gpiomtd->plat.adjust_parts) - gpiomtd->plat.adjust_parts(&gpiomtd->plat, - gpiomtd->mtd_info.size); + if (dev->dev.platform_data) { + if (gpiomtd->plat.adjust_parts) + gpiomtd->plat.adjust_parts(&gpiomtd->plat, + gpiomtd->mtd_info.size); + } else { + ret = of_mtd_parse_partitions(&dev->dev, dev->dev.of_node, + &gpiomtd->plat.parts); + if (ret < 0) + goto err_wp; + gpiomtd->plat.num_parts = (unsigned int)ret; + } mtd_device_register(&gpiomtd->mtd_info, gpiomtd->plat.parts, gpiomtd->plat.num_parts); + platform_set_drvdata(dev, gpiomtd); return 0; @@ -335,7 +409,7 @@ err_ale: gpio_free(gpiomtd->plat.gpio_nwp); err_nwp: gpio_free(gpiomtd->plat.gpio_nce); -err_nce: +err_config: iounmap(gpiomtd->io_sync); if (res1) release_mem_region(res1->start, resource_size(res1)); @@ -352,6 +426,7 @@ static struct platform_driver gpio_nand_driver = { .remove = gpio_nand_remove, .driver = { .name = "gpio-nand", + .of_match_table = gpio_nand_id_table, }, };