oxnas: backport upstream NAND driver

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
Daniel Golle 2016-09-24 01:14:53 +02:00
parent ae21033e76
commit 5cde94d9ab
12 changed files with 5913 additions and 161 deletions

View file

@ -243,8 +243,7 @@ CONFIG_MODULES_USE_ELF_REL=y
CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_ECC=y
CONFIG_MTD_NAND_OXNAS=y
CONFIG_MTD_NAND_PLATFORM=y
CONFIG_MTD_SPLIT_FIRMWARE=y
# CONFIG_MTD_SPLIT_FIRMWARE is not set
CONFIG_MTD_UBI=y
CONFIG_MTD_UBI_BEB_LIMIT=20
CONFIG_MTD_UBI_BLOCK=y

View file

@ -34,15 +34,6 @@
nand@41000000 {
status = "okay";
partition@0 {
label = "boot";
reg = <0x0 0x26c0000>;
};
partition@26c0000 {
label = "ubi";
reg = <0x26c0000 0xd940000>;
};
};
ethernet@40400000 {
@ -132,3 +123,24 @@
};
};
};
&nandc {
status = "okay";
nand@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
nand-ecc-mode = "soft";
nand-ecc-algo = "hamming";
partition@0 {
label = "boot";
reg = <0x00000000 0x026c0000>;
};
partition@26c0000 {
label = "ubi";
reg = <0x026c0000 0x0d940000>;
};
};

View file

@ -31,37 +31,6 @@
nr-ports = <2>;
};
nand@41000000 {
status = "okay";
partition@0 {
label = "stage1";
reg = <0x00000000 0x00040000>;
read-only;
};
partition@40000 {
label = "u-boot";
reg = <0x00040000 0x00200000>;
read-only;
};
partition@240000 {
label = "initrd";
reg = <0x00240000 0x00600000>;
};
partition@840000 {
label = "kernel";
reg = <0x00840000 0x007C0000>;
};
partition@e00000 {
label = "ubi";
reg = <0x01000000 0x07000000>;
};
};
ethernet@40400000 {
status = "okay";
snps,phy-addr = <1>;
@ -163,3 +132,42 @@
gpios = <&GPIOA 9 0>;
};
};
&nandc {
status = "okay";
nand@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
nand-ecc-mode = "soft";
nand-ecc-algo = "hamming";
partition@0 {
label = "stage1";
reg = <0x00000000 0x00040000>;
read-only;
};
partition@40000 {
label = "u-boot";
reg = <0x00040000 0x00200000>;
read-only;
};
partition@240000 {
label = "initrd";
reg = <0x00240000 0x00600000>;
};
partition@840000 {
label = "kernel";
reg = <0x00840000 0x007C0000>;
};
partition@e00000 {
label = "ubi";
reg = <0x01000000 0x07000000>;
};
};
};

View file

@ -28,21 +28,6 @@
status = "okay";
};
nand@41000000 {
status = "okay";
partition@0 {
label = "boot";
reg = <0x00000000 0x00e00000>;
/*read-only;*/
};
partition@e00000 {
label = "ubi";
reg = <0x00e00000 0x07200000>;
};
};
ethernet@40400000 {
status = "okay";
};
@ -84,3 +69,26 @@
};
};
};
&nandc {
status = "okay";
nand@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
nand-ecc-mode = "soft";
nand-ecc-algo = "hamming";
partition@0 {
label = "boot";
reg = <0x00000000 0x00e00000>;
/*read-only;*/
};
partition@e00000 {
label = "ubi";
reg = <0x00e00000 0x07200000>;
};
};
};

View file

@ -25,21 +25,6 @@
status = "okay";
};
nand@41000000 {
status = "okay";
partition@0 {
label = "boot";
reg = <0x00000000 0x00e00000>;
/*read-only;*/
};
partition@e00000 {
label = "ubi";
reg = <0x00e00000 0x07200000>;
};
};
ethernet@40400000 {
status = "okay";
};
@ -81,3 +66,26 @@
};
};
&nandc {
status = "okay";
nand@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
nand-ecc-mode = "soft";
nand-ecc-algo = "hamming";
partition@0 {
label = "boot";
reg = <0x00000000 0x00e00000>;
/*read-only;*/
};
partition@e00000 {
label = "ubi";
reg = <0x00e00000 0x07200000>;
};
};
};

View file

@ -27,20 +27,6 @@
status = "okay";
};
nand@41000000 {
status = "okay";
partition@0 {
label = "boot";
reg = <0x00000000 0x00e00000>;
/*read-only;*/
};
partition@e00000 {
label = "ubi";
reg = <0x00e00000 0x07200000>;
};
};
ethernet@40400000 {
status = "okay";
@ -91,3 +77,26 @@
};
};
&nandc {
status = "okay";
nand@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
nand-ecc-mode = "soft";
nand-ecc-algo = "hamming";
partition@0 {
label = "boot";
reg = <0x00000000 0x00e00000>;
read-only;
};
partition@e00000 {
label = "ubi";
reg = <0x00e00000 0x07200000>;
};
};
};

View file

@ -298,16 +298,15 @@
status = "disabled";
};
nand@41000000 {
compatible = "plxtech,nand-nas782x", "gen_nand";
reg = <0x41000000 0x100000>, <0x41C00000 0x20>;
nand-ecc-mode = "soft";
nandc: nand-controller@41000000 {
compatible = "oxsemi,ox820-nand";
reg = <0x41000000 0x100000>;
clocks = <&stdclk 9>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_nand0>;
resets = <&rst 15>;
#address-cells = <1>;
#size-cells = <1>;
#size-cells = <0>;
status = "disabled";
};

View file

@ -1,94 +1,211 @@
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
* Oxford Semiconductor OXNAS NAND driver
* Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com>
* Heavily based on plat_nand.c :
* Author: Vitaly Wool <vitalywool@gmail.com>
* Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com>
* Copyright (C) 2012 John Crispin <blogic@openwrt.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* based on xway_nand.c
* Copyright © 2012 John Crispin <blogic@openwrt.org>
* and oxnas_nand.c "NAND glue for Oxnas platforms"
* written by Ma Haijun <mahaijuns@gmail.com>
*/
#include <linux/mtd/nand.h>
#include <linux/of_gpio.h>
#include <linux/of_platform.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/of.h>
/* nand commands */
#define NAND_CMD_ALE BIT(18)
#define NAND_CMD_CLE BIT(19)
#define NAND_CMD_CS 0
#define NAND_CMD_RESET 0xff
#define NAND_CMD (NAND_CMD_CS | NAND_CMD_CLE)
#define NAND_ADDR (NAND_CMD_CS | NAND_CMD_ALE)
#define NAND_DATA (NAND_CMD_CS)
/* Nand commands */
#define OXNAS_NAND_CMD_ALE BIT(18)
#define OXNAS_NAND_CMD_CLE BIT(19)
static void oxnas_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
#define OXNAS_NAND_MAX_CHIPS 1
struct oxnas_nand {
struct nand_hw_control base;
void __iomem *io_base;
struct clk *clk;
struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS];
unsigned long ctrl;
struct mtd_partition *partitions;
int nr_partitions;
};
static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd)
{
struct nand_chip *this = mtd->priv;
unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
struct nand_chip *chip = mtd_to_nand(mtd);
struct oxnas_nand *oxnas = nand_get_controller_data(chip);
return readb(oxnas->io_base);
}
static void oxnas_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct oxnas_nand *oxnas = nand_get_controller_data(chip);
ioread8_rep(oxnas->io_base, buf, len);
}
static void oxnas_nand_write_buf(struct mtd_info *mtd,
const uint8_t *buf, int len)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct oxnas_nand *oxnas = nand_get_controller_data(chip);
iowrite8_rep(oxnas->io_base + oxnas->ctrl, buf, len);
}
/* Single CS command control */
static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
struct nand_chip *chip = mtd_to_nand(mtd);
struct oxnas_nand *oxnas = nand_get_controller_data(chip);
if (ctrl & NAND_CTRL_CHANGE) {
nandaddr &= ~(NAND_CMD | NAND_ADDR);
if (ctrl & NAND_CLE)
nandaddr |= NAND_CMD;
oxnas->ctrl = OXNAS_NAND_CMD_CLE;
else if (ctrl & NAND_ALE)
nandaddr |= NAND_ADDR;
this->IO_ADDR_W = (void __iomem *) nandaddr;
oxnas->ctrl = OXNAS_NAND_CMD_ALE;
else
oxnas->ctrl = 0;
}
if (cmd != NAND_CMD_NONE)
writeb(cmd, (void __iomem *) nandaddr);
writeb(cmd, oxnas->io_base + oxnas->ctrl);
}
static int oxnas_nand_probe(struct platform_device *pdev)
{
/* enable clock and release static block reset */
struct clk *clk = of_clk_get(pdev->dev.of_node, 0);
if (IS_ERR(clk))
return PTR_ERR(clk);
clk_prepare_enable(clk);
device_reset(&pdev->dev);
return 0;
}
/* allow users to override the partition in DT using the cmdline */
static const char * part_probes[] = { "cmdlinepart", "ofpart", NULL };
static struct platform_nand_data oxnas_nand_data = {
.chip = {
.nr_chips = 1,
.chip_delay = 30,
.part_probe_types = part_probes,
},
.ctrl = {
.probe = oxnas_nand_probe,
.cmd_ctrl = oxnas_cmd_ctrl,
}
};
/*
* Try to find the node inside the DT. If it is available attach out
* platform_nand_data
* Probe for the NAND device.
*/
static int __init oxnas_register_nand(void)
static int oxnas_nand_probe(struct platform_device *pdev)
{
struct device_node *node;
struct platform_device *pdev;
struct device_node *np = pdev->dev.of_node;
struct device_node *nand_np;
struct oxnas_nand *oxnas;
struct nand_chip *chip;
struct mtd_info *mtd;
struct resource *res;
int nchips = 0;
int count = 0;
int err = 0;
node = of_find_compatible_node(NULL, NULL, "plxtech,nand-nas782x");
if (!node)
return -ENOENT;
pdev = of_find_device_by_node(node);
if (!pdev)
/* Allocate memory for the device structure (and zero it) */
oxnas = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
GFP_KERNEL);
if (!oxnas)
return -ENOMEM;
nand_hw_control_init(&oxnas->base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
oxnas->io_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(oxnas->io_base))
return PTR_ERR(oxnas->io_base);
oxnas->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(oxnas->clk))
oxnas->clk = NULL;
/* Only a single chip node is supported */
count = of_get_child_count(np);
pr_info("########### count: %d\n", count);
if (count > 1)
return -EINVAL;
pdev->dev.platform_data = &oxnas_nand_data;
of_node_put(node);
clk_prepare_enable(oxnas->clk);
device_reset_optional(&pdev->dev);
for_each_child_of_node(np, nand_np) {
chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip),
GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->controller = &oxnas->base;
nand_set_flash_node(chip, nand_np);
nand_set_controller_data(chip, oxnas);
mtd = nand_to_mtd(chip);
mtd->dev.parent = &pdev->dev;
mtd->priv = chip;
chip->cmd_ctrl = oxnas_nand_cmd_ctrl;
chip->read_buf = oxnas_nand_read_buf;
chip->read_byte = oxnas_nand_read_byte;
chip->write_buf = oxnas_nand_write_buf;
chip->chip_delay = 30;
/* Scan to find existence of the device */
err = nand_scan(mtd, 1);
pr_info("########### nand_scan err: %d\n", err);
if (err)
return err;
err = mtd_device_register(mtd, NULL, 0);
pr_info("########### mtd_device_register err: %d\n", err);
if (err) {
nand_release(mtd);
return err;
}
oxnas->chips[nchips] = chip;
++nchips;
}
pr_info("########### nchips: %d\n", nchips);
/* Exit if no chips found */
if (!nchips)
return -ENODEV;
platform_set_drvdata(pdev, oxnas);
return 0;
}
subsys_initcall(oxnas_register_nand);
static int oxnas_nand_remove(struct platform_device *pdev)
{
struct oxnas_nand *oxnas = platform_get_drvdata(pdev);
if (oxnas->chips[0])
nand_release(nand_to_mtd(oxnas->chips[0]));
clk_disable_unprepare(oxnas->clk);
return 0;
}
static const struct of_device_id oxnas_nand_match[] = {
{ .compatible = "oxsemi,ox820-nand" },
{},
};
MODULE_DEVICE_TABLE(of, oxnas_nand_match);
static struct platform_driver oxnas_nand_driver = {
.probe = oxnas_nand_probe,
.remove = oxnas_nand_remove,
.driver = {
.name = "oxnas_nand",
.of_match_table = oxnas_nand_match,
},
};
module_platform_driver(oxnas_nand_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
MODULE_DESCRIPTION("Oxnas NAND driver");
MODULE_ALIAS("platform:oxnas_nand");

View file

@ -0,0 +1,91 @@
From 410a91f6efa1c4c3c4369d1dd2c31286749dff33 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
Date: Wed, 23 Mar 2016 11:19:01 +0100
Subject: [PATCH 073/102] of: mtd: prepare helper reading NAND ECC algo from
DT
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
NAND subsystem is being slightly reworked to store ECC details in
separated fields. In future we'll want to add support for more DT
properties as specifying every possible setup with a single
"nand-ecc-mode" is a pretty bad idea.
To allow this let's add a helper that will support something like
"nand-ecc-algo" in future. Right now we use it for keeping backward
compatibility.
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/of/of_mtd.c | 36 ++++++++++++++++++++++++++++++++++++
include/linux/of_mtd.h | 6 ++++++
2 files changed, 42 insertions(+)
--- a/drivers/of/of_mtd.c
+++ b/drivers/of/of_mtd.c
@@ -50,6 +50,42 @@ int of_get_nand_ecc_mode(struct device_n
EXPORT_SYMBOL_GPL(of_get_nand_ecc_mode);
/**
+ * of_get_nand_ecc_algo - Get nand ecc algorithm for given device_node
+ * @np: Pointer to the given device_node
+ *
+ * The function gets ecc algorithm and returns its enum value, or errno in error
+ * case.
+ */
+int of_get_nand_ecc_algo(struct device_node *np)
+{
+ const char *pm;
+ int err;
+
+ /*
+ * TODO: Read ECC algo OF property and map it to enum nand_ecc_algo.
+ * It's not implemented yet as currently NAND subsystem ignores
+ * algorithm explicitly set this way. Once it's handled we should
+ * document & support new property.
+ */
+
+ /*
+ * For backward compatibility we also read "nand-ecc-mode" checking
+ * for some obsoleted values that were specifying ECC algorithm.
+ */
+ err = of_property_read_string(np, "nand-ecc-mode", &pm);
+ if (err < 0)
+ return err;
+
+ if (!strcasecmp(pm, "soft"))
+ return NAND_ECC_HAMMING;
+ else if (!strcasecmp(pm, "soft_bch"))
+ return NAND_ECC_BCH;
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL_GPL(of_get_nand_ecc_algo);
+
+/**
* of_get_nand_ecc_step_size - Get ECC step size associated to
* the required ECC strength (see below).
* @np: Pointer to the given device_node
--- a/include/linux/of_mtd.h
+++ b/include/linux/of_mtd.h
@@ -13,6 +13,7 @@
#include <linux/of.h>
int of_get_nand_ecc_mode(struct device_node *np);
+int of_get_nand_ecc_algo(struct device_node *np);
int of_get_nand_ecc_step_size(struct device_node *np);
int of_get_nand_ecc_strength(struct device_node *np);
int of_get_nand_bus_width(struct device_node *np);
@@ -24,6 +25,11 @@ static inline int of_get_nand_ecc_mode(s
{
return -ENOSYS;
}
+
+static inline int of_get_nand_ecc_algo(struct device_node *np)
+{
+ return -ENOSYS;
+}
static inline int of_get_nand_ecc_step_size(struct device_node *np)
{

View file

@ -0,0 +1,202 @@
From d45bc58dd3bdcaabc1d7d8d9b0b8dee826635cc6 Mon Sep 17 00:00:00 2001
From: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
Date: Wed, 27 Jul 2016 11:23:52 +0200
Subject: [PATCH] mtd: nand: import nand_hw_control_init()
The code to initialize a struct nand_hw_control is duplicated across
several drivers. Factorize it using an inline function.
Signed-off-by: Marc Gonzalez <marc_gonzalez@sigmadesigns.com>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
drivers/mtd/nand/bf5xx_nand.c | 3 +--
drivers/mtd/nand/brcmnand/brcmnand.c | 3 +--
drivers/mtd/nand/docg4.c | 3 +--
drivers/mtd/nand/fsl_elbc_nand.c | 3 +--
drivers/mtd/nand/fsl_ifc_nand.c | 3 +--
drivers/mtd/nand/jz4780_nand.c | 3 +--
drivers/mtd/nand/nand_base.c | 3 +--
drivers/mtd/nand/ndfc.c | 3 +--
drivers/mtd/nand/pxa3xx_nand.c | 3 +--
drivers/mtd/nand/qcom_nandc.c | 3 +--
drivers/mtd/nand/s3c2410.c | 3 +--
drivers/mtd/nand/sunxi_nand.c | 3 +--
drivers/mtd/nand/txx9ndfmc.c | 3 +--
include/linux/mtd/nand.h | 7 +++++++
14 files changed, 20 insertions(+), 26 deletions(-)
diff --git a/drivers/mtd/nand/bf5xx_nand.c b/drivers/mtd/nand/bf5xx_nand.c
index 37da423..3962f55 100644
--- a/drivers/mtd/nand/bf5xx_nand.c
+++ b/drivers/mtd/nand/bf5xx_nand.c
@@ -761,8 +761,7 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info);
- spin_lock_init(&info->controller.lock);
- init_waitqueue_head(&info->controller.wq);
+ nand_hw_control_init(&info->controller);
info->device = &pdev->dev;
info->platform = plat;
diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c
index 8eb2c64..82ec36b 100644
--- a/drivers/mtd/nand/brcmnand/brcmnand.c
+++ b/drivers/mtd/nand/brcmnand/brcmnand.c
@@ -2370,8 +2370,7 @@ int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
init_completion(&ctrl->done);
init_completion(&ctrl->dma_done);
- spin_lock_init(&ctrl->controller.lock);
- init_waitqueue_head(&ctrl->controller.wq);
+ nand_hw_control_init(&ctrl->controller);
INIT_LIST_HEAD(&ctrl->host_list);
/* NAND register range */
diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c
index 4731699..7af2a3c 100644
--- a/drivers/mtd/nand/docg4.c
+++ b/drivers/mtd/nand/docg4.c
@@ -1249,8 +1249,7 @@ static void __init init_mtd_structs(struct mtd_info *mtd)
nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE;
nand->IO_ADDR_R = nand->IO_ADDR_W = doc->virtadr + DOC_IOSPACE_DATA;
nand->controller = &nand->hwcontrol;
- spin_lock_init(&nand->controller->lock);
- init_waitqueue_head(&nand->controller->wq);
+ nand_hw_control_init(nand->controller);
/* methods */
nand->cmdfunc = docg4_command;
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 60a88f2..113f76e 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -879,8 +879,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
}
elbc_fcm_ctrl->counter++;
- spin_lock_init(&elbc_fcm_ctrl->controller.lock);
- init_waitqueue_head(&elbc_fcm_ctrl->controller.wq);
+ nand_hw_control_init(&elbc_fcm_ctrl->controller);
fsl_lbc_ctrl_dev->nand = elbc_fcm_ctrl;
} else {
elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c
index 4e9e5fd..0a177b1 100644
--- a/drivers/mtd/nand/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/fsl_ifc_nand.c
@@ -987,8 +987,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
ifc_nand_ctrl->addr = NULL;
fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl;
- spin_lock_init(&ifc_nand_ctrl->controller.lock);
- init_waitqueue_head(&ifc_nand_ctrl->controller.wq);
+ nand_hw_control_init(&ifc_nand_ctrl->controller);
} else {
ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand;
}
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 77533f7..53ea796 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3191,8 +3191,7 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
if (!chip->controller) {
chip->controller = &chip->hwcontrol;
- spin_lock_init(&chip->controller->lock);
- init_waitqueue_head(&chip->controller->wq);
+ nand_hw_control_init(chip->controller);
}
}
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index 218c789..28e6118 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -218,8 +218,7 @@ static int ndfc_probe(struct platform_device *ofdev)
ndfc = &ndfc_ctrl[cs];
ndfc->chip_select = cs;
- spin_lock_init(&ndfc->ndfc_control.lock);
- init_waitqueue_head(&ndfc->ndfc_control.wq);
+ nand_hw_control_init(&ndfc->ndfc_control);
ndfc->ofdev = ofdev;
dev_set_drvdata(&ofdev->dev, ndfc);
diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c
index 436dd6d..b121bf4 100644
--- a/drivers/mtd/nand/pxa3xx_nand.c
+++ b/drivers/mtd/nand/pxa3xx_nand.c
@@ -1810,8 +1810,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
chip->cmdfunc = nand_cmdfunc;
}
- spin_lock_init(&chip->controller->lock);
- init_waitqueue_head(&chip->controller->wq);
+ nand_hw_control_init(chip->controller);
info->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed to get nand clock\n");
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index d9309cf..b1734d7 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -977,8 +977,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info);
- spin_lock_init(&info->controller.lock);
- init_waitqueue_head(&info->controller.wq);
+ nand_hw_control_init(&info->controller);
/* get the clock source and enable it */
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index e414b31..8b5dadc 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -2175,8 +2175,7 @@ static int sunxi_nfc_probe(struct platform_device *pdev)
return -ENOMEM;
nfc->dev = dev;
- spin_lock_init(&nfc->controller.lock);
- init_waitqueue_head(&nfc->controller.wq);
+ nand_hw_control_init(&nfc->controller);
INIT_LIST_HEAD(&nfc->chips);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c
index 04d63f5..0a14fda 100644
--- a/drivers/mtd/nand/txx9ndfmc.c
+++ b/drivers/mtd/nand/txx9ndfmc.c
@@ -303,8 +303,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
dev_info(&dev->dev, "CLK:%ldMHz HOLD:%d SPW:%d\n",
(gbusclk + 500000) / 1000000, hold, spw);
- spin_lock_init(&drvdata->hw_control.lock);
- init_waitqueue_head(&drvdata->hw_control.wq);
+ nand_hw_control_init(&drvdata->hw_control);
platform_set_drvdata(dev, drvdata);
txx9ndfmc_initialize(dev);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 8dd6e01..f6a2d5e 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -460,6 +460,13 @@ struct nand_hw_control {
wait_queue_head_t wq;
};
+static inline void nand_hw_control_init(struct nand_hw_control *nfc)
+{
+ nfc->active = NULL;
+ spin_lock_init(&nfc->lock);
+ init_waitqueue_head(&nfc->wq);
+}
+
/**
* struct nand_ecc_ctrl - Control structure for ECC
* @mode: ECC mode
--
2.10.2

View file

@ -1,13 +1,12 @@
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -546,4 +546,12 @@ config MTD_NAND_HISI504
@@ -546,4 +546,11 @@ config MTD_NAND_HISI504
help
Enables support for NAND controller on Hisilicon SoC Hip04.
+config MTD_NAND_OXNAS
+ tristate "Support for NAND on Plxtech NAS782X SoC"
+ depends on ARCH_OXNAS
+ select MTD_NAND_PLATFORM
+ help
+ Enables support for NAND Flash chips on Plxtech NAS782X SoCs. NAND is attached
+ to the STATIC Unit.