From patchwork Tue Jul 23 12:28:19 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Shiyan X-Patchwork-Id: 261065 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from casper.infradead.org (unknown [IPv6:2001:770:15f::2]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id CADD02C00B6 for ; Tue, 23 Jul 2013 22:31:26 +1000 (EST) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1V1bit-0004JU-KM; Tue, 23 Jul 2013 12:29:49 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1V1biO-0000Wk-OU; Tue, 23 Jul 2013 12:29:16 +0000 Received: from smtp39.i.mail.ru ([94.100.177.99]) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1V1bi8-0000Rq-O7 for linux-mtd@lists.infradead.org; Tue, 23 Jul 2013 12:29:09 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mail.ru; s=mail2; h=References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From; bh=QREl5yKeak0EHYCO5DCEqu9mZiPjum34hcgkni2z3Dc=; b=dUHkywJkkb9f+/qF/e2x4fkA4xQOExSIVj1+H6lFxAK1nlQNaGDvOTpqCyOHxmUDx+haQuAEMbYheZAMQPBlmco+aSYFshKwHLEDDtP5qLLk3kTILC/xs6nU/YmEqLVgnjWpteEtXhz4LWkkOVVqjJ2u388Vejr4JqLJhXr9VHc=; Received: from [217.119.30.118] (port=24069 helo=shc.milas.spb.ru) by smtp39.i.mail.ru with esmtpa (envelope-from ) id 1V1bho-0004EP-Hh; Tue, 23 Jul 2013 16:28:40 +0400 From: Alexander Shiyan To: linux-mtd@lists.infradead.org Subject: [PATCH 4/4] mtd: nand: gpio: Add support for multichip devices Date: Tue, 23 Jul 2013 16:28:19 +0400 Message-Id: <1374582499-31823-4-git-send-email-shc_work@mail.ru> X-Mailer: git-send-email 1.8.1.5 In-Reply-To: <1374582499-31823-1-git-send-email-shc_work@mail.ru> References: <1374582499-31823-1-git-send-email-shc_work@mail.ru> X-Spam: Not detected X-Mras: Ok X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130723_082901_816432_D9307DE1 X-CRM114-Status: GOOD ( 24.43 ) X-Spam-Score: -1.2 (-) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-1.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.8 RCVD_IN_SORBS_WEB RBL: SORBS: sender is an abusable web server [217.119.30.118 listed in dnsbl.sorbs.net] 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (shc_work[at]mail.ru) -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: Artem Bityutskiy , Brian Norris , David Woodhouse , Alexander Shiyan X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.15 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" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org This patch adds support for multichip NAND devices controlled through GPIOs. To implement this, the properties of tree have been renamed. All current boards and DTS files converted to use an updated driver. Also driver temporarily keep support for DTS files which use the previous names scheme. Signed-off-by: Alexander Shiyan --- .../devicetree/bindings/mtd/gpio-control-nand.txt | 16 ++-- arch/arm/boot/dts/picoxcell-pc7302-pc3x2.dts | 10 +- arch/arm/boot/dts/picoxcell-pc7302-pc3x3.dts | 10 +- arch/arm/mach-clps711x/board-autcpu12.c | 4 +- arch/arm/mach-clps711x/board-p720t.c | 4 +- arch/arm/mach-pxa/cm-x255.c | 10 +- drivers/mtd/nand/gpio.c | 104 +++++++++++++++------ include/linux/mtd/nand-gpio.h | 12 ++- 8 files changed, 109 insertions(+), 61 deletions(-) diff --git a/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt b/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt index 287b8b8..5c88241 100644 --- a/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt +++ b/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt @@ -12,8 +12,11 @@ Required properties: automatically if size > 1. If size =1, 8 bit bus width is used. - #address-cells, #size-cells : Must be present if the device has sub-nodes representing partitions. -- gpios : specifies the gpio pins to control the NAND device. nwp is an - optional gpio and may be set to 0 if not present. +- gpio-ale : specifies the ALE gpio pin. +- gpio-cle : specifies the CLE gpio pin. +- gpio-nwp : specifies the NWP gpio pin (Optional). +- gpios-nce : specifies the NCE gpio pin or several NCE GPIOs for multichip NAND. +- gpios-rdy : specifies the RDY gpio pin or several RDY GPIOs for multichip NAND. Optional properties: - chip-delay : chip dependent delay for transferring data from array to @@ -34,11 +37,10 @@ gpio-nand@1,0 { reg = <1 0x0000 0x2>; #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 */>; + gpio-ale = <&banka 3 0>; + gpio-cle = <&banka 4 0>; + gpios-nce = <&banka 2 0>; + gpios-rdy = <&banka 1 0>; partition@0 { ... diff --git a/arch/arm/boot/dts/picoxcell-pc7302-pc3x2.dts b/arch/arm/boot/dts/picoxcell-pc7302-pc3x2.dts index 1297414d..fec32ea 100644 --- a/arch/arm/boot/dts/picoxcell-pc7302-pc3x2.dts +++ b/arch/arm/boot/dts/picoxcell-pc7302-pc3x2.dts @@ -44,12 +44,10 @@ bus-clock = <&pclk>, "bus"; gpio-control-nand,io-sync-reg = <0x00000000 0x80220000>; - - gpios = <&banka 1 0 /* rdy */ - &banka 2 0 /* nce */ - &banka 3 0 /* ale */ - &banka 4 0 /* cle */ - 0 /* nwp */>; + gpio-ale = <&banka 3 0>; + gpio-cle = <&banka 4 0>; + gpios-nce = <&banka 2 0>; + gpios-rdy = <&banka 1 0>; boot@100000 { label = "Boot"; diff --git a/arch/arm/boot/dts/picoxcell-pc7302-pc3x3.dts b/arch/arm/boot/dts/picoxcell-pc7302-pc3x3.dts index 9e317a4..ef19635 100644 --- a/arch/arm/boot/dts/picoxcell-pc7302-pc3x3.dts +++ b/arch/arm/boot/dts/picoxcell-pc7302-pc3x3.dts @@ -50,12 +50,10 @@ bus-clock = <&ebi_clk>, "bus"; gpio-control-nand,io-sync-reg = <0x00000000 0x80220000>; - - gpios = <&banka 1 0 /* rdy */ - &banka 2 0 /* nce */ - &banka 3 0 /* ale */ - &banka 4 0 /* cle */ - 0 /* nwp */>; + gpio-ale = <&banka 3 0>; + gpio-cle = <&banka 4 0>; + gpios-nce = <&banka 2 0>; + gpios-rdy = <&banka 1 0>; boot@100000 { label = "Boot"; diff --git a/arch/arm/mach-clps711x/board-autcpu12.c b/arch/arm/mach-clps711x/board-autcpu12.c index 5867aeb..c1fa4bd 100644 --- a/arch/arm/mach-clps711x/board-autcpu12.c +++ b/arch/arm/mach-clps711x/board-autcpu12.c @@ -120,8 +120,8 @@ static void __init autcpu12_adjust_parts(struct gpio_nand_platdata *pdata, } static struct gpio_nand_platdata autcpu12_nand_pdata __initdata = { - .gpio_rdy = AUTCPU12_SMC_RDY, - .gpio_nce = AUTCPU12_SMC_NCE, + .gpio_rdy[0] = AUTCPU12_SMC_RDY, + .gpio_nce[0] = AUTCPU12_SMC_NCE, .gpio_ale = AUTCPU12_SMC_ALE, .gpio_cle = AUTCPU12_SMC_CLE, .gpio_nwp = -1, diff --git a/arch/arm/mach-clps711x/board-p720t.c b/arch/arm/mach-clps711x/board-p720t.c index dd81b06..3774417 100644 --- a/arch/arm/mach-clps711x/board-p720t.c +++ b/arch/arm/mach-clps711x/board-p720t.c @@ -243,8 +243,8 @@ static struct mtd_partition p720t_nand_parts[] __initdata = { }; static struct gpio_nand_platdata p720t_nand_pdata __initdata = { - .gpio_rdy = -1, - .gpio_nce = P720T_NAND_NCE, + .gpio_rdy[0] = -1, + .gpio_nce[0] = P720T_NAND_NCE, .gpio_ale = P720T_NAND_ALE, .gpio_cle = P720T_NAND_CLE, .gpio_nwp = -1, diff --git a/arch/arm/mach-pxa/cm-x255.c b/arch/arm/mach-pxa/cm-x255.c index be75147..3cb9f4d 100644 --- a/arch/arm/mach-pxa/cm-x255.c +++ b/arch/arm/mach-pxa/cm-x255.c @@ -198,11 +198,11 @@ static struct mtd_partition cmx255_nand_parts[] = { }; static struct gpio_nand_platdata cmx255_nand_platdata = { - .gpio_nce = GPIO_NAND_CS, - .gpio_cle = GPIO_NAND_CLE, - .gpio_ale = GPIO_NAND_ALE, - .gpio_rdy = GPIO_NAND_RB, - .gpio_nwp = -1, + .gpio_nce[0] = GPIO_NAND_CS, + .gpio_cle = GPIO_NAND_CLE, + .gpio_ale = GPIO_NAND_ALE, + .gpio_rdy[0] = GPIO_NAND_RB, + .gpio_nwp = -1, .parts = cmx255_nand_parts, .num_parts = ARRAY_SIZE(cmx255_nand_parts), .chip_delay = 25, diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index 7b1dbd3..c7beeeb 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -36,6 +36,7 @@ struct gpiomtd { void __iomem *io_sync; struct mtd_info mtd_info; struct nand_chip nand_chip; + int chip_index; struct gpio_nand_platdata plat; }; @@ -75,7 +76,8 @@ static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) gpio_nand_dosync(gpiomtd); if (ctrl & NAND_CTRL_CHANGE) { - gpio_set_value(gpiomtd->plat.gpio_nce, !(ctrl & NAND_NCE)); + gpio_set_value(gpiomtd->plat.gpio_nce[gpiomtd->chip_index], + !(ctrl & NAND_NCE)); gpio_set_value(gpiomtd->plat.gpio_cle, !!(ctrl & NAND_CLE)); gpio_set_value(gpiomtd->plat.gpio_ale, !!(ctrl & NAND_ALE)); gpio_nand_dosync(gpiomtd); @@ -90,8 +92,26 @@ static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) static int gpio_nand_devready(struct mtd_info *mtd) { struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd); + int idx = gpiomtd->chip_index; - return gpio_get_value(gpiomtd->plat.gpio_rdy); + if (!gpio_is_valid(gpiomtd->plat.gpio_rdy[idx])) + idx = 0; + + return gpio_get_value(gpiomtd->plat.gpio_rdy[idx]); +} + +static void gpio_nand_select_chip(struct mtd_info *mtd, int chipnr) +{ + struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd); + + switch (chipnr) { + case -1: + gpio_nand_cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); + break; + default: + gpiomtd->chip_index = chipnr; + break; + } } #ifdef CONFIG_OF @@ -105,19 +125,34 @@ static int gpio_nand_get_config_of(const struct device *dev, struct gpio_nand_platdata *plat) { u32 val; + int i; if (!dev->of_node) return -ENODEV; - /* Deprecated since 3.11-rc2 */ + /* Deprecated since 3.11-rc2, should be removed around 3.17 */ if (of_find_property(dev->of_node, "bank-width", NULL)) dev_notice(dev, "Property \"bank-width\" is deprecated"); - - 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); + if (of_find_property(dev->of_node, "gpios", NULL)) { + dev_notice(dev, "Property \"gpios\" is deprecated"); + + plat->gpio_rdy[0] = of_get_gpio(dev->of_node, 0); + plat->gpio_nce[0] = 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); + } else { + plat->gpio_ale = of_get_named_gpio(dev->of_node, "gpio-ale", 0); + plat->gpio_cle = of_get_named_gpio(dev->of_node, "gpio-cle", 0); + plat->gpio_nwp = of_get_named_gpio(dev->of_node, "gpio-nwp", 0); + + for (i = 1; i < MAX_NAND_PER_CHIP; i++) { + plat->gpio_nce[i] = of_get_named_gpio(dev->of_node, + "gpios-nce", i); + plat->gpio_rdy[i] = of_get_named_gpio(dev->of_node, + "gpios-rdy", i); + } + } if (!of_property_read_u32(dev->of_node, "chip-delay", &val)) plat->chip_delay = val; @@ -190,12 +225,15 @@ static void gpio_nand_set_wp(struct gpiomtd *gpiomtd, int val) static int gpio_nand_remove(struct platform_device *pdev) { struct gpiomtd *gpiomtd = platform_get_drvdata(pdev); + int i; nand_release(&gpiomtd->mtd_info); gpio_nand_set_wp(gpiomtd, 0); - gpio_set_value(gpiomtd->plat.gpio_nce, 1); + for (i = 1; i < MAX_NAND_PER_CHIP; i++) + if (gpio_is_valid(gpiomtd->plat.gpio_nce[i])) + gpio_set_value(gpiomtd->plat.gpio_nce[i], 1); return 0; } @@ -206,7 +244,7 @@ static int gpio_nand_probe(struct platform_device *pdev) struct nand_chip *chip; struct resource *res; struct mtd_part_parser_data ppdata = {}; - int ret; + int i, ret, found = 0; if (!pdev->dev.of_node && !pdev->dev.platform_data) return -EINVAL; @@ -239,18 +277,6 @@ static int gpio_nand_probe(struct platform_device *pdev) return PTR_ERR(gpiomtd->io_sync); } - ret = devm_gpio_request_one(&pdev->dev, gpiomtd->plat.gpio_nce, - GPIOF_OUT_INIT_HIGH, "NAND NCE"); - if (ret) - return ret; - - if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) { - ret = devm_gpio_request_one(&pdev->dev, gpiomtd->plat.gpio_nwp, - GPIOF_OUT_INIT_LOW, "NAND NWP"); - if (ret) - return ret; - } - ret = devm_gpio_request_one(&pdev->dev, gpiomtd->plat.gpio_ale, GPIOF_OUT_INIT_LOW, "NAND ALE"); if (ret) @@ -261,19 +287,41 @@ static int gpio_nand_probe(struct platform_device *pdev) if (ret) return ret; - if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) { - ret = devm_gpio_request_one(&pdev->dev, gpiomtd->plat.gpio_rdy, - GPIOF_IN, "NAND RDY"); + if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) { + ret = devm_gpio_request_one(&pdev->dev, gpiomtd->plat.gpio_nwp, + GPIOF_OUT_INIT_LOW, "NAND NWP"); if (ret) return ret; - chip->dev_ready = gpio_nand_devready; } + for (i = 0; i < MAX_NAND_PER_CHIP; i++) { + if (!gpio_is_valid(gpiomtd->plat.gpio_nce[i])) + break; + if (devm_gpio_request_one(&pdev->dev, gpiomtd->plat.gpio_nce[i], + GPIOF_OUT_INIT_HIGH, NULL)) + break; + + found++; + + if (gpio_is_valid(gpiomtd->plat.gpio_rdy[i])) { + if (devm_gpio_request_one(&pdev->dev, + gpiomtd->plat.gpio_rdy[i], + GPIOF_IN, NULL)) + gpiomtd->plat.gpio_rdy[i] = -1; + else + chip->dev_ready = gpio_nand_devready; + } + } + + if (!found) + return -EINVAL; + chip->IO_ADDR_W = chip->IO_ADDR_R; chip->ecc.mode = NAND_ECC_SOFT; chip->options = gpiomtd->plat.options; chip->chip_delay = gpiomtd->plat.chip_delay; chip->cmd_ctrl = gpio_nand_cmd_ctrl; + chip->select_chip = gpio_nand_select_chip; gpiomtd->mtd_info.priv = chip; gpiomtd->mtd_info.owner = THIS_MODULE; @@ -282,7 +330,7 @@ static int gpio_nand_probe(struct platform_device *pdev) gpio_nand_set_wp(gpiomtd, 1); - ret = nand_scan(&gpiomtd->mtd_info, 1); + ret = nand_scan(&gpiomtd->mtd_info, found); if (!ret) { if (gpiomtd->plat.adjust_parts) gpiomtd->plat.adjust_parts(&gpiomtd->plat, diff --git a/include/linux/mtd/nand-gpio.h b/include/linux/mtd/nand-gpio.h index 51534e5..4edd9d1 100644 --- a/include/linux/mtd/nand-gpio.h +++ b/include/linux/mtd/nand-gpio.h @@ -3,12 +3,14 @@ #include +#define MAX_NAND_PER_CHIP 2 + struct gpio_nand_platdata { - int gpio_nce; - int gpio_nwp; - int gpio_cle; - int gpio_ale; - int gpio_rdy; + int gpio_ale; /* ALE */ + int gpio_cle; /* CLE */ + int gpio_nwp; /* NWP (Optional) */ + int gpio_nce[MAX_NAND_PER_CHIP]; /* NCE */ + int gpio_rdy[MAX_NAND_PER_CHIP]; /* RDY (Optional) */ void (*adjust_parts)(struct gpio_nand_platdata *, size_t); struct mtd_partition *parts; unsigned int num_parts;