mtd: dataflash: Make use of "extened device information"
authorAndrey Smirnov <andrew.smirnov@gmail.com>
Fri, 21 Apr 2017 16:30:25 +0000 (09:30 -0700)
committerBrian Norris <computersforpeace@gmail.com>
Thu, 11 May 2017 17:04:45 +0000 (10:04 -0700)
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>
drivers/mtd/devices/mtd_dataflash.c

index 2d3e403..3f1a0fb 100644 (file)
@@ -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);
 }