summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/devices/mtd_dataflash.c
diff options
context:
space:
mode:
authorAndrey Smirnov <andrew.smirnov@gmail.com>2017-04-21 09:30:25 -0700
committerBrian Norris <computersforpeace@gmail.com>2017-05-11 10:04:45 -0700
commit1da8869a428317a6d3cd8d47184cf87feb34a98b (patch)
treea153237514fda738c9f2ca0813a0e0c411363db6 /drivers/mtd/devices/mtd_dataflash.c
parenta296a1bc3eb54382d2a61d47529e71c9d3bc615e (diff)
downloadlinux-1da8869a428317a6d3cd8d47184cf87feb34a98b.tar.bz2
mtd: dataflash: Make use of "extened device information"
In anticipation of supporting chips that need it, extend the size of struct flash_info's 'jedec_id' field to make room 2 byte of extended device information as well as add code to fetch this data during jedec_probe(). Cc: cphealy@gmail.com Cc: David Woodhouse <dwmw2@infradead.org> Cc: Brian Norris <computersforpeace@gmail.com> Cc: Boris Brezillon <boris.brezillon@free-electrons.com> Cc: Marek Vasut <marek.vasut@gmail.com> Cc: Richard Weinberger <richard@nod.at> Cc: Cyrille Pitchen <cyrille.pitchen@atmel.com> Cc: linux-kernel@vger.kernel.org Acked-by: Marek Vasut <marek.vasut@gmail.com> Tested-by: Chris Healy <cphealy@gmail.com> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com> Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'drivers/mtd/devices/mtd_dataflash.c')
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c88
1 files changed, 57 insertions, 31 deletions
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index 2d3e4034b591..3f1a0fbe5a58 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -84,6 +84,9 @@
#define CFI_MFR_ATMEL 0x1F
+#define DATAFLASH_SHIFT_EXTID 24
+#define DATAFLASH_SHIFT_ID 40
+
struct dataflash {
u8 command[4];
char name[24];
@@ -687,7 +690,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;
@@ -695,6 +698,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 */
};
@@ -734,42 +738,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) ?
@@ -793,12 +773,58 @@ 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);
}