summaryrefslogtreecommitdiff
path: root/drivers/mtd/nand/raw/socrates_nand.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-04-06 22:15:41 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-06 22:15:41 +0300
commit3fd14cdcc05a682b03743683ce3a726898b20555 (patch)
treed9f1a1f18d8a4168dec47d85397f36eae7f61633 /drivers/mtd/nand/raw/socrates_nand.c
parent83c7c18b169bdac3dabab763d16549c1e4688a8b (diff)
parentfe5f31a8010a0cb13e72cfb72905fefa2a41730c (diff)
downloadlinux-3fd14cdcc05a682b03743683ce3a726898b20555.tar.xz
Merge tag 'mtd/for-4.17' of git://git.infradead.org/linux-mtd
Pull MTD updates from Boris Brezillon: "MTD Core: - Remove support for asynchronous erase (not implemented by any of the existing drivers anyway) - Remove Cyrille from the list of SPI NOR and MTD maintainers - Fix kernel doc headers - Allow users to define the partitions parsers they want to test through a DT property (compatible of the partitions subnode) - Remove the bfin-async-flash driver (the only architecture using it has been removed) - Fix pagetest test - Add extra checks in mtd_erase() - Simplify the MTD partition creation logic and get rid of mtd_add_device_partitions() MTD Drivers: - Add endianness information to the physmap DT binding - Add Eon EN29LV400A IDs to JEDEC probe logic - Use %*ph where appropriate SPI NOR Drivers: - Make fsl-quaspi assign different names to MTD devices connected to the same QSPI controller - Remove an unneeded driver.bus assigned in the fsl-qspi driver NAND Core: - Prepare arrival of the SPI NAND subsystem by implementing a generic (interface-agnostic) layer to ease manipulation of NAND devices - Move onenand code base to the drivers/mtd/nand/ dir - Rework timing mode selection - Provide a generic way for NAND chip drivers to flag a specific GET/SET FEATURE operation as supported/unsupported - Stop embedding ONFI/JEDEC param page in nand_chip NAND Drivers: - Rework/cleanup of the mxc driver - Various cleanups in the vf610 driver - Migrate the fsmc and vf610 to ->exec_op() - Get rid of the pxa driver (replaced by marvell_nand) - Support ->setup_data_interface() in the GPMI driver - Fix probe error path in several drivers - Remove support for unused hw_syndrome mode in sunxi_nand - Various minor improvements" * tag 'mtd/for-4.17' of git://git.infradead.org/linux-mtd: (89 commits) dt-bindings: fsl-quadspi: Add the example of two SPI NOR mtd: fsl-quadspi: Distinguish the mtd device names mtd: nand: Fix some function description mismatches in core.c mtd: fsl-quadspi: Remove unneeded driver.bus assignment mtd: rawnand: marvell: Rename ->ecc_clk into ->core_clk mtd: rawnand: s3c2410: enhance the probe function error path mtd: rawnand: tango: fix probe function error path mtd: rawnand: sh_flctl: fix the probe function error path mtd: rawnand: omap2: fix the probe function error path mtd: rawnand: mxc: fix probe function error path mtd: rawnand: denali: fix probe function error path mtd: rawnand: davinci: fix probe function error path mtd: rawnand: cafe: fix probe function error path mtd: rawnand: brcmnand: fix probe function error path mtd: rawnand: sunxi: Stop supporting ECC_HW_SYNDROME mode mtd: rawnand: marvell: Fix clock resource by adding a register clock mtd: ftl: Use DIV_ROUND_UP() mtd: Fix some function description mismatches in mtdcore.c mtd: physmap_of: update struct map_info's swap as per map requirement dt-bindings: mtd-physmap: Add endianness supports ...
Diffstat (limited to 'drivers/mtd/nand/raw/socrates_nand.c')
-rw-r--r--drivers/mtd/nand/raw/socrates_nand.c241
1 files changed, 241 insertions, 0 deletions
diff --git a/drivers/mtd/nand/raw/socrates_nand.c b/drivers/mtd/nand/raw/socrates_nand.c
new file mode 100644
index 000000000000..9824a9923583
--- /dev/null
+++ b/drivers/mtd/nand/raw/socrates_nand.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright © 2008 Ilya Yanok, Emcraft Systems
+ *
+ *
+ * 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/slab.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/rawnand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+
+#define FPGA_NAND_CMD_MASK (0x7 << 28)
+#define FPGA_NAND_CMD_COMMAND (0x0 << 28)
+#define FPGA_NAND_CMD_ADDR (0x1 << 28)
+#define FPGA_NAND_CMD_READ (0x2 << 28)
+#define FPGA_NAND_CMD_WRITE (0x3 << 28)
+#define FPGA_NAND_BUSY (0x1 << 15)
+#define FPGA_NAND_ENABLE (0x1 << 31)
+#define FPGA_NAND_DATA_SHIFT 16
+
+struct socrates_nand_host {
+ struct nand_chip nand_chip;
+ void __iomem *io_base;
+ struct device *dev;
+};
+
+/**
+ * socrates_nand_write_buf - write buffer to chip
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void socrates_nand_write_buf(struct mtd_info *mtd,
+ const uint8_t *buf, int len)
+{
+ int i;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct socrates_nand_host *host = nand_get_controller_data(this);
+
+ for (i = 0; i < len; i++) {
+ out_be32(host->io_base, FPGA_NAND_ENABLE |
+ FPGA_NAND_CMD_WRITE |
+ (buf[i] << FPGA_NAND_DATA_SHIFT));
+ }
+}
+
+/**
+ * socrates_nand_read_buf - read chip data into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void socrates_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ int i;
+ struct nand_chip *this = mtd_to_nand(mtd);
+ struct socrates_nand_host *host = nand_get_controller_data(this);
+ uint32_t val;
+
+ val = FPGA_NAND_ENABLE | FPGA_NAND_CMD_READ;
+
+ out_be32(host->io_base, val);
+ for (i = 0; i < len; i++) {
+ buf[i] = (in_be32(host->io_base) >>
+ FPGA_NAND_DATA_SHIFT) & 0xff;
+ }
+}
+
+/**
+ * socrates_nand_read_byte - read one byte from the chip
+ * @mtd: MTD device structure
+ */
+static uint8_t socrates_nand_read_byte(struct mtd_info *mtd)
+{
+ uint8_t byte;
+ socrates_nand_read_buf(mtd, &byte, sizeof(byte));
+ return byte;
+}
+
+/**
+ * socrates_nand_read_word - read one word from the chip
+ * @mtd: MTD device structure
+ */
+static uint16_t socrates_nand_read_word(struct mtd_info *mtd)
+{
+ uint16_t word;
+ socrates_nand_read_buf(mtd, (uint8_t *)&word, sizeof(word));
+ return word;
+}
+
+/*
+ * Hardware specific access to control-lines
+ */
+static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+ unsigned int ctrl)
+{
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
+ uint32_t val;
+
+ if (cmd == NAND_CMD_NONE)
+ return;
+
+ if (ctrl & NAND_CLE)
+ val = FPGA_NAND_CMD_COMMAND;
+ else
+ val = FPGA_NAND_CMD_ADDR;
+
+ if (ctrl & NAND_NCE)
+ val |= FPGA_NAND_ENABLE;
+
+ val |= (cmd & 0xff) << FPGA_NAND_DATA_SHIFT;
+
+ out_be32(host->io_base, val);
+}
+
+/*
+ * Read the Device Ready pin.
+ */
+static int socrates_nand_device_ready(struct mtd_info *mtd)
+{
+ struct nand_chip *nand_chip = mtd_to_nand(mtd);
+ struct socrates_nand_host *host = nand_get_controller_data(nand_chip);
+
+ if (in_be32(host->io_base) & FPGA_NAND_BUSY)
+ return 0; /* busy */
+ return 1;
+}
+
+/*
+ * Probe for the NAND device.
+ */
+static int socrates_nand_probe(struct platform_device *ofdev)
+{
+ struct socrates_nand_host *host;
+ struct mtd_info *mtd;
+ struct nand_chip *nand_chip;
+ int res;
+
+ /* Allocate memory for the device structure (and zero it) */
+ host = devm_kzalloc(&ofdev->dev, sizeof(*host), GFP_KERNEL);
+ if (!host)
+ return -ENOMEM;
+
+ host->io_base = of_iomap(ofdev->dev.of_node, 0);
+ if (host->io_base == NULL) {
+ dev_err(&ofdev->dev, "ioremap failed\n");
+ return -EIO;
+ }
+
+ nand_chip = &host->nand_chip;
+ mtd = nand_to_mtd(nand_chip);
+ host->dev = &ofdev->dev;
+
+ /* link the private data structures */
+ nand_set_controller_data(nand_chip, host);
+ nand_set_flash_node(nand_chip, ofdev->dev.of_node);
+ mtd->name = "socrates_nand";
+ mtd->dev.parent = &ofdev->dev;
+
+ /*should never be accessed directly */
+ nand_chip->IO_ADDR_R = (void *)0xdeadbeef;
+ nand_chip->IO_ADDR_W = (void *)0xdeadbeef;
+
+ nand_chip->cmd_ctrl = socrates_nand_cmd_ctrl;
+ nand_chip->read_byte = socrates_nand_read_byte;
+ nand_chip->read_word = socrates_nand_read_word;
+ nand_chip->write_buf = socrates_nand_write_buf;
+ nand_chip->read_buf = socrates_nand_read_buf;
+ nand_chip->dev_ready = socrates_nand_device_ready;
+
+ nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
+ nand_chip->ecc.algo = NAND_ECC_HAMMING;
+
+ /* TODO: I have no idea what real delay is. */
+ nand_chip->chip_delay = 20; /* 20us command delay time */
+
+ dev_set_drvdata(&ofdev->dev, host);
+
+ res = nand_scan(mtd, 1);
+ if (res)
+ goto out;
+
+ res = mtd_device_register(mtd, NULL, 0);
+ if (!res)
+ return res;
+
+ nand_release(mtd);
+
+out:
+ iounmap(host->io_base);
+ return res;
+}
+
+/*
+ * Remove a NAND device.
+ */
+static int socrates_nand_remove(struct platform_device *ofdev)
+{
+ struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev);
+ struct mtd_info *mtd = nand_to_mtd(&host->nand_chip);
+
+ nand_release(mtd);
+
+ iounmap(host->io_base);
+
+ return 0;
+}
+
+static const struct of_device_id socrates_nand_match[] =
+{
+ {
+ .compatible = "abb,socrates-nand",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, socrates_nand_match);
+
+static struct platform_driver socrates_nand_driver = {
+ .driver = {
+ .name = "socrates_nand",
+ .of_match_table = socrates_nand_match,
+ },
+ .probe = socrates_nand_probe,
+ .remove = socrates_nand_remove,
+};
+
+module_platform_driver(socrates_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ilya Yanok");
+MODULE_DESCRIPTION("NAND driver for Socrates board");