xref: /linux/drivers/spi/spi-ti-qspi.c (revision 75f5db39ff14ed95056f2cca3ad98c3cae97170c)
1505a1495SSourav Poddar /*
2505a1495SSourav Poddar  * TI QSPI driver
3505a1495SSourav Poddar  *
4505a1495SSourav Poddar  * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
5505a1495SSourav Poddar  * Author: Sourav Poddar <sourav.poddar@ti.com>
6505a1495SSourav Poddar  *
7505a1495SSourav Poddar  * This program is free software; you can redistribute it and/or
8505a1495SSourav Poddar  * modify it under the terms of the GPLv2.
9505a1495SSourav Poddar  *
10505a1495SSourav Poddar  * This program is distributed in the hope that it will be useful,
11505a1495SSourav Poddar  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12505a1495SSourav Poddar  * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE.  See the
13505a1495SSourav Poddar  * GNU General Public License for more details.
14505a1495SSourav Poddar  */
15505a1495SSourav Poddar 
16505a1495SSourav Poddar #include <linux/kernel.h>
17505a1495SSourav Poddar #include <linux/init.h>
18505a1495SSourav Poddar #include <linux/interrupt.h>
19505a1495SSourav Poddar #include <linux/module.h>
20505a1495SSourav Poddar #include <linux/device.h>
21505a1495SSourav Poddar #include <linux/delay.h>
22505a1495SSourav Poddar #include <linux/dma-mapping.h>
23505a1495SSourav Poddar #include <linux/dmaengine.h>
24505a1495SSourav Poddar #include <linux/omap-dma.h>
25505a1495SSourav Poddar #include <linux/platform_device.h>
26505a1495SSourav Poddar #include <linux/err.h>
27505a1495SSourav Poddar #include <linux/clk.h>
28505a1495SSourav Poddar #include <linux/io.h>
29505a1495SSourav Poddar #include <linux/slab.h>
30505a1495SSourav Poddar #include <linux/pm_runtime.h>
31505a1495SSourav Poddar #include <linux/of.h>
32505a1495SSourav Poddar #include <linux/of_device.h>
33505a1495SSourav Poddar #include <linux/pinctrl/consumer.h>
34505a1495SSourav Poddar 
35505a1495SSourav Poddar #include <linux/spi/spi.h>
36505a1495SSourav Poddar 
37505a1495SSourav Poddar struct ti_qspi_regs {
38505a1495SSourav Poddar 	u32 clkctrl;
39505a1495SSourav Poddar };
40505a1495SSourav Poddar 
41505a1495SSourav Poddar struct ti_qspi {
42505a1495SSourav Poddar 	/* list synchronization */
43505a1495SSourav Poddar 	struct mutex            list_lock;
44505a1495SSourav Poddar 
45505a1495SSourav Poddar 	struct spi_master	*master;
46505a1495SSourav Poddar 	void __iomem            *base;
476b3938aeSSourav Poddar 	void __iomem            *ctrl_base;
486b3938aeSSourav Poddar 	void __iomem            *mmap_base;
49505a1495SSourav Poddar 	struct clk		*fclk;
50505a1495SSourav Poddar 	struct device           *dev;
51505a1495SSourav Poddar 
52505a1495SSourav Poddar 	struct ti_qspi_regs     ctx_reg;
53505a1495SSourav Poddar 
54505a1495SSourav Poddar 	u32 spi_max_frequency;
55505a1495SSourav Poddar 	u32 cmd;
56505a1495SSourav Poddar 	u32 dc;
576b3938aeSSourav Poddar 
586b3938aeSSourav Poddar 	bool ctrl_mod;
59505a1495SSourav Poddar };
60505a1495SSourav Poddar 
61505a1495SSourav Poddar #define QSPI_PID			(0x0)
62505a1495SSourav Poddar #define QSPI_SYSCONFIG			(0x10)
63505a1495SSourav Poddar #define QSPI_SPI_CLOCK_CNTRL_REG	(0x40)
64505a1495SSourav Poddar #define QSPI_SPI_DC_REG			(0x44)
65505a1495SSourav Poddar #define QSPI_SPI_CMD_REG		(0x48)
66505a1495SSourav Poddar #define QSPI_SPI_STATUS_REG		(0x4c)
67505a1495SSourav Poddar #define QSPI_SPI_DATA_REG		(0x50)
68505a1495SSourav Poddar #define QSPI_SPI_SETUP0_REG		(0x54)
69505a1495SSourav Poddar #define QSPI_SPI_SWITCH_REG		(0x64)
70505a1495SSourav Poddar #define QSPI_SPI_SETUP1_REG		(0x58)
71505a1495SSourav Poddar #define QSPI_SPI_SETUP2_REG		(0x5c)
72505a1495SSourav Poddar #define QSPI_SPI_SETUP3_REG		(0x60)
73505a1495SSourav Poddar #define QSPI_SPI_DATA_REG_1		(0x68)
74505a1495SSourav Poddar #define QSPI_SPI_DATA_REG_2		(0x6c)
75505a1495SSourav Poddar #define QSPI_SPI_DATA_REG_3		(0x70)
76505a1495SSourav Poddar 
77505a1495SSourav Poddar #define QSPI_COMPLETION_TIMEOUT		msecs_to_jiffies(2000)
78505a1495SSourav Poddar 
79505a1495SSourav Poddar #define QSPI_FCLK			192000000
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
97505a1495SSourav Poddar 
98505a1495SSourav Poddar /* STATUS REGISTER */
9900611047SMugunthan V N #define BUSY				0x01
100505a1495SSourav Poddar #define WC				0x02
101505a1495SSourav Poddar 
102505a1495SSourav Poddar /* Device Control */
103505a1495SSourav Poddar #define QSPI_DD(m, n)			(m << (3 + n * 8))
104505a1495SSourav Poddar #define QSPI_CKPHA(n)			(1 << (2 + n * 8))
105505a1495SSourav Poddar #define QSPI_CSPOL(n)			(1 << (1 + n * 8))
106505a1495SSourav Poddar #define QSPI_CKPOL(n)			(1 << (n * 8))
107505a1495SSourav Poddar 
108505a1495SSourav Poddar #define	QSPI_FRAME			4096
109505a1495SSourav Poddar 
110505a1495SSourav Poddar #define QSPI_AUTOSUSPEND_TIMEOUT         2000
111505a1495SSourav Poddar 
112505a1495SSourav Poddar static inline unsigned long ti_qspi_read(struct ti_qspi *qspi,
113505a1495SSourav Poddar 		unsigned long reg)
114505a1495SSourav Poddar {
115505a1495SSourav Poddar 	return readl(qspi->base + reg);
116505a1495SSourav Poddar }
117505a1495SSourav Poddar 
118505a1495SSourav Poddar static inline void ti_qspi_write(struct ti_qspi *qspi,
119505a1495SSourav Poddar 		unsigned long val, unsigned long reg)
120505a1495SSourav Poddar {
121505a1495SSourav Poddar 	writel(val, qspi->base + reg);
122505a1495SSourav Poddar }
123505a1495SSourav Poddar 
124505a1495SSourav Poddar static int ti_qspi_setup(struct spi_device *spi)
125505a1495SSourav Poddar {
126505a1495SSourav Poddar 	struct ti_qspi	*qspi = spi_master_get_devdata(spi->master);
127505a1495SSourav Poddar 	struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg;
128505a1495SSourav Poddar 	int clk_div = 0, ret;
129505a1495SSourav Poddar 	u32 clk_ctrl_reg, clk_rate, clk_mask;
130505a1495SSourav Poddar 
131505a1495SSourav Poddar 	if (spi->master->busy) {
132505a1495SSourav Poddar 		dev_dbg(qspi->dev, "master busy doing other trasnfers\n");
133505a1495SSourav Poddar 		return -EBUSY;
134505a1495SSourav Poddar 	}
135505a1495SSourav Poddar 
136505a1495SSourav Poddar 	if (!qspi->spi_max_frequency) {
137505a1495SSourav Poddar 		dev_err(qspi->dev, "spi max frequency not defined\n");
138505a1495SSourav Poddar 		return -EINVAL;
139505a1495SSourav Poddar 	}
140505a1495SSourav Poddar 
141505a1495SSourav Poddar 	clk_rate = clk_get_rate(qspi->fclk);
142505a1495SSourav Poddar 
143505a1495SSourav Poddar 	clk_div = DIV_ROUND_UP(clk_rate, qspi->spi_max_frequency) - 1;
144505a1495SSourav Poddar 
145505a1495SSourav Poddar 	if (clk_div < 0) {
146505a1495SSourav Poddar 		dev_dbg(qspi->dev, "clock divider < 0, using /1 divider\n");
147505a1495SSourav Poddar 		return -EINVAL;
148505a1495SSourav Poddar 	}
149505a1495SSourav Poddar 
150505a1495SSourav Poddar 	if (clk_div > QSPI_CLK_DIV_MAX) {
151505a1495SSourav Poddar 		dev_dbg(qspi->dev, "clock divider >%d , using /%d divider\n",
152505a1495SSourav Poddar 				QSPI_CLK_DIV_MAX, QSPI_CLK_DIV_MAX + 1);
153505a1495SSourav Poddar 		return -EINVAL;
154505a1495SSourav Poddar 	}
155505a1495SSourav Poddar 
156505a1495SSourav Poddar 	dev_dbg(qspi->dev, "hz: %d, clock divider %d\n",
157505a1495SSourav Poddar 			qspi->spi_max_frequency, clk_div);
158505a1495SSourav Poddar 
159505a1495SSourav Poddar 	ret = pm_runtime_get_sync(qspi->dev);
16005b96675SSourav Poddar 	if (ret < 0) {
161505a1495SSourav Poddar 		dev_err(qspi->dev, "pm_runtime_get_sync() failed\n");
162505a1495SSourav Poddar 		return ret;
163505a1495SSourav Poddar 	}
164505a1495SSourav Poddar 
165505a1495SSourav Poddar 	clk_ctrl_reg = ti_qspi_read(qspi, QSPI_SPI_CLOCK_CNTRL_REG);
166505a1495SSourav Poddar 
167505a1495SSourav Poddar 	clk_ctrl_reg &= ~QSPI_CLK_EN;
168505a1495SSourav Poddar 
169505a1495SSourav Poddar 	/* disable SCLK */
170505a1495SSourav Poddar 	ti_qspi_write(qspi, clk_ctrl_reg, QSPI_SPI_CLOCK_CNTRL_REG);
171505a1495SSourav Poddar 
172505a1495SSourav Poddar 	/* enable SCLK */
173505a1495SSourav Poddar 	clk_mask = QSPI_CLK_EN | clk_div;
174505a1495SSourav Poddar 	ti_qspi_write(qspi, clk_mask, QSPI_SPI_CLOCK_CNTRL_REG);
175505a1495SSourav Poddar 	ctx_reg->clkctrl = clk_mask;
176505a1495SSourav Poddar 
177505a1495SSourav Poddar 	pm_runtime_mark_last_busy(qspi->dev);
178505a1495SSourav Poddar 	ret = pm_runtime_put_autosuspend(qspi->dev);
179505a1495SSourav Poddar 	if (ret < 0) {
180505a1495SSourav Poddar 		dev_err(qspi->dev, "pm_runtime_put_autosuspend() failed\n");
181505a1495SSourav Poddar 		return ret;
182505a1495SSourav Poddar 	}
183505a1495SSourav Poddar 
184505a1495SSourav Poddar 	return 0;
185505a1495SSourav Poddar }
186505a1495SSourav Poddar 
187505a1495SSourav Poddar static void ti_qspi_restore_ctx(struct ti_qspi *qspi)
188505a1495SSourav Poddar {
189505a1495SSourav Poddar 	struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg;
190505a1495SSourav Poddar 
191505a1495SSourav Poddar 	ti_qspi_write(qspi, ctx_reg->clkctrl, QSPI_SPI_CLOCK_CNTRL_REG);
192505a1495SSourav Poddar }
193505a1495SSourav Poddar 
19400611047SMugunthan V N static inline u32 qspi_is_busy(struct ti_qspi *qspi)
19500611047SMugunthan V N {
19600611047SMugunthan V N 	u32 stat;
19700611047SMugunthan V N 	unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT;
19800611047SMugunthan V N 
19900611047SMugunthan V N 	stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
20000611047SMugunthan V N 	while ((stat & BUSY) && time_after(timeout, jiffies)) {
20100611047SMugunthan V N 		cpu_relax();
20200611047SMugunthan V N 		stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
20300611047SMugunthan V N 	}
20400611047SMugunthan V N 
20500611047SMugunthan V N 	WARN(stat & BUSY, "qspi busy\n");
20600611047SMugunthan V N 	return stat & BUSY;
20700611047SMugunthan V N }
20800611047SMugunthan V N 
20957c2ecd9SVignesh R static inline int ti_qspi_poll_wc(struct ti_qspi *qspi)
21057c2ecd9SVignesh R {
21157c2ecd9SVignesh R 	u32 stat;
21257c2ecd9SVignesh R 	unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT;
21357c2ecd9SVignesh R 
21457c2ecd9SVignesh R 	do {
21557c2ecd9SVignesh R 		stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
21657c2ecd9SVignesh R 		if (stat & WC)
21757c2ecd9SVignesh R 			return 0;
21857c2ecd9SVignesh R 		cpu_relax();
21957c2ecd9SVignesh R 	} while (time_after(timeout, jiffies));
22057c2ecd9SVignesh R 
22157c2ecd9SVignesh R 	stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG);
22257c2ecd9SVignesh R 	if (stat & WC)
22357c2ecd9SVignesh R 		return 0;
22457c2ecd9SVignesh R 	return  -ETIMEDOUT;
22557c2ecd9SVignesh R }
22657c2ecd9SVignesh R 
227505a1495SSourav Poddar static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
228505a1495SSourav Poddar {
229f682c4ffSVignesh R 	int wlen, count, xfer_len;
230505a1495SSourav Poddar 	unsigned int cmd;
231505a1495SSourav Poddar 	const u8 *txbuf;
232f682c4ffSVignesh R 	u32 data;
233505a1495SSourav Poddar 
234505a1495SSourav Poddar 	txbuf = t->tx_buf;
235505a1495SSourav Poddar 	cmd = qspi->cmd | QSPI_WR_SNGL;
236505a1495SSourav Poddar 	count = t->len;
2373ab54620SAxel Lin 	wlen = t->bits_per_word >> 3;	/* in bytes */
238f682c4ffSVignesh R 	xfer_len = wlen;
239505a1495SSourav Poddar 
240505a1495SSourav Poddar 	while (count) {
24100611047SMugunthan V N 		if (qspi_is_busy(qspi))
24200611047SMugunthan V N 			return -EBUSY;
24300611047SMugunthan V N 
244505a1495SSourav Poddar 		switch (wlen) {
2453ab54620SAxel Lin 		case 1:
246505a1495SSourav Poddar 			dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n",
247505a1495SSourav Poddar 					cmd, qspi->dc, *txbuf);
248f682c4ffSVignesh R 			if (count >= QSPI_WLEN_MAX_BYTES) {
249f682c4ffSVignesh R 				u32 *txp = (u32 *)txbuf;
250f682c4ffSVignesh R 
251f682c4ffSVignesh R 				data = cpu_to_be32(*txp++);
252f682c4ffSVignesh R 				writel(data, qspi->base +
253f682c4ffSVignesh R 				       QSPI_SPI_DATA_REG_3);
254f682c4ffSVignesh R 				data = cpu_to_be32(*txp++);
255f682c4ffSVignesh R 				writel(data, qspi->base +
256f682c4ffSVignesh R 				       QSPI_SPI_DATA_REG_2);
257f682c4ffSVignesh R 				data = cpu_to_be32(*txp++);
258f682c4ffSVignesh R 				writel(data, qspi->base +
259f682c4ffSVignesh R 				       QSPI_SPI_DATA_REG_1);
260f682c4ffSVignesh R 				data = cpu_to_be32(*txp++);
261f682c4ffSVignesh R 				writel(data, qspi->base +
262f682c4ffSVignesh R 				       QSPI_SPI_DATA_REG);
263f682c4ffSVignesh R 				xfer_len = QSPI_WLEN_MAX_BYTES;
264f682c4ffSVignesh R 				cmd |= QSPI_WLEN(QSPI_WLEN_MAX_BITS);
265f682c4ffSVignesh R 			} else {
266505a1495SSourav Poddar 				writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG);
267f682c4ffSVignesh R 				cmd = qspi->cmd | QSPI_WR_SNGL;
268f682c4ffSVignesh R 				xfer_len = wlen;
269f682c4ffSVignesh R 				cmd |= QSPI_WLEN(wlen);
270f682c4ffSVignesh R 			}
271505a1495SSourav Poddar 			break;
2723ab54620SAxel Lin 		case 2:
273505a1495SSourav Poddar 			dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n",
274505a1495SSourav Poddar 					cmd, qspi->dc, *txbuf);
275505a1495SSourav Poddar 			writew(*((u16 *)txbuf), qspi->base + QSPI_SPI_DATA_REG);
276505a1495SSourav Poddar 			break;
2773ab54620SAxel Lin 		case 4:
278505a1495SSourav Poddar 			dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %08x\n",
279505a1495SSourav Poddar 					cmd, qspi->dc, *txbuf);
280505a1495SSourav Poddar 			writel(*((u32 *)txbuf), qspi->base + QSPI_SPI_DATA_REG);
2813ab54620SAxel Lin 			break;
2823ab54620SAxel Lin 		}
2833ab54620SAxel Lin 
284505a1495SSourav Poddar 		ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
28557c2ecd9SVignesh R 		if (ti_qspi_poll_wc(qspi)) {
286505a1495SSourav Poddar 			dev_err(qspi->dev, "write timed out\n");
287505a1495SSourav Poddar 			return -ETIMEDOUT;
288505a1495SSourav Poddar 		}
289f682c4ffSVignesh R 		txbuf += xfer_len;
290f682c4ffSVignesh R 		count -= xfer_len;
291505a1495SSourav Poddar 	}
292505a1495SSourav Poddar 
293505a1495SSourav Poddar 	return 0;
294505a1495SSourav Poddar }
295505a1495SSourav Poddar 
296505a1495SSourav Poddar static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t)
297505a1495SSourav Poddar {
298060556a9SNicholas Mc Guire 	int wlen, count;
299505a1495SSourav Poddar 	unsigned int cmd;
300505a1495SSourav Poddar 	u8 *rxbuf;
301505a1495SSourav Poddar 
302505a1495SSourav Poddar 	rxbuf = t->rx_buf;
30370e2e976SSourav Poddar 	cmd = qspi->cmd;
30470e2e976SSourav Poddar 	switch (t->rx_nbits) {
30570e2e976SSourav Poddar 	case SPI_NBITS_DUAL:
30670e2e976SSourav Poddar 		cmd |= QSPI_RD_DUAL;
30770e2e976SSourav Poddar 		break;
30870e2e976SSourav Poddar 	case SPI_NBITS_QUAD:
30970e2e976SSourav Poddar 		cmd |= QSPI_RD_QUAD;
31070e2e976SSourav Poddar 		break;
31170e2e976SSourav Poddar 	default:
31270e2e976SSourav Poddar 		cmd |= QSPI_RD_SNGL;
31370e2e976SSourav Poddar 		break;
31470e2e976SSourav Poddar 	}
315505a1495SSourav Poddar 	count = t->len;
3163ab54620SAxel Lin 	wlen = t->bits_per_word >> 3;	/* in bytes */
317505a1495SSourav Poddar 
318505a1495SSourav Poddar 	while (count) {
319505a1495SSourav Poddar 		dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc);
32000611047SMugunthan V N 		if (qspi_is_busy(qspi))
32100611047SMugunthan V N 			return -EBUSY;
32200611047SMugunthan V N 
323505a1495SSourav Poddar 		ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
32457c2ecd9SVignesh R 		if (ti_qspi_poll_wc(qspi)) {
325505a1495SSourav Poddar 			dev_err(qspi->dev, "read timed out\n");
326505a1495SSourav Poddar 			return -ETIMEDOUT;
327505a1495SSourav Poddar 		}
328505a1495SSourav Poddar 		switch (wlen) {
3293ab54620SAxel Lin 		case 1:
330505a1495SSourav Poddar 			*rxbuf = readb(qspi->base + QSPI_SPI_DATA_REG);
331505a1495SSourav Poddar 			break;
3323ab54620SAxel Lin 		case 2:
333505a1495SSourav Poddar 			*((u16 *)rxbuf) = readw(qspi->base + QSPI_SPI_DATA_REG);
334505a1495SSourav Poddar 			break;
3353ab54620SAxel Lin 		case 4:
336505a1495SSourav Poddar 			*((u32 *)rxbuf) = readl(qspi->base + QSPI_SPI_DATA_REG);
337505a1495SSourav Poddar 			break;
338505a1495SSourav Poddar 		}
3393ab54620SAxel Lin 		rxbuf += wlen;
3403ab54620SAxel Lin 		count -= wlen;
341505a1495SSourav Poddar 	}
342505a1495SSourav Poddar 
343505a1495SSourav Poddar 	return 0;
344505a1495SSourav Poddar }
345505a1495SSourav Poddar 
346505a1495SSourav Poddar static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t)
347505a1495SSourav Poddar {
348505a1495SSourav Poddar 	int ret;
349505a1495SSourav Poddar 
350505a1495SSourav Poddar 	if (t->tx_buf) {
351505a1495SSourav Poddar 		ret = qspi_write_msg(qspi, t);
352505a1495SSourav Poddar 		if (ret) {
353505a1495SSourav Poddar 			dev_dbg(qspi->dev, "Error while writing\n");
354505a1495SSourav Poddar 			return ret;
355505a1495SSourav Poddar 		}
356505a1495SSourav Poddar 	}
357505a1495SSourav Poddar 
358505a1495SSourav Poddar 	if (t->rx_buf) {
359505a1495SSourav Poddar 		ret = qspi_read_msg(qspi, t);
360505a1495SSourav Poddar 		if (ret) {
361505a1495SSourav Poddar 			dev_dbg(qspi->dev, "Error while reading\n");
362505a1495SSourav Poddar 			return ret;
363505a1495SSourav Poddar 		}
364505a1495SSourav Poddar 	}
365505a1495SSourav Poddar 
366505a1495SSourav Poddar 	return 0;
367505a1495SSourav Poddar }
368505a1495SSourav Poddar 
369505a1495SSourav Poddar static int ti_qspi_start_transfer_one(struct spi_master *master,
370505a1495SSourav Poddar 		struct spi_message *m)
371505a1495SSourav Poddar {
372505a1495SSourav Poddar 	struct ti_qspi *qspi = spi_master_get_devdata(master);
373505a1495SSourav Poddar 	struct spi_device *spi = m->spi;
374505a1495SSourav Poddar 	struct spi_transfer *t;
375505a1495SSourav Poddar 	int status = 0, ret;
376505a1495SSourav Poddar 	int frame_length;
377505a1495SSourav Poddar 
378505a1495SSourav Poddar 	/* setup device control reg */
379505a1495SSourav Poddar 	qspi->dc = 0;
380505a1495SSourav Poddar 
381505a1495SSourav Poddar 	if (spi->mode & SPI_CPHA)
382505a1495SSourav Poddar 		qspi->dc |= QSPI_CKPHA(spi->chip_select);
383505a1495SSourav Poddar 	if (spi->mode & SPI_CPOL)
384505a1495SSourav Poddar 		qspi->dc |= QSPI_CKPOL(spi->chip_select);
385505a1495SSourav Poddar 	if (spi->mode & SPI_CS_HIGH)
386505a1495SSourav Poddar 		qspi->dc |= QSPI_CSPOL(spi->chip_select);
387505a1495SSourav Poddar 
388505a1495SSourav Poddar 	frame_length = (m->frame_length << 3) / spi->bits_per_word;
389505a1495SSourav Poddar 
390505a1495SSourav Poddar 	frame_length = clamp(frame_length, 0, QSPI_FRAME);
391505a1495SSourav Poddar 
392505a1495SSourav Poddar 	/* setup command reg */
393505a1495SSourav Poddar 	qspi->cmd = 0;
394505a1495SSourav Poddar 	qspi->cmd |= QSPI_EN_CS(spi->chip_select);
395505a1495SSourav Poddar 	qspi->cmd |= QSPI_FLEN(frame_length);
396505a1495SSourav Poddar 
397505a1495SSourav Poddar 	ti_qspi_write(qspi, qspi->dc, QSPI_SPI_DC_REG);
398505a1495SSourav Poddar 
399505a1495SSourav Poddar 	mutex_lock(&qspi->list_lock);
400505a1495SSourav Poddar 
401505a1495SSourav Poddar 	list_for_each_entry(t, &m->transfers, transfer_list) {
402505a1495SSourav Poddar 		qspi->cmd |= QSPI_WLEN(t->bits_per_word);
403505a1495SSourav Poddar 
404505a1495SSourav Poddar 		ret = qspi_transfer_msg(qspi, t);
405505a1495SSourav Poddar 		if (ret) {
406505a1495SSourav Poddar 			dev_dbg(qspi->dev, "transfer message failed\n");
407b6460366SWei Yongjun 			mutex_unlock(&qspi->list_lock);
408505a1495SSourav Poddar 			return -EINVAL;
409505a1495SSourav Poddar 		}
410505a1495SSourav Poddar 
411505a1495SSourav Poddar 		m->actual_length += t->len;
412505a1495SSourav Poddar 	}
413505a1495SSourav Poddar 
414505a1495SSourav Poddar 	mutex_unlock(&qspi->list_lock);
415505a1495SSourav Poddar 
416bc27a539SVignesh R 	ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG);
417505a1495SSourav Poddar 	m->status = status;
418505a1495SSourav Poddar 	spi_finalize_current_message(master);
419505a1495SSourav Poddar 
420505a1495SSourav Poddar 	return status;
421505a1495SSourav Poddar }
422505a1495SSourav Poddar 
423505a1495SSourav Poddar static int ti_qspi_runtime_resume(struct device *dev)
424505a1495SSourav Poddar {
425505a1495SSourav Poddar 	struct ti_qspi      *qspi;
426505a1495SSourav Poddar 
427f17414c4SSourav Poddar 	qspi = dev_get_drvdata(dev);
428505a1495SSourav Poddar 	ti_qspi_restore_ctx(qspi);
429505a1495SSourav Poddar 
430505a1495SSourav Poddar 	return 0;
431505a1495SSourav Poddar }
432505a1495SSourav Poddar 
433505a1495SSourav Poddar static const struct of_device_id ti_qspi_match[] = {
434505a1495SSourav Poddar 	{.compatible = "ti,dra7xxx-qspi" },
43509222fc3SSourav Poddar 	{.compatible = "ti,am4372-qspi" },
436505a1495SSourav Poddar 	{},
437505a1495SSourav Poddar };
438e1432d30SSourav Poddar MODULE_DEVICE_TABLE(of, ti_qspi_match);
439505a1495SSourav Poddar 
440505a1495SSourav Poddar static int ti_qspi_probe(struct platform_device *pdev)
441505a1495SSourav Poddar {
442505a1495SSourav Poddar 	struct  ti_qspi *qspi;
443505a1495SSourav Poddar 	struct spi_master *master;
4446b3938aeSSourav Poddar 	struct resource         *r, *res_ctrl, *res_mmap;
445505a1495SSourav Poddar 	struct device_node *np = pdev->dev.of_node;
446505a1495SSourav Poddar 	u32 max_freq;
447505a1495SSourav Poddar 	int ret = 0, num_cs, irq;
448505a1495SSourav Poddar 
449505a1495SSourav Poddar 	master = spi_alloc_master(&pdev->dev, sizeof(*qspi));
450505a1495SSourav Poddar 	if (!master)
451505a1495SSourav Poddar 		return -ENOMEM;
452505a1495SSourav Poddar 
453633795b9SSourav Poddar 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD;
454505a1495SSourav Poddar 
455505a1495SSourav Poddar 	master->flags = SPI_MASTER_HALF_DUPLEX;
456505a1495SSourav Poddar 	master->setup = ti_qspi_setup;
457505a1495SSourav Poddar 	master->auto_runtime_pm = true;
458505a1495SSourav Poddar 	master->transfer_one_message = ti_qspi_start_transfer_one;
459505a1495SSourav Poddar 	master->dev.of_node = pdev->dev.of_node;
460aa188f90SAxel Lin 	master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) |
461aa188f90SAxel Lin 				     SPI_BPW_MASK(8);
462505a1495SSourav Poddar 
463505a1495SSourav Poddar 	if (!of_property_read_u32(np, "num-cs", &num_cs))
464505a1495SSourav Poddar 		master->num_chipselect = num_cs;
465505a1495SSourav Poddar 
466505a1495SSourav Poddar 	qspi = spi_master_get_devdata(master);
467505a1495SSourav Poddar 	qspi->master = master;
468505a1495SSourav Poddar 	qspi->dev = &pdev->dev;
469160a0613SWei Yongjun 	platform_set_drvdata(pdev, qspi);
470505a1495SSourav Poddar 
4716b3938aeSSourav Poddar 	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_base");
4726b3938aeSSourav Poddar 	if (r == NULL) {
473505a1495SSourav Poddar 		r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
4746b3938aeSSourav Poddar 		if (r == NULL) {
4756b3938aeSSourav Poddar 			dev_err(&pdev->dev, "missing platform data\n");
4766b3938aeSSourav Poddar 			return -ENODEV;
4776b3938aeSSourav Poddar 		}
4786b3938aeSSourav Poddar 	}
4796b3938aeSSourav Poddar 
4806b3938aeSSourav Poddar 	res_mmap = platform_get_resource_byname(pdev,
4816b3938aeSSourav Poddar 			IORESOURCE_MEM, "qspi_mmap");
4826b3938aeSSourav Poddar 	if (res_mmap == NULL) {
4836b3938aeSSourav Poddar 		res_mmap = platform_get_resource(pdev, IORESOURCE_MEM, 1);
4846b3938aeSSourav Poddar 		if (res_mmap == NULL) {
4856b3938aeSSourav Poddar 			dev_err(&pdev->dev,
4866b3938aeSSourav Poddar 				"memory mapped resource not required\n");
4876b3938aeSSourav Poddar 		}
4886b3938aeSSourav Poddar 	}
4896b3938aeSSourav Poddar 
4906b3938aeSSourav Poddar 	res_ctrl = platform_get_resource_byname(pdev,
4916b3938aeSSourav Poddar 			IORESOURCE_MEM, "qspi_ctrlmod");
4926b3938aeSSourav Poddar 	if (res_ctrl == NULL) {
4936b3938aeSSourav Poddar 		res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 2);
4946b3938aeSSourav Poddar 		if (res_ctrl == NULL) {
4956b3938aeSSourav Poddar 			dev_dbg(&pdev->dev,
4966b3938aeSSourav Poddar 				"control module resources not required\n");
4976b3938aeSSourav Poddar 		}
4986b3938aeSSourav Poddar 	}
499505a1495SSourav Poddar 
500505a1495SSourav Poddar 	irq = platform_get_irq(pdev, 0);
501505a1495SSourav Poddar 	if (irq < 0) {
502505a1495SSourav Poddar 		dev_err(&pdev->dev, "no irq resource?\n");
503505a1495SSourav Poddar 		return irq;
504505a1495SSourav Poddar 	}
505505a1495SSourav Poddar 
506505a1495SSourav Poddar 	mutex_init(&qspi->list_lock);
507505a1495SSourav Poddar 
508505a1495SSourav Poddar 	qspi->base = devm_ioremap_resource(&pdev->dev, r);
509505a1495SSourav Poddar 	if (IS_ERR(qspi->base)) {
510505a1495SSourav Poddar 		ret = PTR_ERR(qspi->base);
511505a1495SSourav Poddar 		goto free_master;
512505a1495SSourav Poddar 	}
513505a1495SSourav Poddar 
5146b3938aeSSourav Poddar 	if (res_ctrl) {
5156b3938aeSSourav Poddar 		qspi->ctrl_mod = true;
5166b3938aeSSourav Poddar 		qspi->ctrl_base = devm_ioremap_resource(&pdev->dev, res_ctrl);
5176b3938aeSSourav Poddar 		if (IS_ERR(qspi->ctrl_base)) {
5186b3938aeSSourav Poddar 			ret = PTR_ERR(qspi->ctrl_base);
5196b3938aeSSourav Poddar 			goto free_master;
5206b3938aeSSourav Poddar 		}
5216b3938aeSSourav Poddar 	}
5226b3938aeSSourav Poddar 
5236b3938aeSSourav Poddar 	if (res_mmap) {
5246b3938aeSSourav Poddar 		qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap);
5256b3938aeSSourav Poddar 		if (IS_ERR(qspi->mmap_base)) {
5266b3938aeSSourav Poddar 			ret = PTR_ERR(qspi->mmap_base);
5276b3938aeSSourav Poddar 			goto free_master;
5286b3938aeSSourav Poddar 		}
5296b3938aeSSourav Poddar 	}
5306b3938aeSSourav Poddar 
531505a1495SSourav Poddar 	qspi->fclk = devm_clk_get(&pdev->dev, "fck");
532505a1495SSourav Poddar 	if (IS_ERR(qspi->fclk)) {
533505a1495SSourav Poddar 		ret = PTR_ERR(qspi->fclk);
534505a1495SSourav Poddar 		dev_err(&pdev->dev, "could not get clk: %d\n", ret);
535505a1495SSourav Poddar 	}
536505a1495SSourav Poddar 
537505a1495SSourav Poddar 	pm_runtime_use_autosuspend(&pdev->dev);
538505a1495SSourav Poddar 	pm_runtime_set_autosuspend_delay(&pdev->dev, QSPI_AUTOSUSPEND_TIMEOUT);
539505a1495SSourav Poddar 	pm_runtime_enable(&pdev->dev);
540505a1495SSourav Poddar 
541505a1495SSourav Poddar 	if (!of_property_read_u32(np, "spi-max-frequency", &max_freq))
542505a1495SSourav Poddar 		qspi->spi_max_frequency = max_freq;
543505a1495SSourav Poddar 
5447388c03bSJingoo Han 	ret = devm_spi_register_master(&pdev->dev, master);
545505a1495SSourav Poddar 	if (ret)
546505a1495SSourav Poddar 		goto free_master;
547505a1495SSourav Poddar 
548505a1495SSourav Poddar 	return 0;
549505a1495SSourav Poddar 
550505a1495SSourav Poddar free_master:
551505a1495SSourav Poddar 	spi_master_put(master);
552505a1495SSourav Poddar 	return ret;
553505a1495SSourav Poddar }
554505a1495SSourav Poddar 
555505a1495SSourav Poddar static int ti_qspi_remove(struct platform_device *pdev)
556505a1495SSourav Poddar {
557e6b5140bSFelipe Balbi 	pm_runtime_put_sync(&pdev->dev);
558cbcabb7aSSourav Poddar 	pm_runtime_disable(&pdev->dev);
559cbcabb7aSSourav Poddar 
560505a1495SSourav Poddar 	return 0;
561505a1495SSourav Poddar }
562505a1495SSourav Poddar 
563505a1495SSourav Poddar static const struct dev_pm_ops ti_qspi_pm_ops = {
564505a1495SSourav Poddar 	.runtime_resume = ti_qspi_runtime_resume,
565505a1495SSourav Poddar };
566505a1495SSourav Poddar 
567505a1495SSourav Poddar static struct platform_driver ti_qspi_driver = {
568505a1495SSourav Poddar 	.probe	= ti_qspi_probe,
569505a1495SSourav Poddar 	.remove = ti_qspi_remove,
570505a1495SSourav Poddar 	.driver = {
5715a33d30fSAxel Lin 		.name	= "ti-qspi",
572505a1495SSourav Poddar 		.pm =   &ti_qspi_pm_ops,
573505a1495SSourav Poddar 		.of_match_table = ti_qspi_match,
574505a1495SSourav Poddar 	}
575505a1495SSourav Poddar };
576505a1495SSourav Poddar 
577505a1495SSourav Poddar module_platform_driver(ti_qspi_driver);
578505a1495SSourav Poddar 
579505a1495SSourav Poddar MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>");
580505a1495SSourav Poddar MODULE_LICENSE("GPL v2");
581505a1495SSourav Poddar MODULE_DESCRIPTION("TI QSPI controller driver");
5825a33d30fSAxel Lin MODULE_ALIAS("platform:ti-qspi");
583