xref: /openbmc/linux/drivers/spi/spi-ti-qspi.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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