static int sst25l_erase(struct mtd_info *mtd, struct erase_info *instr) { struct sst25l_flash *flash = to_sst25l_flash(mtd); uint32_t addr, end; int err; if (instr->addr + instr->len > flash->mtd.size) return -EINVAL; if ((uint32_t)instr->len % mtd->erasesize) return -EINVAL; if ((uint32_t)instr->addr % mtd->erasesize) return -EINVAL; addr = instr->addr; end = addr + instr->len; mutex_lock(&flash->lock); err = sst25l_wait_till_ready(flash); if (err) { mutex_unlock(&flash->lock); return err; } while (addr < end) { err = sst25l_erase_sector(flash, addr); if (err) { mutex_unlock(&flash->lock); instr->state = MTD_ERASE_FAILED; dev_err(&flash->spi->dev, "Erase failed\n"); return err; } addr += mtd->erasesize; } mutex_unlock(&flash->lock); instr->state = MTD_ERASE_DONE; mtd_erase_callback(instr); return 0; }
static int sst25l_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, unsigned char *buf) { struct sst25l_flash *flash = to_sst25l_flash(mtd); struct spi_transfer transfer[2]; struct spi_message message; unsigned char command[4]; int ret; spi_message_init(&message); memset(&transfer, 0, sizeof(transfer)); command[0] = SST25L_CMD_READ; command[1] = from >> 16; command[2] = from >> 8; command[3] = from; transfer[0].tx_buf = command; transfer[0].len = sizeof(command); spi_message_add_tail(&transfer[0], &message); transfer[1].rx_buf = buf; transfer[1].len = len; spi_message_add_tail(&transfer[1], &message); mutex_lock(&flash->lock); /* Wait for previous write/erase to complete */ ret = sst25l_wait_till_ready(flash); if (ret) { mutex_unlock(&flash->lock); return ret; } spi_sync(flash->spi, &message); if (retlen && message.actual_length > sizeof(command)) *retlen += message.actual_length - sizeof(command); mutex_unlock(&flash->lock); return 0; }
static int sst25l_erase_sector(struct sst25l_flash *flash, uint32_t offset) { unsigned char command[4]; int err; err = sst25l_write_enable(flash, 1); if (err) return err; command[0] = SST25L_CMD_SECTOR_ERASE; command[1] = offset >> 16; command[2] = offset >> 8; command[3] = offset; err = spi_write(flash->spi, command, 4); if (err) return err; err = sst25l_wait_till_ready(flash); if (err) return err; return sst25l_write_enable(flash, 0); }
static int sst25l_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const unsigned char *buf) { struct sst25l_flash *flash = to_sst25l_flash(mtd); int i, j, ret, bytes, copied = 0; unsigned char command[5]; /* Sanity checks */ if (!len) return 0; if (to + len > flash->mtd.size) return -EINVAL; if ((uint32_t)to % mtd->writesize) return -EINVAL; mutex_lock(&flash->lock); ret = sst25l_write_enable(flash, 1); if (ret) goto out; for (i = 0; i < len; i += mtd->writesize) { ret = sst25l_wait_till_ready(flash); if (ret) goto out; /* Write the first byte of the page */ command[0] = SST25L_CMD_AAI_PROGRAM; command[1] = (to + i) >> 16; command[2] = (to + i) >> 8; command[3] = (to + i); command[4] = buf[i]; ret = spi_write(flash->spi, command, 5); if (ret < 0) goto out; copied++; /* * Write the remaining bytes using auto address * increment mode */ bytes = min_t(uint32_t, mtd->writesize, len - i); for (j = 1; j < bytes; j++, copied++) { ret = sst25l_wait_till_ready(flash); if (ret) goto out; command[1] = buf[i + j]; ret = spi_write(flash->spi, command, 2); if (ret) goto out; } } out: ret = sst25l_write_enable(flash, 0); if (retlen) *retlen = copied; mutex_unlock(&flash->lock); return ret; }