mtd: m25p80: Rework probing/JEDEC code
[safe/jmp/linux-2.6] / drivers / mtd / devices / m25p80.c
index 47486fb..e689285 100644 (file)
@@ -709,6 +709,14 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi)
        jedec = jedec << 8;
        jedec |= id[2];
 
+       /*
+        * Some chips (like Numonyx M25P80) have JEDEC and non-JEDEC variants,
+        * which depend on technology process. Officially RDID command doesn't
+        * exist for non-JEDEC chips, but for compatibility they return ID 0.
+        */
+       if (jedec == 0)
+               return NULL;
+
        ext_jedec = id[3] << 8 | id[4];
 
        for (tmp = 0; tmp < ARRAY_SIZE(m25p_ids) - 1; tmp++) {
@@ -730,7 +738,7 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi)
  */
 static int __devinit m25p_probe(struct spi_device *spi)
 {
-       const struct spi_device_id      *id;
+       const struct spi_device_id      *id = spi_get_device_id(spi);
        struct flash_platform_data      *data;
        struct m25p                     *flash;
        struct flash_info               *info;
@@ -743,41 +751,44 @@ static int __devinit m25p_probe(struct spi_device *spi)
         */
        data = spi->dev.platform_data;
        if (data && data->type) {
+               const struct spi_device_id *plat_id;
+
                for (i = 0; i < ARRAY_SIZE(m25p_ids) - 1; i++) {
-                       id = &m25p_ids[i];
-                       info = (void *)m25p_ids[i].driver_data;
-                       if (strcmp(data->type, id->name))
+                       plat_id = &m25p_ids[i];
+                       if (strcmp(data->type, plat_id->name))
                                continue;
                        break;
                }
 
-               /* unrecognized chip? */
-               if (i == ARRAY_SIZE(m25p_ids) - 1) {
-                       DEBUG(MTD_DEBUG_LEVEL0, "%s: unrecognized id %s\n",
-                                       dev_name(&spi->dev), data->type);
-                       info = NULL;
-
-               /* recognized; is that chip really what's there? */
-               } else if (info->jedec_id) {
-                       id = jedec_probe(spi);
-
-                       if (id != &m25p_ids[i]) {
-                               dev_warn(&spi->dev, "found %s, expected %s\n",
-                                               id ? id->name : "UNKNOWN",
-                                               m25p_ids[i].name);
-                               info = NULL;
-                       }
-               }
-       } else {
-               id = jedec_probe(spi);
-               if (!id)
-                       id = spi_get_device_id(spi);
-
-               info = (void *)id->driver_data;
+               if (plat_id)
+                       id = plat_id;
+               else
+                       dev_warn(&spi->dev, "unrecognized id %s\n", data->type);
        }
 
-       if (!info)
-               return -ENODEV;
+       info = (void *)id->driver_data;
+
+       if (info->jedec_id) {
+               const struct spi_device_id *jid;
+
+               jid = jedec_probe(spi);
+               if (!jid) {
+                       dev_info(&spi->dev, "non-JEDEC variant of %s\n",
+                                id->name);
+               } else if (jid != id) {
+                       /*
+                        * JEDEC knows better, so overwrite platform ID. We
+                        * can't trust partitions any longer, but we'll let
+                        * mtd apply them anyway, since some partitions may be
+                        * marked read-only, and we don't want to lose that
+                        * information, even if it's not 100% accurate.
+                        */
+                       dev_warn(&spi->dev, "found %s, expected %s\n",
+                                jid->name, id->name);
+                       id = jid;
+                       info = (void *)jid->driver_data;
+               }
+       }
 
        flash = kzalloc(sizeof *flash, GFP_KERNEL);
        if (!flash)