/*
* SMI (Serial Memory Controller) device driver for Serial NOR Flash on
* SPEAr platform
* The serial nor interface is largely based on drivers/mtd/m25p80.c,
* however the SPI interface has been replaced by SMI.
*
* Copyright © 2010 STMicroelectronics.
* Ashish Priyadarshi
* Shiraz Hashim <shiraz.hashim@st.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/param.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/spear_smi.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/wait.h>
#include <linux/of.h>
#include <linux/of_address.h>
/* SMI clock rate */
#define SMI_MAX_CLOCK_FREQ 50000000 /* 50 MHz */
/* MAX time out to safely come out of a erase or write busy conditions */
#define SMI_PROBE_TIMEOUT (HZ / 10)
#define SMI_MAX_TIME_OUT (3 * HZ)
/* timeout for command completion */
#define SMI_CMD_TIMEOUT (HZ / 10)
/* registers of smi */
#define SMI_CR1 0x0 /* SMI control register 1 */
#define SMI_CR2 0x4 /* SMI control register 2 */
#define SMI_SR 0x8 /* SMI status register */
#define SMI_TR 0xC /* SMI transmit register */
#define SMI_RR 0x10 /* SMI receive register */
/* defines for control_reg 1 */
#define BANK_EN (0xF << 0) /* enables all banks */
#define DSEL_TIME (0x6 << 4) /* Deselect time 6 + 1 SMI_CK periods */
#define SW_MODE (0x1 << 28) /* enables SW Mode */
#define WB_MODE (0x1 << 29) /* Write Burst Mode */
#define FAST_MODE (0x1 << 15) /* Fast Mode */
#define HOLD1 (0x1 << 16) /* Clock Hold period selection */
/* defines for control_reg 2 */
#define SEND (0x1 << 7) /* Send data */
#define TFIE (0x1 << 8) /* Transmission Flag Interrupt Enable */
#define WCIE (0x1 << 9) /* Write Complete Interrupt Enable */
#define RD_STATUS_REG (0x1 << 10) /* reads status reg */
#define WE (0x1 << 11) /* Write Enable */
#define TX_LEN_SHIFT 0
#define RX_LEN_SHIFT 4
#define BANK_SHIFT 12
/* defines for status register */
#define SR_WIP 0x1 /* Write in progress */
#define SR_WEL 0x2 /* Write enable latch */
#define SR_BP0 0x4 /* Block protect 0 */
#define SR_BP1 0x8 /* Block protect 1 */
#define SR_BP2 0x10 /* Block protect 2 */
#define SR_SRWD 0x80 /* SR write protect */
#define TFF 0x100 /* Transfer Finished Flag */
#define WCF 0x200 /* Transfer Finished Flag */
#define ERF1 0x400 /* Forbidden Write Request */
#define ERF2 0x800 /* Forbidden Access */
#define WM_SHIFT 12
/* flash opcodes */
#define OPCODE_RDID 0x9f /* Read JEDEC ID */
/* Flash Device Ids maintenance section */
/* data structure to maintain flash ids from different vendors */
struct flash_device {
char *name;
u8 erase_cmd;
u32 device_id;
u32 pagesize;
unsigned long sectorsize;
unsigned long size_in_bytes;
};
#define FLASH_ID(n, es, id, psize, ssize, size) \
{ \
.name = n, \
.erase_cmd = es, \
.device_id = id, \
.pagesize = psize, \
.sectorsize = ssize, \
.size_in_bytes = size \
}
static struct flash_device flash_devices[] = {
FLASH_ID("st m25p16" , 0xd8, 0x00152020, 0x100, 0x10000, 0x200000),
FLASH_ID("st m25p32" , 0xd8, 0x00162020, 0x100, 0x10000, 0x400000),
FLASH_ID("st m25p64" , 0xd8, 0x00172020, 0x100, 0x10000, 0x800000),
FLASH_ID("st m25p128" , 0xd8, 0x00182020, 0x100, 0x40000, 0x1000000),
FLASH_ID("st m25p05" , 0xd8, 0x00102020, 0x80 , 0x8000 , 0x10000),
FLASH_ID("st m25p10" , 0xd8, 0x00112020, 0x80 , 0x8000 , 0x20000),
FLASH_ID("st m25p20" , 0xd8, 0x00122020, 0x100, 0x10000, 0x40000),
FLASH_ID("st m25p40" , 0xd8, 0x00132020, 0x100, 0x10000, 0x80000),
FLASH_ID("st m25p80" , 0xd8, 0x00142020, 0x100, 0x10000, 0x100000),
FLASH_ID("st m45pe10" , 0xd8, 0x00114020, 0x100, 0x10000, 0x20000),
FLASH_ID("st m45pe20" , 0xd8, 0x00124020, 0x100, 0x10000, 0x40000),
FLASH_ID("st m45pe40" , 0xd8, 0x00134020, 0x100, 0x10000, 0x80000),
FLASH_ID("st m45pe80" , 0xd8, 0x00144020, 0x100, 0x10000, 0x100000),
FLASH_ID("sp s25fl004" , 0xd8, 0x00120201, 0x100, 0x10000, 0x80000),
FLASH_ID("sp s25fl008" , 0xd8, 0x00130201, 0x100, 0x10000, 0x100000),
FLASH_ID("sp s25fl016" , 0xd8, 0x00140201, 0x100, 0x10000, 0x200000),
FLASH_ID("sp s25fl032" , 0xd8, 0x00150201, 0x100, 0x10000, 0x400000),
FLASH_ID("sp s25fl064" , 0xd8, 0x00160201, 0x100, 0x10000, 0x800000),
FLASH_ID