xref: /OK3568_Linux_fs/kernel/drivers/mtd/devices/spear_smi.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * SMI (Serial Memory Controller) device driver for Serial NOR Flash on
3*4882a593Smuzhiyun  * SPEAr platform
4*4882a593Smuzhiyun  * The serial nor interface is largely based on m25p80.c, however the SPI
5*4882a593Smuzhiyun  * interface has been replaced by SMI.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Copyright © 2010 STMicroelectronics.
8*4882a593Smuzhiyun  * Ashish Priyadarshi
9*4882a593Smuzhiyun  * Shiraz Hashim <shiraz.linux.kernel@gmail.com>
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * This file is licensed under the terms of the GNU General Public
12*4882a593Smuzhiyun  * License version 2. This program is licensed "as is" without any
13*4882a593Smuzhiyun  * warranty of any kind, whether express or implied.
14*4882a593Smuzhiyun  */
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <linux/clk.h>
17*4882a593Smuzhiyun #include <linux/delay.h>
18*4882a593Smuzhiyun #include <linux/device.h>
19*4882a593Smuzhiyun #include <linux/err.h>
20*4882a593Smuzhiyun #include <linux/errno.h>
21*4882a593Smuzhiyun #include <linux/interrupt.h>
22*4882a593Smuzhiyun #include <linux/io.h>
23*4882a593Smuzhiyun #include <linux/ioport.h>
24*4882a593Smuzhiyun #include <linux/jiffies.h>
25*4882a593Smuzhiyun #include <linux/kernel.h>
26*4882a593Smuzhiyun #include <linux/module.h>
27*4882a593Smuzhiyun #include <linux/param.h>
28*4882a593Smuzhiyun #include <linux/platform_device.h>
29*4882a593Smuzhiyun #include <linux/pm.h>
30*4882a593Smuzhiyun #include <linux/mtd/mtd.h>
31*4882a593Smuzhiyun #include <linux/mtd/partitions.h>
32*4882a593Smuzhiyun #include <linux/mtd/spear_smi.h>
33*4882a593Smuzhiyun #include <linux/mutex.h>
34*4882a593Smuzhiyun #include <linux/sched.h>
35*4882a593Smuzhiyun #include <linux/slab.h>
36*4882a593Smuzhiyun #include <linux/wait.h>
37*4882a593Smuzhiyun #include <linux/of.h>
38*4882a593Smuzhiyun #include <linux/of_address.h>
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /* SMI clock rate */
41*4882a593Smuzhiyun #define SMI_MAX_CLOCK_FREQ	50000000 /* 50 MHz */
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun /* MAX time out to safely come out of a erase or write busy conditions */
44*4882a593Smuzhiyun #define SMI_PROBE_TIMEOUT	(HZ / 10)
45*4882a593Smuzhiyun #define SMI_MAX_TIME_OUT	(3 * HZ)
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun /* timeout for command completion */
48*4882a593Smuzhiyun #define SMI_CMD_TIMEOUT		(HZ / 10)
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun /* registers of smi */
51*4882a593Smuzhiyun #define SMI_CR1		0x0	/* SMI control register 1 */
52*4882a593Smuzhiyun #define SMI_CR2		0x4	/* SMI control register 2 */
53*4882a593Smuzhiyun #define SMI_SR		0x8	/* SMI status register */
54*4882a593Smuzhiyun #define SMI_TR		0xC	/* SMI transmit register */
55*4882a593Smuzhiyun #define SMI_RR		0x10	/* SMI receive register */
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun /* defines for control_reg 1 */
58*4882a593Smuzhiyun #define BANK_EN		(0xF << 0)	/* enables all banks */
59*4882a593Smuzhiyun #define DSEL_TIME	(0x6 << 4)	/* Deselect time 6 + 1 SMI_CK periods */
60*4882a593Smuzhiyun #define SW_MODE		(0x1 << 28)	/* enables SW Mode */
61*4882a593Smuzhiyun #define WB_MODE		(0x1 << 29)	/* Write Burst Mode */
62*4882a593Smuzhiyun #define FAST_MODE	(0x1 << 15)	/* Fast Mode */
63*4882a593Smuzhiyun #define HOLD1		(0x1 << 16)	/* Clock Hold period selection */
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /* defines for control_reg 2 */
66*4882a593Smuzhiyun #define SEND		(0x1 << 7)	/* Send data */
67*4882a593Smuzhiyun #define TFIE		(0x1 << 8)	/* Transmission Flag Interrupt Enable */
68*4882a593Smuzhiyun #define WCIE		(0x1 << 9)	/* Write Complete Interrupt Enable */
69*4882a593Smuzhiyun #define RD_STATUS_REG	(0x1 << 10)	/* reads status reg */
70*4882a593Smuzhiyun #define WE		(0x1 << 11)	/* Write Enable */
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun #define TX_LEN_SHIFT	0
73*4882a593Smuzhiyun #define RX_LEN_SHIFT	4
74*4882a593Smuzhiyun #define BANK_SHIFT	12
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun /* defines for status register */
77*4882a593Smuzhiyun #define SR_WIP		0x1	/* Write in progress */
78*4882a593Smuzhiyun #define SR_WEL		0x2	/* Write enable latch */
79*4882a593Smuzhiyun #define SR_BP0		0x4	/* Block protect 0 */
80*4882a593Smuzhiyun #define SR_BP1		0x8	/* Block protect 1 */
81*4882a593Smuzhiyun #define SR_BP2		0x10	/* Block protect 2 */
82*4882a593Smuzhiyun #define SR_SRWD		0x80	/* SR write protect */
83*4882a593Smuzhiyun #define TFF		0x100	/* Transfer Finished Flag */
84*4882a593Smuzhiyun #define WCF		0x200	/* Transfer Finished Flag */
85*4882a593Smuzhiyun #define ERF1		0x400	/* Forbidden Write Request */
86*4882a593Smuzhiyun #define ERF2		0x800	/* Forbidden Access */
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun #define WM_SHIFT	12
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun /* flash opcodes */
91*4882a593Smuzhiyun #define OPCODE_RDID	0x9f	/* Read JEDEC ID */
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun /* Flash Device Ids maintenance section */
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun /* data structure to maintain flash ids from different vendors */
96*4882a593Smuzhiyun struct flash_device {
97*4882a593Smuzhiyun 	char *name;
98*4882a593Smuzhiyun 	u8 erase_cmd;
99*4882a593Smuzhiyun 	u32 device_id;
100*4882a593Smuzhiyun 	u32 pagesize;
101*4882a593Smuzhiyun 	unsigned long sectorsize;
102*4882a593Smuzhiyun 	unsigned long size_in_bytes;
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun #define FLASH_ID(n, es, id, psize, ssize, size)	\
106*4882a593Smuzhiyun {				\
107*4882a593Smuzhiyun 	.name = n,		\
108*4882a593Smuzhiyun 	.erase_cmd = es,	\
109*4882a593Smuzhiyun 	.device_id = id,	\
110*4882a593Smuzhiyun 	.pagesize = psize,	\
111*4882a593Smuzhiyun 	.sectorsize = ssize,	\
112*4882a593Smuzhiyun 	.size_in_bytes = size	\
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun static struct flash_device flash_devices[] = {
116*4882a593Smuzhiyun 	FLASH_ID("st m25p16"     , 0xd8, 0x00152020, 0x100, 0x10000, 0x200000),
117*4882a593Smuzhiyun 	FLASH_ID("st m25p32"     , 0xd8, 0x00162020, 0x100, 0x10000, 0x400000),
118*4882a593Smuzhiyun 	FLASH_ID("st m25p64"     , 0xd8, 0x00172020, 0x100, 0x10000, 0x800000),
119*4882a593Smuzhiyun 	FLASH_ID("st m25p128"    , 0xd8, 0x00182020, 0x100, 0x40000, 0x1000000),
120*4882a593Smuzhiyun 	FLASH_ID("st m25p05"     , 0xd8, 0x00102020, 0x80 , 0x8000 , 0x10000),
121*4882a593Smuzhiyun 	FLASH_ID("st m25p10"     , 0xd8, 0x00112020, 0x80 , 0x8000 , 0x20000),
122*4882a593Smuzhiyun 	FLASH_ID("st m25p20"     , 0xd8, 0x00122020, 0x100, 0x10000, 0x40000),
123*4882a593Smuzhiyun 	FLASH_ID("st m25p40"     , 0xd8, 0x00132020, 0x100, 0x10000, 0x80000),
124*4882a593Smuzhiyun 	FLASH_ID("st m25p80"     , 0xd8, 0x00142020, 0x100, 0x10000, 0x100000),
125*4882a593Smuzhiyun 	FLASH_ID("st m45pe10"    , 0xd8, 0x00114020, 0x100, 0x10000, 0x20000),
126*4882a593Smuzhiyun 	FLASH_ID("st m45pe20"    , 0xd8, 0x00124020, 0x100, 0x10000, 0x40000),
127*4882a593Smuzhiyun 	FLASH_ID("st m45pe40"    , 0xd8, 0x00134020, 0x100, 0x10000, 0x80000),
128*4882a593Smuzhiyun 	FLASH_ID("st m45pe80"    , 0xd8, 0x00144020, 0x100, 0x10000, 0x100000),
129*4882a593Smuzhiyun 	FLASH_ID("sp s25fl004"   , 0xd8, 0x00120201, 0x100, 0x10000, 0x80000),
130*4882a593Smuzhiyun 	FLASH_ID("sp s25fl008"   , 0xd8, 0x00130201, 0x100, 0x10000, 0x100000),
131*4882a593Smuzhiyun 	FLASH_ID("sp s25fl016"   , 0xd8, 0x00140201, 0x100, 0x10000, 0x200000),
132*4882a593Smuzhiyun 	FLASH_ID("sp s25fl032"   , 0xd8, 0x00150201, 0x100, 0x10000, 0x400000),
133*4882a593Smuzhiyun 	FLASH_ID("sp s25fl064"   , 0xd8, 0x00160201, 0x100, 0x10000, 0x800000),
134*4882a593Smuzhiyun 	FLASH_ID("atmel 25f512"  , 0x52, 0x0065001F, 0x80 , 0x8000 , 0x10000),
135*4882a593Smuzhiyun 	FLASH_ID("atmel 25f1024" , 0x52, 0x0060001F, 0x100, 0x8000 , 0x20000),
136*4882a593Smuzhiyun 	FLASH_ID("atmel 25f2048" , 0x52, 0x0063001F, 0x100, 0x10000, 0x40000),
137*4882a593Smuzhiyun 	FLASH_ID("atmel 25f4096" , 0x52, 0x0064001F, 0x100, 0x10000, 0x80000),
138*4882a593Smuzhiyun 	FLASH_ID("atmel 25fs040" , 0xd7, 0x0004661F, 0x100, 0x10000, 0x80000),
139*4882a593Smuzhiyun 	FLASH_ID("mac 25l512"    , 0xd8, 0x001020C2, 0x010, 0x10000, 0x10000),
140*4882a593Smuzhiyun 	FLASH_ID("mac 25l1005"   , 0xd8, 0x001120C2, 0x010, 0x10000, 0x20000),
141*4882a593Smuzhiyun 	FLASH_ID("mac 25l2005"   , 0xd8, 0x001220C2, 0x010, 0x10000, 0x40000),
142*4882a593Smuzhiyun 	FLASH_ID("mac 25l4005"   , 0xd8, 0x001320C2, 0x010, 0x10000, 0x80000),
143*4882a593Smuzhiyun 	FLASH_ID("mac 25l4005a"  , 0xd8, 0x001320C2, 0x010, 0x10000, 0x80000),
144*4882a593Smuzhiyun 	FLASH_ID("mac 25l8005"   , 0xd8, 0x001420C2, 0x010, 0x10000, 0x100000),
145*4882a593Smuzhiyun 	FLASH_ID("mac 25l1605"   , 0xd8, 0x001520C2, 0x100, 0x10000, 0x200000),
146*4882a593Smuzhiyun 	FLASH_ID("mac 25l1605a"  , 0xd8, 0x001520C2, 0x010, 0x10000, 0x200000),
147*4882a593Smuzhiyun 	FLASH_ID("mac 25l3205"   , 0xd8, 0x001620C2, 0x100, 0x10000, 0x400000),
148*4882a593Smuzhiyun 	FLASH_ID("mac 25l3205a"  , 0xd8, 0x001620C2, 0x100, 0x10000, 0x400000),
149*4882a593Smuzhiyun 	FLASH_ID("mac 25l6405"   , 0xd8, 0x001720C2, 0x100, 0x10000, 0x800000),
150*4882a593Smuzhiyun };
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun /* Define spear specific structures */
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun struct spear_snor_flash;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun /**
157*4882a593Smuzhiyun  * struct spear_smi - Structure for SMI Device
158*4882a593Smuzhiyun  *
159*4882a593Smuzhiyun  * @clk: functional clock
160*4882a593Smuzhiyun  * @status: current status register of SMI.
161*4882a593Smuzhiyun  * @clk_rate: functional clock rate of SMI (default: SMI_MAX_CLOCK_FREQ)
162*4882a593Smuzhiyun  * @lock: lock to prevent parallel access of SMI.
163*4882a593Smuzhiyun  * @io_base: base address for registers of SMI.
164*4882a593Smuzhiyun  * @pdev: platform device
165*4882a593Smuzhiyun  * @cmd_complete: queue to wait for command completion of NOR-flash.
166*4882a593Smuzhiyun  * @num_flashes: number of flashes actually present on board.
167*4882a593Smuzhiyun  * @flash: separate structure for each Serial NOR-flash attached to SMI.
168*4882a593Smuzhiyun  */
169*4882a593Smuzhiyun struct spear_smi {
170*4882a593Smuzhiyun 	struct clk *clk;
171*4882a593Smuzhiyun 	u32 status;
172*4882a593Smuzhiyun 	unsigned long clk_rate;
173*4882a593Smuzhiyun 	struct mutex lock;
174*4882a593Smuzhiyun 	void __iomem *io_base;
175*4882a593Smuzhiyun 	struct platform_device *pdev;
176*4882a593Smuzhiyun 	wait_queue_head_t cmd_complete;
177*4882a593Smuzhiyun 	u32 num_flashes;
178*4882a593Smuzhiyun 	struct spear_snor_flash *flash[MAX_NUM_FLASH_CHIP];
179*4882a593Smuzhiyun };
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun /**
182*4882a593Smuzhiyun  * struct spear_snor_flash - Structure for Serial NOR Flash
183*4882a593Smuzhiyun  *
184*4882a593Smuzhiyun  * @bank: Bank number(0, 1, 2, 3) for each NOR-flash.
185*4882a593Smuzhiyun  * @dev_id: Device ID of NOR-flash.
186*4882a593Smuzhiyun  * @lock: lock to manage flash read, write and erase operations
187*4882a593Smuzhiyun  * @mtd: MTD info for each NOR-flash.
188*4882a593Smuzhiyun  * @num_parts: Total number of partition in each bank of NOR-flash.
189*4882a593Smuzhiyun  * @parts: Partition info for each bank of NOR-flash.
190*4882a593Smuzhiyun  * @page_size: Page size of NOR-flash.
191*4882a593Smuzhiyun  * @base_addr: Base address of NOR-flash.
192*4882a593Smuzhiyun  * @erase_cmd: erase command may vary on different flash types
193*4882a593Smuzhiyun  * @fast_mode: flash supports read in fast mode
194*4882a593Smuzhiyun  */
195*4882a593Smuzhiyun struct spear_snor_flash {
196*4882a593Smuzhiyun 	u32 bank;
197*4882a593Smuzhiyun 	u32 dev_id;
198*4882a593Smuzhiyun 	struct mutex lock;
199*4882a593Smuzhiyun 	struct mtd_info mtd;
200*4882a593Smuzhiyun 	u32 num_parts;
201*4882a593Smuzhiyun 	struct mtd_partition *parts;
202*4882a593Smuzhiyun 	u32 page_size;
203*4882a593Smuzhiyun 	void __iomem *base_addr;
204*4882a593Smuzhiyun 	u8 erase_cmd;
205*4882a593Smuzhiyun 	u8 fast_mode;
206*4882a593Smuzhiyun };
207*4882a593Smuzhiyun 
get_flash_data(struct mtd_info * mtd)208*4882a593Smuzhiyun static inline struct spear_snor_flash *get_flash_data(struct mtd_info *mtd)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	return container_of(mtd, struct spear_snor_flash, mtd);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun /**
214*4882a593Smuzhiyun  * spear_smi_read_sr - Read status register of flash through SMI
215*4882a593Smuzhiyun  * @dev: structure of SMI information.
216*4882a593Smuzhiyun  * @bank: bank to which flash is connected
217*4882a593Smuzhiyun  *
218*4882a593Smuzhiyun  * This routine will return the status register of the flash chip present at the
219*4882a593Smuzhiyun  * given bank.
220*4882a593Smuzhiyun  */
spear_smi_read_sr(struct spear_smi * dev,u32 bank)221*4882a593Smuzhiyun static int spear_smi_read_sr(struct spear_smi *dev, u32 bank)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	int ret;
224*4882a593Smuzhiyun 	u32 ctrlreg1;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	mutex_lock(&dev->lock);
227*4882a593Smuzhiyun 	dev->status = 0; /* Will be set in interrupt handler */
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	ctrlreg1 = readl(dev->io_base + SMI_CR1);
230*4882a593Smuzhiyun 	/* program smi in hw mode */
231*4882a593Smuzhiyun 	writel(ctrlreg1 & ~(SW_MODE | WB_MODE), dev->io_base + SMI_CR1);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	/* performing a rsr instruction in hw mode */
234*4882a593Smuzhiyun 	writel((bank << BANK_SHIFT) | RD_STATUS_REG | TFIE,
235*4882a593Smuzhiyun 			dev->io_base + SMI_CR2);
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	/* wait for tff */
238*4882a593Smuzhiyun 	ret = wait_event_interruptible_timeout(dev->cmd_complete,
239*4882a593Smuzhiyun 			dev->status & TFF, SMI_CMD_TIMEOUT);
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	/* copy dev->status (lower 16 bits) in order to release lock */
242*4882a593Smuzhiyun 	if (ret > 0)
243*4882a593Smuzhiyun 		ret = dev->status & 0xffff;
244*4882a593Smuzhiyun 	else if (ret == 0)
245*4882a593Smuzhiyun 		ret = -ETIMEDOUT;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	/* restore the ctrl regs state */
248*4882a593Smuzhiyun 	writel(ctrlreg1, dev->io_base + SMI_CR1);
249*4882a593Smuzhiyun 	writel(0, dev->io_base + SMI_CR2);
250*4882a593Smuzhiyun 	mutex_unlock(&dev->lock);
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	return ret;
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun /**
256*4882a593Smuzhiyun  * spear_smi_wait_till_ready - wait till flash is ready
257*4882a593Smuzhiyun  * @dev: structure of SMI information.
258*4882a593Smuzhiyun  * @bank: flash corresponding to this bank
259*4882a593Smuzhiyun  * @timeout: timeout for busy wait condition
260*4882a593Smuzhiyun  *
261*4882a593Smuzhiyun  * This routine checks for WIP (write in progress) bit in Status register
262*4882a593Smuzhiyun  * If successful the routine returns 0 else -EBUSY
263*4882a593Smuzhiyun  */
spear_smi_wait_till_ready(struct spear_smi * dev,u32 bank,unsigned long timeout)264*4882a593Smuzhiyun static int spear_smi_wait_till_ready(struct spear_smi *dev, u32 bank,
265*4882a593Smuzhiyun 		unsigned long timeout)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun 	unsigned long finish;
268*4882a593Smuzhiyun 	int status;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	finish = jiffies + timeout;
271*4882a593Smuzhiyun 	do {
272*4882a593Smuzhiyun 		status = spear_smi_read_sr(dev, bank);
273*4882a593Smuzhiyun 		if (status < 0) {
274*4882a593Smuzhiyun 			if (status == -ETIMEDOUT)
275*4882a593Smuzhiyun 				continue; /* try till finish */
276*4882a593Smuzhiyun 			return status;
277*4882a593Smuzhiyun 		} else if (!(status & SR_WIP)) {
278*4882a593Smuzhiyun 			return 0;
279*4882a593Smuzhiyun 		}
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 		cond_resched();
282*4882a593Smuzhiyun 	} while (!time_after_eq(jiffies, finish));
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	dev_err(&dev->pdev->dev, "smi controller is busy, timeout\n");
285*4882a593Smuzhiyun 	return -EBUSY;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun /**
289*4882a593Smuzhiyun  * spear_smi_int_handler - SMI Interrupt Handler.
290*4882a593Smuzhiyun  * @irq: irq number
291*4882a593Smuzhiyun  * @dev_id: structure of SMI device, embedded in dev_id.
292*4882a593Smuzhiyun  *
293*4882a593Smuzhiyun  * The handler clears all interrupt conditions and records the status in
294*4882a593Smuzhiyun  * dev->status which is used by the driver later.
295*4882a593Smuzhiyun  */
spear_smi_int_handler(int irq,void * dev_id)296*4882a593Smuzhiyun static irqreturn_t spear_smi_int_handler(int irq, void *dev_id)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun 	u32 status = 0;
299*4882a593Smuzhiyun 	struct spear_smi *dev = dev_id;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	status = readl(dev->io_base + SMI_SR);
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	if (unlikely(!status))
304*4882a593Smuzhiyun 		return IRQ_NONE;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	/* clear all interrupt conditions */
307*4882a593Smuzhiyun 	writel(0, dev->io_base + SMI_SR);
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	/* copy the status register in dev->status */
310*4882a593Smuzhiyun 	dev->status |= status;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	/* send the completion */
313*4882a593Smuzhiyun 	wake_up_interruptible(&dev->cmd_complete);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	return IRQ_HANDLED;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun /**
319*4882a593Smuzhiyun  * spear_smi_hw_init - initializes the smi controller.
320*4882a593Smuzhiyun  * @dev: structure of smi device
321*4882a593Smuzhiyun  *
322*4882a593Smuzhiyun  * this routine initializes the smi controller wit the default values
323*4882a593Smuzhiyun  */
spear_smi_hw_init(struct spear_smi * dev)324*4882a593Smuzhiyun static void spear_smi_hw_init(struct spear_smi *dev)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun 	unsigned long rate = 0;
327*4882a593Smuzhiyun 	u32 prescale = 0;
328*4882a593Smuzhiyun 	u32 val;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	rate = clk_get_rate(dev->clk);
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	/* functional clock of smi */
333*4882a593Smuzhiyun 	prescale = DIV_ROUND_UP(rate, dev->clk_rate);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	/*
336*4882a593Smuzhiyun 	 * setting the standard values, fast mode, prescaler for
337*4882a593Smuzhiyun 	 * SMI_MAX_CLOCK_FREQ (50MHz) operation and bank enable
338*4882a593Smuzhiyun 	 */
339*4882a593Smuzhiyun 	val = HOLD1 | BANK_EN | DSEL_TIME | (prescale << 8);
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	mutex_lock(&dev->lock);
342*4882a593Smuzhiyun 	/* clear all interrupt conditions */
343*4882a593Smuzhiyun 	writel(0, dev->io_base + SMI_SR);
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	writel(val, dev->io_base + SMI_CR1);
346*4882a593Smuzhiyun 	mutex_unlock(&dev->lock);
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun /**
350*4882a593Smuzhiyun  * get_flash_index - match chip id from a flash list.
351*4882a593Smuzhiyun  * @flash_id: a valid nor flash chip id obtained from board.
352*4882a593Smuzhiyun  *
353*4882a593Smuzhiyun  * try to validate the chip id by matching from a list, if not found then simply
354*4882a593Smuzhiyun  * returns negative. In case of success returns index in to the flash devices
355*4882a593Smuzhiyun  * array.
356*4882a593Smuzhiyun  */
get_flash_index(u32 flash_id)357*4882a593Smuzhiyun static int get_flash_index(u32 flash_id)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun 	int index;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	/* Matches chip-id to entire list of 'serial-nor flash' ids */
362*4882a593Smuzhiyun 	for (index = 0; index < ARRAY_SIZE(flash_devices); index++) {
363*4882a593Smuzhiyun 		if (flash_devices[index].device_id == flash_id)
364*4882a593Smuzhiyun 			return index;
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	/* Memory chip is not listed and not supported */
368*4882a593Smuzhiyun 	return -ENODEV;
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun /**
372*4882a593Smuzhiyun  * spear_smi_write_enable - Enable the flash to do write operation
373*4882a593Smuzhiyun  * @dev: structure of SMI device
374*4882a593Smuzhiyun  * @bank: enable write for flash connected to this bank
375*4882a593Smuzhiyun  *
376*4882a593Smuzhiyun  * Set write enable latch with Write Enable command.
377*4882a593Smuzhiyun  * Returns 0 on success.
378*4882a593Smuzhiyun  */
spear_smi_write_enable(struct spear_smi * dev,u32 bank)379*4882a593Smuzhiyun static int spear_smi_write_enable(struct spear_smi *dev, u32 bank)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun 	int ret;
382*4882a593Smuzhiyun 	u32 ctrlreg1;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	mutex_lock(&dev->lock);
385*4882a593Smuzhiyun 	dev->status = 0; /* Will be set in interrupt handler */
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	ctrlreg1 = readl(dev->io_base + SMI_CR1);
388*4882a593Smuzhiyun 	/* program smi in h/w mode */
389*4882a593Smuzhiyun 	writel(ctrlreg1 & ~SW_MODE, dev->io_base + SMI_CR1);
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	/* give the flash, write enable command */
392*4882a593Smuzhiyun 	writel((bank << BANK_SHIFT) | WE | TFIE, dev->io_base + SMI_CR2);
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	ret = wait_event_interruptible_timeout(dev->cmd_complete,
395*4882a593Smuzhiyun 			dev->status & TFF, SMI_CMD_TIMEOUT);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	/* restore the ctrl regs state */
398*4882a593Smuzhiyun 	writel(ctrlreg1, dev->io_base + SMI_CR1);
399*4882a593Smuzhiyun 	writel(0, dev->io_base + SMI_CR2);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	if (ret == 0) {
402*4882a593Smuzhiyun 		ret = -EIO;
403*4882a593Smuzhiyun 		dev_err(&dev->pdev->dev,
404*4882a593Smuzhiyun 			"smi controller failed on write enable\n");
405*4882a593Smuzhiyun 	} else if (ret > 0) {
406*4882a593Smuzhiyun 		/* check whether write mode status is set for required bank */
407*4882a593Smuzhiyun 		if (dev->status & (1 << (bank + WM_SHIFT)))
408*4882a593Smuzhiyun 			ret = 0;
409*4882a593Smuzhiyun 		else {
410*4882a593Smuzhiyun 			dev_err(&dev->pdev->dev, "couldn't enable write\n");
411*4882a593Smuzhiyun 			ret = -EIO;
412*4882a593Smuzhiyun 		}
413*4882a593Smuzhiyun 	}
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	mutex_unlock(&dev->lock);
416*4882a593Smuzhiyun 	return ret;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun static inline u32
get_sector_erase_cmd(struct spear_snor_flash * flash,u32 offset)420*4882a593Smuzhiyun get_sector_erase_cmd(struct spear_snor_flash *flash, u32 offset)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun 	u32 cmd;
423*4882a593Smuzhiyun 	u8 *x = (u8 *)&cmd;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	x[0] = flash->erase_cmd;
426*4882a593Smuzhiyun 	x[1] = offset >> 16;
427*4882a593Smuzhiyun 	x[2] = offset >> 8;
428*4882a593Smuzhiyun 	x[3] = offset;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	return cmd;
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun /**
434*4882a593Smuzhiyun  * spear_smi_erase_sector - erase one sector of flash
435*4882a593Smuzhiyun  * @dev: structure of SMI information
436*4882a593Smuzhiyun  * @command: erase command to be send
437*4882a593Smuzhiyun  * @bank: bank to which this command needs to be send
438*4882a593Smuzhiyun  * @bytes: size of command
439*4882a593Smuzhiyun  *
440*4882a593Smuzhiyun  * Erase one sector of flash memory at offset ``offset'' which is any
441*4882a593Smuzhiyun  * address within the sector which should be erased.
442*4882a593Smuzhiyun  * Returns 0 if successful, non-zero otherwise.
443*4882a593Smuzhiyun  */
spear_smi_erase_sector(struct spear_smi * dev,u32 bank,u32 command,u32 bytes)444*4882a593Smuzhiyun static int spear_smi_erase_sector(struct spear_smi *dev,
445*4882a593Smuzhiyun 		u32 bank, u32 command, u32 bytes)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun 	u32 ctrlreg1 = 0;
448*4882a593Smuzhiyun 	int ret;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	ret = spear_smi_wait_till_ready(dev, bank, SMI_MAX_TIME_OUT);
451*4882a593Smuzhiyun 	if (ret)
452*4882a593Smuzhiyun 		return ret;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	ret = spear_smi_write_enable(dev, bank);
455*4882a593Smuzhiyun 	if (ret)
456*4882a593Smuzhiyun 		return ret;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	mutex_lock(&dev->lock);
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	ctrlreg1 = readl(dev->io_base + SMI_CR1);
461*4882a593Smuzhiyun 	writel((ctrlreg1 | SW_MODE) & ~WB_MODE, dev->io_base + SMI_CR1);
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	/* send command in sw mode */
464*4882a593Smuzhiyun 	writel(command, dev->io_base + SMI_TR);
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	writel((bank << BANK_SHIFT) | SEND | TFIE | (bytes << TX_LEN_SHIFT),
467*4882a593Smuzhiyun 			dev->io_base + SMI_CR2);
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	ret = wait_event_interruptible_timeout(dev->cmd_complete,
470*4882a593Smuzhiyun 			dev->status & TFF, SMI_CMD_TIMEOUT);
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	if (ret == 0) {
473*4882a593Smuzhiyun 		ret = -EIO;
474*4882a593Smuzhiyun 		dev_err(&dev->pdev->dev, "sector erase failed\n");
475*4882a593Smuzhiyun 	} else if (ret > 0)
476*4882a593Smuzhiyun 		ret = 0; /* success */
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun 	/* restore ctrl regs */
479*4882a593Smuzhiyun 	writel(ctrlreg1, dev->io_base + SMI_CR1);
480*4882a593Smuzhiyun 	writel(0, dev->io_base + SMI_CR2);
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	mutex_unlock(&dev->lock);
483*4882a593Smuzhiyun 	return ret;
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun /**
487*4882a593Smuzhiyun  * spear_mtd_erase - perform flash erase operation as requested by user
488*4882a593Smuzhiyun  * @mtd: Provides the memory characteristics
489*4882a593Smuzhiyun  * @e_info: Provides the erase information
490*4882a593Smuzhiyun  *
491*4882a593Smuzhiyun  * Erase an address range on the flash chip. The address range may extend
492*4882a593Smuzhiyun  * one or more erase sectors. Return an error is there is a problem erasing.
493*4882a593Smuzhiyun  */
spear_mtd_erase(struct mtd_info * mtd,struct erase_info * e_info)494*4882a593Smuzhiyun static int spear_mtd_erase(struct mtd_info *mtd, struct erase_info *e_info)
495*4882a593Smuzhiyun {
496*4882a593Smuzhiyun 	struct spear_snor_flash *flash = get_flash_data(mtd);
497*4882a593Smuzhiyun 	struct spear_smi *dev = mtd->priv;
498*4882a593Smuzhiyun 	u32 addr, command, bank;
499*4882a593Smuzhiyun 	int len, ret;
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	if (!flash || !dev)
502*4882a593Smuzhiyun 		return -ENODEV;
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	bank = flash->bank;
505*4882a593Smuzhiyun 	if (bank > dev->num_flashes - 1) {
506*4882a593Smuzhiyun 		dev_err(&dev->pdev->dev, "Invalid Bank Num");
507*4882a593Smuzhiyun 		return -EINVAL;
508*4882a593Smuzhiyun 	}
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	addr = e_info->addr;
511*4882a593Smuzhiyun 	len = e_info->len;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	mutex_lock(&flash->lock);
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	/* now erase sectors in loop */
516*4882a593Smuzhiyun 	while (len) {
517*4882a593Smuzhiyun 		command = get_sector_erase_cmd(flash, addr);
518*4882a593Smuzhiyun 		/* preparing the command for flash */
519*4882a593Smuzhiyun 		ret = spear_smi_erase_sector(dev, bank, command, 4);
520*4882a593Smuzhiyun 		if (ret) {
521*4882a593Smuzhiyun 			mutex_unlock(&flash->lock);
522*4882a593Smuzhiyun 			return ret;
523*4882a593Smuzhiyun 		}
524*4882a593Smuzhiyun 		addr += mtd->erasesize;
525*4882a593Smuzhiyun 		len -= mtd->erasesize;
526*4882a593Smuzhiyun 	}
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 	mutex_unlock(&flash->lock);
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	return 0;
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun /**
534*4882a593Smuzhiyun  * spear_mtd_read - performs flash read operation as requested by the user
535*4882a593Smuzhiyun  * @mtd: MTD information of the memory bank
536*4882a593Smuzhiyun  * @from: Address from which to start read
537*4882a593Smuzhiyun  * @len: Number of bytes to be read
538*4882a593Smuzhiyun  * @retlen: Fills the Number of bytes actually read
539*4882a593Smuzhiyun  * @buf: Fills this after reading
540*4882a593Smuzhiyun  *
541*4882a593Smuzhiyun  * Read an address range from the flash chip. The address range
542*4882a593Smuzhiyun  * may be any size provided it is within the physical boundaries.
543*4882a593Smuzhiyun  * Returns 0 on success, non zero otherwise
544*4882a593Smuzhiyun  */
spear_mtd_read(struct mtd_info * mtd,loff_t from,size_t len,size_t * retlen,u8 * buf)545*4882a593Smuzhiyun static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
546*4882a593Smuzhiyun 		size_t *retlen, u8 *buf)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun 	struct spear_snor_flash *flash = get_flash_data(mtd);
549*4882a593Smuzhiyun 	struct spear_smi *dev = mtd->priv;
550*4882a593Smuzhiyun 	void __iomem *src;
551*4882a593Smuzhiyun 	u32 ctrlreg1, val;
552*4882a593Smuzhiyun 	int ret;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	if (!flash || !dev)
555*4882a593Smuzhiyun 		return -ENODEV;
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	if (flash->bank > dev->num_flashes - 1) {
558*4882a593Smuzhiyun 		dev_err(&dev->pdev->dev, "Invalid Bank Num");
559*4882a593Smuzhiyun 		return -EINVAL;
560*4882a593Smuzhiyun 	}
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	/* select address as per bank number */
563*4882a593Smuzhiyun 	src = flash->base_addr + from;
564*4882a593Smuzhiyun 
565*4882a593Smuzhiyun 	mutex_lock(&flash->lock);
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	/* wait till previous write/erase is done. */
568*4882a593Smuzhiyun 	ret = spear_smi_wait_till_ready(dev, flash->bank, SMI_MAX_TIME_OUT);
569*4882a593Smuzhiyun 	if (ret) {
570*4882a593Smuzhiyun 		mutex_unlock(&flash->lock);
571*4882a593Smuzhiyun 		return ret;
572*4882a593Smuzhiyun 	}
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	mutex_lock(&dev->lock);
575*4882a593Smuzhiyun 	/* put smi in hw mode not wbt mode */
576*4882a593Smuzhiyun 	ctrlreg1 = val = readl(dev->io_base + SMI_CR1);
577*4882a593Smuzhiyun 	val &= ~(SW_MODE | WB_MODE);
578*4882a593Smuzhiyun 	if (flash->fast_mode)
579*4882a593Smuzhiyun 		val |= FAST_MODE;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	writel(val, dev->io_base + SMI_CR1);
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	memcpy_fromio(buf, src, len);
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	/* restore ctrl reg1 */
586*4882a593Smuzhiyun 	writel(ctrlreg1, dev->io_base + SMI_CR1);
587*4882a593Smuzhiyun 	mutex_unlock(&dev->lock);
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	*retlen = len;
590*4882a593Smuzhiyun 	mutex_unlock(&flash->lock);
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	return 0;
593*4882a593Smuzhiyun }
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun /*
596*4882a593Smuzhiyun  * The purpose of this function is to ensure a memcpy_toio() with byte writes
597*4882a593Smuzhiyun  * only. Its structure is inspired from the ARM implementation of _memcpy_toio()
598*4882a593Smuzhiyun  * which also does single byte writes but cannot be used here as this is just an
599*4882a593Smuzhiyun  * implementation detail and not part of the API. Not mentioning the comment
600*4882a593Smuzhiyun  * stating that _memcpy_toio() should be optimized.
601*4882a593Smuzhiyun  */
spear_smi_memcpy_toio_b(volatile void __iomem * dest,const void * src,size_t len)602*4882a593Smuzhiyun static void spear_smi_memcpy_toio_b(volatile void __iomem *dest,
603*4882a593Smuzhiyun 				    const void *src, size_t len)
604*4882a593Smuzhiyun {
605*4882a593Smuzhiyun 	const unsigned char *from = src;
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	while (len) {
608*4882a593Smuzhiyun 		len--;
609*4882a593Smuzhiyun 		writeb(*from, dest);
610*4882a593Smuzhiyun 		from++;
611*4882a593Smuzhiyun 		dest++;
612*4882a593Smuzhiyun 	}
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun 
spear_smi_cpy_toio(struct spear_smi * dev,u32 bank,void __iomem * dest,const void * src,size_t len)615*4882a593Smuzhiyun static inline int spear_smi_cpy_toio(struct spear_smi *dev, u32 bank,
616*4882a593Smuzhiyun 		void __iomem *dest, const void *src, size_t len)
617*4882a593Smuzhiyun {
618*4882a593Smuzhiyun 	int ret;
619*4882a593Smuzhiyun 	u32 ctrlreg1;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 	/* wait until finished previous write command. */
622*4882a593Smuzhiyun 	ret = spear_smi_wait_till_ready(dev, bank, SMI_MAX_TIME_OUT);
623*4882a593Smuzhiyun 	if (ret)
624*4882a593Smuzhiyun 		return ret;
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	/* put smi in write enable */
627*4882a593Smuzhiyun 	ret = spear_smi_write_enable(dev, bank);
628*4882a593Smuzhiyun 	if (ret)
629*4882a593Smuzhiyun 		return ret;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	/* put smi in hw, write burst mode */
632*4882a593Smuzhiyun 	mutex_lock(&dev->lock);
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	ctrlreg1 = readl(dev->io_base + SMI_CR1);
635*4882a593Smuzhiyun 	writel((ctrlreg1 | WB_MODE) & ~SW_MODE, dev->io_base + SMI_CR1);
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 	/*
638*4882a593Smuzhiyun 	 * In Write Burst mode (WB_MODE), the specs states that writes must be:
639*4882a593Smuzhiyun 	 * - incremental
640*4882a593Smuzhiyun 	 * - of the same size
641*4882a593Smuzhiyun 	 * The ARM implementation of memcpy_toio() will optimize the number of
642*4882a593Smuzhiyun 	 * I/O by using as much 4-byte writes as possible, surrounded by
643*4882a593Smuzhiyun 	 * 2-byte/1-byte access if:
644*4882a593Smuzhiyun 	 * - the destination is not 4-byte aligned
645*4882a593Smuzhiyun 	 * - the length is not a multiple of 4-byte.
646*4882a593Smuzhiyun 	 * Avoid this alternance of write access size by using our own 'byte
647*4882a593Smuzhiyun 	 * access' helper if at least one of the two conditions above is true.
648*4882a593Smuzhiyun 	 */
649*4882a593Smuzhiyun 	if (IS_ALIGNED(len, sizeof(u32)) &&
650*4882a593Smuzhiyun 	    IS_ALIGNED((uintptr_t)dest, sizeof(u32)))
651*4882a593Smuzhiyun 		memcpy_toio(dest, src, len);
652*4882a593Smuzhiyun 	else
653*4882a593Smuzhiyun 		spear_smi_memcpy_toio_b(dest, src, len);
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	writel(ctrlreg1, dev->io_base + SMI_CR1);
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	mutex_unlock(&dev->lock);
658*4882a593Smuzhiyun 	return 0;
659*4882a593Smuzhiyun }
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun /**
662*4882a593Smuzhiyun  * spear_mtd_write - performs write operation as requested by the user.
663*4882a593Smuzhiyun  * @mtd: MTD information of the memory bank.
664*4882a593Smuzhiyun  * @to:	Address to write.
665*4882a593Smuzhiyun  * @len: Number of bytes to be written.
666*4882a593Smuzhiyun  * @retlen: Number of bytes actually wrote.
667*4882a593Smuzhiyun  * @buf: Buffer from which the data to be taken.
668*4882a593Smuzhiyun  *
669*4882a593Smuzhiyun  * Write an address range to the flash chip. Data must be written in
670*4882a593Smuzhiyun  * flash_page_size chunks. The address range may be any size provided
671*4882a593Smuzhiyun  * it is within the physical boundaries.
672*4882a593Smuzhiyun  * Returns 0 on success, non zero otherwise
673*4882a593Smuzhiyun  */
spear_mtd_write(struct mtd_info * mtd,loff_t to,size_t len,size_t * retlen,const u8 * buf)674*4882a593Smuzhiyun static int spear_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
675*4882a593Smuzhiyun 		size_t *retlen, const u8 *buf)
676*4882a593Smuzhiyun {
677*4882a593Smuzhiyun 	struct spear_snor_flash *flash = get_flash_data(mtd);
678*4882a593Smuzhiyun 	struct spear_smi *dev = mtd->priv;
679*4882a593Smuzhiyun 	void __iomem *dest;
680*4882a593Smuzhiyun 	u32 page_offset, page_size;
681*4882a593Smuzhiyun 	int ret;
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	if (!flash || !dev)
684*4882a593Smuzhiyun 		return -ENODEV;
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	if (flash->bank > dev->num_flashes - 1) {
687*4882a593Smuzhiyun 		dev_err(&dev->pdev->dev, "Invalid Bank Num");
688*4882a593Smuzhiyun 		return -EINVAL;
689*4882a593Smuzhiyun 	}
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	/* select address as per bank number */
692*4882a593Smuzhiyun 	dest = flash->base_addr + to;
693*4882a593Smuzhiyun 	mutex_lock(&flash->lock);
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	page_offset = (u32)to % flash->page_size;
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun 	/* do if all the bytes fit onto one page */
698*4882a593Smuzhiyun 	if (page_offset + len <= flash->page_size) {
699*4882a593Smuzhiyun 		ret = spear_smi_cpy_toio(dev, flash->bank, dest, buf, len);
700*4882a593Smuzhiyun 		if (!ret)
701*4882a593Smuzhiyun 			*retlen += len;
702*4882a593Smuzhiyun 	} else {
703*4882a593Smuzhiyun 		u32 i;
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 		/* the size of data remaining on the first page */
706*4882a593Smuzhiyun 		page_size = flash->page_size - page_offset;
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 		ret = spear_smi_cpy_toio(dev, flash->bank, dest, buf,
709*4882a593Smuzhiyun 				page_size);
710*4882a593Smuzhiyun 		if (ret)
711*4882a593Smuzhiyun 			goto err_write;
712*4882a593Smuzhiyun 		else
713*4882a593Smuzhiyun 			*retlen += page_size;
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 		/* write everything in pagesize chunks */
716*4882a593Smuzhiyun 		for (i = page_size; i < len; i += page_size) {
717*4882a593Smuzhiyun 			page_size = len - i;
718*4882a593Smuzhiyun 			if (page_size > flash->page_size)
719*4882a593Smuzhiyun 				page_size = flash->page_size;
720*4882a593Smuzhiyun 
721*4882a593Smuzhiyun 			ret = spear_smi_cpy_toio(dev, flash->bank, dest + i,
722*4882a593Smuzhiyun 					buf + i, page_size);
723*4882a593Smuzhiyun 			if (ret)
724*4882a593Smuzhiyun 				break;
725*4882a593Smuzhiyun 			else
726*4882a593Smuzhiyun 				*retlen += page_size;
727*4882a593Smuzhiyun 		}
728*4882a593Smuzhiyun 	}
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun err_write:
731*4882a593Smuzhiyun 	mutex_unlock(&flash->lock);
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	return ret;
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun /**
737*4882a593Smuzhiyun  * spear_smi_probe_flash - Detects the NOR Flash chip.
738*4882a593Smuzhiyun  * @dev: structure of SMI information.
739*4882a593Smuzhiyun  * @bank: bank on which flash must be probed
740*4882a593Smuzhiyun  *
741*4882a593Smuzhiyun  * This routine will check whether there exists a flash chip on a given memory
742*4882a593Smuzhiyun  * bank ID.
743*4882a593Smuzhiyun  * Return index of the probed flash in flash devices structure
744*4882a593Smuzhiyun  */
spear_smi_probe_flash(struct spear_smi * dev,u32 bank)745*4882a593Smuzhiyun static int spear_smi_probe_flash(struct spear_smi *dev, u32 bank)
746*4882a593Smuzhiyun {
747*4882a593Smuzhiyun 	int ret;
748*4882a593Smuzhiyun 	u32 val = 0;
749*4882a593Smuzhiyun 
750*4882a593Smuzhiyun 	ret = spear_smi_wait_till_ready(dev, bank, SMI_PROBE_TIMEOUT);
751*4882a593Smuzhiyun 	if (ret)
752*4882a593Smuzhiyun 		return ret;
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	mutex_lock(&dev->lock);
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 	dev->status = 0; /* Will be set in interrupt handler */
757*4882a593Smuzhiyun 	/* put smi in sw mode */
758*4882a593Smuzhiyun 	val = readl(dev->io_base + SMI_CR1);
759*4882a593Smuzhiyun 	writel(val | SW_MODE, dev->io_base + SMI_CR1);
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 	/* send readid command in sw mode */
762*4882a593Smuzhiyun 	writel(OPCODE_RDID, dev->io_base + SMI_TR);
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	val = (bank << BANK_SHIFT) | SEND | (1 << TX_LEN_SHIFT) |
765*4882a593Smuzhiyun 		(3 << RX_LEN_SHIFT) | TFIE;
766*4882a593Smuzhiyun 	writel(val, dev->io_base + SMI_CR2);
767*4882a593Smuzhiyun 
768*4882a593Smuzhiyun 	/* wait for TFF */
769*4882a593Smuzhiyun 	ret = wait_event_interruptible_timeout(dev->cmd_complete,
770*4882a593Smuzhiyun 			dev->status & TFF, SMI_CMD_TIMEOUT);
771*4882a593Smuzhiyun 	if (ret <= 0) {
772*4882a593Smuzhiyun 		ret = -ENODEV;
773*4882a593Smuzhiyun 		goto err_probe;
774*4882a593Smuzhiyun 	}
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	/* get memory chip id */
777*4882a593Smuzhiyun 	val = readl(dev->io_base + SMI_RR);
778*4882a593Smuzhiyun 	val &= 0x00ffffff;
779*4882a593Smuzhiyun 	ret = get_flash_index(val);
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun err_probe:
782*4882a593Smuzhiyun 	/* clear sw mode */
783*4882a593Smuzhiyun 	val = readl(dev->io_base + SMI_CR1);
784*4882a593Smuzhiyun 	writel(val & ~SW_MODE, dev->io_base + SMI_CR1);
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 	mutex_unlock(&dev->lock);
787*4882a593Smuzhiyun 	return ret;
788*4882a593Smuzhiyun }
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 
791*4882a593Smuzhiyun #ifdef CONFIG_OF
spear_smi_probe_config_dt(struct platform_device * pdev,struct device_node * np)792*4882a593Smuzhiyun static int spear_smi_probe_config_dt(struct platform_device *pdev,
793*4882a593Smuzhiyun 				     struct device_node *np)
794*4882a593Smuzhiyun {
795*4882a593Smuzhiyun 	struct spear_smi_plat_data *pdata = dev_get_platdata(&pdev->dev);
796*4882a593Smuzhiyun 	struct device_node *pp;
797*4882a593Smuzhiyun 	const __be32 *addr;
798*4882a593Smuzhiyun 	u32 val;
799*4882a593Smuzhiyun 	int len;
800*4882a593Smuzhiyun 	int i = 0;
801*4882a593Smuzhiyun 
802*4882a593Smuzhiyun 	if (!np)
803*4882a593Smuzhiyun 		return -ENODEV;
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	of_property_read_u32(np, "clock-rate", &val);
806*4882a593Smuzhiyun 	pdata->clk_rate = val;
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun 	pdata->board_flash_info = devm_kzalloc(&pdev->dev,
809*4882a593Smuzhiyun 					       sizeof(*pdata->board_flash_info),
810*4882a593Smuzhiyun 					       GFP_KERNEL);
811*4882a593Smuzhiyun 	if (!pdata->board_flash_info)
812*4882a593Smuzhiyun 		return -ENOMEM;
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun 	/* Fill structs for each subnode (flash device) */
815*4882a593Smuzhiyun 	for_each_child_of_node(np, pp) {
816*4882a593Smuzhiyun 		pdata->np[i] = pp;
817*4882a593Smuzhiyun 
818*4882a593Smuzhiyun 		/* Read base-addr and size from DT */
819*4882a593Smuzhiyun 		addr = of_get_property(pp, "reg", &len);
820*4882a593Smuzhiyun 		pdata->board_flash_info->mem_base = be32_to_cpup(&addr[0]);
821*4882a593Smuzhiyun 		pdata->board_flash_info->size = be32_to_cpup(&addr[1]);
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun 		if (of_get_property(pp, "st,smi-fast-mode", NULL))
824*4882a593Smuzhiyun 			pdata->board_flash_info->fast_mode = 1;
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 		i++;
827*4882a593Smuzhiyun 	}
828*4882a593Smuzhiyun 
829*4882a593Smuzhiyun 	pdata->num_flashes = i;
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 	return 0;
832*4882a593Smuzhiyun }
833*4882a593Smuzhiyun #else
spear_smi_probe_config_dt(struct platform_device * pdev,struct device_node * np)834*4882a593Smuzhiyun static int spear_smi_probe_config_dt(struct platform_device *pdev,
835*4882a593Smuzhiyun 				     struct device_node *np)
836*4882a593Smuzhiyun {
837*4882a593Smuzhiyun 	return -ENOSYS;
838*4882a593Smuzhiyun }
839*4882a593Smuzhiyun #endif
840*4882a593Smuzhiyun 
spear_smi_setup_banks(struct platform_device * pdev,u32 bank,struct device_node * np)841*4882a593Smuzhiyun static int spear_smi_setup_banks(struct platform_device *pdev,
842*4882a593Smuzhiyun 				 u32 bank, struct device_node *np)
843*4882a593Smuzhiyun {
844*4882a593Smuzhiyun 	struct spear_smi *dev = platform_get_drvdata(pdev);
845*4882a593Smuzhiyun 	struct spear_smi_flash_info *flash_info;
846*4882a593Smuzhiyun 	struct spear_smi_plat_data *pdata;
847*4882a593Smuzhiyun 	struct spear_snor_flash *flash;
848*4882a593Smuzhiyun 	struct mtd_partition *parts = NULL;
849*4882a593Smuzhiyun 	int count = 0;
850*4882a593Smuzhiyun 	int flash_index;
851*4882a593Smuzhiyun 	int ret = 0;
852*4882a593Smuzhiyun 
853*4882a593Smuzhiyun 	pdata = dev_get_platdata(&pdev->dev);
854*4882a593Smuzhiyun 	if (bank > pdata->num_flashes - 1)
855*4882a593Smuzhiyun 		return -EINVAL;
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 	flash_info = &pdata->board_flash_info[bank];
858*4882a593Smuzhiyun 	if (!flash_info)
859*4882a593Smuzhiyun 		return -ENODEV;
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 	flash = devm_kzalloc(&pdev->dev, sizeof(*flash), GFP_ATOMIC);
862*4882a593Smuzhiyun 	if (!flash)
863*4882a593Smuzhiyun 		return -ENOMEM;
864*4882a593Smuzhiyun 	flash->bank = bank;
865*4882a593Smuzhiyun 	flash->fast_mode = flash_info->fast_mode ? 1 : 0;
866*4882a593Smuzhiyun 	mutex_init(&flash->lock);
867*4882a593Smuzhiyun 
868*4882a593Smuzhiyun 	/* verify whether nor flash is really present on board */
869*4882a593Smuzhiyun 	flash_index = spear_smi_probe_flash(dev, bank);
870*4882a593Smuzhiyun 	if (flash_index < 0) {
871*4882a593Smuzhiyun 		dev_info(&dev->pdev->dev, "smi-nor%d not found\n", bank);
872*4882a593Smuzhiyun 		return flash_index;
873*4882a593Smuzhiyun 	}
874*4882a593Smuzhiyun 	/* map the memory for nor flash chip */
875*4882a593Smuzhiyun 	flash->base_addr = devm_ioremap(&pdev->dev, flash_info->mem_base,
876*4882a593Smuzhiyun 					flash_info->size);
877*4882a593Smuzhiyun 	if (!flash->base_addr)
878*4882a593Smuzhiyun 		return -EIO;
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun 	dev->flash[bank] = flash;
881*4882a593Smuzhiyun 	flash->mtd.priv = dev;
882*4882a593Smuzhiyun 
883*4882a593Smuzhiyun 	if (flash_info->name)
884*4882a593Smuzhiyun 		flash->mtd.name = flash_info->name;
885*4882a593Smuzhiyun 	else
886*4882a593Smuzhiyun 		flash->mtd.name = flash_devices[flash_index].name;
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 	flash->mtd.dev.parent = &pdev->dev;
889*4882a593Smuzhiyun 	mtd_set_of_node(&flash->mtd, np);
890*4882a593Smuzhiyun 	flash->mtd.type = MTD_NORFLASH;
891*4882a593Smuzhiyun 	flash->mtd.writesize = 1;
892*4882a593Smuzhiyun 	flash->mtd.flags = MTD_CAP_NORFLASH;
893*4882a593Smuzhiyun 	flash->mtd.size = flash_info->size;
894*4882a593Smuzhiyun 	flash->mtd.erasesize = flash_devices[flash_index].sectorsize;
895*4882a593Smuzhiyun 	flash->page_size = flash_devices[flash_index].pagesize;
896*4882a593Smuzhiyun 	flash->mtd.writebufsize = flash->page_size;
897*4882a593Smuzhiyun 	flash->erase_cmd = flash_devices[flash_index].erase_cmd;
898*4882a593Smuzhiyun 	flash->mtd._erase = spear_mtd_erase;
899*4882a593Smuzhiyun 	flash->mtd._read = spear_mtd_read;
900*4882a593Smuzhiyun 	flash->mtd._write = spear_mtd_write;
901*4882a593Smuzhiyun 	flash->dev_id = flash_devices[flash_index].device_id;
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun 	dev_info(&dev->pdev->dev, "mtd .name=%s .size=%llx(%lluM)\n",
904*4882a593Smuzhiyun 			flash->mtd.name, flash->mtd.size,
905*4882a593Smuzhiyun 			flash->mtd.size / (1024 * 1024));
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	dev_info(&dev->pdev->dev, ".erasesize = 0x%x(%uK)\n",
908*4882a593Smuzhiyun 			flash->mtd.erasesize, flash->mtd.erasesize / 1024);
909*4882a593Smuzhiyun 
910*4882a593Smuzhiyun #ifndef CONFIG_OF
911*4882a593Smuzhiyun 	if (flash_info->partitions) {
912*4882a593Smuzhiyun 		parts = flash_info->partitions;
913*4882a593Smuzhiyun 		count = flash_info->nr_partitions;
914*4882a593Smuzhiyun 	}
915*4882a593Smuzhiyun #endif
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 	ret = mtd_device_register(&flash->mtd, parts, count);
918*4882a593Smuzhiyun 	if (ret) {
919*4882a593Smuzhiyun 		dev_err(&dev->pdev->dev, "Err MTD partition=%d\n", ret);
920*4882a593Smuzhiyun 		return ret;
921*4882a593Smuzhiyun 	}
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	return 0;
924*4882a593Smuzhiyun }
925*4882a593Smuzhiyun 
926*4882a593Smuzhiyun /**
927*4882a593Smuzhiyun  * spear_smi_probe - Entry routine
928*4882a593Smuzhiyun  * @pdev: platform device structure
929*4882a593Smuzhiyun  *
930*4882a593Smuzhiyun  * This is the first routine which gets invoked during booting and does all
931*4882a593Smuzhiyun  * initialization/allocation work. The routine looks for available memory banks,
932*4882a593Smuzhiyun  * and do proper init for any found one.
933*4882a593Smuzhiyun  * Returns 0 on success, non zero otherwise
934*4882a593Smuzhiyun  */
spear_smi_probe(struct platform_device * pdev)935*4882a593Smuzhiyun static int spear_smi_probe(struct platform_device *pdev)
936*4882a593Smuzhiyun {
937*4882a593Smuzhiyun 	struct device_node *np = pdev->dev.of_node;
938*4882a593Smuzhiyun 	struct spear_smi_plat_data *pdata = NULL;
939*4882a593Smuzhiyun 	struct spear_smi *dev;
940*4882a593Smuzhiyun 	struct resource *smi_base;
941*4882a593Smuzhiyun 	int irq, ret = 0;
942*4882a593Smuzhiyun 	int i;
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun 	if (np) {
945*4882a593Smuzhiyun 		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
946*4882a593Smuzhiyun 		if (!pdata) {
947*4882a593Smuzhiyun 			ret = -ENOMEM;
948*4882a593Smuzhiyun 			goto err;
949*4882a593Smuzhiyun 		}
950*4882a593Smuzhiyun 		pdev->dev.platform_data = pdata;
951*4882a593Smuzhiyun 		ret = spear_smi_probe_config_dt(pdev, np);
952*4882a593Smuzhiyun 		if (ret) {
953*4882a593Smuzhiyun 			ret = -ENODEV;
954*4882a593Smuzhiyun 			dev_err(&pdev->dev, "no platform data\n");
955*4882a593Smuzhiyun 			goto err;
956*4882a593Smuzhiyun 		}
957*4882a593Smuzhiyun 	} else {
958*4882a593Smuzhiyun 		pdata = dev_get_platdata(&pdev->dev);
959*4882a593Smuzhiyun 		if (!pdata) {
960*4882a593Smuzhiyun 			ret = -ENODEV;
961*4882a593Smuzhiyun 			dev_err(&pdev->dev, "no platform data\n");
962*4882a593Smuzhiyun 			goto err;
963*4882a593Smuzhiyun 		}
964*4882a593Smuzhiyun 	}
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 	irq = platform_get_irq(pdev, 0);
967*4882a593Smuzhiyun 	if (irq < 0) {
968*4882a593Smuzhiyun 		ret = -ENODEV;
969*4882a593Smuzhiyun 		goto err;
970*4882a593Smuzhiyun 	}
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_ATOMIC);
973*4882a593Smuzhiyun 	if (!dev) {
974*4882a593Smuzhiyun 		ret = -ENOMEM;
975*4882a593Smuzhiyun 		goto err;
976*4882a593Smuzhiyun 	}
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun 	smi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun 	dev->io_base = devm_ioremap_resource(&pdev->dev, smi_base);
981*4882a593Smuzhiyun 	if (IS_ERR(dev->io_base)) {
982*4882a593Smuzhiyun 		ret = PTR_ERR(dev->io_base);
983*4882a593Smuzhiyun 		goto err;
984*4882a593Smuzhiyun 	}
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun 	dev->pdev = pdev;
987*4882a593Smuzhiyun 	dev->clk_rate = pdata->clk_rate;
988*4882a593Smuzhiyun 
989*4882a593Smuzhiyun 	if (dev->clk_rate > SMI_MAX_CLOCK_FREQ)
990*4882a593Smuzhiyun 		dev->clk_rate = SMI_MAX_CLOCK_FREQ;
991*4882a593Smuzhiyun 
992*4882a593Smuzhiyun 	dev->num_flashes = pdata->num_flashes;
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun 	if (dev->num_flashes > MAX_NUM_FLASH_CHIP) {
995*4882a593Smuzhiyun 		dev_err(&pdev->dev, "exceeding max number of flashes\n");
996*4882a593Smuzhiyun 		dev->num_flashes = MAX_NUM_FLASH_CHIP;
997*4882a593Smuzhiyun 	}
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun 	dev->clk = devm_clk_get(&pdev->dev, NULL);
1000*4882a593Smuzhiyun 	if (IS_ERR(dev->clk)) {
1001*4882a593Smuzhiyun 		ret = PTR_ERR(dev->clk);
1002*4882a593Smuzhiyun 		goto err;
1003*4882a593Smuzhiyun 	}
1004*4882a593Smuzhiyun 
1005*4882a593Smuzhiyun 	ret = clk_prepare_enable(dev->clk);
1006*4882a593Smuzhiyun 	if (ret)
1007*4882a593Smuzhiyun 		goto err;
1008*4882a593Smuzhiyun 
1009*4882a593Smuzhiyun 	ret = devm_request_irq(&pdev->dev, irq, spear_smi_int_handler, 0,
1010*4882a593Smuzhiyun 			       pdev->name, dev);
1011*4882a593Smuzhiyun 	if (ret) {
1012*4882a593Smuzhiyun 		dev_err(&dev->pdev->dev, "SMI IRQ allocation failed\n");
1013*4882a593Smuzhiyun 		goto err_irq;
1014*4882a593Smuzhiyun 	}
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun 	mutex_init(&dev->lock);
1017*4882a593Smuzhiyun 	init_waitqueue_head(&dev->cmd_complete);
1018*4882a593Smuzhiyun 	spear_smi_hw_init(dev);
1019*4882a593Smuzhiyun 	platform_set_drvdata(pdev, dev);
1020*4882a593Smuzhiyun 
1021*4882a593Smuzhiyun 	/* loop for each serial nor-flash which is connected to smi */
1022*4882a593Smuzhiyun 	for (i = 0; i < dev->num_flashes; i++) {
1023*4882a593Smuzhiyun 		ret = spear_smi_setup_banks(pdev, i, pdata->np[i]);
1024*4882a593Smuzhiyun 		if (ret) {
1025*4882a593Smuzhiyun 			dev_err(&dev->pdev->dev, "bank setup failed\n");
1026*4882a593Smuzhiyun 			goto err_irq;
1027*4882a593Smuzhiyun 		}
1028*4882a593Smuzhiyun 	}
1029*4882a593Smuzhiyun 
1030*4882a593Smuzhiyun 	return 0;
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun err_irq:
1033*4882a593Smuzhiyun 	clk_disable_unprepare(dev->clk);
1034*4882a593Smuzhiyun err:
1035*4882a593Smuzhiyun 	return ret;
1036*4882a593Smuzhiyun }
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun /**
1039*4882a593Smuzhiyun  * spear_smi_remove - Exit routine
1040*4882a593Smuzhiyun  * @pdev: platform device structure
1041*4882a593Smuzhiyun  *
1042*4882a593Smuzhiyun  * free all allocations and delete the partitions.
1043*4882a593Smuzhiyun  */
spear_smi_remove(struct platform_device * pdev)1044*4882a593Smuzhiyun static int spear_smi_remove(struct platform_device *pdev)
1045*4882a593Smuzhiyun {
1046*4882a593Smuzhiyun 	struct spear_smi *dev;
1047*4882a593Smuzhiyun 	struct spear_snor_flash *flash;
1048*4882a593Smuzhiyun 	int ret, i;
1049*4882a593Smuzhiyun 
1050*4882a593Smuzhiyun 	dev = platform_get_drvdata(pdev);
1051*4882a593Smuzhiyun 	if (!dev) {
1052*4882a593Smuzhiyun 		dev_err(&pdev->dev, "dev is null\n");
1053*4882a593Smuzhiyun 		return -ENODEV;
1054*4882a593Smuzhiyun 	}
1055*4882a593Smuzhiyun 
1056*4882a593Smuzhiyun 	/* clean up for all nor flash */
1057*4882a593Smuzhiyun 	for (i = 0; i < dev->num_flashes; i++) {
1058*4882a593Smuzhiyun 		flash = dev->flash[i];
1059*4882a593Smuzhiyun 		if (!flash)
1060*4882a593Smuzhiyun 			continue;
1061*4882a593Smuzhiyun 
1062*4882a593Smuzhiyun 		/* clean up mtd stuff */
1063*4882a593Smuzhiyun 		ret = mtd_device_unregister(&flash->mtd);
1064*4882a593Smuzhiyun 		if (ret)
1065*4882a593Smuzhiyun 			dev_err(&pdev->dev, "error removing mtd\n");
1066*4882a593Smuzhiyun 	}
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 	clk_disable_unprepare(dev->clk);
1069*4882a593Smuzhiyun 
1070*4882a593Smuzhiyun 	return 0;
1071*4882a593Smuzhiyun }
1072*4882a593Smuzhiyun 
1073*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
spear_smi_suspend(struct device * dev)1074*4882a593Smuzhiyun static int spear_smi_suspend(struct device *dev)
1075*4882a593Smuzhiyun {
1076*4882a593Smuzhiyun 	struct spear_smi *sdev = dev_get_drvdata(dev);
1077*4882a593Smuzhiyun 
1078*4882a593Smuzhiyun 	if (sdev && sdev->clk)
1079*4882a593Smuzhiyun 		clk_disable_unprepare(sdev->clk);
1080*4882a593Smuzhiyun 
1081*4882a593Smuzhiyun 	return 0;
1082*4882a593Smuzhiyun }
1083*4882a593Smuzhiyun 
spear_smi_resume(struct device * dev)1084*4882a593Smuzhiyun static int spear_smi_resume(struct device *dev)
1085*4882a593Smuzhiyun {
1086*4882a593Smuzhiyun 	struct spear_smi *sdev = dev_get_drvdata(dev);
1087*4882a593Smuzhiyun 	int ret = -EPERM;
1088*4882a593Smuzhiyun 
1089*4882a593Smuzhiyun 	if (sdev && sdev->clk)
1090*4882a593Smuzhiyun 		ret = clk_prepare_enable(sdev->clk);
1091*4882a593Smuzhiyun 
1092*4882a593Smuzhiyun 	if (!ret)
1093*4882a593Smuzhiyun 		spear_smi_hw_init(sdev);
1094*4882a593Smuzhiyun 	return ret;
1095*4882a593Smuzhiyun }
1096*4882a593Smuzhiyun #endif
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(spear_smi_pm_ops, spear_smi_suspend, spear_smi_resume);
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun #ifdef CONFIG_OF
1101*4882a593Smuzhiyun static const struct of_device_id spear_smi_id_table[] = {
1102*4882a593Smuzhiyun 	{ .compatible = "st,spear600-smi" },
1103*4882a593Smuzhiyun 	{}
1104*4882a593Smuzhiyun };
1105*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, spear_smi_id_table);
1106*4882a593Smuzhiyun #endif
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun static struct platform_driver spear_smi_driver = {
1109*4882a593Smuzhiyun 	.driver = {
1110*4882a593Smuzhiyun 		.name = "smi",
1111*4882a593Smuzhiyun 		.bus = &platform_bus_type,
1112*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(spear_smi_id_table),
1113*4882a593Smuzhiyun 		.pm = &spear_smi_pm_ops,
1114*4882a593Smuzhiyun 	},
1115*4882a593Smuzhiyun 	.probe = spear_smi_probe,
1116*4882a593Smuzhiyun 	.remove = spear_smi_remove,
1117*4882a593Smuzhiyun };
1118*4882a593Smuzhiyun module_platform_driver(spear_smi_driver);
1119*4882a593Smuzhiyun 
1120*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1121*4882a593Smuzhiyun MODULE_AUTHOR("Ashish Priyadarshi, Shiraz Hashim <shiraz.linux.kernel@gmail.com>");
1122*4882a593Smuzhiyun MODULE_DESCRIPTION("MTD SMI driver for serial nor flash chips");
1123