public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
From: Jagan Teki <jagan@openedev.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v9 12/21] mtd: spi-nor: Add m25p80 driver
Date: Sun, 30 Oct 2016 23:53:44 +0530	[thread overview]
Message-ID: <1477851833-23960-13-git-send-email-jagan@openedev.com> (raw)
In-Reply-To: <1477851833-23960-1-git-send-email-jagan@openedev.com>

This is MTD SPI-NOR driver for ST M25Pxx (and similar)
serial flash chips which is written as MTD_UCLASS.

Signed-off-by: Jagan Teki <jagan@openedev.com>
---
 drivers/mtd/spi-nor/Makefile |   3 +
 drivers/mtd/spi-nor/m25p80.c | 217 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 220 insertions(+)
 create mode 100644 drivers/mtd/spi-nor/m25p80.c

diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index 15e43ea..d11ccf4 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -7,3 +7,6 @@
 ifdef CONFIG_MTD_SPI_NOR
 obj-y	+= spi-nor.o spi-nor-ids.o
 endif
+
+## spi-nor to spi interface driver
+obj-$(CONFIG_MTD_M25P80)	+= m25p80.o
diff --git a/drivers/mtd/spi-nor/m25p80.c b/drivers/mtd/spi-nor/m25p80.c
new file mode 100644
index 0000000..740d3f6
--- /dev/null
+++ b/drivers/mtd/spi-nor/m25p80.c
@@ -0,0 +1,217 @@
+/*
+ * MTD SPI-NOR driver for ST M25Pxx (and similar) serial flash chips
+ *
+ * Copyright (C) 2016 Jagan Teki <jagan@openedev.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dma.h>
+#include <errno.h>
+#include <mtd.h>
+#include <spi.h>
+
+#include <dm/device-internal.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/spi-nor.h>
+
+#define MAX_CMD_SIZE		6
+struct m25p {
+	struct spi_slave	*spi;
+	struct spi_nor		spi_nor;
+	u8			command[MAX_CMD_SIZE];
+};
+
+static void m25p_addr2cmd(struct spi_nor *nor, unsigned int addr, u8 *cmd)
+{
+	/* opcode is in cmd[0] */
+	cmd[1] = addr >> (nor->addr_width * 8 -  8);
+	cmd[2] = addr >> (nor->addr_width * 8 - 16);
+	cmd[3] = addr >> (nor->addr_width * 8 - 24);
+}
+
+static int m25p_cmdsz(struct spi_nor *nor)
+{
+	return 1 + nor->addr_width;
+}
+
+static int m25p80_read_reg(struct spi_nor *nor, u8 opcode, u8 *val, int len)
+{
+	struct m25p *flash = nor->priv;
+	struct spi_slave *spi = flash->spi;
+	int ret;
+
+	ret = spi_write_then_read(spi, &opcode, 1, NULL, val, len);
+	if (ret < 0) {
+		debug("m25p80: error %d reading register %x\n", ret, opcode);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
+{
+	struct m25p *flash = nor->priv;
+	struct spi_slave *spi = flash->spi;
+	int ret;
+
+	ret = spi_write_then_read(spi, &opcode, 1, buf, NULL, len);
+	if (ret < 0) {
+		debug("m25p80: error %d writing register %x\n", ret, opcode);
+		return ret;
+	}
+
+	return ret;
+}
+
+/*
+ * TODO: remove the weak after all the other spi_flash_copy_mmap
+ * implementations removed from drivers
+ */
+void __weak flash_copy_mmap(void *data, void *offset, size_t len)
+{
+#ifdef CONFIG_DMA
+	if (!dma_memcpy(data, offset, len))
+		return;
+#endif
+	memcpy(data, offset, len);
+}
+
+static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
+		       u_char *buf)
+{
+	struct m25p *flash = nor->priv;
+	struct spi_slave *spi = flash->spi;
+	unsigned int dummy = nor->read_dummy;
+	int ret;
+
+	if (nor->memory_map) {
+		spi_xfer(spi, 0, NULL, NULL, SPI_XFER_MMAP);
+		flash_copy_mmap(buf, nor->memory_map + from, len);
+		spi_xfer(spi, 0, NULL, NULL, SPI_XFER_MMAP_END);
+		spi_release_bus(spi);
+		return 0;
+	}
+
+	/* convert the dummy cycles to the number of bytes */
+	dummy /= 8;
+
+	flash->command[0] = nor->read_opcode;
+	m25p_addr2cmd(nor, from, flash->command);
+
+	ret = spi_write_then_read(spi, flash->command, m25p_cmdsz(nor) + dummy,
+				  NULL, buf, len);
+	if (ret < 0) {
+		debug("m25p80: error %d reading %x\n", ret, flash->command[0]);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
+			const u_char *buf)
+{
+	struct m25p *flash = nor->priv;
+	struct spi_slave *spi = flash->spi;
+	int cmd_sz = m25p_cmdsz(nor);
+	int ret;
+
+	if ((nor->program_opcode == SNOR_OP_AAI_WP) && (buf != NULL))
+		cmd_sz = 1;
+
+	flash->command[0] = nor->program_opcode;
+	if (buf == NULL)
+		flash->command[0] = nor->erase_opcode;
+	m25p_addr2cmd(nor, to, flash->command);
+
+	ret = spi_write_then_read(spi, flash->command, cmd_sz, buf, NULL, len);
+	if (ret < 0) {
+		debug("m25p80: error %d writing %x\n", ret, flash->command[0]);
+		return ret;
+	}
+
+	return ret;
+}
+
+static int m25p_probe(struct udevice *dev)
+{
+	struct mtd_info *mtd = mtd_get_info(dev);
+	struct spi_slave *spi = dev_get_parent_priv(dev);
+	struct m25p *flash = dev_get_priv(dev);
+	struct spi_nor *nor;
+	int ret;
+
+	nor = &flash->spi_nor;
+
+	flash->spi = spi;
+	nor->priv = flash;
+	mtd->priv = nor;
+	nor->dev = dev;
+
+	/* install hooks */
+	nor->read = m25p80_read;
+	nor->write = m25p80_write;
+	nor->read_reg = m25p80_read_reg;
+	nor->write_reg = m25p80_write_reg;
+
+	/* claim spi bus */
+	ret = spi_claim_bus(spi);
+	if (ret) {
+		debug("m25p80: failed to claim SPI bus: %d\n", ret);
+		return ret;
+	}
+
+	if (spi->mode & SPI_RX_SLOW)
+		nor->mode = SNOR_READ;
+	else if (spi->mode & SPI_RX_DUAL)
+		nor->mode = SNOR_READ_1_1_2;
+	else if (spi->mode & SPI_RX_QUAD)
+		nor->mode = SNOR_READ_1_1_4;
+
+	if (spi->mode & SPI_TX_BYTE)
+		nor->mode |= SNOR_WRITE_1_1_BYTE;
+	else if (spi->mode & SPI_TX_QUAD)
+		nor->mode |= SNOR_WRITE_1_1_4;
+
+	nor->memory_map = spi->memory_map;
+	nor->max_write_size = spi->max_write_size;
+
+	ret = spi_nor_scan(dev);
+	if (ret)
+		goto err_scan;
+
+	ret = dm_add_mtd_device(dev);
+	if (ret)
+		goto err_mtd;
+
+	return 0;
+
+err_mtd:
+	device_remove(dev);
+	spi_free_slave(spi);
+err_scan:
+	spi_release_bus(spi);
+	return ret;
+}
+
+static const struct udevice_id m25p_ids[] = {
+	/*
+	 * Generic compatibility for SPI NOR that can be identified by the
+	 * JEDEC READ ID opcode (0x9F). Use this, if possible.
+	 */
+	{ .compatible = "jedec,spi-nor" },
+	{ }
+};
+
+U_BOOT_DRIVER(m25p80) = {
+	.name		= "m25p80",
+	.id		= UCLASS_MTD,
+	.of_match	= m25p_ids,
+	.probe		= m25p_probe,
+	.priv_auto_alloc_size = sizeof(struct m25p),
+};
-- 
2.7.4

  parent reply	other threads:[~2016-10-30 18:23 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-30 18:23 [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Jagan Teki
2016-10-30 18:23 ` [U-Boot] [PATCH v9 01/21] dm: mtd: Add dm mtd core ops Jagan Teki
2016-11-05 16:07   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 02/21] mtd: Add SPI-NOR core support Jagan Teki
2016-11-05 16:10   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 03/21] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR entry Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 04/21] mtd: spi-nor: Kconfig: Add MTD_SPI_NOR_USE_4K_SECTORS Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 05/21] mtd: spi-nor: Kconfig: Add SPI_NOR_MISC entry Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 06/21] mtd: spi-nor: Kconfig: Add SPI_NOR_MACRONIX entry Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 07/21] mtd: spi-nor: Kconfig: Add SPI_NOR_SPANSION entry Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 08/21] mtd: spi-nor: Kconfig: Add SPI_NOR_STMICRO entry Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 09/21] mtd: spi-nor: Kconfig: Add SPI_NOR_SST entry Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 10/21] mtd: spi-nor: Kconfig: Add SPI_NOR_WINBOND entry Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 11/21] spi: Add spi_write_then_read Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` Jagan Teki [this message]
2016-11-05 16:10   ` [U-Boot] [PATCH v9 12/21] mtd: spi-nor: Add m25p80 driver Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 13/21] mtd: spi-nor: Kconfig: Add MTD_M25P80 entry Jagan Teki
2016-11-05 16:09   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 14/21] mtd: spi-nor: Add zynq qspinor driver Jagan Teki
2016-10-30 18:23 ` [U-Boot] [PATCH v9 15/21] mtd: spi-nor: zynq_qspi: Kconfig: Add MTD_ZYNQ Jagan Teki
2016-10-30 18:23 ` [U-Boot] [PATCH v9 16/21] mtd: spi-nor: Add 4-byte addresswidth support Jagan Teki
2016-10-30 18:23 ` [U-Boot] [PATCH v9 17/21] dm: mtd: Add uclass_driver.flags Jagan Teki
2016-11-05 16:10   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 18/21] dm: mtd: Add post_bind Jagan Teki
2016-11-05 16:10   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 19/21] cmd: Add mtd command support Jagan Teki
2016-11-05 16:10   ` Simon Glass
2016-10-30 18:23 ` [U-Boot] [PATCH v9 20/21] arm: dts: zynq: Add zynq-qspinor node Jagan Teki
2016-10-30 18:23 ` [U-Boot] [PATCH v9 21/21] dm: zynq: microzed: Enable MTD/SPI-NOR Jagan Teki
2016-11-05 16:07 ` [U-Boot] [PATCH v9 00/21] dm: Generic MTD Subsystem/SPI-NOR Simon Glass

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=1477851833-23960-13-git-send-email-jagan@openedev.com \
    --to=jagan@openedev.com \
    --cc=u-boot@lists.denx.de \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox