diff options
Diffstat (limited to 'drivers/mtd/devices')
-rw-r--r-- | drivers/mtd/devices/docg3.c | 20 | ||||
-rw-r--r-- | drivers/mtd/devices/m25p80.c | 226 | ||||
-rw-r--r-- | drivers/mtd/devices/ms02-nv.c | 2 | ||||
-rw-r--r-- | drivers/mtd/devices/mtd_dataflash.c | 5 | ||||
-rw-r--r-- | drivers/mtd/devices/mtdram.c | 2 |
5 files changed, 218 insertions, 37 deletions
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 4f091c1a9981..dd5e1018d37b 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -2047,21 +2047,21 @@ static int __init docg3_probe(struct platform_device *pdev) ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!ress) { dev_err(dev, "No I/O memory resource defined\n"); - goto noress; + return ret; } - base = ioremap(ress->start, DOC_IOSPACE_SIZE); + base = devm_ioremap(dev, ress->start, DOC_IOSPACE_SIZE); ret = -ENOMEM; - cascade = kzalloc(sizeof(*cascade) * DOC_MAX_NBFLOORS, - GFP_KERNEL); + cascade = devm_kzalloc(dev, sizeof(*cascade) * DOC_MAX_NBFLOORS, + GFP_KERNEL); if (!cascade) - goto nomem1; + return ret; cascade->base = base; mutex_init(&cascade->lock); cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T, DOC_ECC_BCH_PRIMPOLY); if (!cascade->bch) - goto nomem2; + return ret; for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) { mtd = doc_probe_device(cascade, floor, dev); @@ -2101,11 +2101,6 @@ err_probe: for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) if (cascade->floors[floor]) doc_release_device(cascade->floors[floor]); -nomem2: - kfree(cascade); -nomem1: - iounmap(base); -noress: return ret; } @@ -2119,7 +2114,6 @@ static int __exit docg3_release(struct platform_device *pdev) { struct docg3_cascade *cascade = platform_get_drvdata(pdev); struct docg3 *docg3 = cascade->floors[0]->priv; - void __iomem *base = cascade->base; int floor; doc_unregister_sysfs(pdev, cascade); @@ -2129,8 +2123,6 @@ static int __exit docg3_release(struct platform_device *pdev) doc_release_device(cascade->floors[floor]); free_bch(docg3->cascade->bch); - kfree(cascade); - iounmap(base); return 0; } diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 7eda71dbc183..ad1913909702 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -41,6 +41,7 @@ #define OPCODE_WRSR 0x01 /* Write status register 1 byte */ #define OPCODE_NORM_READ 0x03 /* Read data bytes (low frequency) */ #define OPCODE_FAST_READ 0x0b /* Read data bytes (high frequency) */ +#define OPCODE_QUAD_READ 0x6b /* Read data bytes */ #define OPCODE_PP 0x02 /* Page program (up to 256 bytes) */ #define OPCODE_BE_4K 0x20 /* Erase 4KiB block */ #define OPCODE_BE_4K_PMC 0xd7 /* Erase 4KiB block on PMC chips */ @@ -48,10 +49,12 @@ #define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */ #define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ #define OPCODE_RDID 0x9f /* Read JEDEC ID */ +#define OPCODE_RDCR 0x35 /* Read configuration register */ /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */ #define OPCODE_NORM_READ_4B 0x13 /* Read data bytes (low frequency) */ #define OPCODE_FAST_READ_4B 0x0c /* Read data bytes (high frequency) */ +#define OPCODE_QUAD_READ_4B 0x6c /* Read data bytes */ #define OPCODE_PP_4B 0x12 /* Page program (up to 256 bytes) */ #define OPCODE_SE_4B 0xdc /* Sector erase (usually 64KiB) */ @@ -76,6 +79,11 @@ #define SR_BP2 0x10 /* Block protect 2 */ #define SR_SRWD 0x80 /* SR write protect */ +#define SR_QUAD_EN_MX 0x40 /* Macronix Quad I/O */ + +/* Configuration Register bits. */ +#define CR_QUAD_EN_SPAN 0x2 /* Spansion Quad I/O */ + /* Define max times to check status register before we give up. */ #define MAX_READY_WAIT_JIFFIES (40 * HZ) /* M25P16 specs 40s max chip erase */ #define MAX_CMD_SIZE 6 @@ -84,6 +92,12 @@ /****************************************************************************/ +enum read_type { + M25P80_NORMAL = 0, + M25P80_FAST, + M25P80_QUAD, +}; + struct m25p { struct spi_device *spi; struct mutex lock; @@ -94,7 +108,7 @@ struct m25p { u8 read_opcode; u8 program_opcode; u8 *command; - bool fast_read; + enum read_type flash_read; }; static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd) @@ -131,6 +145,26 @@ static int read_sr(struct m25p *flash) } /* + * Read configuration register, returning its value in the + * location. Return the configuration register value. + * Returns negative if error occured. + */ +static int read_cr(struct m25p *flash) +{ + u8 code = OPCODE_RDCR; + int ret; + u8 val; + + ret = spi_write_then_read(flash->spi, &code, 1, &val, 1); + if (ret < 0) { + dev_err(&flash->spi->dev, "error %d reading CR\n", ret); + return ret; + } + + return val; +} + +/* * Write status register 1 byte * Returns negative if error occurred. */ @@ -220,6 +254,93 @@ static int wait_till_ready(struct m25p *flash) } /* + * Write status Register and configuration register with 2 bytes + * The first byte will be written to the status register, while the + * second byte will be written to the configuration register. + * Return negative if error occured. + */ +static int write_sr_cr(struct m25p *flash, u16 val) +{ + flash->command[0] = OPCODE_WRSR; + flash->command[1] = val & 0xff; + flash->command[2] = (val >> 8); + + return spi_write(flash->spi, flash->command, 3); +} + +static int macronix_quad_enable(struct m25p *flash) +{ + int ret, val; + u8 cmd[2]; + cmd[0] = OPCODE_WRSR; + + val = read_sr(flash); + cmd[1] = val | SR_QUAD_EN_MX; + write_enable(flash); + + spi_write(flash->spi, &cmd, 2); + + if (wait_till_ready(flash)) + return 1; + + ret = read_sr(flash); + if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) { + dev_err(&flash->spi->dev, "Macronix Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + +static int spansion_quad_enable(struct m25p *flash) +{ + int ret; + int quad_en = CR_QUAD_EN_SPAN << 8; + + write_enable(flash); + + ret = write_sr_cr(flash, quad_en); + if (ret < 0) { + dev_err(&flash->spi->dev, + "error while writing configuration register\n"); + return -EINVAL; + } + + /* read back and check it */ + ret = read_cr(flash); + if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) { + dev_err(&flash->spi->dev, "Spansion Quad bit not set\n"); + return -EINVAL; + } + + return 0; +} + +static int set_quad_mode(struct m25p *flash, u32 jedec_id) +{ + int status; + + switch (JEDEC_MFR(jedec_id)) { + case CFI_MFR_MACRONIX: + status = macronix_quad_enable(flash); + if (status) { + dev_err(&flash->spi->dev, + "Macronix quad-read not enabled\n"); + return -EINVAL; + } + return status; + default: + status = spansion_quad_enable(flash); + if (status) { + dev_err(&flash->spi->dev, + "Spansion quad-read not enabled\n"); + return -EINVAL; + } + return status; + } +} + +/* * Erase the whole flash memory * * Returns 0 if successful, non-zero otherwise. @@ -350,6 +471,35 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) } /* + * Dummy Cycle calculation for different type of read. + * It can be used to support more commands with + * different dummy cycle requirements. + */ +static inline int m25p80_dummy_cycles_read(struct m25p *flash) +{ + switch (flash->flash_read) { + case M25P80_FAST: + case M25P80_QUAD: + return 1; + case M25P80_NORMAL: + return 0; + default: + dev_err(&flash->spi->dev, "No valid read type supported\n"); + return -1; + } +} + +static inline unsigned int m25p80_rx_nbits(const struct m25p *flash) +{ + switch (flash->flash_read) { + case M25P80_QUAD: + return 4; + default: + return 0; + } +} + +/* * Read an address range from the flash chip. The address range * may be any size provided it is within the physical boundaries. */ @@ -360,6 +510,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, struct spi_transfer t[2]; struct spi_message m; uint8_t opcode; + int dummy; pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev), __func__, (u32)from, len); @@ -367,11 +518,18 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, spi_message_init(&m); memset(t, 0, (sizeof t)); + dummy = m25p80_dummy_cycles_read(flash); + if (dummy < 0) { + dev_err(&flash->spi->dev, "No valid read command supported\n"); + return -EINVAL; + } + t[0].tx_buf = flash->command; - t[0].len = m25p_cmdsz(flash) + (flash->fast_read ? 1 : 0); + t[0].len = m25p_cmdsz(flash) + dummy; spi_message_add_tail(&t[0], &m); t[1].rx_buf = buf; + t[1].rx_nbits = m25p80_rx_nbits(flash); t[1].len = len; spi_message_add_tail(&t[1], &m); @@ -391,8 +549,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, spi_sync(flash->spi, &m); - *retlen = m.actual_length - m25p_cmdsz(flash) - - (flash->fast_read ? 1 : 0); + *retlen = m.actual_length - m25p_cmdsz(flash) - dummy; mutex_unlock(&flash->lock); @@ -698,6 +855,7 @@ struct flash_info { #define SST_WRITE 0x04 /* use SST byte programming */ #define M25P_NO_FR 0x08 /* Can't do fastread */ #define SECT_4K_PMC 0x10 /* OPCODE_BE_4K_PMC works uniformly */ +#define M25P80_QUAD_READ 0x20 /* Flash supports Quad Read */ }; #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ @@ -775,7 +933,7 @@ static const struct spi_device_id m25p_ids[] = { { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, - { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, 0) }, + { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, M25P80_QUAD_READ) }, /* Micron */ { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) }, @@ -795,8 +953,8 @@ static const struct spi_device_id m25p_ids[] = { { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, 0) }, { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, 0) }, { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, - { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, 0) }, - { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, 0) }, + { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, M25P80_QUAD_READ) }, + { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, M25P80_QUAD_READ) }, { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, @@ -851,6 +1009,7 @@ static const struct spi_device_id m25p_ids[] = { { "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) }, { "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) }, + { "m25px16", INFO(0x207115, 0, 64 * 1024, 32, SECT_4K) }, { "m25px32", INFO(0x207116, 0, 64 * 1024, 64, SECT_4K) }, { "m25px32-s0", INFO(0x207316, 0, 64 * 1024, 64, SECT_4K) }, { "m25px32-s1", INFO(0x206316, 0, 64 * 1024, 64, SECT_4K) }, @@ -937,6 +1096,7 @@ static int m25p_probe(struct spi_device *spi) unsigned i; struct mtd_part_parser_data ppdata; struct device_node *np = spi->dev.of_node; + int ret; /* Platform data helps sort out which chip type we have, as * well as how this board partitions it. If we don't have @@ -1051,22 +1211,46 @@ static int m25p_probe(struct spi_device *spi) flash->page_size = info->page_size; flash->mtd.writebufsize = flash->page_size; - if (np) + if (np) { /* If we were instantiated by DT, use it */ - flash->fast_read = of_property_read_bool(np, "m25p,fast-read"); - else + if (of_property_read_bool(np, "m25p,fast-read")) + flash->flash_read = M25P80_FAST; + else + flash->flash_read = M25P80_NORMAL; + } else { /* If we weren't instantiated by DT, default to fast-read */ - flash->fast_read = true; + flash->flash_read = M25P80_FAST; + } /* Some devices cannot do fast-read, no matter what DT tells us */ if (info->flags & M25P_NO_FR) - flash->fast_read = false; + flash->flash_read = M25P80_NORMAL; + + /* Quad-read mode takes precedence over fast/normal */ + if (spi->mode & SPI_RX_QUAD && info->flags & M25P80_QUAD_READ) { + ret = set_quad_mode(flash, info->jedec_id); + if (ret) { + dev_err(&flash->spi->dev, "quad mode not supported\n"); + return ret; + } + flash->flash_read = M25P80_QUAD; + } /* Default commands */ - if (flash->fast_read) + switch (flash->flash_read) { + case M25P80_QUAD: + flash->read_opcode = OPCODE_QUAD_READ; + break; + case M25P80_FAST: flash->read_opcode = OPCODE_FAST_READ; - else + break; + case M25P80_NORMAL: flash->read_opcode = OPCODE_NORM_READ; + break; + default: + dev_err(&flash->spi->dev, "No Read opcode defined\n"); + return -EINVAL; + } flash->program_opcode = OPCODE_PP; @@ -1077,9 +1261,17 @@ static int m25p_probe(struct spi_device *spi) flash->addr_width = 4; if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) { /* Dedicated 4-byte command set */ - flash->read_opcode = flash->fast_read ? - OPCODE_FAST_READ_4B : - OPCODE_NORM_READ_4B; + switch (flash->flash_read) { + case M25P80_QUAD: + flash->read_opcode = OPCODE_QUAD_READ_4B; + break; + case M25P80_FAST: + flash->read_opcode = OPCODE_FAST_READ_4B; + break; + case M25P80_NORMAL: + flash->read_opcode = OPCODE_NORM_READ_4B; + break; + } flash->program_opcode = OPCODE_PP_4B; /* No small sector erase for 4-byte command set */ flash->erase_opcode = OPCODE_SE_4B; diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c index 182849d39c61..5c8b322ba904 100644 --- a/drivers/mtd/devices/ms02-nv.c +++ b/drivers/mtd/devices/ms02-nv.c @@ -205,7 +205,7 @@ static int __init ms02nv_init_one(ulong addr) mtd->type = MTD_RAM; mtd->flags = MTD_CAP_RAM; mtd->size = fixsize; - mtd->name = (char *)ms02nv_name; + mtd->name = ms02nv_name; mtd->owner = THIS_MODULE; mtd->_read = ms02nv_read; mtd->_write = ms02nv_write; diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 4a47b0266d4e..624069de4f28 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -669,7 +669,6 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages, if (!err) return 0; - spi_set_drvdata(spi, NULL); kfree(priv); return err; } @@ -899,10 +898,8 @@ static int dataflash_remove(struct spi_device *spi) pr_debug("%s: remove\n", dev_name(&spi->dev)); status = mtd_device_unregister(&flash->mtd); - if (status == 0) { - spi_set_drvdata(spi, NULL); + if (status == 0) kfree(flash); - } return status; } diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c index ec59d65897fb..8e285089229c 100644 --- a/drivers/mtd/devices/mtdram.c +++ b/drivers/mtd/devices/mtdram.c @@ -92,7 +92,7 @@ static void __exit cleanup_mtdram(void) } int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, - unsigned long size, char *name) + unsigned long size, const char *name) { memset(mtd, 0, sizeof(*mtd)); |