|
@@ -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)
|