141a1c9ecSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2505a1495SSourav Poddar /*
3505a1495SSourav Poddar * TI QSPI driver
4505a1495SSourav Poddar *
53ea4eac3SAlexander A. Klimov * Copyright (C) 2013 Texas Instruments Incorporated - https://www.ti.com
6505a1495SSourav Poddar * Author: Sourav Poddar <sourav.poddar@ti.com>
7505a1495SSourav Poddar */
8505a1495SSourav Poddar
9505a1495SSourav Poddar #include <linux/kernel.h>
10505a1495SSourav Poddar #include <linux/init.h>
11505a1495SSourav Poddar #include <linux/interrupt.h>
12505a1495SSourav Poddar #include <linux/module.h>
13505a1495SSourav Poddar #include <linux/device.h>
14505a1495SSourav Poddar #include <linux/delay.h>
15505a1495SSourav Poddar #include <linux/dma-mapping.h>
16505a1495SSourav Poddar #include <linux/dmaengine.h>
17505a1495SSourav Poddar #include <linux/omap-dma.h>
18505a1495SSourav Poddar #include <linux/platform_device.h>
19505a1495SSourav Poddar #include <linux/err.h>
20505a1495SSourav Poddar #include <linux/clk.h>
21505a1495SSourav Poddar #include <linux/io.h>
22505a1495SSourav Poddar #include <linux/slab.h>
23505a1495SSourav Poddar #include <linux/pm_runtime.h>
24505a1495SSourav Poddar #include <linux/of.h>
25505a1495SSourav Poddar #include <linux/pinctrl/consumer.h>
264dea6c9bSVignesh R #include <linux/mfd/syscon.h>
274dea6c9bSVignesh R #include <linux/regmap.h>
28c687c46eSVignesh R #include <linux/sizes.h>
29505a1495SSourav Poddar
30505a1495SSourav Poddar #include <linux/spi/spi.h>
31b95cb394SBoris Brezillon #include <linux/spi/spi-mem.h>
32505a1495SSourav Poddar
33505a1495SSourav Poddar struct ti_qspi_regs {
34505a1495SSourav Poddar u32 clkctrl;
35505a1495SSourav Poddar };
36505a1495SSourav Poddar
37505a1495SSourav Poddar struct ti_qspi {
385720ec0aSVignesh R struct completion transfer_complete;
395720ec0aSVignesh R
40505a1495SSourav Poddar /* list synchronization */
41505a1495SSourav Poddar struct mutex list_lock;
42505a1495SSourav Poddar
43505a1495SSourav Poddar struct spi_master *master;
44505a1495SSourav Poddar void __iomem *base;
456b3938aeSSourav Poddar void __iomem *mmap_base;
46b95cb394SBoris Brezillon size_t mmap_size;
474dea6c9bSVignesh R struct regmap *ctrl_base;
484dea6c9bSVignesh R unsigned int ctrl_reg;
49505a1495SSourav Poddar struct clk *fclk;
50505a1495SSourav Poddar struct device *dev;
51505a1495SSourav Poddar
52505a1495SSourav Poddar struct ti_qspi_regs ctx_reg;
53505a1495SSourav Poddar
545720ec0aSVignesh R dma_addr_t mmap_phys_base;
55c687c46eSVignesh R dma_addr_t rx_bb_dma_addr;
56c687c46eSVignesh R void *rx_bb_addr;
575720ec0aSVignesh R struct dma_chan *rx_chan;
585720ec0aSVignesh R
59505a1495SSourav Poddar u32 cmd;
60505a1495SSourav Poddar u32 dc;
616b3938aeSSourav Poddar
624dea6c9bSVignesh R bool mmap_enabled;
63c52c91bbSVignesh Raghavendra int current_cs;
64505a1495SSourav Poddar };
65505a1495SSourav Poddar
66505a1495SSourav Poddar #define QSPI_PID (0x0)
67505a1495SSourav Poddar #define QSPI_SYSCONFIG (0x10)
68505a1495SSourav Poddar #define QSPI_SPI_CLOCK_CNTRL_REG (0x40)
69505a1495SSourav Poddar #define QSPI_SPI_DC_REG (0x44)
70505a1495SSourav Poddar #define QSPI_SPI_CMD_REG (0x48)
71505a1495SSourav Poddar #define QSPI_SPI_STATUS_REG (0x4c)
72505a1495SSourav Poddar #define QSPI_SPI_DATA_REG (0x50)
734dea6c9bSVignesh R #define QSPI_SPI_SETUP_REG(n) ((0x54 + 4 * n))
74505a1495SSourav Poddar #define QSPI_SPI_SWITCH_REG (0x64)
75505a1495SSourav Poddar #define QSPI_SPI_DATA_REG_1 (0x68)
76505a1495SSourav Poddar #define QSPI_SPI_DATA_REG_2 (0x6c)
77505a1495SSourav Poddar #define QSPI_SPI_DATA_REG_3 (0x70)
78505a1495SSourav Poddar
79505a1495SSourav Poddar #define QSPI_COMPLETION_TIMEOUT msecs_to_jiffies(2000)
80505a1495SSourav Poddar
81505a1495SSourav Poddar /* Clock Control */
82505a1495SSourav Poddar #define QSPI_CLK_EN (1 << 31)
83505a1495SSourav Poddar #define QSPI_CLK_DIV_MAX 0xffff
84505a1495SSourav Poddar
85505a1495SSourav Poddar /* Command */
86505a1495SSourav Poddar #define QSPI_EN_CS(n) (n << 28)
87505a1495SSourav Poddar #define QSPI_WLEN(n) ((n - 1) << 19)
88505a1495SSourav Poddar #define QSPI_3_PIN (1 << 18)
89505a1495SSourav Poddar #define QSPI_RD_SNGL (1 << 16)
90505a1495SSourav Poddar #define QSPI_WR_SNGL (2 << 16)
91505a1495SSourav Poddar #define QSPI_RD_DUAL (3 << 16)
92505a1495SSourav Poddar #define QSPI_RD_QUAD (7 << 16)
93505a1495SSourav Poddar #define QSPI_INVAL (4 << 16)
94505a1495SSourav Poddar #define QSPI_FLEN(n) ((n - 1) << 0)
95f682c4ffSVignesh R #define QSPI_WLEN_MAX_BITS 128
96f682c4ffSVignesh R #define QSPI_WLEN_MAX_BYTES 16
97ea1b60fbSBen Hutchings #define QSPI_WLEN_MASK QSPI_WLEN(QSPI_WLEN_MAX_BITS)
98505a1495SSourav Poddar
99505a1495SSourav Poddar /* STATUS REGISTER */
10000611047SMugunthan V N #define BUSY 0x01
101505a1495SSourav Poddar #define WC 0x02
102505a1495SSourav Poddar
103505a1495SSourav Poddar /* Device Control */
104505a1495SSourav Poddar #define QSPI_DD(m, n) (m << (3 + n * 8))
105505a1495SSourav Poddar #define QSPI_CKPHA(n) (1 << (2 + n * 8))
106505a1495SSourav Poddar #define QSPI_CSPOL(n) (1 << (1 + n * 8))
107505a1495SSourav Poddar #define QSPI_CKPOL(n) (1 << (n * 8))
108505a1495SSourav Poddar
109505a1495SSourav Poddar #define QSPI_FRAME 4096
110505a1495SSourav Poddar
111505a1495SSourav Poddar #define QSPI_AUTOSUSPEND_TIMEOUT 2000
112505a1495SSourav Poddar
1134dea6c9bSVignesh R #define MEM_CS_EN(n) ((n + 1) << 8)
1144dea6c9bSVignesh R #define MEM_CS_MASK (7 << 8)
1154dea6c9bSVignesh R
1164dea6c9bSVignesh R #define MM_SWITCH 0x1
1174dea6c9bSVignesh R
1184dea6c9bSVignesh R #define QSPI_SETUP_RD_NORMAL (0x0 << 12)
1194dea6c9bSVignesh R #define QSPI_SETUP_RD_DUAL (0x1 << 12)
1204dea6c9bSVignesh R #define QSPI_SETUP_RD_QUAD (0x3 << 12)
1214dea6c9bSVignesh R #define QSPI_SETUP_ADDR_SHIFT 8
1224dea6c9bSVignesh R #define QSPI_SETUP_DUMMY_SHIFT 10
1234dea6c9bSVignesh R
124c687c46eSVignesh R #define QSPI_DMA_BUFFER_SIZE SZ_64K
125c687c46eSVignesh R
ti_qspi_read(struct ti_qspi * qspi,unsigned long reg)126505a1495SSourav Poddar static inline unsigned long ti_qspi_read(struct ti_qspi *qspi,
127505a1495SSourav Poddar unsigned long reg)
128505a1495SSourav Poddar {
129505a1495SSourav Poddar return readl(qspi->base + reg);
130505a1495SSourav Poddar }
131505a1495SSourav Poddar
ti_qspi_write(struct ti_qspi * qspi,unsigned long val,unsigned long reg)132505a1495SSourav Poddar static inline void ti_qspi_write(struct ti_qspi *qspi,
133505a1495SSourav Poddar unsigned long val, unsigned long reg)
134505a1495SSourav Poddar {
135505a1495SSourav Poddar writel(val, qspi->base + reg);
136505a1495SSourav Poddar }
137505a1495SSourav Poddar
ti_qspi_setup(struct spi_device * spi)138505a1495SSourav Poddar static int ti_qspi_setup(struct spi_device *spi)
139505a1495SSourav Poddar {
140505a1495SSourav Poddar struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
1418d0b5128SAtsushi Nemoto int ret;
142505a1495SSourav Poddar
143505a1495SSourav Poddar if (spi->master->busy) {
14477cca63aSColin Ian King dev_dbg(qspi->dev, "master busy doing other transfers\n");
145505a1495SSourav Poddar return -EBUSY;
146505a1495SSourav Poddar }
147505a1495SSourav Poddar
1488d0b5128SAtsushi Nemoto if (!qspi->master->max_speed_hz) {
149505a1495SSourav Poddar dev_err(qspi->dev, "spi max frequency not defined\n");
150505a1495SSourav Poddar return -EINVAL;
151505a1495SSourav Poddar }
152505a1495SSourav Poddar
1538d0b5128SAtsushi Nemoto spi->max_speed_hz = min(spi->max_speed_hz, qspi->master->max_speed_hz);
154505a1495SSourav Poddar
155c03ae487SMinghao Chi ret = pm_runtime_resume_and_get(qspi->dev);
15605b96675SSourav Poddar if (ret < 0) {
157505a1495SSourav Poddar dev_err(qspi->dev, "pm_runtime_get_sync() failed\n");
158505a1495SSourav Poddar return ret;
159505a1495SSourav Poddar }
160505a1495SSourav Poddar
161505a1495SSourav Poddar pm_runtime_mark_last_busy(qspi->dev);
162505a1495SSourav Poddar ret = pm_runtime_put_autosuspend(qspi->dev);
163505a1495SSourav Poddar if (ret < 0) {
164505a1495SSourav Poddar dev_err(qspi->dev, "pm_runtime_put_autosuspend() failed\n");
165505a1495SSourav Poddar return ret;
166505a1495SSourav Poddar }
167505a1495SSourav Poddar
168505a1495SSourav Poddar return 0;
169505a1495SSourav Poddar }
170505a1495SSourav Poddar
ti_qspi_setup_clk(struct ti_qspi * qspi,u32 speed_hz)1718d0b5128SAtsushi Nemoto static void ti_qspi_setup_clk(struct ti_qspi *qspi, u32 speed_hz)
1728d0b5128SAtsushi Nemoto {
1738d0b5128SAtsushi Nemoto struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg;
1748d0b5128SAtsushi Nemoto int clk_div;
1758d0b5128SAtsushi Nemoto u32 clk_ctrl_reg, clk_rate, clk_ctrl_new;
1768d0b5128SAtsushi Nemoto
1778d0b5128SAtsushi Nemoto clk_rate = clk_get_rate(qspi->fclk);
1788d0b5128SAtsushi Nemoto clk_div = DIV_ROUND_UP(clk_rate, speed_hz) - 1;
1798d0b5128SAtsushi Nemoto clk_div = clamp(clk_div, 0, QSPI_CLK_DIV_MAX);
1808d0b5128SAtsushi Nemoto dev_dbg(qspi->dev, "hz: %d, clock divider %d\n", speed_hz, clk_div);
1818d0b5128SAtsushi Nemoto
1828d0b5128SAtsushi Nemoto pm_runtime_resume_and_get(qspi->dev);
1838d0b5128SAtsushi Nemoto
1848d0b5128SAtsushi Nemoto clk_ctrl_new = QSPI_CLK_EN | clk_div;
1858d0b5128SAtsushi Nemoto if (ctx_reg->clkctrl != clk_ctrl_new) {
1868d0b5128SAtsushi Nemoto clk_ctrl_reg = ti_qspi_read(qspi, QSPI_SPI_CLOCK_CNTRL_REG);
1878d0b5128SAtsushi Nemoto
1888d0b5128SAtsushi Nemoto clk_ctrl_reg &= ~QSPI_CLK_EN;
1898d0b5128SAtsushi Nemoto
1908d0b5128SAtsushi Nemoto /* disable SCLK */
1918d0b5128SAtsushi Nemoto ti_qspi_write(qspi, clk_ctrl_reg, QSPI_SPI_CLOCK_CNTRL_REG);
1928d0b5128SAtsushi Nemoto
1938d0b5128SAtsushi Nemoto /* enable SCLK */
1948d0b5128SAtsushi Nemoto ti_qspi_write(qspi, clk_ctrl_new, QSPI_SPI_CLOCK_CNTRL_REG);
1958d0b5128SAtsushi Nemoto ctx_reg->clkctrl = clk_ctrl_new;
1968d0b5128SAtsushi Nemoto }
1978d0b5128SAtsushi Nemoto
1988d0b5128SAtsushi Nemoto pm_runtime_mark_last_busy(qspi->dev);
1998d0b5128SAtsushi Nemoto pm_runtime_put_autosuspend(qspi->dev);
2008d0b5128SAtsushi Nemoto }
2018d0b5128SAtsushi Nemoto
ti_qspi_restore_ctx(struct ti_qspi * qspi)202505a1495SSourav Poddar static void ti_qspi_restore_ctx(struct ti_qspi *qspi)
203505a1495SSourav Poddar {
204505a1495SSourav Poddar struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg;
205505a1495SSourav Poddar
206505a1495SSourav Poddar ti_qspi_write(qspi, ctx_reg->clkctrl, QSPI_SPI_CLOCK_CNTRL_REG);
207505a1495SSourav Poddar }
208505a1495SSourav Poddar
qspi_is_busy(struct ti_qspi * qspi)20900611047SMugunthan V N static inline u32 qspi_is_busy(struct ti_qspi *qspi)
21000611047SMugunthan V N {
21100611047SMugunthan V N u32 stat;
21200611047SMugunthan V N unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT;
21300611047SMugunthan V N
21400611047SMugunthan V N stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
21500611047SMugunthan V N while ((stat & BUSY) && time_after(timeout, jiffies)) {
21600611047SMugunthan V N cpu_relax();
21700611047SMugunthan V N stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
21800611047SMugunthan V N }
21900611047SMugunthan V N
22000611047SMugunthan V N WARN(stat & BUSY, "qspi busy\n");
22100611047SMugunthan V N return stat & BUSY;
22200611047SMugunthan V N }
22300611047SMugunthan V N
ti_qspi_poll_wc(struct ti_qspi * qspi)22457c2ecd9SVignesh R static inline int ti_qspi_poll_wc(struct ti_qspi *qspi)
22557c2ecd9SVignesh R {
22657c2ecd9SVignesh R u32 stat;
22757c2ecd9SVignesh R unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT;
22857c2ecd9SVignesh R
22957c2ecd9SVignesh R do {
23057c2ecd9SVignesh R stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
23157c2ecd9SVignesh R if (stat & WC)
23257c2ecd9SVignesh R return 0;
23357c2ecd9SVignesh R cpu_relax();
23457c2ecd9SVignesh R } while (time_after(timeout, jiffies));
23557c2ecd9SVignesh R
23657c2ecd9SVignesh R stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
23757c2ecd9SVignesh R if (stat & WC)
23857c2ecd9SVignesh R return 0;
23957c2ecd9SVignesh R return -ETIMEDOUT;
24057c2ecd9SVignesh R }
24157c2ecd9SVignesh R
qspi_write_msg(struct ti_qspi * qspi,struct spi_transfer * t,int count)2421ff7760fSBen Hutchings static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t,
2431ff7760fSBen Hutchings int count)
244505a1495SSourav Poddar {
2451ff7760fSBen Hutchings int wlen, xfer_len;
246505a1495SSourav Poddar unsigned int cmd;
247505a1495SSourav Poddar const u8 *txbuf;
248f682c4ffSVignesh R u32 data;
249505a1495SSourav Poddar
250505a1495SSourav Poddar txbuf = t->tx_buf;
251505a1495SSourav Poddar cmd = qspi->cmd | QSPI_WR_SNGL;
2523ab54620SAxel Lin wlen = t->bits_per_word >> 3; /* in bytes */
253f682c4ffSVignesh R xfer_len = wlen;
254505a1495SSourav Poddar
255505a1495SSourav Poddar while (count) {
25600611047SMugunthan V N if (qspi_is_busy(qspi))
25700611047SMugunthan V N return -EBUSY;
25800611047SMugunthan V N
259505a1495SSourav Poddar switch (wlen) {
2603ab54620SAxel Lin case 1:
261505a1495SSourav Poddar dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n",
262505a1495SSourav Poddar cmd, qspi->dc, *txbuf);
263f682c4ffSVignesh R if (count >= QSPI_WLEN_MAX_BYTES) {
264f682c4ffSVignesh R u32 *txp = (u32 *)txbuf;
265f682c4ffSVignesh R
266f682c4ffSVignesh R data = cpu_to_be32(*txp++);
267f682c4ffSVignesh R writel(data, qspi->base +
268f682c4ffSVignesh R QSPI_SPI_DATA_REG_3);
269f682c4ffSVignesh R data = cpu_to_be32(*txp++);
270f682c4ffSVignesh R writel(data, qspi->base +
271f682c4ffSVignesh R QSPI_SPI_DATA_REG_2);
272f682c4ffSVignesh R data = cpu_to_be32(*txp++);
273f682c4ffSVignesh R writel(data, qspi->base +
274f682c4ffSVignesh R QSPI_SPI_DATA_REG_1);
275f682c4ffSVignesh R data = cpu_to_be32(*txp++);
276f682c4ffSVignesh R writel(data, qspi->base +
277f682c4ffSVignesh R QSPI_SPI_DATA_REG);
278f682c4ffSVignesh R xfer_len = QSPI_WLEN_MAX_BYTES;
279f682c4ffSVignesh R cmd |= QSPI_WLEN(QSPI_WLEN_MAX_BITS);
280f682c4ffSVignesh R } else {
281505a1495SSourav Poddar writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG);
282f682c4ffSVignesh R cmd = qspi->cmd | QSPI_WR_SNGL;
283f682c4ffSVignesh R xfer_len = wlen;
284f682c4ffSVignesh R cmd |= QSPI_WLEN(wlen);
285f682c4ffSVignesh R }
286505a1495SSourav Poddar break;
2873ab54620SAxel Lin case 2:
288505a1495SSourav Poddar dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n",
289505a1495SSourav Poddar cmd, qspi->dc, *txbuf);
290505a1495SSourav Poddar writew(*((u16 *)txbuf), qspi->base + QSPI_SPI_DATA_REG);
291505a1495SSourav Poddar break;
2923ab54620SAxel Lin case 4:
293505a1495SSourav Poddar dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %08x\n",
294505a1495SSourav Poddar cmd, qspi->dc, *txbuf);
295505a1495SSourav Poddar writel(*((u32 *)txbuf), qspi->base + QSPI_SPI_DATA_REG);
2963ab54620SAxel Lin break;
2973ab54620SAxel Lin }
2983ab54620SAxel Lin
299505a1495SSourav Poddar ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
30057c2ecd9SVignesh R if (ti_qspi_poll_wc(qspi)) {
301505a1495SSourav Poddar dev_err(qspi->dev, "write timed out\n");
302505a1495SSourav Poddar return -ETIMEDOUT;
303505a1495SSourav Poddar }
304f682c4ffSVignesh R txbuf += xfer_len;
305f682c4ffSVignesh R count -= xfer_len;
306505a1495SSourav Poddar }
307505a1495SSourav Poddar
308505a1495SSourav Poddar return 0;
309505a1495SSourav Poddar }
310505a1495SSourav Poddar
qspi_read_msg(struct ti_qspi * qspi,struct spi_transfer * t,int count)3111ff7760fSBen Hutchings static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t,
3121ff7760fSBen Hutchings int count)
313505a1495SSourav Poddar {
3141ff7760fSBen Hutchings int wlen;
315505a1495SSourav Poddar unsigned int cmd;
316e7cc5cfbSJean Pihet u32 rx;
317e7cc5cfbSJean Pihet u8 rxlen, rx_wlen;
318505a1495SSourav Poddar u8 *rxbuf;
319505a1495SSourav Poddar
320505a1495SSourav Poddar rxbuf = t->rx_buf;
32170e2e976SSourav Poddar cmd = qspi->cmd;
32270e2e976SSourav Poddar switch (t->rx_nbits) {
32370e2e976SSourav Poddar case SPI_NBITS_DUAL:
32470e2e976SSourav Poddar cmd |= QSPI_RD_DUAL;
32570e2e976SSourav Poddar break;
32670e2e976SSourav Poddar case SPI_NBITS_QUAD:
32770e2e976SSourav Poddar cmd |= QSPI_RD_QUAD;
32870e2e976SSourav Poddar break;
32970e2e976SSourav Poddar default:
33070e2e976SSourav Poddar cmd |= QSPI_RD_SNGL;
33170e2e976SSourav Poddar break;
33270e2e976SSourav Poddar }
3333ab54620SAxel Lin wlen = t->bits_per_word >> 3; /* in bytes */
3346925212fSJean Pihet rx_wlen = wlen;
335505a1495SSourav Poddar
336505a1495SSourav Poddar while (count) {
337505a1495SSourav Poddar dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc);
33800611047SMugunthan V N if (qspi_is_busy(qspi))
33900611047SMugunthan V N return -EBUSY;
34000611047SMugunthan V N
341e7cc5cfbSJean Pihet switch (wlen) {
342e7cc5cfbSJean Pihet case 1:
343e7cc5cfbSJean Pihet /*
344e7cc5cfbSJean Pihet * Optimize the 8-bit words transfers, as used by
345e7cc5cfbSJean Pihet * the SPI flash devices.
346e7cc5cfbSJean Pihet */
347e7cc5cfbSJean Pihet if (count >= QSPI_WLEN_MAX_BYTES) {
348e7cc5cfbSJean Pihet rxlen = QSPI_WLEN_MAX_BYTES;
349e7cc5cfbSJean Pihet } else {
350e7cc5cfbSJean Pihet rxlen = min(count, 4);
351e7cc5cfbSJean Pihet }
352e7cc5cfbSJean Pihet rx_wlen = rxlen << 3;
353e7cc5cfbSJean Pihet cmd &= ~QSPI_WLEN_MASK;
354e7cc5cfbSJean Pihet cmd |= QSPI_WLEN(rx_wlen);
355e7cc5cfbSJean Pihet break;
356e7cc5cfbSJean Pihet default:
357e7cc5cfbSJean Pihet rxlen = wlen;
358e7cc5cfbSJean Pihet break;
359e7cc5cfbSJean Pihet }
360e7cc5cfbSJean Pihet
361505a1495SSourav Poddar ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
36257c2ecd9SVignesh R if (ti_qspi_poll_wc(qspi)) {
363505a1495SSourav Poddar dev_err(qspi->dev, "read timed out\n");
364505a1495SSourav Poddar return -ETIMEDOUT;
365505a1495SSourav Poddar }
366e7cc5cfbSJean Pihet
367505a1495SSourav Poddar switch (wlen) {
3683ab54620SAxel Lin case 1:
369e7cc5cfbSJean Pihet /*
370e7cc5cfbSJean Pihet * Optimize the 8-bit words transfers, as used by
371e7cc5cfbSJean Pihet * the SPI flash devices.
372e7cc5cfbSJean Pihet */
373e7cc5cfbSJean Pihet if (count >= QSPI_WLEN_MAX_BYTES) {
374e7cc5cfbSJean Pihet u32 *rxp = (u32 *) rxbuf;
375e7cc5cfbSJean Pihet rx = readl(qspi->base + QSPI_SPI_DATA_REG_3);
376e7cc5cfbSJean Pihet *rxp++ = be32_to_cpu(rx);
377e7cc5cfbSJean Pihet rx = readl(qspi->base + QSPI_SPI_DATA_REG_2);
378e7cc5cfbSJean Pihet *rxp++ = be32_to_cpu(rx);
379e7cc5cfbSJean Pihet rx = readl(qspi->base + QSPI_SPI_DATA_REG_1);
380e7cc5cfbSJean Pihet *rxp++ = be32_to_cpu(rx);
381e7cc5cfbSJean Pihet rx = readl(qspi->base + QSPI_SPI_DATA_REG);
382e7cc5cfbSJean Pihet *rxp++ = be32_to_cpu(rx);
383e7cc5cfbSJean Pihet } else {
384e7cc5cfbSJean Pihet u8 *rxp = rxbuf;
385e7cc5cfbSJean Pihet rx = readl(qspi->base + QSPI_SPI_DATA_REG);
386e7cc5cfbSJean Pihet if (rx_wlen >= 8)
387e7cc5cfbSJean Pihet *rxp++ = rx >> (rx_wlen - 8);
388e7cc5cfbSJean Pihet if (rx_wlen >= 16)
389e7cc5cfbSJean Pihet *rxp++ = rx >> (rx_wlen - 16);
390e7cc5cfbSJean Pihet if (rx_wlen >= 24)
391e7cc5cfbSJean Pihet *rxp++ = rx >> (rx_wlen - 24);
392e7cc5cfbSJean Pihet if (rx_wlen >= 32)
393e7cc5cfbSJean Pihet *rxp++ = rx;
394e7cc5cfbSJean Pihet }
395505a1495SSourav Poddar break;
3963ab54620SAxel Lin case 2:
397505a1495SSourav Poddar *((u16 *)rxbuf) = readw(qspi->base + QSPI_SPI_DATA_REG);
398505a1495SSourav Poddar break;
3993ab54620SAxel Lin case 4:
400505a1495SSourav Poddar *((u32 *)rxbuf) = readl(qspi->base + QSPI_SPI_DATA_REG);
401505a1495SSourav Poddar break;
402505a1495SSourav Poddar }
403e7cc5cfbSJean Pihet rxbuf += rxlen;
404e7cc5cfbSJean Pihet count -= rxlen;
405505a1495SSourav Poddar }
406505a1495SSourav Poddar
407505a1495SSourav Poddar return 0;
408505a1495SSourav Poddar }
409505a1495SSourav Poddar
qspi_transfer_msg(struct ti_qspi * qspi,struct spi_transfer * t,int count)4101ff7760fSBen Hutchings static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t,
4111ff7760fSBen Hutchings int count)
412505a1495SSourav Poddar {
413505a1495SSourav Poddar int ret;
414505a1495SSourav Poddar
415505a1495SSourav Poddar if (t->tx_buf) {
4161ff7760fSBen Hutchings ret = qspi_write_msg(qspi, t, count);
417505a1495SSourav Poddar if (ret) {
418505a1495SSourav Poddar dev_dbg(qspi->dev, "Error while writing\n");
419505a1495SSourav Poddar return ret;
420505a1495SSourav Poddar }
421505a1495SSourav Poddar }
422505a1495SSourav Poddar
423505a1495SSourav Poddar if (t->rx_buf) {
4241ff7760fSBen Hutchings ret = qspi_read_msg(qspi, t, count);
425505a1495SSourav Poddar if (ret) {
426505a1495SSourav Poddar dev_dbg(qspi->dev, "Error while reading\n");
427505a1495SSourav Poddar return ret;
428505a1495SSourav Poddar }
429505a1495SSourav Poddar }
430505a1495SSourav Poddar
431505a1495SSourav Poddar return 0;
432505a1495SSourav Poddar }
433505a1495SSourav Poddar
ti_qspi_dma_callback(void * param)4345720ec0aSVignesh R static void ti_qspi_dma_callback(void *param)
4355720ec0aSVignesh R {
4365720ec0aSVignesh R struct ti_qspi *qspi = param;
4375720ec0aSVignesh R
4385720ec0aSVignesh R complete(&qspi->transfer_complete);
4395720ec0aSVignesh R }
4405720ec0aSVignesh R
ti_qspi_dma_xfer(struct ti_qspi * qspi,dma_addr_t dma_dst,dma_addr_t dma_src,size_t len)4415720ec0aSVignesh R static int ti_qspi_dma_xfer(struct ti_qspi *qspi, dma_addr_t dma_dst,
4425720ec0aSVignesh R dma_addr_t dma_src, size_t len)
4435720ec0aSVignesh R {
4445720ec0aSVignesh R struct dma_chan *chan = qspi->rx_chan;
4455720ec0aSVignesh R dma_cookie_t cookie;
4465720ec0aSVignesh R enum dma_ctrl_flags flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
4475720ec0aSVignesh R struct dma_async_tx_descriptor *tx;
4485720ec0aSVignesh R int ret;
4498b1ea69aSMiaoqian Lin unsigned long time_left;
4505720ec0aSVignesh R
4511351aaebSVignesh R tx = dmaengine_prep_dma_memcpy(chan, dma_dst, dma_src, len, flags);
4525720ec0aSVignesh R if (!tx) {
4535720ec0aSVignesh R dev_err(qspi->dev, "device_prep_dma_memcpy error\n");
4545720ec0aSVignesh R return -EIO;
4555720ec0aSVignesh R }
4565720ec0aSVignesh R
4575720ec0aSVignesh R tx->callback = ti_qspi_dma_callback;
4585720ec0aSVignesh R tx->callback_param = qspi;
4595720ec0aSVignesh R cookie = tx->tx_submit(tx);
460d06a3507SPrahlad V reinit_completion(&qspi->transfer_complete);
4615720ec0aSVignesh R
4625720ec0aSVignesh R ret = dma_submit_error(cookie);
4635720ec0aSVignesh R if (ret) {
4645720ec0aSVignesh R dev_err(qspi->dev, "dma_submit_error %d\n", cookie);
4655720ec0aSVignesh R return -EIO;
4665720ec0aSVignesh R }
4675720ec0aSVignesh R
4685720ec0aSVignesh R dma_async_issue_pending(chan);
4698b1ea69aSMiaoqian Lin time_left = wait_for_completion_timeout(&qspi->transfer_complete,
4705720ec0aSVignesh R msecs_to_jiffies(len));
4718b1ea69aSMiaoqian Lin if (time_left == 0) {
4725720ec0aSVignesh R dmaengine_terminate_sync(chan);
4735720ec0aSVignesh R dev_err(qspi->dev, "DMA wait_for_completion_timeout\n");
4745720ec0aSVignesh R return -ETIMEDOUT;
4755720ec0aSVignesh R }
4765720ec0aSVignesh R
4775720ec0aSVignesh R return 0;
4785720ec0aSVignesh R }
4795720ec0aSVignesh R
ti_qspi_dma_bounce_buffer(struct ti_qspi * qspi,loff_t offs,void * to,size_t readsize)480b95cb394SBoris Brezillon static int ti_qspi_dma_bounce_buffer(struct ti_qspi *qspi, loff_t offs,
481b95cb394SBoris Brezillon void *to, size_t readsize)
482c687c46eSVignesh R {
483b95cb394SBoris Brezillon dma_addr_t dma_src = qspi->mmap_phys_base + offs;
484c687c46eSVignesh R int ret = 0;
485c687c46eSVignesh R
486c687c46eSVignesh R /*
487c687c46eSVignesh R * Use bounce buffer as FS like jffs2, ubifs may pass
488c687c46eSVignesh R * buffers that does not belong to kernel lowmem region.
489c687c46eSVignesh R */
490c687c46eSVignesh R while (readsize != 0) {
491c687c46eSVignesh R size_t xfer_len = min_t(size_t, QSPI_DMA_BUFFER_SIZE,
492c687c46eSVignesh R readsize);
493c687c46eSVignesh R
494c687c46eSVignesh R ret = ti_qspi_dma_xfer(qspi, qspi->rx_bb_dma_addr,
495c687c46eSVignesh R dma_src, xfer_len);
496c687c46eSVignesh R if (ret != 0)
497c687c46eSVignesh R return ret;
498c687c46eSVignesh R memcpy(to, qspi->rx_bb_addr, xfer_len);
499c687c46eSVignesh R readsize -= xfer_len;
500c687c46eSVignesh R dma_src += xfer_len;
501c687c46eSVignesh R to += xfer_len;
502c687c46eSVignesh R }
503c687c46eSVignesh R
504c687c46eSVignesh R return ret;
505c687c46eSVignesh R }
506c687c46eSVignesh R
ti_qspi_dma_xfer_sg(struct ti_qspi * qspi,struct sg_table rx_sg,loff_t from)5075720ec0aSVignesh R static int ti_qspi_dma_xfer_sg(struct ti_qspi *qspi, struct sg_table rx_sg,
5085720ec0aSVignesh R loff_t from)
5095720ec0aSVignesh R {
5105720ec0aSVignesh R struct scatterlist *sg;
5115720ec0aSVignesh R dma_addr_t dma_src = qspi->mmap_phys_base + from;
5125720ec0aSVignesh R dma_addr_t dma_dst;
5135720ec0aSVignesh R int i, len, ret;
5145720ec0aSVignesh R
5155720ec0aSVignesh R for_each_sg(rx_sg.sgl, sg, rx_sg.nents, i) {
5165720ec0aSVignesh R dma_dst = sg_dma_address(sg);
5175720ec0aSVignesh R len = sg_dma_len(sg);
5185720ec0aSVignesh R ret = ti_qspi_dma_xfer(qspi, dma_dst, dma_src, len);
5195720ec0aSVignesh R if (ret)
5205720ec0aSVignesh R return ret;
5215720ec0aSVignesh R dma_src += len;
5225720ec0aSVignesh R }
5235720ec0aSVignesh R
5245720ec0aSVignesh R return 0;
5255720ec0aSVignesh R }
5265720ec0aSVignesh R
ti_qspi_enable_memory_map(struct spi_device * spi)5274dea6c9bSVignesh R static void ti_qspi_enable_memory_map(struct spi_device *spi)
5284dea6c9bSVignesh R {
5294dea6c9bSVignesh R struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
5304dea6c9bSVignesh R
5314dea6c9bSVignesh R ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG);
5324dea6c9bSVignesh R if (qspi->ctrl_base) {
5334dea6c9bSVignesh R regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg,
534673c865eSVignesh R MEM_CS_MASK,
5359e264f3fSAmit Kumar Mahapatra via Alsa-devel MEM_CS_EN(spi_get_chipselect(spi, 0)));
5364dea6c9bSVignesh R }
5374dea6c9bSVignesh R qspi->mmap_enabled = true;
5389e264f3fSAmit Kumar Mahapatra via Alsa-devel qspi->current_cs = spi_get_chipselect(spi, 0);
5394dea6c9bSVignesh R }
5404dea6c9bSVignesh R
ti_qspi_disable_memory_map(struct spi_device * spi)5414dea6c9bSVignesh R static void ti_qspi_disable_memory_map(struct spi_device *spi)
5424dea6c9bSVignesh R {
5434dea6c9bSVignesh R struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
5444dea6c9bSVignesh R
5454dea6c9bSVignesh R ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG);
5464dea6c9bSVignesh R if (qspi->ctrl_base)
5474dea6c9bSVignesh R regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg,
548673c865eSVignesh R MEM_CS_MASK, 0);
5494dea6c9bSVignesh R qspi->mmap_enabled = false;
550c52c91bbSVignesh Raghavendra qspi->current_cs = -1;
5514dea6c9bSVignesh R }
5524dea6c9bSVignesh R
ti_qspi_setup_mmap_read(struct spi_device * spi,u8 opcode,u8 data_nbits,u8 addr_width,u8 dummy_bytes)553b95cb394SBoris Brezillon static void ti_qspi_setup_mmap_read(struct spi_device *spi, u8 opcode,
554b95cb394SBoris Brezillon u8 data_nbits, u8 addr_width,
555b95cb394SBoris Brezillon u8 dummy_bytes)
5564dea6c9bSVignesh R {
5574dea6c9bSVignesh R struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
558b95cb394SBoris Brezillon u32 memval = opcode;
5594dea6c9bSVignesh R
560b95cb394SBoris Brezillon switch (data_nbits) {
5614dea6c9bSVignesh R case SPI_NBITS_QUAD:
5624dea6c9bSVignesh R memval |= QSPI_SETUP_RD_QUAD;
5634dea6c9bSVignesh R break;
5644dea6c9bSVignesh R case SPI_NBITS_DUAL:
5654dea6c9bSVignesh R memval |= QSPI_SETUP_RD_DUAL;
5664dea6c9bSVignesh R break;
5674dea6c9bSVignesh R default:
5684dea6c9bSVignesh R memval |= QSPI_SETUP_RD_NORMAL;
5694dea6c9bSVignesh R break;
5704dea6c9bSVignesh R }
571b95cb394SBoris Brezillon memval |= ((addr_width - 1) << QSPI_SETUP_ADDR_SHIFT |
572b95cb394SBoris Brezillon dummy_bytes << QSPI_SETUP_DUMMY_SHIFT);
5734dea6c9bSVignesh R ti_qspi_write(qspi, memval,
5749e264f3fSAmit Kumar Mahapatra via Alsa-devel QSPI_SPI_SETUP_REG(spi_get_chipselect(spi, 0)));
5754dea6c9bSVignesh R }
5764dea6c9bSVignesh R
ti_qspi_adjust_op_size(struct spi_mem * mem,struct spi_mem_op * op)577e97f4914SJean Pihet static int ti_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
578e97f4914SJean Pihet {
579e97f4914SJean Pihet struct ti_qspi *qspi = spi_controller_get_devdata(mem->spi->master);
580e97f4914SJean Pihet size_t max_len;
581e97f4914SJean Pihet
582e97f4914SJean Pihet if (op->data.dir == SPI_MEM_DATA_IN) {
583e97f4914SJean Pihet if (op->addr.val < qspi->mmap_size) {
584e97f4914SJean Pihet /* Limit MMIO to the mmaped region */
585e97f4914SJean Pihet if (op->addr.val + op->data.nbytes > qspi->mmap_size) {
586e97f4914SJean Pihet max_len = qspi->mmap_size - op->addr.val;
587e97f4914SJean Pihet op->data.nbytes = min((size_t) op->data.nbytes,
588e97f4914SJean Pihet max_len);
589e97f4914SJean Pihet }
590e97f4914SJean Pihet } else {
591e97f4914SJean Pihet /*
592e97f4914SJean Pihet * Use fallback mode (SW generated transfers) above the
593e97f4914SJean Pihet * mmaped region.
594e97f4914SJean Pihet * Adjust size to comply with the QSPI max frame length.
595e97f4914SJean Pihet */
596e97f4914SJean Pihet max_len = QSPI_FRAME;
597e97f4914SJean Pihet max_len -= 1 + op->addr.nbytes + op->dummy.nbytes;
598e97f4914SJean Pihet op->data.nbytes = min((size_t) op->data.nbytes,
599e97f4914SJean Pihet max_len);
600e97f4914SJean Pihet }
601e97f4914SJean Pihet }
602e97f4914SJean Pihet
603e97f4914SJean Pihet return 0;
604e97f4914SJean Pihet }
605e97f4914SJean Pihet
ti_qspi_exec_mem_op(struct spi_mem * mem,const struct spi_mem_op * op)606b95cb394SBoris Brezillon static int ti_qspi_exec_mem_op(struct spi_mem *mem,
607b95cb394SBoris Brezillon const struct spi_mem_op *op)
608b95cb394SBoris Brezillon {
609b95cb394SBoris Brezillon struct ti_qspi *qspi = spi_master_get_devdata(mem->spi->master);
610b95cb394SBoris Brezillon u32 from = 0;
611b95cb394SBoris Brezillon int ret = 0;
612b95cb394SBoris Brezillon
613b95cb394SBoris Brezillon /* Only optimize read path. */
614b95cb394SBoris Brezillon if (!op->data.nbytes || op->data.dir != SPI_MEM_DATA_IN ||
615b95cb394SBoris Brezillon !op->addr.nbytes || op->addr.nbytes > 4)
616b95cb394SBoris Brezillon return -ENOTSUPP;
617b95cb394SBoris Brezillon
618b95cb394SBoris Brezillon /* Address exceeds MMIO window size, fall back to regular mode. */
619b95cb394SBoris Brezillon from = op->addr.val;
620b95cb394SBoris Brezillon if (from + op->data.nbytes > qspi->mmap_size)
621b95cb394SBoris Brezillon return -ENOTSUPP;
622b95cb394SBoris Brezillon
623b95cb394SBoris Brezillon mutex_lock(&qspi->list_lock);
624b95cb394SBoris Brezillon
6259e264f3fSAmit Kumar Mahapatra via Alsa-devel if (!qspi->mmap_enabled || qspi->current_cs != spi_get_chipselect(mem->spi, 0)) {
6268d0b5128SAtsushi Nemoto ti_qspi_setup_clk(qspi, mem->spi->max_speed_hz);
627b95cb394SBoris Brezillon ti_qspi_enable_memory_map(mem->spi);
6288d0b5128SAtsushi Nemoto }
629b95cb394SBoris Brezillon ti_qspi_setup_mmap_read(mem->spi, op->cmd.opcode, op->data.buswidth,
630b95cb394SBoris Brezillon op->addr.nbytes, op->dummy.nbytes);
631b95cb394SBoris Brezillon
632b95cb394SBoris Brezillon if (qspi->rx_chan) {
633b95cb394SBoris Brezillon struct sg_table sgt;
634b95cb394SBoris Brezillon
635b95cb394SBoris Brezillon if (virt_addr_valid(op->data.buf.in) &&
636b95cb394SBoris Brezillon !spi_controller_dma_map_mem_op_data(mem->spi->master, op,
637b95cb394SBoris Brezillon &sgt)) {
638b95cb394SBoris Brezillon ret = ti_qspi_dma_xfer_sg(qspi, sgt, from);
639b95cb394SBoris Brezillon spi_controller_dma_unmap_mem_op_data(mem->spi->master,
640b95cb394SBoris Brezillon op, &sgt);
641b95cb394SBoris Brezillon } else {
642b95cb394SBoris Brezillon ret = ti_qspi_dma_bounce_buffer(qspi, from,
643b95cb394SBoris Brezillon op->data.buf.in,
644b95cb394SBoris Brezillon op->data.nbytes);
645b95cb394SBoris Brezillon }
646b95cb394SBoris Brezillon } else {
647b95cb394SBoris Brezillon memcpy_fromio(op->data.buf.in, qspi->mmap_base + from,
648b95cb394SBoris Brezillon op->data.nbytes);
649b95cb394SBoris Brezillon }
650b95cb394SBoris Brezillon
651b95cb394SBoris Brezillon mutex_unlock(&qspi->list_lock);
652b95cb394SBoris Brezillon
653b95cb394SBoris Brezillon return ret;
654b95cb394SBoris Brezillon }
655b95cb394SBoris Brezillon
656b95cb394SBoris Brezillon static const struct spi_controller_mem_ops ti_qspi_mem_ops = {
657b95cb394SBoris Brezillon .exec_op = ti_qspi_exec_mem_op,
658e97f4914SJean Pihet .adjust_op_size = ti_qspi_adjust_op_size,
659b95cb394SBoris Brezillon };
660b95cb394SBoris Brezillon
ti_qspi_start_transfer_one(struct spi_master * master,struct spi_message * m)661505a1495SSourav Poddar static int ti_qspi_start_transfer_one(struct spi_master *master,
662505a1495SSourav Poddar struct spi_message *m)
663505a1495SSourav Poddar {
664505a1495SSourav Poddar struct ti_qspi *qspi = spi_master_get_devdata(master);
665505a1495SSourav Poddar struct spi_device *spi = m->spi;
666505a1495SSourav Poddar struct spi_transfer *t;
667505a1495SSourav Poddar int status = 0, ret;
6681ff7760fSBen Hutchings unsigned int frame_len_words, transfer_len_words;
6691ff7760fSBen Hutchings int wlen;
670505a1495SSourav Poddar
671505a1495SSourav Poddar /* setup device control reg */
672505a1495SSourav Poddar qspi->dc = 0;
673505a1495SSourav Poddar
674505a1495SSourav Poddar if (spi->mode & SPI_CPHA)
6759e264f3fSAmit Kumar Mahapatra via Alsa-devel qspi->dc |= QSPI_CKPHA(spi_get_chipselect(spi, 0));
676505a1495SSourav Poddar if (spi->mode & SPI_CPOL)
6779e264f3fSAmit Kumar Mahapatra via Alsa-devel qspi->dc |= QSPI_CKPOL(spi_get_chipselect(spi, 0));
678505a1495SSourav Poddar if (spi->mode & SPI_CS_HIGH)
6799e264f3fSAmit Kumar Mahapatra via Alsa-devel qspi->dc |= QSPI_CSPOL(spi_get_chipselect(spi, 0));
680505a1495SSourav Poddar
681ea1b60fbSBen Hutchings frame_len_words = 0;
682ea1b60fbSBen Hutchings list_for_each_entry(t, &m->transfers, transfer_list)
683ea1b60fbSBen Hutchings frame_len_words += t->len / (t->bits_per_word >> 3);
684ea1b60fbSBen Hutchings frame_len_words = min_t(unsigned int, frame_len_words, QSPI_FRAME);
685505a1495SSourav Poddar
686505a1495SSourav Poddar /* setup command reg */
687505a1495SSourav Poddar qspi->cmd = 0;
6889e264f3fSAmit Kumar Mahapatra via Alsa-devel qspi->cmd |= QSPI_EN_CS(spi_get_chipselect(spi, 0));
689ea1b60fbSBen Hutchings qspi->cmd |= QSPI_FLEN(frame_len_words);
690505a1495SSourav Poddar
691505a1495SSourav Poddar ti_qspi_write(qspi, qspi->dc, QSPI_SPI_DC_REG);
692505a1495SSourav Poddar
693505a1495SSourav Poddar mutex_lock(&qspi->list_lock);
694505a1495SSourav Poddar
6954dea6c9bSVignesh R if (qspi->mmap_enabled)
6964dea6c9bSVignesh R ti_qspi_disable_memory_map(spi);
6974dea6c9bSVignesh R
698505a1495SSourav Poddar list_for_each_entry(t, &m->transfers, transfer_list) {
699ea1b60fbSBen Hutchings qspi->cmd = ((qspi->cmd & ~QSPI_WLEN_MASK) |
700ea1b60fbSBen Hutchings QSPI_WLEN(t->bits_per_word));
701505a1495SSourav Poddar
7021ff7760fSBen Hutchings wlen = t->bits_per_word >> 3;
7031ff7760fSBen Hutchings transfer_len_words = min(t->len / wlen, frame_len_words);
7041ff7760fSBen Hutchings
7058d0b5128SAtsushi Nemoto ti_qspi_setup_clk(qspi, t->speed_hz);
7061ff7760fSBen Hutchings ret = qspi_transfer_msg(qspi, t, transfer_len_words * wlen);
707505a1495SSourav Poddar if (ret) {
708505a1495SSourav Poddar dev_dbg(qspi->dev, "transfer message failed\n");
709b6460366SWei Yongjun mutex_unlock(&qspi->list_lock);
710505a1495SSourav Poddar return -EINVAL;
711505a1495SSourav Poddar }
712505a1495SSourav Poddar
7131ff7760fSBen Hutchings m->actual_length += transfer_len_words * wlen;
7141ff7760fSBen Hutchings frame_len_words -= transfer_len_words;
7151ff7760fSBen Hutchings if (frame_len_words == 0)
7161ff7760fSBen Hutchings break;
717505a1495SSourav Poddar }
718505a1495SSourav Poddar
719505a1495SSourav Poddar mutex_unlock(&qspi->list_lock);
720505a1495SSourav Poddar
721bc27a539SVignesh R ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG);
722505a1495SSourav Poddar m->status = status;
723505a1495SSourav Poddar spi_finalize_current_message(master);
724505a1495SSourav Poddar
725505a1495SSourav Poddar return status;
726505a1495SSourav Poddar }
727505a1495SSourav Poddar
ti_qspi_runtime_resume(struct device * dev)728505a1495SSourav Poddar static int ti_qspi_runtime_resume(struct device *dev)
729505a1495SSourav Poddar {
730505a1495SSourav Poddar struct ti_qspi *qspi;
731505a1495SSourav Poddar
732f17414c4SSourav Poddar qspi = dev_get_drvdata(dev);
733505a1495SSourav Poddar ti_qspi_restore_ctx(qspi);
734505a1495SSourav Poddar
735505a1495SSourav Poddar return 0;
736505a1495SSourav Poddar }
737505a1495SSourav Poddar
ti_qspi_dma_cleanup(struct ti_qspi * qspi)7381d309cd6STudor Ambarus static void ti_qspi_dma_cleanup(struct ti_qspi *qspi)
7391d309cd6STudor Ambarus {
7401d309cd6STudor Ambarus if (qspi->rx_bb_addr)
7411d309cd6STudor Ambarus dma_free_coherent(qspi->dev, QSPI_DMA_BUFFER_SIZE,
7421d309cd6STudor Ambarus qspi->rx_bb_addr,
7431d309cd6STudor Ambarus qspi->rx_bb_dma_addr);
7441d309cd6STudor Ambarus
7451d309cd6STudor Ambarus if (qspi->rx_chan)
7461d309cd6STudor Ambarus dma_release_channel(qspi->rx_chan);
7471d309cd6STudor Ambarus }
7481d309cd6STudor Ambarus
749505a1495SSourav Poddar static const struct of_device_id ti_qspi_match[] = {
750505a1495SSourav Poddar {.compatible = "ti,dra7xxx-qspi" },
75109222fc3SSourav Poddar {.compatible = "ti,am4372-qspi" },
752505a1495SSourav Poddar {},
753505a1495SSourav Poddar };
754e1432d30SSourav Poddar MODULE_DEVICE_TABLE(of, ti_qspi_match);
755505a1495SSourav Poddar
ti_qspi_probe(struct platform_device * pdev)756505a1495SSourav Poddar static int ti_qspi_probe(struct platform_device *pdev)
757505a1495SSourav Poddar {
758505a1495SSourav Poddar struct ti_qspi *qspi;
759505a1495SSourav Poddar struct spi_master *master;
7604dea6c9bSVignesh R struct resource *r, *res_mmap;
761505a1495SSourav Poddar struct device_node *np = pdev->dev.of_node;
762505a1495SSourav Poddar u32 max_freq;
763505a1495SSourav Poddar int ret = 0, num_cs, irq;
7645720ec0aSVignesh R dma_cap_mask_t mask;
765505a1495SSourav Poddar
766505a1495SSourav Poddar master = spi_alloc_master(&pdev->dev, sizeof(*qspi));
767505a1495SSourav Poddar if (!master)
768505a1495SSourav Poddar return -ENOMEM;
769505a1495SSourav Poddar
770633795b9SSourav Poddar master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD;
771505a1495SSourav Poddar
772*7a2b552cSAndy Shevchenko master->flags = SPI_CONTROLLER_HALF_DUPLEX;
773505a1495SSourav Poddar master->setup = ti_qspi_setup;
774505a1495SSourav Poddar master->auto_runtime_pm = true;
775505a1495SSourav Poddar master->transfer_one_message = ti_qspi_start_transfer_one;
776505a1495SSourav Poddar master->dev.of_node = pdev->dev.of_node;
777aa188f90SAxel Lin master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
778aa188f90SAxel Lin SPI_BPW_MASK(8);
779b95cb394SBoris Brezillon master->mem_ops = &ti_qspi_mem_ops;
780505a1495SSourav Poddar
781505a1495SSourav Poddar if (!of_property_read_u32(np, "num-cs", &num_cs))
782505a1495SSourav Poddar master->num_chipselect = num_cs;
783505a1495SSourav Poddar
784505a1495SSourav Poddar qspi = spi_master_get_devdata(master);
785505a1495SSourav Poddar qspi->master = master;
786505a1495SSourav Poddar qspi->dev = &pdev->dev;
787160a0613SWei Yongjun platform_set_drvdata(pdev, qspi);
788505a1495SSourav Poddar
7896b3938aeSSourav Poddar r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_base");
7906b3938aeSSourav Poddar if (r == NULL) {
791505a1495SSourav Poddar r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
7926b3938aeSSourav Poddar if (r == NULL) {
7936b3938aeSSourav Poddar dev_err(&pdev->dev, "missing platform data\n");
794cce59c22SPrahlad V ret = -ENODEV;
795cce59c22SPrahlad V goto free_master;
7966b3938aeSSourav Poddar }
7976b3938aeSSourav Poddar }
7986b3938aeSSourav Poddar
7996b3938aeSSourav Poddar res_mmap = platform_get_resource_byname(pdev,
8006b3938aeSSourav Poddar IORESOURCE_MEM, "qspi_mmap");
8016b3938aeSSourav Poddar if (res_mmap == NULL) {
8026b3938aeSSourav Poddar res_mmap = platform_get_resource(pdev, IORESOURCE_MEM, 1);
8036b3938aeSSourav Poddar if (res_mmap == NULL) {
8046b3938aeSSourav Poddar dev_err(&pdev->dev,
8056b3938aeSSourav Poddar "memory mapped resource not required\n");
8066b3938aeSSourav Poddar }
8076b3938aeSSourav Poddar }
8086282f122SBoris Brezillon
8096282f122SBoris Brezillon if (res_mmap)
810b95cb394SBoris Brezillon qspi->mmap_size = resource_size(res_mmap);
8116b3938aeSSourav Poddar
812505a1495SSourav Poddar irq = platform_get_irq(pdev, 0);
813505a1495SSourav Poddar if (irq < 0) {
814cce59c22SPrahlad V ret = irq;
815cce59c22SPrahlad V goto free_master;
816505a1495SSourav Poddar }
817505a1495SSourav Poddar
818505a1495SSourav Poddar mutex_init(&qspi->list_lock);
819505a1495SSourav Poddar
820505a1495SSourav Poddar qspi->base = devm_ioremap_resource(&pdev->dev, r);
821505a1495SSourav Poddar if (IS_ERR(qspi->base)) {
822505a1495SSourav Poddar ret = PTR_ERR(qspi->base);
823505a1495SSourav Poddar goto free_master;
824505a1495SSourav Poddar }
825505a1495SSourav Poddar
8264dea6c9bSVignesh R
8274dea6c9bSVignesh R if (of_property_read_bool(np, "syscon-chipselects")) {
8284dea6c9bSVignesh R qspi->ctrl_base =
8294dea6c9bSVignesh R syscon_regmap_lookup_by_phandle(np,
8304dea6c9bSVignesh R "syscon-chipselects");
831cce59c22SPrahlad V if (IS_ERR(qspi->ctrl_base)) {
832cce59c22SPrahlad V ret = PTR_ERR(qspi->ctrl_base);
833cce59c22SPrahlad V goto free_master;
834cce59c22SPrahlad V }
8354dea6c9bSVignesh R ret = of_property_read_u32_index(np,
8364dea6c9bSVignesh R "syscon-chipselects",
8374dea6c9bSVignesh R 1, &qspi->ctrl_reg);
8384dea6c9bSVignesh R if (ret) {
8394dea6c9bSVignesh R dev_err(&pdev->dev,
8404dea6c9bSVignesh R "couldn't get ctrl_mod reg index\n");
841cce59c22SPrahlad V goto free_master;
8426b3938aeSSourav Poddar }
8436b3938aeSSourav Poddar }
8446b3938aeSSourav Poddar
845505a1495SSourav Poddar qspi->fclk = devm_clk_get(&pdev->dev, "fck");
846505a1495SSourav Poddar if (IS_ERR(qspi->fclk)) {
847505a1495SSourav Poddar ret = PTR_ERR(qspi->fclk);
848505a1495SSourav Poddar dev_err(&pdev->dev, "could not get clk: %d\n", ret);
849505a1495SSourav Poddar }
850505a1495SSourav Poddar
851505a1495SSourav Poddar pm_runtime_use_autosuspend(&pdev->dev);
852505a1495SSourav Poddar pm_runtime_set_autosuspend_delay(&pdev->dev, QSPI_AUTOSUSPEND_TIMEOUT);
853505a1495SSourav Poddar pm_runtime_enable(&pdev->dev);
854505a1495SSourav Poddar
855505a1495SSourav Poddar if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
8568d0b5128SAtsushi Nemoto master->max_speed_hz = max_freq;
857505a1495SSourav Poddar
8585720ec0aSVignesh R dma_cap_zero(mask);
8595720ec0aSVignesh R dma_cap_set(DMA_MEMCPY, mask);
860505a1495SSourav Poddar
8615720ec0aSVignesh R qspi->rx_chan = dma_request_chan_by_mask(&mask);
8627abfe04cSChristophe JAILLET if (IS_ERR(qspi->rx_chan)) {
8635720ec0aSVignesh R dev_err(qspi->dev,
8645720ec0aSVignesh R "No Rx DMA available, trying mmap mode\n");
8657abfe04cSChristophe JAILLET qspi->rx_chan = NULL;
8665720ec0aSVignesh R ret = 0;
8675720ec0aSVignesh R goto no_dma;
8685720ec0aSVignesh R }
869c687c46eSVignesh R qspi->rx_bb_addr = dma_alloc_coherent(qspi->dev,
870c687c46eSVignesh R QSPI_DMA_BUFFER_SIZE,
871c687c46eSVignesh R &qspi->rx_bb_dma_addr,
872c687c46eSVignesh R GFP_KERNEL | GFP_DMA);
873c687c46eSVignesh R if (!qspi->rx_bb_addr) {
874c687c46eSVignesh R dev_err(qspi->dev,
875c687c46eSVignesh R "dma_alloc_coherent failed, using PIO mode\n");
876c687c46eSVignesh R dma_release_channel(qspi->rx_chan);
877c687c46eSVignesh R goto no_dma;
878c687c46eSVignesh R }
8795720ec0aSVignesh R master->dma_rx = qspi->rx_chan;
8805720ec0aSVignesh R init_completion(&qspi->transfer_complete);
8815720ec0aSVignesh R if (res_mmap)
8825720ec0aSVignesh R qspi->mmap_phys_base = (dma_addr_t)res_mmap->start;
8835720ec0aSVignesh R
8845720ec0aSVignesh R no_dma:
8855720ec0aSVignesh R if (!qspi->rx_chan && res_mmap) {
8865720ec0aSVignesh R qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap);
8875720ec0aSVignesh R if (IS_ERR(qspi->mmap_base)) {
8885720ec0aSVignesh R dev_info(&pdev->dev,
8895720ec0aSVignesh R "mmap failed with error %ld using PIO mode\n",
8905720ec0aSVignesh R PTR_ERR(qspi->mmap_base));
8915720ec0aSVignesh R qspi->mmap_base = NULL;
892b95cb394SBoris Brezillon master->mem_ops = NULL;
8935720ec0aSVignesh R }
8945720ec0aSVignesh R }
8955720ec0aSVignesh R qspi->mmap_enabled = false;
896c52c91bbSVignesh Raghavendra qspi->current_cs = -1;
8975720ec0aSVignesh R
8985720ec0aSVignesh R ret = devm_spi_register_master(&pdev->dev, master);
8995720ec0aSVignesh R if (!ret)
900505a1495SSourav Poddar return 0;
901505a1495SSourav Poddar
9021d309cd6STudor Ambarus ti_qspi_dma_cleanup(qspi);
9031d309cd6STudor Ambarus
904cce59c22SPrahlad V pm_runtime_disable(&pdev->dev);
905505a1495SSourav Poddar free_master:
906505a1495SSourav Poddar spi_master_put(master);
907505a1495SSourav Poddar return ret;
908505a1495SSourav Poddar }
909505a1495SSourav Poddar
ti_qspi_remove(struct platform_device * pdev)910505a1495SSourav Poddar static int ti_qspi_remove(struct platform_device *pdev)
911505a1495SSourav Poddar {
9123ac066e2SJean-Jacques Hiblot struct ti_qspi *qspi = platform_get_drvdata(pdev);
9133ac066e2SJean-Jacques Hiblot int rc;
9143ac066e2SJean-Jacques Hiblot
9153ac066e2SJean-Jacques Hiblot rc = spi_master_suspend(qspi->master);
9163ac066e2SJean-Jacques Hiblot if (rc)
9173ac066e2SJean-Jacques Hiblot return rc;
9183ac066e2SJean-Jacques Hiblot
919e6b5140bSFelipe Balbi pm_runtime_put_sync(&pdev->dev);
920cbcabb7aSSourav Poddar pm_runtime_disable(&pdev->dev);
921cbcabb7aSSourav Poddar
9221d309cd6STudor Ambarus ti_qspi_dma_cleanup(qspi);
9235720ec0aSVignesh R
924505a1495SSourav Poddar return 0;
925505a1495SSourav Poddar }
926505a1495SSourav Poddar
927505a1495SSourav Poddar static const struct dev_pm_ops ti_qspi_pm_ops = {
928505a1495SSourav Poddar .runtime_resume = ti_qspi_runtime_resume,
929505a1495SSourav Poddar };
930505a1495SSourav Poddar
931505a1495SSourav Poddar static struct platform_driver ti_qspi_driver = {
932505a1495SSourav Poddar .probe = ti_qspi_probe,
933505a1495SSourav Poddar .remove = ti_qspi_remove,
934505a1495SSourav Poddar .driver = {
9355a33d30fSAxel Lin .name = "ti-qspi",
936505a1495SSourav Poddar .pm = &ti_qspi_pm_ops,
937505a1495SSourav Poddar .of_match_table = ti_qspi_match,
938505a1495SSourav Poddar }
939505a1495SSourav Poddar };
940505a1495SSourav Poddar
941505a1495SSourav Poddar module_platform_driver(ti_qspi_driver);
942505a1495SSourav Poddar
943505a1495SSourav Poddar MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>");
944505a1495SSourav Poddar MODULE_LICENSE("GPL v2");
945505a1495SSourav Poddar MODULE_DESCRIPTION("TI QSPI controller driver");
9465a33d30fSAxel Lin MODULE_ALIAS("platform:ti-qspi");
947