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.c89
1 files changed, 58 insertions, 31 deletions
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index fae36b679b..c1c29b7a1a 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -85,6 +85,9 @@
#define CFI_MFR_ATMEL 0x1F
+#define DATAFLASH_SHIFT_EXTID 24
+#define DATAFLASH_SHIFT_ID 40
+
struct dataflash {
u8 command[4];
char name[24];
@@ -665,7 +668,7 @@ struct flash_info {
/* JEDEC id has a high byte of zero plus three data bytes:
* the manufacturer id, then a two byte device id.
*/
- u32 jedec_id;
+ u64 jedec_id;
/* The size listed here is what works with OP_ERASE_PAGE. */
unsigned nr_pages;
@@ -673,6 +676,7 @@ struct flash_info {
u16 pageoffset;
u16 flags;
+#define SUP_EXTID 0x0004 /* supports extended ID data */
#define SUP_POW2PS 0x0002 /* supports 2^N byte pages */
#define IS_POW2PS 0x0001 /* uses 2^N byte pages */
};
@@ -712,42 +716,18 @@ static struct flash_info dataflash_data [] = {
{ "at45db642d", 0x1f2800, 8192, 1024, 10, SUP_POW2PS | IS_POW2PS},
};
-static struct flash_info * jedec_probe(struct spi_device *spi)
+static struct flash_info *jedec_lookup(struct spi_device *spi,
+ u64 jedec, bool use_extid)
{
- int ret;
- u8 code = OP_READ_ID;
- u8 id[3];
- u32 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.
- *
- * If the vendor ID isn't Atmel's (0x1f), assume this call failed.
- * That's not an error; only rev C and newer chips handle it, and
- * only Atmel sells these chips.
- */
- ret = spi_write_then_read(spi, &code, 1, id, 3);
- if (ret < 0) {
- dev_dbg(&spi->dev, "error %d reading JEDEC ID\n", ret);
- return ERR_PTR(ret);
- }
-
- if (id[0] != CFI_MFR_ATMEL)
- return NULL;
-
- jedec = id[0];
- jedec = jedec << 8;
- jedec |= id[1];
- jedec = jedec << 8;
- jedec |= id[2];
-
for (info = dataflash_data;
info < dataflash_data + ARRAY_SIZE(dataflash_data);
info++) {
+ if (use_extid && !(info->flags & SUP_EXTID))
+ continue;
+
if (info->jedec_id == jedec) {
dev_dbg(&spi->dev, "OTP, sector protect%s\n",
(info->flags & SUP_POW2PS) ?
@@ -771,12 +751,59 @@ static struct flash_info * jedec_probe(struct spi_device *spi)
}
}
+ return ERR_PTR(-ENODEV);
+}
+
+static struct flash_info * jedec_probe(struct spi_device *spi)
+{
+ int ret;
+ u8 code = OP_READ_ID;
+ u64 jedec;
+ u8 id[sizeof(jedec)] = {0};
+ const unsigned int id_size = 5;
+ struct flash_info *info;
+
+ /*
+ * 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.
+ *
+ * If the vendor ID isn't Atmel's (0x1f), assume this call failed.
+ * That's not an error; only rev C and newer chips handle it, and
+ * only Atmel sells these chips.
+ */
+ ret = spi_write_then_read(spi, &code, 1, id, id_size);
+ if (ret < 0) {
+ dev_dbg(&spi->dev, "error %d reading JEDEC ID\n", ret);
+ return ERR_PTR(ret);
+ }
+
+ if (id[0] != CFI_MFR_ATMEL)
+ return NULL;
+
+ jedec = be64_to_cpup((__be64 *)id);
+
+ /*
+ * First, try to match device using extended device
+ * information
+ */
+ info = jedec_lookup(spi, jedec >> DATAFLASH_SHIFT_EXTID, true);
+ if (!IS_ERR(info))
+ return info;
+ /*
+ * If that fails, make another pass using regular ID
+ * information
+ */
+ info = jedec_lookup(spi, jedec >> DATAFLASH_SHIFT_ID, false);
+ if (!IS_ERR(info))
+ return info;
+
/*
* Treat other chips as errors ... we won't know the right page
* size (it might be binary) even when we can tell which density
* class is involved (legacy chip id scheme).
*/
- dev_warn(&spi->dev, "JEDEC id %06x not handled\n", jedec);
+ dev_warn(&spi->dev, "JEDEC id %016llx not handled\n", jedec);
return ERR_PTR(-ENODEV);
}