[PATCH 1/2] m25p80: re-import it againt mtd_add_host

Jean-Christophe PLAGNIOL-VILLARD plagnioj at jcrosoft.com
Wed Oct 31 08:04:02 EDT 2012


so we now create the cdev via mtd

This will also simplify sync with linux

to avoid the m25p8000 or m25p00 the cdev is still named name m25p and the
drivers m25p80

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj at jcrosoft.com>
---
 arch/arm/boards/freescale-mx6-sabrelite/board.c |    2 +-
 drivers/mtd/devices/Kconfig                     |   27 ++
 drivers/mtd/devices/Makefile                    |    1 +
 drivers/{nor => mtd/devices}/m25p80.c           |  470 ++++++++++++-----------
 drivers/nor/Kconfig                             |   27 --
 drivers/nor/Makefile                            |    1 -
 drivers/nor/m25p80.h                            |   84 ----
 include/linux/mtd/cfi.h                         |   65 ++++
 8 files changed, 338 insertions(+), 339 deletions(-)
 rename drivers/{nor => mtd/devices}/m25p80.c (69%)
 delete mode 100644 drivers/nor/m25p80.h
 create mode 100644 include/linux/mtd/cfi.h

diff --git a/arch/arm/boards/freescale-mx6-sabrelite/board.c b/arch/arm/boards/freescale-mx6-sabrelite/board.c
index 25402d7..1c1ae56 100644
--- a/arch/arm/boards/freescale-mx6-sabrelite/board.c
+++ b/arch/arm/boards/freescale-mx6-sabrelite/board.c
@@ -209,7 +209,7 @@ static struct spi_imx_master sabrelite_spi_0_data = {
 
 static const struct spi_board_info sabrelite_spi_board_info[] = {
 	{
-		.name = "m25p",
+		.name = "m25p80",
 		.max_speed_hz = 40000000,
 		.bus_num = 0,
 		.chip_select = 0,
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index e956921..679ea80 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -19,6 +19,33 @@ config MTD_DATAFLASH_WRITE_VERIFY
 	  device thinks the write was successful, a bit could have been
 	  flipped accidentally due to device wear or something else.
 
+config MTD_M25P80
+	tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)"
+	depends on SPI
+	help
+	  This enables access to most modern SPI flash chips, used for
+	  program and data storage.   Series supported include Atmel AT26DF,
+	  Spansion S25SL, SST 25VF, ST M25P, and Winbond W25X.  Other chips
+	  are supported as well.  See the driver source for the current list,
+	  or to add other chips.
+
+	  Note that the original DataFlash chips (AT45 series, not AT26DF),
+	  need an entirely different driver.
+
+	  Set up your spi devices with the right board-specific platform data,
+	  if you want to specify device partitioning or to use a device which
+	  doesn't support the JEDEC ID instruction.
+
+config MTD_SST25L
+	tristate "Support SST25L (non JEDEC) SPI Flash chips"
+	depends on MTD_M25P80
+	help
+	  This enables access to the non JEDEC SST25L SPI flash chips, used
+	  for program and data storage.
+
+	  Set up your spi devices with the right board-specific platform data,
+	  if you want to specify device partitioning.
+
 config MTD_DOCG3
 	bool "M-Systems Disk-On-Chip G3"
 	select BCH
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index d7e27d1..bf1f8a9 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_MTD_DATAFLASH)	+= mtd_dataflash.o
 obj-$(CONFIG_MTD_DOCG3)		+= docg3.o
+obj-$(CONFIG_MTD_M25P80)	+= m25p80.o
diff --git a/drivers/nor/m25p80.c b/drivers/mtd/devices/m25p80.c
similarity index 69%
rename from drivers/nor/m25p80.c
rename to drivers/mtd/devices/m25p80.c
index e3b5b95..b4ac045 100644
--- a/drivers/nor/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -4,9 +4,6 @@
  * Author: Mike Lavender, mike at steroidmicros.com
  * Copyright (c) 2005, Intec Automation Inc.
  *
- * Adapted to barebox :  Franck JULLIEN <elec4fun at gmail.com>
- * Copyright (c) 2011
- *
  * Some parts are based on lart.c by Abraham Van Der Merwe
  *
  * Cleaned up and generalized based on mtd_dataflash.c
@@ -27,8 +24,74 @@
 #include <errno.h>
 #include <linux/err.h>
 #include <clock.h>
+#include <linux/math64.h>
+#include <linux/mtd/cfi.h>
 #include <linux/mtd/mtd.h>
-#include "m25p80.h"
+
+/* Flash opcodes. */
+#define	OPCODE_WREN		0x06	/* Write enable */
+#define	OPCODE_RDSR		0x05	/* Read status register */
+#define	OPCODE_WRSR		0x01	/* Write status register 1 byte */
+#define	OPCODE_NORM_READ	0x03	/* Read data bytes (low frequency) */
+#define	OPCODE_FAST_READ	0x0b	/* Read data bytes (high frequency) */
+#define	OPCODE_PP		0x02	/* Page program (up to 256 bytes) */
+#define	OPCODE_BE_4K		0x20	/* Erase 4KiB block */
+#define	OPCODE_BE_32K		0x52	/* Erase 32KiB block */
+#define	OPCODE_CHIP_ERASE	0xc7	/* Erase whole flash chip */
+#define	OPCODE_SE		0xd8	/* Sector erase (usually 64KiB) */
+#define	OPCODE_RDID		0x9f	/* Read JEDEC ID */
+
+/* Used for SST flashes only. */
+#define	OPCODE_BP		0x02	/* Byte program */
+#define	OPCODE_WRDI		0x04	/* Write disable */
+#define	OPCODE_AAI_WP		0xad	/* Auto address increment word program */
+
+/* Used for Macronix flashes only. */
+#define	OPCODE_EN4B		0xb7	/* Enter 4-byte mode */
+#define	OPCODE_EX4B		0xe9	/* Exit 4-byte mode */
+
+/* Used for Spansion flashes only. */
+#define	OPCODE_BRWR		0x17	/* Bank register write */
+
+/* Status Register bits. */
+#define	SR_WIP			1	/* Write in progress */
+#define	SR_WEL			2	/* Write enable latch */
+/* meaning of other SR_* bits may differ between vendors */
+#define	SR_BP0			4	/* Block protect 0 */
+#define	SR_BP1			8	/* Block protect 1 */
+#define	SR_BP2			0x10	/* Block protect 2 */
+#define	SR_SRWD			0x80	/* SR write protect */
+
+/* Define max times to check status register before we give up. */
+#define	MAX_READY_WAIT		40	/* M25P16 specs 40s max chip erase */
+#define MAX_CMD_SIZE		6
+
+#define JEDEC_MFR(_jedec_id)	((_jedec_id) >> 16)
+
+/****************************************************************************/
+
+#define SPI_NAME_SIZE   32
+
+struct spi_device_id {
+	char name[SPI_NAME_SIZE];
+	unsigned long driver_data;
+};
+
+struct m25p {
+	struct spi_device	*spi;
+	struct mtd_info		mtd;
+	u16			page_size;
+	unsigned		sector_size;
+	u16			addr_width;
+	u8			erase_opcode;
+	u8			erase_opcode_4k;
+	u8			*command;
+};
+
+static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
+{
+	return container_of(mtd, struct m25p, mtd);
+}
 
 /****************************************************************************/
 
@@ -94,11 +157,18 @@ static inline int write_disable(struct m25p *flash)
 /*
  * Enable/disable 4-byte addressing mode.
  */
-static inline int set_4byte(struct m25p *flash, int enable)
+static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable)
 {
-	u8	code = enable ? OPCODE_EN4B : OPCODE_EX4B;
-
-	return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
+	switch (JEDEC_MFR(jedec_id)) {
+	case CFI_MFR_MACRONIX:
+		flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B;
+		return spi_write(flash->spi, flash->command, 1);
+	default:
+		/* Spansion style */
+		flash->command[0] = OPCODE_BRWR;
+		flash->command[1] = enable << 7;
+		return spi_write(flash->spi, flash->command, 2);
+	}
 }
 
 /*
@@ -131,7 +201,7 @@ static int wait_till_ready(struct m25p *flash)
 static int erase_chip(struct m25p *flash)
 {
 	dev_dbg(&flash->spi->dev, "%s %lldKiB\n",
-		__func__, (long long)(flash->size >> 10));
+		__func__, (long long)(flash->mtd.size >> 10));
 
 	/* Wait until finished previous write command. */
 	if (wait_till_ready(flash))
@@ -171,7 +241,7 @@ static int m25p_cmdsz(struct m25p *flash)
 static int erase_sector(struct m25p *flash, u32 offset, u32 command)
 {
 	dev_dbg(&flash->spi->dev, "%s %dKiB at 0x%08x\n",
-		__func__, flash->erasesize / 1024, offset);
+		__func__, flash->mtd.erasesize / 1024, offset);
 
 	/* Wait until finished previous write command. */
 	if (wait_till_ready(flash))
@@ -189,30 +259,39 @@ static int erase_sector(struct m25p *flash, u32 offset, u32 command)
 	return 0;
 }
 
+/****************************************************************************/
+
+/*
+ * MTD implementation
+ */
+
 /*
  * Erase an address range on the flash chip.  The address range may extend
  * one or more erase sectors.  Return an error is there is a problem erasing.
  */
-static ssize_t m25p80_erase(struct cdev *cdev, size_t count, loff_t offset)
+static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
 {
-	struct m25p *flash = cdev->priv;
+	struct m25p *flash = mtd_to_m25p(mtd);
 	u32 addr, len;
+	uint32_t rem;
 
-	dev_dbg(&flash->spi->dev, "%s %s 0x%llx, len %lld\n",
-		__func__, "at", (long long)offset, (long long)count);
+	dev_dbg(&flash->spi->dev, "%s at 0x%llx, len %lld\n",
+			__func__, (long long)instr->addr,
+			(long long)instr->len);
 
-	/* sanity checks */
-	if (offset + count > flash->size)
+	div_u64_rem(instr->len, mtd->erasesize, &rem);
+	if (rem)
 		return -EINVAL;
 
-	/* Align start and len to erase blocks */
-	addr = offset & ~(flash->erasesize - 1);
-	len = ALIGN(offset + count, flash->erasesize) - addr;
+	addr = instr->addr;
+	len = instr->len;
 
 	/* whole-chip erase? */
-	if (len == flash->size) {
-		if (erase_chip(flash))
+	if (len == flash->mtd.size) {
+		if (erase_chip(flash)) {
+			instr->state = MTD_ERASE_FAILED;
 			return -EIO;
+		}
 		return 0;
 	}
 
@@ -222,8 +301,8 @@ static ssize_t m25p80_erase(struct cdev *cdev, size_t count, loff_t offset)
 				return -EINTR;
 			if (erase_sector(flash, addr, flash->erase_opcode_4k))
 				return -EIO;
-			addr += flash->erasesize;
-			len -= flash->erasesize;
+			addr += mtd->erasesize;
+			len -= mtd->erasesize;
 		}
 
 		while (len >= flash->sector_size) {
@@ -240,8 +319,8 @@ static ssize_t m25p80_erase(struct cdev *cdev, size_t count, loff_t offset)
 				return -EINTR;
 			if (erase_sector(flash, addr, flash->erase_opcode_4k))
 				return -EIO;
-			addr += flash->erasesize;
-			len -= flash->erasesize;
+			addr += mtd->erasesize;
+			len -= mtd->erasesize;
 		}
 	} else {
 		while (len) {
@@ -250,35 +329,34 @@ static ssize_t m25p80_erase(struct cdev *cdev, size_t count, loff_t offset)
 			if (erase_sector(flash, addr, flash->erase_opcode))
 				return -EIO;
 
-			if (len <= flash->erasesize)
+			if (len <= mtd->erasesize)
 				break;
-			addr += flash->erasesize;
-			len -= flash->erasesize;
+			addr += mtd->erasesize;
+			len -= mtd->erasesize;
 		}
 	}
 
 	if (wait_till_ready(flash))
 		return -ETIMEDOUT;
 
+	instr->state = MTD_ERASE_DONE;
+	mtd_erase_callback(instr);
+
 	return 0;
 }
 
-ssize_t m25p80_read(struct cdev *cdev, void *buf, size_t count, loff_t offset,
-		ulong flags)
+/*
+ * Read an address range from the flash chip.  The address range
+ * may be any size provided it is within the physical boundaries.
+ */
+static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
+	size_t *retlen, u_char *buf)
 {
-	struct m25p *flash = cdev->priv;
+	struct m25p *flash = mtd_to_m25p(mtd);
 	struct spi_transfer t[2];
 	struct spi_message m;
-	ssize_t retlen;
 	int fast_read = 0;
 
-	/* sanity checks */
-	if (!count)
-		return 0;
-
-	if (offset + count > flash->size)
-		return -EINVAL;
-
 	if (flash->spi->max_speed_hz >= 25000000)
 		fast_read = 1;
 
@@ -294,12 +372,9 @@ ssize_t m25p80_read(struct cdev *cdev, void *buf, size_t count, loff_t offset,
 	spi_message_add_tail(&t[0], &m);
 
 	t[1].rx_buf = buf;
-	t[1].len = count;
+	t[1].len = len;
 	spi_message_add_tail(&t[1], &m);
 
-	/* Byte count starts at zero. */
-	retlen = 0;
-
 	/* Wait till previous write/erase is done. */
 	if (wait_till_ready(flash))
 		return -ETIMEDOUT;
@@ -311,29 +386,30 @@ ssize_t m25p80_read(struct cdev *cdev, void *buf, size_t count, loff_t offset,
 
 	/* Set up the write data buffer. */
 	flash->command[0] = fast_read ? OPCODE_FAST_READ : OPCODE_NORM_READ;
-	m25p_addr2cmd(flash, offset, flash->command);
+	m25p_addr2cmd(flash, from, flash->command);
 
 	spi_sync(flash->spi, &m);
 
-	retlen = m.actual_length - m25p_cmdsz(flash) - fast_read;
+	*retlen = m.actual_length - m25p_cmdsz(flash) - fast_read;
 
-	return retlen;
+	return 0;
 }
 
-ssize_t m25p80_write(struct cdev *cdev, const void *buf, size_t count,
-		loff_t offset, ulong flags)
+/*
+ * Write an address range to the flash chip.  Data must be written in
+ * FLASH_PAGESIZE chunks.  The address range may be any size provided
+ * it is within the physical boundaries.
+ */
+static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
+	size_t *retlen, const u_char *buf)
 {
-	struct m25p *flash = cdev->priv;
+	struct m25p *flash = mtd_to_m25p(mtd);
+	u32 page_offset, page_size;
 	struct spi_transfer t[2];
 	struct spi_message m;
-	ssize_t retlen = 0;
-	u32 page_offset, page_size;
 
 	debug("m25p80_write %ld bytes at 0x%08lX\n", (unsigned long)count, offset);
 
-	if (offset + count > flash->size)
-		return -EINVAL;
-
 	spi_message_init(&m);
 	memset(t, 0, (sizeof t));
 
@@ -352,17 +428,17 @@ ssize_t m25p80_write(struct cdev *cdev, const void *buf, size_t count,
 
 	/* Set up the opcode in the write buffer. */
 	flash->command[0] = OPCODE_PP;
-	m25p_addr2cmd(flash, offset, flash->command);
+	m25p_addr2cmd(flash, to, flash->command);
 
-	page_offset = offset & (flash->page_size - 1);
+	page_offset = to & (flash->page_size - 1);
 
 	/* do all the bytes fit onto one page? */
-	if (page_offset + count <= flash->page_size) {
-		t[1].len = count;
+	if (page_offset + len <= flash->page_size) {
+		t[1].len = len;
 
 		spi_sync(flash->spi, &m);
 
-		retlen = m.actual_length - m25p_cmdsz(flash);
+		*retlen = m.actual_length - m25p_cmdsz(flash);
 	} else {
 		u32 i;
 
@@ -372,16 +448,16 @@ ssize_t m25p80_write(struct cdev *cdev, const void *buf, size_t count,
 		t[1].len = page_size;
 		spi_sync(flash->spi, &m);
 
-		retlen = m.actual_length - m25p_cmdsz(flash);
+		*retlen = m.actual_length - m25p_cmdsz(flash);
 
 		/* write everything in flash->page_size chunks */
-		for (i = page_size; i < count; i += page_size) {
-			page_size = count - i;
+		for (i = page_size; i < len; i += page_size) {
+			page_size = len - i;
 			if (page_size > flash->page_size)
 				page_size = flash->page_size;
 
 			/* write the next page to flash */
-			m25p_addr2cmd(flash, offset + i, flash->command);
+			m25p_addr2cmd(flash, to + i, flash->command);
 
 			t[1].tx_buf = buf + i;
 			t[1].len = page_size;
@@ -392,34 +468,24 @@ ssize_t m25p80_write(struct cdev *cdev, const void *buf, size_t count,
 
 			spi_sync(flash->spi, &m);
 
-			retlen += m.actual_length - m25p_cmdsz(flash);
-
+			*retlen += m.actual_length - m25p_cmdsz(flash);
 		}
 	}
 
-	return retlen;
+	return 0;
 }
-#ifdef CONFIG_MTD_SST25L
-ssize_t sst_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset,
-		ulong flags)
+
+static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
+		size_t *retlen, const u_char *buf)
 {
-	struct m25p *flash = cdev->priv;
+	struct m25p *flash = mtd_to_m25p(mtd);
 	struct spi_transfer t[2];
 	struct spi_message m;
 	size_t actual;
-	ssize_t retlen;
 	int cmd_sz, ret;
 
-	debug("sst_write %ld bytes at 0x%08lX\n", (unsigned long)count, offset);
-
-	retlen = 0;
-
-	/* sanity checks */
-	if (!count)
-		return 0;
-
-	if (offset + count > flash->size)
-		return -EINVAL;
+	pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
+			__func__, (u32)to, len);
 
 	spi_message_init(&m);
 	memset(t, 0, (sizeof t));
@@ -438,11 +504,11 @@ ssize_t sst_write(struct cdev *cdev, const void *buf, size_t count, loff_t offse
 
 	write_enable(flash);
 
-	actual = offset % 2;
+	actual = to % 2;
 	/* Start write from odd address. */
 	if (actual) {
 		flash->command[0] = OPCODE_BP;
-		m25p_addr2cmd(flash, offset, flash->command);
+		m25p_addr2cmd(flash, to, flash->command);
 
 		/* write one byte. */
 		t[1].len = 1;
@@ -450,16 +516,16 @@ ssize_t sst_write(struct cdev *cdev, const void *buf, size_t count, loff_t offse
 		ret = wait_till_ready(flash);
 		if (ret)
 			goto time_out;
-		retlen += m.actual_length - m25p_cmdsz(flash);
+		*retlen += m.actual_length - m25p_cmdsz(flash);
 	}
-	offset += actual;
+	to += actual;
 
 	flash->command[0] = OPCODE_AAI_WP;
-	m25p_addr2cmd(flash, offset, flash->command);
+	m25p_addr2cmd(flash, to, flash->command);
 
 	/* Write out most of the data here. */
 	cmd_sz = m25p_cmdsz(flash);
-	for (; actual < count - 1; actual += 2) {
+	for (; actual < len - 1; actual += 2) {
 		t[0].len = cmd_sz;
 		/* write two bytes. */
 		t[1].len = 2;
@@ -469,9 +535,9 @@ ssize_t sst_write(struct cdev *cdev, const void *buf, size_t count, loff_t offse
 		ret = wait_till_ready(flash);
 		if (ret)
 			goto time_out;
-		retlen += m.actual_length - cmd_sz;
+		*retlen += m.actual_length - cmd_sz;
 		cmd_sz = 1;
-		offset += 2;
+		to += 2;
 	}
 	write_disable(flash);
 	ret = wait_till_ready(flash);
@@ -479,10 +545,10 @@ ssize_t sst_write(struct cdev *cdev, const void *buf, size_t count, loff_t offse
 		goto time_out;
 
 	/* Write out trailing byte if it exists. */
-	if (actual != count) {
+	if (actual != len) {
 		write_enable(flash);
 		flash->command[0] = OPCODE_BP;
-		m25p_addr2cmd(flash, offset, flash->command);
+		m25p_addr2cmd(flash, to, flash->command);
 		t[0].len = m25p_cmdsz(flash);
 		t[1].len = 1;
 		t[1].tx_buf = buf + actual;
@@ -491,34 +557,42 @@ ssize_t sst_write(struct cdev *cdev, const void *buf, size_t count, loff_t offse
 		ret = wait_till_ready(flash);
 		if (ret)
 			goto time_out;
-		retlen += m.actual_length - m25p_cmdsz(flash);
+		*retlen += m.actual_length - m25p_cmdsz(flash);
 		write_disable(flash);
 	}
 
 time_out:
-	return retlen;
-}
-#endif
-
-static void m25p80_info(struct device_d *dev)
-{
-	struct m25p		*flash = dev->priv;
-	struct flash_info	*info = flash->info;
-
-	printf("Flash type        : %s\n", flash->name);
-	printf("Size              : %lldKiB\n", (long long)flash->size / 1024);
-	printf("Number of sectors : %d\n", info->n_sectors);
-	printf("Sector size       : %dKiB\n", info->sector_size / 1024);
-	printf("\n");
+	return ret;
 }
 
-
 /****************************************************************************/
 
 /*
  * SPI device driver setup and teardown
  */
 
+struct flash_info {
+	/* JEDEC id zero means "no ID" (most older chips); otherwise it has
+	 * a high byte of zero plus three data bytes: the manufacturer id,
+	 * then a two byte device id.
+	 */
+	u32		jedec_id;
+	u16             ext_id;
+
+	/* The size listed here is what works with OPCODE_SE, which isn't
+	 * necessarily called a "sector" by the vendor.
+	 */
+	unsigned	sector_size;
+	u16		n_sectors;
+
+	u16		page_size;
+	u16		addr_width;
+
+	u16		flags;
+#define	SECT_4K		0x01		/* OPCODE_BE_4K works uniformly */
+#define	M25P_NO_ERASE	0x02		/* No erase command needed */
+};
+
 #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
 	((unsigned long)&(struct flash_info) {				\
 		.jedec_id = (_jedec_id),				\
@@ -667,8 +741,12 @@ static const struct spi_device_id *jedec_probe(struct spi_device *spi)
 	 * string for after vendor-specific data, after the three bytes
 	 * we use here.  Supporting some chips might require using it.
 	 */
-	spi_write_then_read(spi, &code, 1, id, 5);
-
+	tmp = spi_write_then_read(spi, &code, 1, id, 5);
+	if (tmp < 0) {
+		pr_debug("%s: error %d reading JEDEC ID\n",
+				dev_name(&spi->dev), tmp);
+		return ERR_PTR(tmp);
+	}
 	jedec = id[0];
 	jedec = jedec << 8;
 	jedec |= id[1];
@@ -686,84 +764,9 @@ static const struct spi_device_id *jedec_probe(struct spi_device *spi)
 		}
 	}
 	dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec);
-
-	return NULL;
+	return ERR_PTR(-ENODEV);
 }
 
-static struct file_operations m25p80_ops = {
-	.read   = m25p80_read,
-	.write  = m25p80_write,
-	.erase  = m25p80_erase,
-	.lseek  = dev_lseek_default,
-};
-
-static int m25p_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
-		size_t *retlen, u_char *buf)
-{
-	struct m25p *flash = container_of(mtd, struct m25p, mtd);
-	ssize_t ret;
-
-	ret = flash->cdev.ops->read(&flash->cdev, buf, len, from, 0);
-	if (ret < 0) {
-		*retlen = 0;
-		return ret;
-	}
-
-	*retlen = ret;
-	return 0;
-}
-
-static int m25p_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
-		size_t *retlen, const u_char *buf)
-{
-	struct m25p *flash = container_of(mtd, struct m25p, mtd);
-	ssize_t ret;
-
-	ret = flash->cdev.ops->write(&flash->cdev, buf, len, to, 0);
-	if (ret < 0) {
-		*retlen = 0;
-		return ret;
-	}
-
-	*retlen = ret;
-	return 0;
-}
-
-static int m25p_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-	struct m25p *flash = container_of(mtd, struct m25p, mtd);
-	ssize_t ret;
-
-	ret = flash->cdev.ops->erase(&flash->cdev, instr->len, instr->addr);
-
-	if (ret) {
-		instr->state = MTD_ERASE_FAILED;
-		return -EIO;
-	}
-
-	instr->state = MTD_ERASE_DONE;
-	mtd_erase_callback(instr);
-
-	return 0;
-}
-
-static void m25p_init_mtd(struct m25p *flash)
-{
-	struct mtd_info *mtd = &flash->mtd;
-
-	mtd->read = m25p_mtd_read;
-	mtd->write = m25p_mtd_write;
-	mtd->erase = m25p_mtd_erase;
-	mtd->size = flash->size;
-	mtd->name = flash->cdev.name;
-	mtd->erasesize = flash->erasesize;
-	mtd->writesize = 1;
-	mtd->subpage_sft = 0;
-	mtd->eraseregions = NULL;
-	mtd->numeraseregions = 0;
-	mtd->flags = MTD_CAP_NORFLASH;
-	flash->cdev.mtd = mtd;
-}
 
 /*
  * board specific setup should have ensured the SPI clock used here
@@ -774,9 +777,9 @@ static int m25p_probe(struct device_d *dev)
 {
 	struct spi_device *spi = (struct spi_device *)dev->type_data;
 	const struct spi_device_id	*id = NULL;
-	struct flash_info		*info = NULL;
 	struct flash_platform_data	*data;
 	struct m25p			*flash;
+	struct flash_info		*info = NULL;
 	unsigned			i;
 	unsigned			do_jdec_probe = 1;
 
@@ -786,7 +789,6 @@ static int m25p_probe(struct device_d *dev)
 	 * newer chips, even if we don't recognize the particular chip.
 	 */
 	data = dev->platform_data;
-
 	if (data && data->type) {
 		const struct spi_device_id *plat_id;
 
@@ -812,10 +814,9 @@ static int m25p_probe(struct device_d *dev)
 		const struct spi_device_id *jid;
 
 		jid = jedec_probe(spi);
-		if (!jid) {
-			return -ENODEV;
+		if (IS_ERR(jid)) {
+			return PTR_ERR(jid);
 		} else if (jid != id) {
-
 			/*
 			 * JEDEC knows better, so overwrite platform ID. We
 			 * can't trust partitions any longer, but we'll let
@@ -842,78 +843,95 @@ static int m25p_probe(struct device_d *dev)
 	 * up with the software protection bits set
 	 */
 
-	if (info->jedec_id >> 16 == 0x1f ||
-	    info->jedec_id >> 16 == 0x89 ||
-	    info->jedec_id >> 16 == 0xbf) {
+	if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ATMEL ||
+	    JEDEC_MFR(info->jedec_id) == CFI_MFR_INTEL ||
+	    JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) {
 		write_enable(flash);
 		write_sr(flash, 0);
 	}
 
-	flash->name = (char *)id->name;
-	flash->info = info;
-	flash->size = info->sector_size * info->n_sectors;
-	flash->erasesize = info->sector_size;
-	flash->sector_size = info->sector_size;
-	flash->cdev.size = info->sector_size * info->n_sectors;
-	flash->cdev.dev = dev;
-	flash->cdev.ops = &m25p80_ops;
-	flash->cdev.priv = flash;
-
 	if (data && data->name)
-		flash->cdev.name = asprintf("%s%d", data->name, dev->id);
+		flash->mtd.name = data->name;
 	else
-		flash->cdev.name = asprintf("%s", (char *)dev_name(&spi->dev));
+		flash->mtd.name = "m25p";
+
+	flash->mtd.type = MTD_NORFLASH;
+	flash->mtd.writesize = 1;
+	flash->mtd.flags = MTD_CAP_NORFLASH;
+	flash->mtd.size = info->sector_size * info->n_sectors;
+	flash->mtd.erase = m25p80_erase;
+	flash->mtd.read = m25p80_read;
 
-#ifdef CONFIG_MTD_SST25L
 	/* sst flash chips use AAI word program */
-	if (info->jedec_id >> 16 == 0xbf)
-		m25p80_ops.write = sst_write;
+	if (IS_ENABLED(CONFIG_MTD_SST25L) && JEDEC_MFR(info->jedec_id) == CFI_MFR_SST)
+		flash->mtd.write = sst_write;
 	else
-#endif
-		m25p80_ops.write = m25p80_write;
+		flash->mtd.write = m25p80_write;
 
 	/* prefer "small sector" erase if possible */
 	if (info->flags & SECT_4K) {
 		flash->erase_opcode_4k = OPCODE_BE_4K;
 		flash->erase_opcode = OPCODE_SE;
-		flash->erasesize = 4096;
+		flash->mtd.erasesize = 4096;
 	} else {
 		flash->erase_opcode = OPCODE_SE;
+		flash->mtd.erasesize = info->sector_size;
 	}
 
+	if (info->flags & M25P_NO_ERASE)
+		flash->mtd.flags |= MTD_NO_ERASE;
+
+	flash->mtd.parent = &spi->dev;
 	flash->page_size = info->page_size;
+	flash->sector_size = info->sector_size;
 
 	if (info->addr_width)
 		flash->addr_width = info->addr_width;
 	else {
 		/* enable 4-byte addressing if the device exceeds 16MiB */
-		if (flash->size > 0x1000000) {
+		if (flash->mtd.size > 0x1000000) {
 			flash->addr_width = 4;
-			set_4byte(flash, 1);
+			set_4byte(flash, info->jedec_id, 1);
 		} else
 			flash->addr_width = 3;
 	}
 
-	dev_info(dev, "%s (%lld Kbytes)\n", id->name, (long long)flash->size >> 10);
+	dev_info(dev, "%s (%lld Kbytes)\n", id->name,
+			(long long)flash->mtd.size >> 10);
 
-	if (IS_ENABLED(CONFIG_PARTITION_NEED_MTD))
-		m25p_init_mtd(flash);
+	pr_debug("mtd .name = %s, .size = 0x%llx (%lldMiB) "
+			".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
+		flash->mtd.name,
+		(long long)flash->mtd.size, (long long)(flash->mtd.size >> 20),
+		flash->mtd.erasesize, flash->mtd.erasesize / 1024,
+		flash->mtd.numeraseregions);
 
-	devfs_create(&flash->cdev);
+	if (flash->mtd.numeraseregions)
+		for (i = 0; i < flash->mtd.numeraseregions; i++)
+			pr_debug("mtd.eraseregions[%d] = { .offset = 0x%llx, "
+				".erasesize = 0x%.8x (%uKiB), "
+				".numblocks = %d }\n",
+				i, (long long)flash->mtd.eraseregions[i].offset,
+				flash->mtd.eraseregions[i].erasesize,
+				flash->mtd.eraseregions[i].erasesize / 1024,
+				flash->mtd.eraseregions[i].numblocks);
 
-	return 0;
+
+
+	return add_mtd_device(&flash->mtd, flash->mtd.name);
 }
 
-static struct driver_d epcs_flash_driver = {
-	.name  = "m25p",
-	.probe = m25p_probe,
-	.info = m25p80_info,
+static struct driver_d m25p80_driver = {
+	.name	= "m25p80",
+	.probe	= m25p_probe,
 };
 
-static int epcs_init(void)
+static int m25p80_init(void)
 {
-	spi_register_driver(&epcs_flash_driver);
-	return 0;
+	return spi_register_driver(&m25p80_driver);
 }
+device_initcall(m25p80_init);
 
-device_initcall(epcs_init);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mike Lavender");
+MODULE_DESCRIPTION("MTD SPI driver for ST M25Pxx flash chips");
diff --git a/drivers/nor/Kconfig b/drivers/nor/Kconfig
index 8652d27..a3c0223 100644
--- a/drivers/nor/Kconfig
+++ b/drivers/nor/Kconfig
@@ -56,31 +56,4 @@ config CFI_BUFFER_WRITE
 
 endif
 
-config MTD_M25P80
-	tristate "SPI Flash chips (AT26DF, M25P, W25X, ...)"
-	depends on SPI
-	help
-	  This enables access to most modern SPI flash chips, used for
-	  program and data storage.   Series supported include Atmel AT26DF,
-	  Spansion S25SL, SST 25VF, ST M25P, and Winbond W25X.  Other chips
-	  are supported as well.  See the driver source for the current list,
-	  or to add other chips.
-
-	  Note that the original DataFlash chips (AT45 series, not AT26DF),
-	  need an entirely different driver.
-
-	  Set up your spi devices with the right board-specific platform data,
-	  if you want to specify device partitioning or to use a device which
-	  doesn't support the JEDEC ID instruction.
-
-config MTD_SST25L
-	tristate "Support SST25L (non JEDEC) SPI Flash chips"
-	depends on MTD_M25P80
-	help
-	  This enables access to the non JEDEC SST25L SPI flash chips, used
-	  for program and data storage.
-
-	  Set up your spi devices with the right board-specific platform data,
-	  if you want to specify device partitioning.
-
 endmenu
diff --git a/drivers/nor/Makefile b/drivers/nor/Makefile
index d676c55..d255043 100644
--- a/drivers/nor/Makefile
+++ b/drivers/nor/Makefile
@@ -1,5 +1,4 @@
 obj-$(CONFIG_DRIVER_CFI) += cfi_flash.o
 obj-$(CONFIG_DRIVER_CFI_INTEL) += cfi_flash_intel.o
 obj-$(CONFIG_DRIVER_CFI_AMD) += cfi_flash_amd.o
-obj-$(CONFIG_MTD_M25P80) += m25p80.o
 
diff --git a/drivers/nor/m25p80.h b/drivers/nor/m25p80.h
deleted file mode 100644
index 957900e..0000000
--- a/drivers/nor/m25p80.h
+++ /dev/null
@@ -1,84 +0,0 @@
-#ifndef _M25P80_H_
-#define _M25P80_H_
-
-/* Flash opcodes. */
-#define	OPCODE_WREN		0x06	/* Write enable */
-#define	OPCODE_RDSR		0x05	/* Read status register */
-#define	OPCODE_WRSR		0x01	/* Write status register 1 byte */
-#define	OPCODE_NORM_READ	0x03	/* Read data bytes (low frequency) */
-#define	OPCODE_FAST_READ	0x0b	/* Read data bytes (high frequency) */
-#define	OPCODE_PP		0x02	/* Page program (up to 256 bytes) */
-#define	OPCODE_BE_4K		0x20	/* Erase 4KiB block */
-#define	OPCODE_BE_32K		0x52	/* Erase 32KiB block */
-#define	OPCODE_CHIP_ERASE	0xc7	/* Erase whole flash chip */
-#define	OPCODE_SE		0xd8	/* Sector erase (usually 64KiB) */
-#define	OPCODE_RDID		0x9f	/* Read JEDEC ID */
-
-/* Used for SST flashes only. */
-#define	OPCODE_BP		0x02	/* Byte program */
-#define	OPCODE_WRDI		0x04	/* Write disable */
-#define	OPCODE_AAI_WP		0xad	/* Auto address increment word program */
-
-/* Used for Macronix flashes only. */
-#define	OPCODE_EN4B		0xb7	/* Enter 4-byte mode */
-#define	OPCODE_EX4B		0xe9	/* Exit 4-byte mode */
-
-/* Status Register bits. */
-#define	SR_WIP			1	/* Write in progress */
-#define	SR_WEL			2	/* Write enable latch */
-/* meaning of other SR_* bits may differ between vendors */
-#define	SR_BP0			4	/* Block protect 0 */
-#define	SR_BP1			8	/* Block protect 1 */
-#define	SR_BP2			0x10	/* Block protect 2 */
-#define	SR_SRWD			0x80	/* SR write protect */
-
-/* Define max times to check status register before we give up. */
-#define	MAX_READY_WAIT		40	/* M25P16 specs 40s max chip erase */
-#define MAX_CMD_SIZE		6
-
-#define SPI_NAME_SIZE   32
-
-struct spi_device_id {
-	char name[SPI_NAME_SIZE];
-	unsigned long driver_data;
-};
-
-struct m25p {
-	struct spi_device	*spi;
-	struct flash_info	*info;
-	struct mtd_info		mtd;
-	struct cdev		cdev;
-	char			*name;
-	u32			erasesize;
-	u32			sector_size;
-	u16			page_size;
-	u16			addr_width;
-	u8			erase_opcode;
-	u8			erase_opcode_4k;
-	u8			*command;
-	u32			size;
-};
-
-struct flash_info {
-	/* JEDEC id zero means "no ID" (most older chips); otherwise it has
-	 * a high byte of zero plus three data bytes: the manufacturer id,
-	 * then a two byte device id.
-	 */
-	u32		jedec_id;
-	u16		ext_id;
-
-	/* The size listed here is what works with OPCODE_SE, which isn't
-	 * necessarily called a "sector" by the vendor.
-	 */
-	unsigned	sector_size;
-	u16		n_sectors;
-
-	u16		page_size;
-	u16		addr_width;
-
-	u16		flags;
-#define	SECT_4K		0x01		/* OPCODE_BE_4K works uniformly */
-#define	M25P_NO_ERASE	0x02		/* No erase command needed */
-};
-
-#endif
diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h
new file mode 100644
index 0000000..793f363
--- /dev/null
+++ b/include/linux/mtd/cfi.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2000-2010 David Woodhouse <dwmw2 at infradead.org> et al.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __MTD_CFI_H__
+#define __MTD_CFI_H__
+
+/* NB: these values must represents the number of bytes needed to meet the
+ *     device type (x8, x16, x32).  Eg. a 32 bit device is 4 x 8 bytes.
+ *     These numbers are used in calculations.
+ */
+#define CFI_DEVICETYPE_X8  (8 / 8)
+#define CFI_DEVICETYPE_X16 (16 / 8)
+#define CFI_DEVICETYPE_X32 (32 / 8)
+#define CFI_DEVICETYPE_X64 (64 / 8)
+
+
+/* Device Interface Code Assignments from the "Common Flash Memory Interface
+ * Publication 100" dated December 1, 2001.
+ */
+#define CFI_INTERFACE_X8_ASYNC		0x0000
+#define CFI_INTERFACE_X16_ASYNC		0x0001
+#define CFI_INTERFACE_X8_BY_X16_ASYNC	0x0002
+#define CFI_INTERFACE_X32_ASYNC		0x0003
+#define CFI_INTERFACE_X16_BY_X32_ASYNC	0x0005
+#define CFI_INTERFACE_NOT_ALLOWED	0xffff
+
+
+#define CFI_MFR_ANY		0xFFFF
+#define CFI_ID_ANY		0xFFFF
+#define CFI_MFR_CONTINUATION	0x007F
+
+#define CFI_MFR_AMD		0x0001
+#define CFI_MFR_AMIC		0x0037
+#define CFI_MFR_ATMEL		0x001F
+#define CFI_MFR_EON		0x001C
+#define CFI_MFR_FUJITSU		0x0004
+#define CFI_MFR_HYUNDAI		0x00AD
+#define CFI_MFR_INTEL		0x0089
+#define CFI_MFR_MACRONIX	0x00C2
+#define CFI_MFR_NEC		0x0010
+#define CFI_MFR_PMC		0x009D
+#define CFI_MFR_SAMSUNG		0x00EC
+#define CFI_MFR_SHARP		0x00B0
+#define CFI_MFR_SST		0x00BF
+#define CFI_MFR_ST		0x0020 /* STMicroelectronics */
+#define CFI_MFR_TOSHIBA		0x0098
+#define CFI_MFR_WINBOND		0x00DA
+
+#endif /* __MTD_CFI_H__ */
-- 
1.7.10.4




More information about the barebox mailing list