/*
* MTD SPI driver for ST M25Pxx (and similar) serial flash chips
*
* Author: Mike Lavender, mike@steroidmicros.com
*
* Copyright (c) 2005, Intec Automation Inc.
*
* Some parts are based on lart.c by Abraham Van Der Merwe
*
* Cleaned up and generalized based on mtd_dataflash.c
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/init.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/math64.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/mod_devicetable.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
/* Flash opcodes. */
#define OPCODE_WREN 0x06 /* Write enable */
#define OPCODE_RDSR 0x05 /* Read status register */
#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_PP 0x02 /* Page program (up to 256 bytes) */
#define OPCODE_BE_4K 0x20 /* Erase 4KiB block */
#define OPCODE_BE_32K 0x52 /* Erase 32KiB block */
#define OPCODE_CHIP_ERASE 0xc7 /* Erase whole flash chip */
#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */
#define OPCODE_RDID 0x9f /* Read JEDEC ID */
/* Used for SST flashes only. */
#define OPCODE_BP 0x02 /* Byte program */
#define OPCODE_WRDI 0x04 /* Write disable */
#define OPCODE_AAI_WP 0xad /* Auto address increment word program */
/* Used for Macronix flashes only. */
#define OPCODE_EN4B 0xb7 /* Enter 4-byte mode */
#define OPCODE_EX4B 0xe9 /* Exit 4-byte mode */
/* Status Register bits. */
#define SR_WIP 1 /* Write in progress */
#define SR_WEL 2 /* Write enable latch */
/* meaning of other SR_* bits may differ between vendors */
#define SR_BP0 4 /* Block protect 0 */
#define SR_BP1 8 /* Block protect 1 */
#define SR_BP2 0x10 /* Block protect 2 */
#define SR_SRWD 0x80 /* SR write protect */
/* 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 5
#ifdef CONFIG_M25PXX_USE_FAST_READ
#define OPCODE_READ OPCODE_FAST_READ
#define FAST_READ_DUMMY_BYTE 1
#else
#define OPCODE_READ OPCODE_NORM_READ
#define FAST_READ_DUMMY_BYTE 0
#endif
/****************************************************************************/
struct m25p {
struct spi_device *spi;
struct mutex lock;
struct mtd_info mtd;
unsigned partitioned:1;
u16 page_size;
u16 addr_width;
u8 erase_opcode;
u8 *command;
};
static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
{
return container_of(mtd, struct m25p, mtd);
}
/****************************************************************************/
/*
* Internal helper functions
*/
/*
* Read the status register, returning its value in the location
* Return the status register value.
* Returns negative if error occurred.
*/
static int read_sr(struct m25p *flash)
{
ssize_t retval;
u8 code = OPCODE_RDSR;
u8 val;
retval = spi_write_then_read(flash->spi, &code, 1, &val, 1);
if (retval < 0) {
dev_err(&flash->spi->dev, "error %d reading SR\n",
(int) retval);
return retval;
}
return val;
}
/*
* Write status register 1 byte
* Returns negative if error occurred.
*/
static int write_sr(struct m25p *flash, u8 val)
{
flash->command[0] = OPCODE_WRSR;
flash->command[1] = val;
return spi_write(flash->spi, flash->command, 2);
}
/*
* Set write enable latch with Write Enable command.
* Returns negative if error occurred.
*/
static inline int write_enable(struct m25p *flash)
{
u8 code = OPCODE_WREN;
return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
}
/*
* Send write disble instruction to the chip.
*/
static inline int write_disable(struct m25p *flash)
{
u8 code = OPCODE_WRDI;
return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
}
/*
* Enable/disable 4-byte addressing mode.
*/
static inline int set_4byte(struct m25p *flash, int enable)
{
u8 code = enable ? OPCODE_EN4B : OPCODE_EX4B;
return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
}
/*
* Service routine to read status register until ready, or timeout occurs.
* Returns non-zero if error.
*/
static int wait_till_ready(struct m25p *flash)
{
unsigned long deadline;
int sr;
deadline = jiffies + MAX_READY_WAIT_JIFFIES;
do {
if ((sr = read_sr(flash)) < 0)
break;
else if (!(sr & SR_WIP))
return 0;
cond_resched();
} while (!time_after_eq(jiffies, deadline));
return 1;
}
/*
* Erase the whole flash memory
*
* Returns 0 if successful, non-zero otherwise.
*/
static int erase_chip(struct m25p *flash)
{
DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %lldKiB\n",
dev_name(&flash->spi->dev),<