From: Neil Armstrong <narmstrong@baylibre.com>
To: dwmw2@infradead.org, computersforpeace@gmail.com,
boris.brezillon@free-electrons.com, richard@nod.at
Cc: Neil Armstrong <narmstrong@baylibre.com>,
linux-mtd@lists.infradead.org,
linux-arm-kernel@lists.infradead.org,
linux-oxnas@lists.tuxfamily.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org
Subject: [RFC PATCH] mtd: nand: Add OX820 NAND Support
Date: Tue, 18 Oct 2016 11:09:27 +0200 [thread overview]
Message-ID: <20161018090927.1990-1-narmstrong@baylibre.com> (raw)
Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
This is a simple memory mapped NAND controller with single chip select and
software ECC.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
.../devicetree/bindings/mtd/oxnas-nand.txt | 24 ++++
drivers/mtd/nand/Kconfig | 5 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/oxnas_nand.c | 144 +++++++++++++++++++++
4 files changed, 174 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
create mode 100644 drivers/mtd/nand/oxnas_nand.c
diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
new file mode 100644
index 0000000..83b684d
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
@@ -0,0 +1,24 @@
+* Oxford Semiconductor OXNAS NAND Controller
+
+Please refer to nand.txt for generic information regarding MTD NAND bindings.
+
+Required properties:
+ - compatible: "oxsemi,ox820-nand"
+ - reg: Base address and length for NAND mapped memory.
+
+Optional Properties:
+ - clocks: phandle to the NAND gate clock if needed.
+ - resets: phandle to the NAND reset control if needed.
+
+Example:
+
+nand: nand@41000000 {
+ compatible = "oxsemi,ox820-nand";
+ reg = <0x41000000 0x100000>;
+ nand-ecc-mode = "soft";
+ clocks = <&stdclk CLK_820_NAND>;
+ resets = <&reset RESET_NAND>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+};
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7b7a887..c023125 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -426,6 +426,11 @@ config MTD_NAND_ORION
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
+config MTD_NAND_OXNAS
+ tristate "NAND Flash support for Oxford Semiconductor SoC"
+ help
+ This enables the NAND flash controller on Oxford Semiconductor SoCs.
+
config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
depends on FSL_SOC
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index cafde6f..05fc054 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
+obj-$(CONFIG_MTD_NAND_OXNAS) += oxnas_nand.o
obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
new file mode 100644
index 0000000..ee402ab
--- /dev/null
+++ b/drivers/mtd/nand/oxnas_nand.c
@@ -0,0 +1,144 @@
+/*
+ * Oxford Semiconductor OXNAS NAND driver
+ *
+ * Heavily based on plat_nand.c :
+ * Author: Vitaly Wool <vitalywool@gmail.com>
+ *
+ * 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.
+ *
+ */
+
+#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>
+
+/* 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)
+
+struct oxnas_nand_data {
+ struct nand_chip chip;
+ void __iomem *io_base;
+ struct clk *clk;
+};
+
+static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+ struct nand_chip *this = mtd->priv;
+ unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ nandaddr &= ~(NAND_CMD | NAND_ADDR);
+ if (ctrl & NAND_CLE)
+ nandaddr |= NAND_CMD;
+ else if (ctrl & NAND_ALE)
+ nandaddr |= NAND_ADDR;
+ this->IO_ADDR_W = (void __iomem *) nandaddr;
+ }
+
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, (void __iomem *) nandaddr);
+}
+
+/*
+ * Probe for the NAND device.
+ */
+static int oxnas_nand_probe(struct platform_device *pdev)
+{
+ struct oxnas_nand_data *data;
+ struct mtd_info *mtd;
+ struct resource *res;
+ int err = 0;
+
+ /* Allocate memory for the device structure (and zero it) */
+ data = devm_kzalloc(&pdev->dev, sizeof(struct oxnas_nand_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->io_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(data->io_base))
+ return PTR_ERR(data->io_base);
+
+ data->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(data->clk))
+ data->clk = NULL;
+
+ nand_set_flash_node(&data->chip, pdev->dev.of_node);
+ mtd = nand_to_mtd(&data->chip);
+ mtd->dev.parent = &pdev->dev;
+ mtd->priv = &data->chip;
+
+ data->chip.IO_ADDR_R = data->io_base;
+ data->chip.IO_ADDR_W = data->io_base;
+ data->chip.cmd_ctrl = oxnas_nand_cmd_ctrl;
+ data->chip.chip_delay = 30;
+ data->chip.ecc.mode = NAND_ECC_SOFT;
+ data->chip.ecc.algo = NAND_ECC_HAMMING;
+
+ platform_set_drvdata(pdev, data);
+
+ clk_prepare_enable(data->clk);
+ device_reset_optional(&pdev->dev);
+
+ /* Scan to find existence of the device */
+ if (nand_scan(mtd, 1)) {
+ err = -ENXIO;
+ goto out;
+ }
+
+ err = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
+ if (!err)
+ return err;
+
+ nand_release(mtd);
+out:
+ return err;
+}
+
+static int oxnas_nand_remove(struct platform_device *pdev)
+{
+ struct oxnas_nand_data *data = platform_get_drvdata(pdev);
+
+ nand_release(nand_to_mtd(&data->chip));
+
+ 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("Vitaly Wool");
+MODULE_DESCRIPTION("Oxnas NAND driver");
+MODULE_ALIAS("platform:oxnas_nand");
--
2.7.0
WARNING: multiple messages have this Message-ID (diff)
From: narmstrong@baylibre.com (Neil Armstrong)
To: linux-arm-kernel@lists.infradead.org
Subject: [RFC PATCH] mtd: nand: Add OX820 NAND Support
Date: Tue, 18 Oct 2016 11:09:27 +0200 [thread overview]
Message-ID: <20161018090927.1990-1-narmstrong@baylibre.com> (raw)
Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller.
This is a simple memory mapped NAND controller with single chip select and
software ECC.
Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
---
.../devicetree/bindings/mtd/oxnas-nand.txt | 24 ++++
drivers/mtd/nand/Kconfig | 5 +
drivers/mtd/nand/Makefile | 1 +
drivers/mtd/nand/oxnas_nand.c | 144 +++++++++++++++++++++
4 files changed, 174 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt
create mode 100644 drivers/mtd/nand/oxnas_nand.c
diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
new file mode 100644
index 0000000..83b684d
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt
@@ -0,0 +1,24 @@
+* Oxford Semiconductor OXNAS NAND Controller
+
+Please refer to nand.txt for generic information regarding MTD NAND bindings.
+
+Required properties:
+ - compatible: "oxsemi,ox820-nand"
+ - reg: Base address and length for NAND mapped memory.
+
+Optional Properties:
+ - clocks: phandle to the NAND gate clock if needed.
+ - resets: phandle to the NAND reset control if needed.
+
+Example:
+
+nand: nand at 41000000 {
+ compatible = "oxsemi,ox820-nand";
+ reg = <0x41000000 0x100000>;
+ nand-ecc-mode = "soft";
+ clocks = <&stdclk CLK_820_NAND>;
+ resets = <&reset RESET_NAND>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ status = "disabled";
+};
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7b7a887..c023125 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -426,6 +426,11 @@ config MTD_NAND_ORION
No board specific support is done by this driver, each board
must advertise a platform_device for the driver to attach.
+config MTD_NAND_OXNAS
+ tristate "NAND Flash support for Oxford Semiconductor SoC"
+ help
+ This enables the NAND flash controller on Oxford Semiconductor SoCs.
+
config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
depends on FSL_SOC
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index cafde6f..05fc054 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
+obj-$(CONFIG_MTD_NAND_OXNAS) += oxnas_nand.o
obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o
obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o
diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c
new file mode 100644
index 0000000..ee402ab
--- /dev/null
+++ b/drivers/mtd/nand/oxnas_nand.c
@@ -0,0 +1,144 @@
+/*
+ * Oxford Semiconductor OXNAS NAND driver
+ *
+ * Heavily based on plat_nand.c :
+ * Author: Vitaly Wool <vitalywool@gmail.com>
+ *
+ * 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.
+ *
+ */
+
+#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>
+
+/* 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)
+
+struct oxnas_nand_data {
+ struct nand_chip chip;
+ void __iomem *io_base;
+ struct clk *clk;
+};
+
+static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+ struct nand_chip *this = mtd->priv;
+ unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ nandaddr &= ~(NAND_CMD | NAND_ADDR);
+ if (ctrl & NAND_CLE)
+ nandaddr |= NAND_CMD;
+ else if (ctrl & NAND_ALE)
+ nandaddr |= NAND_ADDR;
+ this->IO_ADDR_W = (void __iomem *) nandaddr;
+ }
+
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, (void __iomem *) nandaddr);
+}
+
+/*
+ * Probe for the NAND device.
+ */
+static int oxnas_nand_probe(struct platform_device *pdev)
+{
+ struct oxnas_nand_data *data;
+ struct mtd_info *mtd;
+ struct resource *res;
+ int err = 0;
+
+ /* Allocate memory for the device structure (and zero it) */
+ data = devm_kzalloc(&pdev->dev, sizeof(struct oxnas_nand_data),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->io_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(data->io_base))
+ return PTR_ERR(data->io_base);
+
+ data->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(data->clk))
+ data->clk = NULL;
+
+ nand_set_flash_node(&data->chip, pdev->dev.of_node);
+ mtd = nand_to_mtd(&data->chip);
+ mtd->dev.parent = &pdev->dev;
+ mtd->priv = &data->chip;
+
+ data->chip.IO_ADDR_R = data->io_base;
+ data->chip.IO_ADDR_W = data->io_base;
+ data->chip.cmd_ctrl = oxnas_nand_cmd_ctrl;
+ data->chip.chip_delay = 30;
+ data->chip.ecc.mode = NAND_ECC_SOFT;
+ data->chip.ecc.algo = NAND_ECC_HAMMING;
+
+ platform_set_drvdata(pdev, data);
+
+ clk_prepare_enable(data->clk);
+ device_reset_optional(&pdev->dev);
+
+ /* Scan to find existence of the device */
+ if (nand_scan(mtd, 1)) {
+ err = -ENXIO;
+ goto out;
+ }
+
+ err = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0);
+ if (!err)
+ return err;
+
+ nand_release(mtd);
+out:
+ return err;
+}
+
+static int oxnas_nand_remove(struct platform_device *pdev)
+{
+ struct oxnas_nand_data *data = platform_get_drvdata(pdev);
+
+ nand_release(nand_to_mtd(&data->chip));
+
+ 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("Vitaly Wool");
+MODULE_DESCRIPTION("Oxnas NAND driver");
+MODULE_ALIAS("platform:oxnas_nand");
--
2.7.0
next reply other threads:[~2016-10-18 9:09 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-10-18 9:09 Neil Armstrong [this message]
2016-10-18 9:09 ` [RFC PATCH] mtd: nand: Add OX820 NAND Support Neil Armstrong
2016-10-18 11:08 ` Daniel Golle
2016-10-18 11:08 ` Daniel Golle
2016-10-18 11:08 ` Daniel Golle
2016-10-18 11:24 ` Neil Armstrong
2016-10-18 11:24 ` Neil Armstrong
2016-10-18 11:24 ` Neil Armstrong
2016-10-18 11:51 ` Daniel Golle
2016-10-18 11:51 ` Daniel Golle
2016-10-18 11:51 ` Daniel Golle
2016-10-18 12:08 ` Neil Armstrong
2016-10-18 12:08 ` Neil Armstrong
2016-10-18 12:08 ` Neil Armstrong
2016-10-18 20:17 ` Boris Brezillon
2016-10-18 20:17 ` Boris Brezillon
2016-10-18 20:17 ` Boris Brezillon
2016-10-19 9:29 ` Neil Armstrong
2016-10-19 9:29 ` Neil Armstrong
2016-10-19 9:29 ` Neil Armstrong
2016-10-19 11:13 ` Boris Brezillon
2016-10-19 11:13 ` Boris Brezillon
2016-10-19 11:13 ` Boris Brezillon
2016-10-19 3:17 ` Rob Herring
2016-10-19 3:17 ` Rob Herring
2016-10-19 3:17 ` Rob Herring
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20161018090927.1990-1-narmstrong@baylibre.com \
--to=narmstrong@baylibre.com \
--cc=boris.brezillon@free-electrons.com \
--cc=computersforpeace@gmail.com \
--cc=devicetree@vger.kernel.org \
--cc=dwmw2@infradead.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mtd@lists.infradead.org \
--cc=linux-oxnas@lists.tuxfamily.org \
--cc=richard@nod.at \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.