blob: 4fe13dd535f8bff35421081788bb9f198cd3d87e [file] [log] [blame]
Huang Shijiee46ecda2014-02-24 18:37:42 +08001/*
2 * Freescale QuadSPI driver.
3 *
4 * Copyright (C) 2013 Freescale Semiconductor, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/interrupt.h>
14#include <linux/errno.h>
15#include <linux/platform_device.h>
16#include <linux/sched.h>
17#include <linux/delay.h>
18#include <linux/io.h>
19#include <linux/clk.h>
20#include <linux/err.h>
21#include <linux/of.h>
22#include <linux/of_device.h>
23#include <linux/timer.h>
24#include <linux/jiffies.h>
25#include <linux/completion.h>
26#include <linux/mtd/mtd.h>
27#include <linux/mtd/partitions.h>
28#include <linux/mtd/spi-nor.h>
Han Xu392d39c2015-05-13 14:40:57 -050029#include <linux/mutex.h>
Huang Shijiee46ecda2014-02-24 18:37:42 +080030
31/* The registers */
32#define QUADSPI_MCR 0x00
33#define QUADSPI_MCR_RESERVED_SHIFT 16
34#define QUADSPI_MCR_RESERVED_MASK (0xF << QUADSPI_MCR_RESERVED_SHIFT)
35#define QUADSPI_MCR_MDIS_SHIFT 14
36#define QUADSPI_MCR_MDIS_MASK (1 << QUADSPI_MCR_MDIS_SHIFT)
37#define QUADSPI_MCR_CLR_TXF_SHIFT 11
38#define QUADSPI_MCR_CLR_TXF_MASK (1 << QUADSPI_MCR_CLR_TXF_SHIFT)
39#define QUADSPI_MCR_CLR_RXF_SHIFT 10
40#define QUADSPI_MCR_CLR_RXF_MASK (1 << QUADSPI_MCR_CLR_RXF_SHIFT)
41#define QUADSPI_MCR_DDR_EN_SHIFT 7
42#define QUADSPI_MCR_DDR_EN_MASK (1 << QUADSPI_MCR_DDR_EN_SHIFT)
43#define QUADSPI_MCR_END_CFG_SHIFT 2
44#define QUADSPI_MCR_END_CFG_MASK (3 << QUADSPI_MCR_END_CFG_SHIFT)
45#define QUADSPI_MCR_SWRSTHD_SHIFT 1
46#define QUADSPI_MCR_SWRSTHD_MASK (1 << QUADSPI_MCR_SWRSTHD_SHIFT)
47#define QUADSPI_MCR_SWRSTSD_SHIFT 0
48#define QUADSPI_MCR_SWRSTSD_MASK (1 << QUADSPI_MCR_SWRSTSD_SHIFT)
49
50#define QUADSPI_IPCR 0x08
51#define QUADSPI_IPCR_SEQID_SHIFT 24
52#define QUADSPI_IPCR_SEQID_MASK (0xF << QUADSPI_IPCR_SEQID_SHIFT)
53
54#define QUADSPI_BUF0CR 0x10
55#define QUADSPI_BUF1CR 0x14
56#define QUADSPI_BUF2CR 0x18
57#define QUADSPI_BUFXCR_INVALID_MSTRID 0xe
58
59#define QUADSPI_BUF3CR 0x1c
60#define QUADSPI_BUF3CR_ALLMST_SHIFT 31
Allen Xu4e898ce2015-01-14 00:28:56 +080061#define QUADSPI_BUF3CR_ALLMST_MASK (1 << QUADSPI_BUF3CR_ALLMST_SHIFT)
62#define QUADSPI_BUF3CR_ADATSZ_SHIFT 8
63#define QUADSPI_BUF3CR_ADATSZ_MASK (0xFF << QUADSPI_BUF3CR_ADATSZ_SHIFT)
Huang Shijiee46ecda2014-02-24 18:37:42 +080064
65#define QUADSPI_BFGENCR 0x20
66#define QUADSPI_BFGENCR_PAR_EN_SHIFT 16
67#define QUADSPI_BFGENCR_PAR_EN_MASK (1 << (QUADSPI_BFGENCR_PAR_EN_SHIFT))
68#define QUADSPI_BFGENCR_SEQID_SHIFT 12
69#define QUADSPI_BFGENCR_SEQID_MASK (0xF << QUADSPI_BFGENCR_SEQID_SHIFT)
70
71#define QUADSPI_BUF0IND 0x30
72#define QUADSPI_BUF1IND 0x34
73#define QUADSPI_BUF2IND 0x38
74#define QUADSPI_SFAR 0x100
75
76#define QUADSPI_SMPR 0x108
77#define QUADSPI_SMPR_DDRSMP_SHIFT 16
78#define QUADSPI_SMPR_DDRSMP_MASK (7 << QUADSPI_SMPR_DDRSMP_SHIFT)
79#define QUADSPI_SMPR_FSDLY_SHIFT 6
80#define QUADSPI_SMPR_FSDLY_MASK (1 << QUADSPI_SMPR_FSDLY_SHIFT)
81#define QUADSPI_SMPR_FSPHS_SHIFT 5
82#define QUADSPI_SMPR_FSPHS_MASK (1 << QUADSPI_SMPR_FSPHS_SHIFT)
83#define QUADSPI_SMPR_HSENA_SHIFT 0
84#define QUADSPI_SMPR_HSENA_MASK (1 << QUADSPI_SMPR_HSENA_SHIFT)
85
86#define QUADSPI_RBSR 0x10c
87#define QUADSPI_RBSR_RDBFL_SHIFT 8
88#define QUADSPI_RBSR_RDBFL_MASK (0x3F << QUADSPI_RBSR_RDBFL_SHIFT)
89
90#define QUADSPI_RBCT 0x110
91#define QUADSPI_RBCT_WMRK_MASK 0x1F
92#define QUADSPI_RBCT_RXBRD_SHIFT 8
93#define QUADSPI_RBCT_RXBRD_USEIPS (0x1 << QUADSPI_RBCT_RXBRD_SHIFT)
94
95#define QUADSPI_TBSR 0x150
96#define QUADSPI_TBDR 0x154
97#define QUADSPI_SR 0x15c
98#define QUADSPI_SR_IP_ACC_SHIFT 1
99#define QUADSPI_SR_IP_ACC_MASK (0x1 << QUADSPI_SR_IP_ACC_SHIFT)
100#define QUADSPI_SR_AHB_ACC_SHIFT 2
101#define QUADSPI_SR_AHB_ACC_MASK (0x1 << QUADSPI_SR_AHB_ACC_SHIFT)
102
103#define QUADSPI_FR 0x160
104#define QUADSPI_FR_TFF_MASK 0x1
105
106#define QUADSPI_SFA1AD 0x180
107#define QUADSPI_SFA2AD 0x184
108#define QUADSPI_SFB1AD 0x188
109#define QUADSPI_SFB2AD 0x18c
110#define QUADSPI_RBDR 0x200
111
112#define QUADSPI_LUTKEY 0x300
113#define QUADSPI_LUTKEY_VALUE 0x5AF05AF0
114
115#define QUADSPI_LCKCR 0x304
116#define QUADSPI_LCKER_LOCK 0x1
117#define QUADSPI_LCKER_UNLOCK 0x2
118
119#define QUADSPI_RSER 0x164
120#define QUADSPI_RSER_TFIE (0x1 << 0)
121
122#define QUADSPI_LUT_BASE 0x310
123
124/*
125 * The definition of the LUT register shows below:
126 *
127 * ---------------------------------------------------
128 * | INSTR1 | PAD1 | OPRND1 | INSTR0 | PAD0 | OPRND0 |
129 * ---------------------------------------------------
130 */
131#define OPRND0_SHIFT 0
132#define PAD0_SHIFT 8
133#define INSTR0_SHIFT 10
134#define OPRND1_SHIFT 16
135
136/* Instruction set for the LUT register. */
137#define LUT_STOP 0
138#define LUT_CMD 1
139#define LUT_ADDR 2
140#define LUT_DUMMY 3
141#define LUT_MODE 4
142#define LUT_MODE2 5
143#define LUT_MODE4 6
144#define LUT_READ 7
145#define LUT_WRITE 8
146#define LUT_JMP_ON_CS 9
147#define LUT_ADDR_DDR 10
148#define LUT_MODE_DDR 11
149#define LUT_MODE2_DDR 12
150#define LUT_MODE4_DDR 13
151#define LUT_READ_DDR 14
152#define LUT_WRITE_DDR 15
153#define LUT_DATA_LEARN 16
154
155/*
156 * The PAD definitions for LUT register.
157 *
158 * The pad stands for the lines number of IO[0:3].
159 * For example, the Quad read need four IO lines, so you should
160 * set LUT_PAD4 which means we use four IO lines.
161 */
162#define LUT_PAD1 0
163#define LUT_PAD2 1
164#define LUT_PAD4 2
165
166/* Oprands for the LUT register. */
167#define ADDR24BIT 0x18
168#define ADDR32BIT 0x20
169
170/* Macros for constructing the LUT register. */
171#define LUT0(ins, pad, opr) \
172 (((opr) << OPRND0_SHIFT) | ((LUT_##pad) << PAD0_SHIFT) | \
173 ((LUT_##ins) << INSTR0_SHIFT))
174
175#define LUT1(ins, pad, opr) (LUT0(ins, pad, opr) << OPRND1_SHIFT)
176
177/* other macros for LUT register. */
178#define QUADSPI_LUT(x) (QUADSPI_LUT_BASE + (x) * 4)
179#define QUADSPI_LUT_NUM 64
180
181/* SEQID -- we can have 16 seqids at most. */
182#define SEQID_QUAD_READ 0
183#define SEQID_WREN 1
184#define SEQID_WRDI 2
185#define SEQID_RDSR 3
186#define SEQID_SE 4
187#define SEQID_CHIP_ERASE 5
188#define SEQID_PP 6
189#define SEQID_RDID 7
190#define SEQID_WRSR 8
191#define SEQID_RDCR 9
192#define SEQID_EN4B 10
193#define SEQID_BRWR 11
194
195enum fsl_qspi_devtype {
196 FSL_QUADSPI_VYBRID,
197 FSL_QUADSPI_IMX6SX,
198};
199
200struct fsl_qspi_devtype_data {
201 enum fsl_qspi_devtype devtype;
202 int rxfifo;
203 int txfifo;
Allen Xu4e898ce2015-01-14 00:28:56 +0800204 int ahb_buf_size;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800205};
206
207static struct fsl_qspi_devtype_data vybrid_data = {
208 .devtype = FSL_QUADSPI_VYBRID,
209 .rxfifo = 128,
Allen Xu4e898ce2015-01-14 00:28:56 +0800210 .txfifo = 64,
211 .ahb_buf_size = 1024
Huang Shijiee46ecda2014-02-24 18:37:42 +0800212};
213
214static struct fsl_qspi_devtype_data imx6sx_data = {
215 .devtype = FSL_QUADSPI_IMX6SX,
216 .rxfifo = 128,
Allen Xu4e898ce2015-01-14 00:28:56 +0800217 .txfifo = 512,
218 .ahb_buf_size = 1024
Huang Shijiee46ecda2014-02-24 18:37:42 +0800219};
220
221#define FSL_QSPI_MAX_CHIP 4
222struct fsl_qspi {
223 struct mtd_info mtd[FSL_QSPI_MAX_CHIP];
224 struct spi_nor nor[FSL_QSPI_MAX_CHIP];
225 void __iomem *iobase;
226 void __iomem *ahb_base; /* Used when read from AHB bus */
227 u32 memmap_phy;
228 struct clk *clk, *clk_en;
229 struct device *dev;
230 struct completion c;
231 struct fsl_qspi_devtype_data *devtype_data;
232 u32 nor_size;
233 u32 nor_num;
234 u32 clk_rate;
235 unsigned int chip_base_addr; /* We may support two chips. */
Fabio Estevamcfe4af32015-01-13 20:14:15 -0200236 bool has_second_chip;
Han Xu392d39c2015-05-13 14:40:57 -0500237 struct mutex lock;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800238};
239
240static inline int is_vybrid_qspi(struct fsl_qspi *q)
241{
242 return q->devtype_data->devtype == FSL_QUADSPI_VYBRID;
243}
244
245static inline int is_imx6sx_qspi(struct fsl_qspi *q)
246{
247 return q->devtype_data->devtype == FSL_QUADSPI_IMX6SX;
248}
249
250/*
251 * An IC bug makes us to re-arrange the 32-bit data.
252 * The following chips, such as IMX6SLX, have fixed this bug.
253 */
254static inline u32 fsl_qspi_endian_xchg(struct fsl_qspi *q, u32 a)
255{
256 return is_vybrid_qspi(q) ? __swab32(a) : a;
257}
258
259static inline void fsl_qspi_unlock_lut(struct fsl_qspi *q)
260{
261 writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
262 writel(QUADSPI_LCKER_UNLOCK, q->iobase + QUADSPI_LCKCR);
263}
264
265static inline void fsl_qspi_lock_lut(struct fsl_qspi *q)
266{
267 writel(QUADSPI_LUTKEY_VALUE, q->iobase + QUADSPI_LUTKEY);
268 writel(QUADSPI_LCKER_LOCK, q->iobase + QUADSPI_LCKCR);
269}
270
271static irqreturn_t fsl_qspi_irq_handler(int irq, void *dev_id)
272{
273 struct fsl_qspi *q = dev_id;
274 u32 reg;
275
276 /* clear interrupt */
277 reg = readl(q->iobase + QUADSPI_FR);
278 writel(reg, q->iobase + QUADSPI_FR);
279
280 if (reg & QUADSPI_FR_TFF_MASK)
281 complete(&q->c);
282
283 dev_dbg(q->dev, "QUADSPI_FR : 0x%.8x:0x%.8x\n", q->chip_base_addr, reg);
284 return IRQ_HANDLED;
285}
286
287static void fsl_qspi_init_lut(struct fsl_qspi *q)
288{
Brian Norrisa965d042014-04-10 15:49:38 -0700289 void __iomem *base = q->iobase;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800290 int rxfifo = q->devtype_data->rxfifo;
291 u32 lut_base;
292 u8 cmd, addrlen, dummy;
293 int i;
294
295 fsl_qspi_unlock_lut(q);
296
297 /* Clear all the LUT table */
298 for (i = 0; i < QUADSPI_LUT_NUM; i++)
299 writel(0, base + QUADSPI_LUT_BASE + i * 4);
300
301 /* Quad Read */
302 lut_base = SEQID_QUAD_READ * 4;
303
304 if (q->nor_size <= SZ_16M) {
Brian Norris58b89a12014-04-08 19:16:49 -0700305 cmd = SPINOR_OP_READ_1_1_4;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800306 addrlen = ADDR24BIT;
307 dummy = 8;
308 } else {
309 /* use the 4-byte address */
Brian Norris58b89a12014-04-08 19:16:49 -0700310 cmd = SPINOR_OP_READ_1_1_4;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800311 addrlen = ADDR32BIT;
312 dummy = 8;
313 }
314
315 writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
316 base + QUADSPI_LUT(lut_base));
317 writel(LUT0(DUMMY, PAD1, dummy) | LUT1(READ, PAD4, rxfifo),
318 base + QUADSPI_LUT(lut_base + 1));
319
320 /* Write enable */
321 lut_base = SEQID_WREN * 4;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700322 writel(LUT0(CMD, PAD1, SPINOR_OP_WREN), base + QUADSPI_LUT(lut_base));
Huang Shijiee46ecda2014-02-24 18:37:42 +0800323
324 /* Page Program */
325 lut_base = SEQID_PP * 4;
326
327 if (q->nor_size <= SZ_16M) {
Brian Norrisb02e7f32014-04-08 18:15:31 -0700328 cmd = SPINOR_OP_PP;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800329 addrlen = ADDR24BIT;
330 } else {
331 /* use the 4-byte address */
Brian Norrisb02e7f32014-04-08 18:15:31 -0700332 cmd = SPINOR_OP_PP;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800333 addrlen = ADDR32BIT;
334 }
335
336 writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
337 base + QUADSPI_LUT(lut_base));
338 writel(LUT0(WRITE, PAD1, 0), base + QUADSPI_LUT(lut_base + 1));
339
340 /* Read Status */
341 lut_base = SEQID_RDSR * 4;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700342 writel(LUT0(CMD, PAD1, SPINOR_OP_RDSR) | LUT1(READ, PAD1, 0x1),
Huang Shijiee46ecda2014-02-24 18:37:42 +0800343 base + QUADSPI_LUT(lut_base));
344
345 /* Erase a sector */
346 lut_base = SEQID_SE * 4;
347
348 if (q->nor_size <= SZ_16M) {
Brian Norrisb02e7f32014-04-08 18:15:31 -0700349 cmd = SPINOR_OP_SE;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800350 addrlen = ADDR24BIT;
351 } else {
352 /* use the 4-byte address */
Brian Norrisb02e7f32014-04-08 18:15:31 -0700353 cmd = SPINOR_OP_SE;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800354 addrlen = ADDR32BIT;
355 }
356
357 writel(LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen),
358 base + QUADSPI_LUT(lut_base));
359
360 /* Erase the whole chip */
361 lut_base = SEQID_CHIP_ERASE * 4;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700362 writel(LUT0(CMD, PAD1, SPINOR_OP_CHIP_ERASE),
Huang Shijiee46ecda2014-02-24 18:37:42 +0800363 base + QUADSPI_LUT(lut_base));
364
365 /* READ ID */
366 lut_base = SEQID_RDID * 4;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700367 writel(LUT0(CMD, PAD1, SPINOR_OP_RDID) | LUT1(READ, PAD1, 0x8),
Huang Shijiee46ecda2014-02-24 18:37:42 +0800368 base + QUADSPI_LUT(lut_base));
369
370 /* Write Register */
371 lut_base = SEQID_WRSR * 4;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700372 writel(LUT0(CMD, PAD1, SPINOR_OP_WRSR) | LUT1(WRITE, PAD1, 0x2),
Huang Shijiee46ecda2014-02-24 18:37:42 +0800373 base + QUADSPI_LUT(lut_base));
374
375 /* Read Configuration Register */
376 lut_base = SEQID_RDCR * 4;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700377 writel(LUT0(CMD, PAD1, SPINOR_OP_RDCR) | LUT1(READ, PAD1, 0x1),
Huang Shijiee46ecda2014-02-24 18:37:42 +0800378 base + QUADSPI_LUT(lut_base));
379
380 /* Write disable */
381 lut_base = SEQID_WRDI * 4;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700382 writel(LUT0(CMD, PAD1, SPINOR_OP_WRDI), base + QUADSPI_LUT(lut_base));
Huang Shijiee46ecda2014-02-24 18:37:42 +0800383
384 /* Enter 4 Byte Mode (Micron) */
385 lut_base = SEQID_EN4B * 4;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700386 writel(LUT0(CMD, PAD1, SPINOR_OP_EN4B), base + QUADSPI_LUT(lut_base));
Huang Shijiee46ecda2014-02-24 18:37:42 +0800387
388 /* Enter 4 Byte Mode (Spansion) */
389 lut_base = SEQID_BRWR * 4;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700390 writel(LUT0(CMD, PAD1, SPINOR_OP_BRWR), base + QUADSPI_LUT(lut_base));
Huang Shijiee46ecda2014-02-24 18:37:42 +0800391
392 fsl_qspi_lock_lut(q);
393}
394
395/* Get the SEQID for the command */
396static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd)
397{
398 switch (cmd) {
Brian Norris58b89a12014-04-08 19:16:49 -0700399 case SPINOR_OP_READ_1_1_4:
Huang Shijiee46ecda2014-02-24 18:37:42 +0800400 return SEQID_QUAD_READ;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700401 case SPINOR_OP_WREN:
Huang Shijiee46ecda2014-02-24 18:37:42 +0800402 return SEQID_WREN;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700403 case SPINOR_OP_WRDI:
Huang Shijiee46ecda2014-02-24 18:37:42 +0800404 return SEQID_WRDI;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700405 case SPINOR_OP_RDSR:
Huang Shijiee46ecda2014-02-24 18:37:42 +0800406 return SEQID_RDSR;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700407 case SPINOR_OP_SE:
Huang Shijiee46ecda2014-02-24 18:37:42 +0800408 return SEQID_SE;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700409 case SPINOR_OP_CHIP_ERASE:
Huang Shijiee46ecda2014-02-24 18:37:42 +0800410 return SEQID_CHIP_ERASE;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700411 case SPINOR_OP_PP:
Huang Shijiee46ecda2014-02-24 18:37:42 +0800412 return SEQID_PP;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700413 case SPINOR_OP_RDID:
Huang Shijiee46ecda2014-02-24 18:37:42 +0800414 return SEQID_RDID;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700415 case SPINOR_OP_WRSR:
Huang Shijiee46ecda2014-02-24 18:37:42 +0800416 return SEQID_WRSR;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700417 case SPINOR_OP_RDCR:
Huang Shijiee46ecda2014-02-24 18:37:42 +0800418 return SEQID_RDCR;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700419 case SPINOR_OP_EN4B:
Huang Shijiee46ecda2014-02-24 18:37:42 +0800420 return SEQID_EN4B;
Brian Norrisb02e7f32014-04-08 18:15:31 -0700421 case SPINOR_OP_BRWR:
Huang Shijiee46ecda2014-02-24 18:37:42 +0800422 return SEQID_BRWR;
423 default:
424 dev_err(q->dev, "Unsupported cmd 0x%.2x\n", cmd);
425 break;
426 }
427 return -EINVAL;
428}
429
430static int
431fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
432{
Brian Norrisa965d042014-04-10 15:49:38 -0700433 void __iomem *base = q->iobase;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800434 int seqid;
435 u32 reg, reg2;
436 int err;
437
438 init_completion(&q->c);
439 dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len:%d, cmd:%.2x\n",
440 q->chip_base_addr, addr, len, cmd);
441
442 /* save the reg */
443 reg = readl(base + QUADSPI_MCR);
444
445 writel(q->memmap_phy + q->chip_base_addr + addr, base + QUADSPI_SFAR);
446 writel(QUADSPI_RBCT_WMRK_MASK | QUADSPI_RBCT_RXBRD_USEIPS,
447 base + QUADSPI_RBCT);
448 writel(reg | QUADSPI_MCR_CLR_RXF_MASK, base + QUADSPI_MCR);
449
450 do {
451 reg2 = readl(base + QUADSPI_SR);
452 if (reg2 & (QUADSPI_SR_IP_ACC_MASK | QUADSPI_SR_AHB_ACC_MASK)) {
453 udelay(1);
454 dev_dbg(q->dev, "The controller is busy, 0x%x\n", reg2);
455 continue;
456 }
457 break;
458 } while (1);
459
460 /* trigger the LUT now */
461 seqid = fsl_qspi_get_seqid(q, cmd);
462 writel((seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, base + QUADSPI_IPCR);
463
464 /* Wait for the interrupt. */
Nicholas Mc Guire219a8d12015-02-01 06:15:46 -0500465 if (!wait_for_completion_timeout(&q->c, msecs_to_jiffies(1000))) {
Huang Shijiee46ecda2014-02-24 18:37:42 +0800466 dev_err(q->dev,
467 "cmd 0x%.2x timeout, addr@%.8x, FR:0x%.8x, SR:0x%.8x\n",
468 cmd, addr, readl(base + QUADSPI_FR),
469 readl(base + QUADSPI_SR));
470 err = -ETIMEDOUT;
471 } else {
472 err = 0;
473 }
474
475 /* restore the MCR */
476 writel(reg, base + QUADSPI_MCR);
477
478 return err;
479}
480
481/* Read out the data from the QUADSPI_RBDR buffer registers. */
482static void fsl_qspi_read_data(struct fsl_qspi *q, int len, u8 *rxbuf)
483{
484 u32 tmp;
485 int i = 0;
486
487 while (len > 0) {
488 tmp = readl(q->iobase + QUADSPI_RBDR + i * 4);
489 tmp = fsl_qspi_endian_xchg(q, tmp);
490 dev_dbg(q->dev, "chip addr:0x%.8x, rcv:0x%.8x\n",
491 q->chip_base_addr, tmp);
492
493 if (len >= 4) {
494 *((u32 *)rxbuf) = tmp;
495 rxbuf += 4;
496 } else {
497 memcpy(rxbuf, &tmp, len);
498 break;
499 }
500
501 len -= 4;
502 i++;
503 }
504}
505
506/*
507 * If we have changed the content of the flash by writing or erasing,
508 * we need to invalidate the AHB buffer. If we do not do so, we may read out
509 * the wrong data. The spec tells us reset the AHB domain and Serial Flash
510 * domain at the same time.
511 */
512static inline void fsl_qspi_invalid(struct fsl_qspi *q)
513{
514 u32 reg;
515
516 reg = readl(q->iobase + QUADSPI_MCR);
517 reg |= QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK;
518 writel(reg, q->iobase + QUADSPI_MCR);
519
520 /*
521 * The minimum delay : 1 AHB + 2 SFCK clocks.
522 * Delay 1 us is enough.
523 */
524 udelay(1);
525
526 reg &= ~(QUADSPI_MCR_SWRSTHD_MASK | QUADSPI_MCR_SWRSTSD_MASK);
527 writel(reg, q->iobase + QUADSPI_MCR);
528}
529
530static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor,
531 u8 opcode, unsigned int to, u32 *txbuf,
532 unsigned count, size_t *retlen)
533{
534 int ret, i, j;
535 u32 tmp;
536
537 dev_dbg(q->dev, "to 0x%.8x:0x%.8x, len : %d\n",
538 q->chip_base_addr, to, count);
539
540 /* clear the TX FIFO. */
541 tmp = readl(q->iobase + QUADSPI_MCR);
542 writel(tmp | QUADSPI_MCR_CLR_RXF_MASK, q->iobase + QUADSPI_MCR);
543
544 /* fill the TX data to the FIFO */
545 for (j = 0, i = ((count + 3) / 4); j < i; j++) {
546 tmp = fsl_qspi_endian_xchg(q, *txbuf);
547 writel(tmp, q->iobase + QUADSPI_TBDR);
548 txbuf++;
549 }
550
551 /* Trigger it */
552 ret = fsl_qspi_runcmd(q, opcode, to, count);
553
554 if (ret == 0 && retlen)
555 *retlen += count;
556
557 return ret;
558}
559
560static void fsl_qspi_set_map_addr(struct fsl_qspi *q)
561{
562 int nor_size = q->nor_size;
563 void __iomem *base = q->iobase;
564
565 writel(nor_size + q->memmap_phy, base + QUADSPI_SFA1AD);
566 writel(nor_size * 2 + q->memmap_phy, base + QUADSPI_SFA2AD);
567 writel(nor_size * 3 + q->memmap_phy, base + QUADSPI_SFB1AD);
568 writel(nor_size * 4 + q->memmap_phy, base + QUADSPI_SFB2AD);
569}
570
571/*
572 * There are two different ways to read out the data from the flash:
573 * the "IP Command Read" and the "AHB Command Read".
574 *
575 * The IC guy suggests we use the "AHB Command Read" which is faster
576 * then the "IP Command Read". (What's more is that there is a bug in
577 * the "IP Command Read" in the Vybrid.)
578 *
579 * After we set up the registers for the "AHB Command Read", we can use
580 * the memcpy to read the data directly. A "missed" access to the buffer
581 * causes the controller to clear the buffer, and use the sequence pointed
582 * by the QUADSPI_BFGENCR[SEQID] to initiate a read from the flash.
583 */
584static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
585{
586 void __iomem *base = q->iobase;
587 int seqid;
588
589 /* AHB configuration for access buffer 0/1/2 .*/
590 writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR);
591 writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR);
592 writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR);
Allen Xu4e898ce2015-01-14 00:28:56 +0800593 /*
594 * Set ADATSZ with the maximum AHB buffer size to improve the
595 * read performance.
596 */
597 writel(QUADSPI_BUF3CR_ALLMST_MASK | ((q->devtype_data->ahb_buf_size / 8)
598 << QUADSPI_BUF3CR_ADATSZ_SHIFT), base + QUADSPI_BUF3CR);
Huang Shijiee46ecda2014-02-24 18:37:42 +0800599
600 /* We only use the buffer3 */
601 writel(0, base + QUADSPI_BUF0IND);
602 writel(0, base + QUADSPI_BUF1IND);
603 writel(0, base + QUADSPI_BUF2IND);
604
605 /* Set the default lut sequence for AHB Read. */
606 seqid = fsl_qspi_get_seqid(q, q->nor[0].read_opcode);
607 writel(seqid << QUADSPI_BFGENCR_SEQID_SHIFT,
608 q->iobase + QUADSPI_BFGENCR);
609}
610
611/* We use this function to do some basic init for spi_nor_scan(). */
612static int fsl_qspi_nor_setup(struct fsl_qspi *q)
613{
614 void __iomem *base = q->iobase;
615 u32 reg;
616 int ret;
617
618 /* the default frequency, we will change it in the future.*/
619 ret = clk_set_rate(q->clk, 66000000);
620 if (ret)
621 return ret;
622
623 /* Init the LUT table. */
624 fsl_qspi_init_lut(q);
625
626 /* Disable the module */
627 writel(QUADSPI_MCR_MDIS_MASK | QUADSPI_MCR_RESERVED_MASK,
628 base + QUADSPI_MCR);
629
630 reg = readl(base + QUADSPI_SMPR);
631 writel(reg & ~(QUADSPI_SMPR_FSDLY_MASK
632 | QUADSPI_SMPR_FSPHS_MASK
633 | QUADSPI_SMPR_HSENA_MASK
634 | QUADSPI_SMPR_DDRSMP_MASK), base + QUADSPI_SMPR);
635
636 /* Enable the module */
637 writel(QUADSPI_MCR_RESERVED_MASK | QUADSPI_MCR_END_CFG_MASK,
638 base + QUADSPI_MCR);
639
640 /* enable the interrupt */
641 writel(QUADSPI_RSER_TFIE, q->iobase + QUADSPI_RSER);
642
643 return 0;
644}
645
646static int fsl_qspi_nor_setup_last(struct fsl_qspi *q)
647{
648 unsigned long rate = q->clk_rate;
649 int ret;
650
651 if (is_imx6sx_qspi(q))
652 rate *= 4;
653
654 ret = clk_set_rate(q->clk, rate);
655 if (ret)
656 return ret;
657
658 /* Init the LUT table again. */
659 fsl_qspi_init_lut(q);
660
661 /* Init for AHB read */
662 fsl_qspi_init_abh_read(q);
663
664 return 0;
665}
666
Fabian Frederick66610442015-03-16 20:20:28 +0100667static const struct of_device_id fsl_qspi_dt_ids[] = {
Huang Shijiee46ecda2014-02-24 18:37:42 +0800668 { .compatible = "fsl,vf610-qspi", .data = (void *)&vybrid_data, },
669 { .compatible = "fsl,imx6sx-qspi", .data = (void *)&imx6sx_data, },
670 { /* sentinel */ }
671};
672MODULE_DEVICE_TABLE(of, fsl_qspi_dt_ids);
673
674static void fsl_qspi_set_base_addr(struct fsl_qspi *q, struct spi_nor *nor)
675{
676 q->chip_base_addr = q->nor_size * (nor - q->nor);
677}
678
679static int fsl_qspi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
680{
681 int ret;
682 struct fsl_qspi *q = nor->priv;
683
684 ret = fsl_qspi_runcmd(q, opcode, 0, len);
685 if (ret)
686 return ret;
687
688 fsl_qspi_read_data(q, len, buf);
689 return 0;
690}
691
692static int fsl_qspi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
693 int write_enable)
694{
695 struct fsl_qspi *q = nor->priv;
696 int ret;
697
698 if (!buf) {
699 ret = fsl_qspi_runcmd(q, opcode, 0, 1);
700 if (ret)
701 return ret;
702
Brian Norrisb02e7f32014-04-08 18:15:31 -0700703 if (opcode == SPINOR_OP_CHIP_ERASE)
Huang Shijiee46ecda2014-02-24 18:37:42 +0800704 fsl_qspi_invalid(q);
705
706 } else if (len > 0) {
707 ret = fsl_qspi_nor_write(q, nor, opcode, 0,
708 (u32 *)buf, len, NULL);
709 } else {
710 dev_err(q->dev, "invalid cmd %d\n", opcode);
711 ret = -EINVAL;
712 }
713
714 return ret;
715}
716
717static void fsl_qspi_write(struct spi_nor *nor, loff_t to,
718 size_t len, size_t *retlen, const u_char *buf)
719{
720 struct fsl_qspi *q = nor->priv;
721
722 fsl_qspi_nor_write(q, nor, nor->program_opcode, to,
723 (u32 *)buf, len, retlen);
724
725 /* invalid the data in the AHB buffer. */
726 fsl_qspi_invalid(q);
727}
728
729static int fsl_qspi_read(struct spi_nor *nor, loff_t from,
730 size_t len, size_t *retlen, u_char *buf)
731{
732 struct fsl_qspi *q = nor->priv;
733 u8 cmd = nor->read_opcode;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800734
735 dev_dbg(q->dev, "cmd [%x],read from (0x%p, 0x%.8x, 0x%.8x),len:%d\n",
736 cmd, q->ahb_base, q->chip_base_addr, (unsigned int)from, len);
737
Huang Shijiee46ecda2014-02-24 18:37:42 +0800738 /* Read out the data directly from the AHB buffer.*/
739 memcpy(buf, q->ahb_base + q->chip_base_addr + from, len);
740
741 *retlen += len;
742 return 0;
743}
744
745static int fsl_qspi_erase(struct spi_nor *nor, loff_t offs)
746{
747 struct fsl_qspi *q = nor->priv;
748 int ret;
749
750 dev_dbg(nor->dev, "%dKiB at 0x%08x:0x%08x\n",
751 nor->mtd->erasesize / 1024, q->chip_base_addr, (u32)offs);
752
Huang Shijiee46ecda2014-02-24 18:37:42 +0800753 ret = fsl_qspi_runcmd(q, nor->erase_opcode, offs, 0);
754 if (ret)
755 return ret;
756
757 fsl_qspi_invalid(q);
758 return 0;
759}
760
761static int fsl_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
762{
763 struct fsl_qspi *q = nor->priv;
764 int ret;
765
Han Xu392d39c2015-05-13 14:40:57 -0500766 mutex_lock(&q->lock);
Huang Shijiee46ecda2014-02-24 18:37:42 +0800767 ret = clk_enable(q->clk_en);
768 if (ret)
Han Xu392d39c2015-05-13 14:40:57 -0500769 goto err_mutex;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800770
771 ret = clk_enable(q->clk);
Han Xu392d39c2015-05-13 14:40:57 -0500772 if (ret)
773 goto err_clk;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800774
775 fsl_qspi_set_base_addr(q, nor);
776 return 0;
Han Xu392d39c2015-05-13 14:40:57 -0500777
778err_clk:
779 clk_disable(q->clk_en);
780err_mutex:
781 mutex_unlock(&q->lock);
782
783 return ret;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800784}
785
786static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
787{
788 struct fsl_qspi *q = nor->priv;
789
790 clk_disable(q->clk);
791 clk_disable(q->clk_en);
Han Xu392d39c2015-05-13 14:40:57 -0500792 mutex_unlock(&q->lock);
Huang Shijiee46ecda2014-02-24 18:37:42 +0800793}
794
795static int fsl_qspi_probe(struct platform_device *pdev)
796{
797 struct device_node *np = pdev->dev.of_node;
798 struct mtd_part_parser_data ppdata;
799 struct device *dev = &pdev->dev;
800 struct fsl_qspi *q;
801 struct resource *res;
802 struct spi_nor *nor;
803 struct mtd_info *mtd;
804 int ret, i = 0;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800805 const struct of_device_id *of_id =
806 of_match_device(fsl_qspi_dt_ids, &pdev->dev);
807
808 q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL);
809 if (!q)
810 return -ENOMEM;
811
812 q->nor_num = of_get_child_count(dev->of_node);
813 if (!q->nor_num || q->nor_num > FSL_QSPI_MAX_CHIP)
814 return -ENODEV;
815
816 /* find the resources */
817 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI");
818 q->iobase = devm_ioremap_resource(dev, res);
Fabio Estevamb1ab4742015-01-22 22:43:07 -0200819 if (IS_ERR(q->iobase))
820 return PTR_ERR(q->iobase);
Huang Shijiee46ecda2014-02-24 18:37:42 +0800821
822 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
823 "QuadSPI-memory");
824 q->ahb_base = devm_ioremap_resource(dev, res);
Fabio Estevamb1ab4742015-01-22 22:43:07 -0200825 if (IS_ERR(q->ahb_base))
826 return PTR_ERR(q->ahb_base);
827
Huang Shijiee46ecda2014-02-24 18:37:42 +0800828 q->memmap_phy = res->start;
829
830 /* find the clocks */
831 q->clk_en = devm_clk_get(dev, "qspi_en");
Fabio Estevamb1ab4742015-01-22 22:43:07 -0200832 if (IS_ERR(q->clk_en))
833 return PTR_ERR(q->clk_en);
Huang Shijiee46ecda2014-02-24 18:37:42 +0800834
835 q->clk = devm_clk_get(dev, "qspi");
Fabio Estevamb1ab4742015-01-22 22:43:07 -0200836 if (IS_ERR(q->clk))
837 return PTR_ERR(q->clk);
Huang Shijiee46ecda2014-02-24 18:37:42 +0800838
839 ret = clk_prepare_enable(q->clk_en);
840 if (ret) {
Fabio Estevamdc6525c2015-02-09 10:07:19 -0200841 dev_err(dev, "cannot enable the qspi_en clock: %d\n", ret);
Fabio Estevamb1ab4742015-01-22 22:43:07 -0200842 return ret;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800843 }
844
845 ret = clk_prepare_enable(q->clk);
846 if (ret) {
Fabio Estevamdc6525c2015-02-09 10:07:19 -0200847 dev_err(dev, "cannot enable the qspi clock: %d\n", ret);
Fabio Estevam77adc082014-10-17 17:14:01 -0300848 goto clk_failed;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800849 }
850
851 /* find the irq */
852 ret = platform_get_irq(pdev, 0);
853 if (ret < 0) {
Fabio Estevamdc6525c2015-02-09 10:07:19 -0200854 dev_err(dev, "failed to get the irq: %d\n", ret);
Huang Shijiee46ecda2014-02-24 18:37:42 +0800855 goto irq_failed;
856 }
857
858 ret = devm_request_irq(dev, ret,
859 fsl_qspi_irq_handler, 0, pdev->name, q);
860 if (ret) {
Fabio Estevamdc6525c2015-02-09 10:07:19 -0200861 dev_err(dev, "failed to request irq: %d\n", ret);
Huang Shijiee46ecda2014-02-24 18:37:42 +0800862 goto irq_failed;
863 }
864
865 q->dev = dev;
866 q->devtype_data = (struct fsl_qspi_devtype_data *)of_id->data;
867 platform_set_drvdata(pdev, q);
868
869 ret = fsl_qspi_nor_setup(q);
870 if (ret)
871 goto irq_failed;
872
873 if (of_get_property(np, "fsl,qspi-has-second-chip", NULL))
Fabio Estevamcfe4af32015-01-13 20:14:15 -0200874 q->has_second_chip = true;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800875
Han Xu392d39c2015-05-13 14:40:57 -0500876 mutex_init(&q->lock);
877
Huang Shijiee46ecda2014-02-24 18:37:42 +0800878 /* iterate the subnodes. */
879 for_each_available_child_of_node(dev->of_node, np) {
Huang Shijiee46ecda2014-02-24 18:37:42 +0800880 char modalias[40];
881
882 /* skip the holes */
Fabio Estevamcfe4af32015-01-13 20:14:15 -0200883 if (!q->has_second_chip)
Huang Shijiee46ecda2014-02-24 18:37:42 +0800884 i *= 2;
885
886 nor = &q->nor[i];
887 mtd = &q->mtd[i];
888
889 nor->mtd = mtd;
890 nor->dev = dev;
891 nor->priv = q;
892 mtd->priv = nor;
893
894 /* fill the hooks */
895 nor->read_reg = fsl_qspi_read_reg;
896 nor->write_reg = fsl_qspi_write_reg;
897 nor->read = fsl_qspi_read;
898 nor->write = fsl_qspi_write;
899 nor->erase = fsl_qspi_erase;
900
901 nor->prepare = fsl_qspi_prep;
902 nor->unprepare = fsl_qspi_unprep;
903
Fabio Estevamb26171e2014-10-17 15:31:08 -0300904 ret = of_modalias_node(np, modalias, sizeof(modalias));
905 if (ret < 0)
Han Xu392d39c2015-05-13 14:40:57 -0500906 goto mutex_failed;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800907
Huang Shijiee46ecda2014-02-24 18:37:42 +0800908 ret = of_property_read_u32(np, "spi-max-frequency",
909 &q->clk_rate);
910 if (ret < 0)
Han Xu392d39c2015-05-13 14:40:57 -0500911 goto mutex_failed;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800912
913 /* set the chip address for READID */
914 fsl_qspi_set_base_addr(q, nor);
915
Ben Hutchings70f3ce02014-09-29 11:47:54 +0200916 ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD);
Huang Shijiee46ecda2014-02-24 18:37:42 +0800917 if (ret)
Han Xu392d39c2015-05-13 14:40:57 -0500918 goto mutex_failed;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800919
920 ppdata.of_node = np;
921 ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
922 if (ret)
Han Xu392d39c2015-05-13 14:40:57 -0500923 goto mutex_failed;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800924
925 /* Set the correct NOR size now. */
926 if (q->nor_size == 0) {
927 q->nor_size = mtd->size;
928
929 /* Map the SPI NOR to accessiable address */
930 fsl_qspi_set_map_addr(q);
931 }
932
933 /*
934 * The TX FIFO is 64 bytes in the Vybrid, but the Page Program
935 * may writes 265 bytes per time. The write is working in the
936 * unit of the TX FIFO, not in the unit of the SPI NOR's page
937 * size.
938 *
939 * So shrink the spi_nor->page_size if it is larger then the
940 * TX FIFO.
941 */
942 if (nor->page_size > q->devtype_data->txfifo)
943 nor->page_size = q->devtype_data->txfifo;
944
945 i++;
946 }
947
948 /* finish the rest init. */
949 ret = fsl_qspi_nor_setup_last(q);
950 if (ret)
951 goto last_init_failed;
952
953 clk_disable(q->clk);
954 clk_disable(q->clk_en);
Huang Shijiee46ecda2014-02-24 18:37:42 +0800955 return 0;
956
957last_init_failed:
Fabio Estevamcfe4af32015-01-13 20:14:15 -0200958 for (i = 0; i < q->nor_num; i++) {
959 /* skip the holes */
960 if (!q->has_second_chip)
961 i *= 2;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800962 mtd_device_unregister(&q->mtd[i]);
Fabio Estevamcfe4af32015-01-13 20:14:15 -0200963 }
Han Xu392d39c2015-05-13 14:40:57 -0500964mutex_failed:
965 mutex_destroy(&q->lock);
Huang Shijiee46ecda2014-02-24 18:37:42 +0800966irq_failed:
967 clk_disable_unprepare(q->clk);
Fabio Estevam77adc082014-10-17 17:14:01 -0300968clk_failed:
Huang Shijiee46ecda2014-02-24 18:37:42 +0800969 clk_disable_unprepare(q->clk_en);
Huang Shijiee46ecda2014-02-24 18:37:42 +0800970 return ret;
971}
972
973static int fsl_qspi_remove(struct platform_device *pdev)
974{
975 struct fsl_qspi *q = platform_get_drvdata(pdev);
976 int i;
977
Fabio Estevamcfe4af32015-01-13 20:14:15 -0200978 for (i = 0; i < q->nor_num; i++) {
979 /* skip the holes */
980 if (!q->has_second_chip)
981 i *= 2;
Huang Shijiee46ecda2014-02-24 18:37:42 +0800982 mtd_device_unregister(&q->mtd[i]);
Fabio Estevamcfe4af32015-01-13 20:14:15 -0200983 }
Huang Shijiee46ecda2014-02-24 18:37:42 +0800984
985 /* disable the hardware */
986 writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
987 writel(0x0, q->iobase + QUADSPI_RSER);
988
Han Xu392d39c2015-05-13 14:40:57 -0500989 mutex_destroy(&q->lock);
Huang Shijiee46ecda2014-02-24 18:37:42 +0800990 clk_unprepare(q->clk);
991 clk_unprepare(q->clk_en);
992 return 0;
993}
994
Allen Xu45c6a0c2015-01-13 04:56:40 +0800995static int fsl_qspi_suspend(struct platform_device *pdev, pm_message_t state)
996{
997 return 0;
998}
999
1000static int fsl_qspi_resume(struct platform_device *pdev)
1001{
1002 struct fsl_qspi *q = platform_get_drvdata(pdev);
1003
1004 fsl_qspi_nor_setup(q);
1005 fsl_qspi_set_map_addr(q);
1006 fsl_qspi_nor_setup_last(q);
1007
1008 return 0;
1009}
1010
Huang Shijiee46ecda2014-02-24 18:37:42 +08001011static struct platform_driver fsl_qspi_driver = {
1012 .driver = {
1013 .name = "fsl-quadspi",
1014 .bus = &platform_bus_type,
Huang Shijiee46ecda2014-02-24 18:37:42 +08001015 .of_match_table = fsl_qspi_dt_ids,
1016 },
1017 .probe = fsl_qspi_probe,
1018 .remove = fsl_qspi_remove,
Allen Xu45c6a0c2015-01-13 04:56:40 +08001019 .suspend = fsl_qspi_suspend,
1020 .resume = fsl_qspi_resume,
Huang Shijiee46ecda2014-02-24 18:37:42 +08001021};
1022module_platform_driver(fsl_qspi_driver);
1023
1024MODULE_DESCRIPTION("Freescale QuadSPI Controller Driver");
1025MODULE_AUTHOR("Freescale Semiconductor Inc.");
1026MODULE_LICENSE("GPL v2");