summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/devices/mtd_dataflash.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/devices/mtd_dataflash.c')
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c135
1 files changed, 121 insertions, 14 deletions
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index b35e4813a3a5..54e36bfc2c3b 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -82,7 +82,7 @@
struct dataflash {
- u8 command[4];
+ uint8_t command[4];
char name[24];
unsigned partitioned:1;
@@ -150,7 +150,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
struct spi_transfer x = { .tx_dma = 0, };
struct spi_message msg;
unsigned blocksize = priv->page_size << 3;
- u8 *command;
+ uint8_t *command;
DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%x len 0x%x\n",
spi->dev.bus_id,
@@ -182,8 +182,8 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
pageaddr = pageaddr << priv->page_offset;
command[0] = do_block ? OP_ERASE_BLOCK : OP_ERASE_PAGE;
- command[1] = (u8)(pageaddr >> 16);
- command[2] = (u8)(pageaddr >> 8);
+ command[1] = (uint8_t)(pageaddr >> 16);
+ command[2] = (uint8_t)(pageaddr >> 8);
command[3] = 0;
DEBUG(MTD_DEBUG_LEVEL3, "ERASE %s: (%x) %x %x %x [%i]\n",
@@ -234,7 +234,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
struct spi_transfer x[2] = { { .tx_dma = 0, }, };
struct spi_message msg;
unsigned int addr;
- u8 *command;
+ uint8_t *command;
int status;
DEBUG(MTD_DEBUG_LEVEL2, "%s: read 0x%x..0x%x\n",
@@ -274,9 +274,9 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
* fewer "don't care" bytes. Both buffers stay unchanged.
*/
command[0] = OP_READ_CONTINUOUS;
- command[1] = (u8)(addr >> 16);
- command[2] = (u8)(addr >> 8);
- command[3] = (u8)(addr >> 0);
+ command[1] = (uint8_t)(addr >> 16);
+ command[2] = (uint8_t)(addr >> 8);
+ command[3] = (uint8_t)(addr >> 0);
/* plus 4 "don't care" bytes */
status = spi_sync(priv->spi, &msg);
@@ -311,7 +311,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t remaining = len;
u_char *writebuf = (u_char *) buf;
int status = -EINVAL;
- u8 *command;
+ uint8_t *command;
DEBUG(MTD_DEBUG_LEVEL2, "%s: write 0x%x..0x%x\n",
spi->dev.bus_id, (unsigned)to, (unsigned)(to + len));
@@ -487,7 +487,9 @@ add_dataflash(struct spi_device *spi, char *name,
device->write = dataflash_write;
device->priv = priv;
- dev_info(&spi->dev, "%s (%d KBytes)\n", name, device->size/1024);
+ dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes, "
+ "erasesize %d bytes\n", name, device->size/1024,
+ pagesize, pagesize * 8); /* 8 pages = 1 block */
dev_set_drvdata(&spi->dev, priv);
if (mtd_has_partitions()) {
@@ -521,7 +523,7 @@ add_dataflash(struct spi_device *spi, char *name,
*
* Device Density ID code #Pages PageSize Offset
* AT45DB011B 1Mbit (128K) xx0011xx (0x0c) 512 264 9
- * AT45DB021B 2Mbit (256K) xx0101xx (0x14) 1025 264 9
+ * AT45DB021B 2Mbit (256K) xx0101xx (0x14) 1024 264 9
* AT45DB041B 4Mbit (512K) xx0111xx (0x1c) 2048 264 9
* AT45DB081B 8Mbit (1M) xx1001xx (0x24) 4096 264 9
* AT45DB0161B 16Mbit (2M) xx1011xx (0x2c) 4096 528 10
@@ -529,9 +531,114 @@ add_dataflash(struct spi_device *spi, char *name,
* AT45DB0642 64Mbit (8M) xx111xxx (0x3c) 8192 1056 11
* AT45DB1282 128Mbit (16M) xx0100xx (0x10) 16384 1056 11
*/
+
+struct flash_info {
+ char *name;
+
+ /* 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.
+ */
+ uint32_t jedec_id;
+
+ /* The size listed here is what works with OPCODE_SE, which isn't
+ * necessarily called a "sector" by the vendor.
+ */
+ unsigned nr_pages;
+ uint16_t pagesize;
+ uint16_t pageoffset;
+
+ uint16_t flags;
+#define SUP_POW2PS 0x02
+#define IS_POW2PS 0x01
+};
+
+static struct flash_info __devinitdata dataflash_data [] = {
+
+ { "at45db011d", 0x1f2200, 512, 264, 9, SUP_POW2PS},
+ { "at45db011d", 0x1f2200, 512, 256, 8, SUP_POW2PS | IS_POW2PS},
+
+ { "at45db021d", 0x1f2300, 1024, 264, 9, SUP_POW2PS},
+ { "at45db021d", 0x1f2300, 1024, 256, 8, SUP_POW2PS | IS_POW2PS},
+
+ { "at45db041d", 0x1f2400, 2048, 264, 9, SUP_POW2PS},
+ { "at45db041d", 0x1f2400, 2048, 256, 8, SUP_POW2PS | IS_POW2PS},
+
+ { "at45db081d", 0x1f2500, 4096, 264, 9, SUP_POW2PS},
+ { "at45db081d", 0x1f2500, 4096, 256, 8, SUP_POW2PS | IS_POW2PS},
+
+ { "at45db161d", 0x1f2600, 4096, 528, 10, SUP_POW2PS},
+ { "at45db161d", 0x1f2600, 4096, 512, 9, SUP_POW2PS | IS_POW2PS},
+
+ { "at45db321c", 0x1f2700, 8192, 528, 10, },
+
+ { "at45db321d", 0x1f2701, 8192, 528, 10, SUP_POW2PS},
+ { "at45db321d", 0x1f2701, 8192, 512, 9, SUP_POW2PS | IS_POW2PS},
+
+ { "at45db641d", 0x1f2800, 8192, 1056, 11, SUP_POW2PS},
+ { "at45db641d", 0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS},
+};
+
+static struct flash_info *__devinit jedec_probe(struct spi_device *spi)
+{
+ int tmp;
+ uint8_t code = OP_READ_ID;
+ uint8_t id[3];
+ uint32_t jedec;
+ struct flash_info *info;
+ int status;
+
+
+ /* JEDEC also defines an optional "extended device information"
+ * string for after vendor-specific data, after the three bytes
+ * we use here. Supporting some chips might require using it.
+ */
+ tmp = spi_write_then_read(spi, &code, 1, id, 3);
+ if (tmp < 0) {
+ DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n",
+ spi->dev.bus_id, tmp);
+ return NULL;
+ }
+ jedec = id[0];
+ jedec = jedec << 8;
+ jedec |= id[1];
+ jedec = jedec << 8;
+ jedec |= id[2];
+
+ for (tmp = 0, info = dataflash_data;
+ tmp < ARRAY_SIZE(dataflash_data);
+ tmp++, info++) {
+ if (info->jedec_id == jedec) {
+ if (info->flags & SUP_POW2PS) {
+ status = dataflash_status(spi);
+ if (status & 0x1)
+ /* return power of 2 pagesize */
+ return ++info;
+ else
+ return info;
+ }
+ }
+ }
+ return NULL;
+}
+
static int __devinit dataflash_probe(struct spi_device *spi)
{
int status;
+ struct flash_info *info;
+
+ /*
+ * Try to detect dataflash by JEDEC ID.
+ * If it succeeds we know we have either a C or D part.
+ * D will support power of 2 pagesize option.
+ */
+
+ info = jedec_probe(spi);
+
+ if (info != NULL)
+ return add_dataflash(spi, info->name, info->nr_pages,
+ info->pagesize, info->pageoffset);
+
status = dataflash_status(spi);
if (status <= 0 || status == 0xff) {
@@ -551,16 +658,16 @@ static int __devinit dataflash_probe(struct spi_device *spi)
status = add_dataflash(spi, "AT45DB011B", 512, 264, 9);
break;
case 0x14: /* 0 1 0 1 x x */
- status = add_dataflash(spi, "AT45DB021B", 1025, 264, 9);
+ status = add_dataflash(spi, "AT45DB021B", 1024, 264, 9);
break;
case 0x1c: /* 0 1 1 1 x x */
- status = add_dataflash(spi, "AT45DB041x", 2048, 264, 9);
+ status = add_dataflash(spi, "AT45DB041B", 2048, 264, 9);
break;
case 0x24: /* 1 0 0 1 x x */
status = add_dataflash(spi, "AT45DB081B", 4096, 264, 9);
break;
case 0x2c: /* 1 0 1 1 x x */
- status = add_dataflash(spi, "AT45DB161x", 4096, 528, 10);
+ status = add_dataflash(spi, "AT45DB161B", 4096, 528, 10);
break;
case 0x34: /* 1 1 0 1 x x */
status = add_dataflash(spi, "AT45DB321x", 8192, 528, 10);