xref: /openbmc/linux/drivers/spi/spi-synquacer.c (revision 917e43de)
1b0823ee3SMasahisa Kojima // SPDX-License-Identifier: GPL-2.0
2b0823ee3SMasahisa Kojima //
3b0823ee3SMasahisa Kojima // Synquacer HSSPI controller driver
4b0823ee3SMasahisa Kojima //
5b0823ee3SMasahisa Kojima // Copyright (c) 2015-2018 Socionext Inc.
6b0823ee3SMasahisa Kojima // Copyright (c) 2018-2019 Linaro Ltd.
7b0823ee3SMasahisa Kojima //
8b0823ee3SMasahisa Kojima 
9b0823ee3SMasahisa Kojima #include <linux/acpi.h>
10b0823ee3SMasahisa Kojima #include <linux/delay.h>
11b0823ee3SMasahisa Kojima #include <linux/interrupt.h>
12b0823ee3SMasahisa Kojima #include <linux/io.h>
13b0823ee3SMasahisa Kojima #include <linux/module.h>
14b0823ee3SMasahisa Kojima #include <linux/of.h>
15b0823ee3SMasahisa Kojima #include <linux/platform_device.h>
16b0823ee3SMasahisa Kojima #include <linux/pm_runtime.h>
17b0823ee3SMasahisa Kojima #include <linux/scatterlist.h>
18b0823ee3SMasahisa Kojima #include <linux/slab.h>
19b0823ee3SMasahisa Kojima #include <linux/spi/spi.h>
20b0823ee3SMasahisa Kojima #include <linux/spinlock.h>
21b0823ee3SMasahisa Kojima #include <linux/clk.h>
22b0823ee3SMasahisa Kojima 
23b0823ee3SMasahisa Kojima /* HSSPI register address definitions */
24b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_MCTRL	0x00
25b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_PCC0	0x04
26b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_PCC(n)	(SYNQUACER_HSSPI_REG_PCC0 + (n) * 4)
27b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_TXF		0x14
28b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_TXE		0x18
29b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_TXC		0x1C
30b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_RXF		0x20
31b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_RXE		0x24
32b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_RXC		0x28
33b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_FAULTF	0x2C
34b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_FAULTC	0x30
35b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_DMCFG	0x34
36b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_DMSTART	0x38
37b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_DMBCC	0x3C
38b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_DMSTATUS	0x40
39b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_FIFOCFG	0x4C
40b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_TX_FIFO	0x50
41b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_RX_FIFO	0x90
42b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_MID		0xFC
43b0823ee3SMasahisa Kojima 
44b0823ee3SMasahisa Kojima /* HSSPI register bit definitions */
45b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_MCTRL_MEN			BIT(0)
46b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_MCTRL_COMMAND_SEQUENCE_EN	BIT(1)
47b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_MCTRL_CDSS			BIT(3)
48b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_MCTRL_MES			BIT(4)
49b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_MCTRL_SYNCON			BIT(5)
50b0823ee3SMasahisa Kojima 
51b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_CPHA		BIT(0)
52b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_CPOL		BIT(1)
53b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_ACES		BIT(2)
54b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_RTM			BIT(3)
55b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_SSPOL		BIT(4)
56b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_SDIR		BIT(7)
57b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_SENDIAN		BIT(8)
58b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_SAFESYNC		BIT(16)
59b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_SS2CD_SHIFT		5U
60b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_CDRS_MASK		0x7f
61b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_CDRS_SHIFT		9U
62b0823ee3SMasahisa Kojima 
63b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TXF_FIFO_FULL		BIT(0)
64b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TXF_FIFO_EMPTY		BIT(1)
65b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TXF_SLAVE_RELEASED	BIT(6)
66b0823ee3SMasahisa Kojima 
67b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TXE_FIFO_FULL		BIT(0)
68b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TXE_FIFO_EMPTY		BIT(1)
69b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TXE_SLAVE_RELEASED	BIT(6)
70b0823ee3SMasahisa Kojima 
71b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_RXF_FIFO_MORE_THAN_THRESHOLD		BIT(5)
72b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_RXF_SLAVE_RELEASED			BIT(6)
73b0823ee3SMasahisa Kojima 
74b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_RXE_FIFO_MORE_THAN_THRESHOLD		BIT(5)
75b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_RXE_SLAVE_RELEASED			BIT(6)
76b0823ee3SMasahisa Kojima 
77b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMCFG_SSDC		BIT(1)
78b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMCFG_MSTARTEN		BIT(2)
79b0823ee3SMasahisa Kojima 
80b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMSTART_START		BIT(0)
81b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMSTOP_STOP		BIT(8)
82b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMPSEL_CS_MASK		0x3
83b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMPSEL_CS_SHIFT		16U
84b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT	24U
85b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMTRP_DATA_MASK		0x3
86b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMTRP_DATA_SHIFT	26U
87b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMTRP_DATA_TXRX		0
88b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMTRP_DATA_RX		1
89b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMTRP_DATA_TX		2
90b0823ee3SMasahisa Kojima 
91b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMSTATUS_RX_DATA_MASK	0x1f
92b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMSTATUS_RX_DATA_SHIFT	8U
93b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMSTATUS_TX_DATA_MASK	0x1f
94b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMSTATUS_TX_DATA_SHIFT	16U
95b0823ee3SMasahisa Kojima 
96b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_MASK	0xf
97b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT	0U
98b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFOCFG_TX_THRESHOLD_MASK	0xf
99b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFOCFG_TX_THRESHOLD_SHIFT	4U
100b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_MASK		0x3
101b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT	8U
102b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFOCFG_RX_FLUSH		BIT(11)
103b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFOCFG_TX_FLUSH		BIT(12)
104b0823ee3SMasahisa Kojima 
105b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFO_DEPTH		16U
106b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFO_TX_THRESHOLD	4U
107b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFO_RX_THRESHOLD \
108b0823ee3SMasahisa Kojima 	(SYNQUACER_HSSPI_FIFO_DEPTH - SYNQUACER_HSSPI_FIFO_TX_THRESHOLD)
109b0823ee3SMasahisa Kojima 
110b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TRANSFER_MODE_TX	BIT(1)
111b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TRANSFER_MODE_RX	BIT(2)
112b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC	2000U
113b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_ENABLE_TMOUT_MSEC	1000U
114b0823ee3SMasahisa Kojima 
115b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_CLOCK_SRC_IHCLK		0
116b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_CLOCK_SRC_IPCLK		1
117b0823ee3SMasahisa Kojima 
118b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_NUM_CHIP_SELECT		4U
119b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_IRQ_NAME_MAX		32U
120b0823ee3SMasahisa Kojima 
121b0823ee3SMasahisa Kojima struct synquacer_spi {
122b0823ee3SMasahisa Kojima 	struct device *dev;
123b0823ee3SMasahisa Kojima 	struct completion transfer_done;
124b0823ee3SMasahisa Kojima 	unsigned int cs;
125b0823ee3SMasahisa Kojima 	unsigned int bpw;
126b0823ee3SMasahisa Kojima 	unsigned int mode;
127b0823ee3SMasahisa Kojima 	unsigned int speed;
128b0823ee3SMasahisa Kojima 	bool aces, rtm;
129b0823ee3SMasahisa Kojima 	void *rx_buf;
130b0823ee3SMasahisa Kojima 	const void *tx_buf;
131b0823ee3SMasahisa Kojima 	struct clk *clk;
132b0823ee3SMasahisa Kojima 	int clk_src_type;
133b0823ee3SMasahisa Kojima 	void __iomem *regs;
134b0823ee3SMasahisa Kojima 	u32 tx_words, rx_words;
135b0823ee3SMasahisa Kojima 	unsigned int bus_width;
136b0823ee3SMasahisa Kojima 	unsigned int transfer_mode;
137b0823ee3SMasahisa Kojima 	char rx_irq_name[SYNQUACER_HSSPI_IRQ_NAME_MAX];
138b0823ee3SMasahisa Kojima 	char tx_irq_name[SYNQUACER_HSSPI_IRQ_NAME_MAX];
139b0823ee3SMasahisa Kojima };
140b0823ee3SMasahisa Kojima 
141b0823ee3SMasahisa Kojima static int read_fifo(struct synquacer_spi *sspi)
142b0823ee3SMasahisa Kojima {
143b0823ee3SMasahisa Kojima 	u32 len = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTATUS);
144b0823ee3SMasahisa Kojima 
145b0823ee3SMasahisa Kojima 	len = (len >> SYNQUACER_HSSPI_DMSTATUS_RX_DATA_SHIFT) &
146b0823ee3SMasahisa Kojima 	       SYNQUACER_HSSPI_DMSTATUS_RX_DATA_MASK;
147b0823ee3SMasahisa Kojima 	len = min(len, sspi->rx_words);
148b0823ee3SMasahisa Kojima 
149b0823ee3SMasahisa Kojima 	switch (sspi->bpw) {
150b0823ee3SMasahisa Kojima 	case 8: {
151b0823ee3SMasahisa Kojima 		u8 *buf = sspi->rx_buf;
152b0823ee3SMasahisa Kojima 
15351c711f2SMasahisa Kojima 		ioread8_rep(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO,
15451c711f2SMasahisa Kojima 			    buf, len);
155b0823ee3SMasahisa Kojima 		sspi->rx_buf = buf + len;
156b0823ee3SMasahisa Kojima 		break;
157b0823ee3SMasahisa Kojima 	}
158b0823ee3SMasahisa Kojima 	case 16: {
159b0823ee3SMasahisa Kojima 		u16 *buf = sspi->rx_buf;
160b0823ee3SMasahisa Kojima 
16151c711f2SMasahisa Kojima 		ioread16_rep(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO,
16251c711f2SMasahisa Kojima 			     buf, len);
163b0823ee3SMasahisa Kojima 		sspi->rx_buf = buf + len;
164b0823ee3SMasahisa Kojima 		break;
165b0823ee3SMasahisa Kojima 	}
166b0823ee3SMasahisa Kojima 	case 24:
167b0823ee3SMasahisa Kojima 		/* fallthrough, should use 32-bits access */
168b0823ee3SMasahisa Kojima 	case 32: {
169b0823ee3SMasahisa Kojima 		u32 *buf = sspi->rx_buf;
170b0823ee3SMasahisa Kojima 
17151c711f2SMasahisa Kojima 		ioread32_rep(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO,
17251c711f2SMasahisa Kojima 			     buf, len);
173b0823ee3SMasahisa Kojima 		sspi->rx_buf = buf + len;
174b0823ee3SMasahisa Kojima 		break;
175b0823ee3SMasahisa Kojima 	}
176b0823ee3SMasahisa Kojima 	default:
177b0823ee3SMasahisa Kojima 		return -EINVAL;
178b0823ee3SMasahisa Kojima 	}
179b0823ee3SMasahisa Kojima 
180b0823ee3SMasahisa Kojima 	sspi->rx_words -= len;
181b0823ee3SMasahisa Kojima 	return 0;
182b0823ee3SMasahisa Kojima }
183b0823ee3SMasahisa Kojima 
184b0823ee3SMasahisa Kojima static int write_fifo(struct synquacer_spi *sspi)
185b0823ee3SMasahisa Kojima {
186b0823ee3SMasahisa Kojima 	u32 len = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTATUS);
187b0823ee3SMasahisa Kojima 
188b0823ee3SMasahisa Kojima 	len = (len >> SYNQUACER_HSSPI_DMSTATUS_TX_DATA_SHIFT) &
189b0823ee3SMasahisa Kojima 	       SYNQUACER_HSSPI_DMSTATUS_TX_DATA_MASK;
190b0823ee3SMasahisa Kojima 	len = min(SYNQUACER_HSSPI_FIFO_DEPTH - len,
191b0823ee3SMasahisa Kojima 		    sspi->tx_words);
192b0823ee3SMasahisa Kojima 
193b0823ee3SMasahisa Kojima 	switch (sspi->bpw) {
194b0823ee3SMasahisa Kojima 	case 8: {
195b0823ee3SMasahisa Kojima 		const u8 *buf = sspi->tx_buf;
196b0823ee3SMasahisa Kojima 
19751c711f2SMasahisa Kojima 		iowrite8_rep(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO,
19851c711f2SMasahisa Kojima 			     buf, len);
199b0823ee3SMasahisa Kojima 		sspi->tx_buf = buf + len;
200b0823ee3SMasahisa Kojima 		break;
201b0823ee3SMasahisa Kojima 	}
202b0823ee3SMasahisa Kojima 	case 16: {
203b0823ee3SMasahisa Kojima 		const u16 *buf = sspi->tx_buf;
204b0823ee3SMasahisa Kojima 
20551c711f2SMasahisa Kojima 		iowrite16_rep(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO,
20651c711f2SMasahisa Kojima 			      buf, len);
207b0823ee3SMasahisa Kojima 		sspi->tx_buf = buf + len;
208b0823ee3SMasahisa Kojima 		break;
209b0823ee3SMasahisa Kojima 	}
210b0823ee3SMasahisa Kojima 	case 24:
211b0823ee3SMasahisa Kojima 		/* fallthrough, should use 32-bits access */
212b0823ee3SMasahisa Kojima 	case 32: {
213b0823ee3SMasahisa Kojima 		const u32 *buf = sspi->tx_buf;
214b0823ee3SMasahisa Kojima 
21551c711f2SMasahisa Kojima 		iowrite32_rep(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO,
21651c711f2SMasahisa Kojima 			      buf, len);
217b0823ee3SMasahisa Kojima 		sspi->tx_buf = buf + len;
218b0823ee3SMasahisa Kojima 		break;
219b0823ee3SMasahisa Kojima 	}
220b0823ee3SMasahisa Kojima 	default:
221b0823ee3SMasahisa Kojima 		return -EINVAL;
222b0823ee3SMasahisa Kojima 	}
223b0823ee3SMasahisa Kojima 
224b0823ee3SMasahisa Kojima 	sspi->tx_words -= len;
225b0823ee3SMasahisa Kojima 	return 0;
226b0823ee3SMasahisa Kojima }
227b0823ee3SMasahisa Kojima 
228b0823ee3SMasahisa Kojima static int synquacer_spi_config(struct spi_master *master,
229b0823ee3SMasahisa Kojima 				struct spi_device *spi,
230b0823ee3SMasahisa Kojima 				struct spi_transfer *xfer)
231b0823ee3SMasahisa Kojima {
232b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi = spi_master_get_devdata(master);
233b0823ee3SMasahisa Kojima 	unsigned int speed, mode, bpw, cs, bus_width, transfer_mode;
234b0823ee3SMasahisa Kojima 	u32 rate, val, div;
235b0823ee3SMasahisa Kojima 
236b0823ee3SMasahisa Kojima 	/* Full Duplex only on 1-bit wide bus */
237b0823ee3SMasahisa Kojima 	if (xfer->rx_buf && xfer->tx_buf &&
238b0823ee3SMasahisa Kojima 	    (xfer->rx_nbits != 1 || xfer->tx_nbits != 1)) {
239b0823ee3SMasahisa Kojima 		dev_err(sspi->dev,
240b0823ee3SMasahisa Kojima 			"RX and TX bus widths must be 1-bit for Full-Duplex!\n");
241b0823ee3SMasahisa Kojima 		return -EINVAL;
242b0823ee3SMasahisa Kojima 	}
243b0823ee3SMasahisa Kojima 
244b0823ee3SMasahisa Kojima 	if (xfer->tx_buf) {
245b0823ee3SMasahisa Kojima 		bus_width = xfer->tx_nbits;
246b0823ee3SMasahisa Kojima 		transfer_mode = SYNQUACER_HSSPI_TRANSFER_MODE_TX;
247b0823ee3SMasahisa Kojima 	} else {
248b0823ee3SMasahisa Kojima 		bus_width = xfer->rx_nbits;
249b0823ee3SMasahisa Kojima 		transfer_mode = SYNQUACER_HSSPI_TRANSFER_MODE_RX;
250b0823ee3SMasahisa Kojima 	}
251b0823ee3SMasahisa Kojima 
252b0823ee3SMasahisa Kojima 	mode = spi->mode;
253b0823ee3SMasahisa Kojima 	cs = spi->chip_select;
254b0823ee3SMasahisa Kojima 	speed = xfer->speed_hz;
255b0823ee3SMasahisa Kojima 	bpw = xfer->bits_per_word;
256b0823ee3SMasahisa Kojima 
257b0823ee3SMasahisa Kojima 	/* return if nothing to change */
258b0823ee3SMasahisa Kojima 	if (speed == sspi->speed &&
259b0823ee3SMasahisa Kojima 		bus_width == sspi->bus_width && bpw == sspi->bpw &&
260b0823ee3SMasahisa Kojima 		mode == sspi->mode && cs == sspi->cs &&
261b0823ee3SMasahisa Kojima 		transfer_mode == sspi->transfer_mode) {
262b0823ee3SMasahisa Kojima 		return 0;
263b0823ee3SMasahisa Kojima 	}
264b0823ee3SMasahisa Kojima 
265b0823ee3SMasahisa Kojima 	sspi->transfer_mode = transfer_mode;
266b0823ee3SMasahisa Kojima 	rate = master->max_speed_hz;
267b0823ee3SMasahisa Kojima 
268b0823ee3SMasahisa Kojima 	div = DIV_ROUND_UP(rate, speed);
269b0823ee3SMasahisa Kojima 	if (div > 254) {
270b0823ee3SMasahisa Kojima 		dev_err(sspi->dev, "Requested rate too low (%u)\n",
271b0823ee3SMasahisa Kojima 			sspi->speed);
272b0823ee3SMasahisa Kojima 		return -EINVAL;
273b0823ee3SMasahisa Kojima 	}
274b0823ee3SMasahisa Kojima 
275b0823ee3SMasahisa Kojima 	val = readl(sspi->regs + SYNQUACER_HSSPI_REG_PCC(cs));
276b0823ee3SMasahisa Kojima 	val &= ~SYNQUACER_HSSPI_PCC_SAFESYNC;
277b0823ee3SMasahisa Kojima 	if (bpw == 8 &&	(mode & (SPI_TX_DUAL | SPI_RX_DUAL)) && div < 3)
278b0823ee3SMasahisa Kojima 		val |= SYNQUACER_HSSPI_PCC_SAFESYNC;
279b0823ee3SMasahisa Kojima 	if (bpw == 8 &&	(mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 6)
280b0823ee3SMasahisa Kojima 		val |= SYNQUACER_HSSPI_PCC_SAFESYNC;
281b0823ee3SMasahisa Kojima 	if (bpw == 16 && (mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 3)
282b0823ee3SMasahisa Kojima 		val |= SYNQUACER_HSSPI_PCC_SAFESYNC;
283b0823ee3SMasahisa Kojima 
284b0823ee3SMasahisa Kojima 	if (mode & SPI_CPHA)
285b0823ee3SMasahisa Kojima 		val |= SYNQUACER_HSSPI_PCC_CPHA;
286b0823ee3SMasahisa Kojima 	else
287b0823ee3SMasahisa Kojima 		val &= ~SYNQUACER_HSSPI_PCC_CPHA;
288b0823ee3SMasahisa Kojima 
289b0823ee3SMasahisa Kojima 	if (mode & SPI_CPOL)
290b0823ee3SMasahisa Kojima 		val |= SYNQUACER_HSSPI_PCC_CPOL;
291b0823ee3SMasahisa Kojima 	else
292b0823ee3SMasahisa Kojima 		val &= ~SYNQUACER_HSSPI_PCC_CPOL;
293b0823ee3SMasahisa Kojima 
294b0823ee3SMasahisa Kojima 	if (mode & SPI_CS_HIGH)
295b0823ee3SMasahisa Kojima 		val |= SYNQUACER_HSSPI_PCC_SSPOL;
296b0823ee3SMasahisa Kojima 	else
297b0823ee3SMasahisa Kojima 		val &= ~SYNQUACER_HSSPI_PCC_SSPOL;
298b0823ee3SMasahisa Kojima 
299b0823ee3SMasahisa Kojima 	if (mode & SPI_LSB_FIRST)
300b0823ee3SMasahisa Kojima 		val |= SYNQUACER_HSSPI_PCC_SDIR;
301b0823ee3SMasahisa Kojima 	else
302b0823ee3SMasahisa Kojima 		val &= ~SYNQUACER_HSSPI_PCC_SDIR;
303b0823ee3SMasahisa Kojima 
304b0823ee3SMasahisa Kojima 	if (sspi->aces)
305b0823ee3SMasahisa Kojima 		val |= SYNQUACER_HSSPI_PCC_ACES;
306b0823ee3SMasahisa Kojima 	else
307b0823ee3SMasahisa Kojima 		val &= ~SYNQUACER_HSSPI_PCC_ACES;
308b0823ee3SMasahisa Kojima 
309b0823ee3SMasahisa Kojima 	if (sspi->rtm)
310b0823ee3SMasahisa Kojima 		val |= SYNQUACER_HSSPI_PCC_RTM;
311b0823ee3SMasahisa Kojima 	else
312b0823ee3SMasahisa Kojima 		val &= ~SYNQUACER_HSSPI_PCC_RTM;
313b0823ee3SMasahisa Kojima 
314b0823ee3SMasahisa Kojima 	val |= (3 << SYNQUACER_HSSPI_PCC_SS2CD_SHIFT);
315b0823ee3SMasahisa Kojima 	val |= SYNQUACER_HSSPI_PCC_SENDIAN;
316b0823ee3SMasahisa Kojima 
317b0823ee3SMasahisa Kojima 	val &= ~(SYNQUACER_HSSPI_PCC_CDRS_MASK <<
318b0823ee3SMasahisa Kojima 		 SYNQUACER_HSSPI_PCC_CDRS_SHIFT);
319b0823ee3SMasahisa Kojima 	val |= ((div >> 1) << SYNQUACER_HSSPI_PCC_CDRS_SHIFT);
320b0823ee3SMasahisa Kojima 
321b0823ee3SMasahisa Kojima 	writel(val, sspi->regs + SYNQUACER_HSSPI_REG_PCC(cs));
322b0823ee3SMasahisa Kojima 
323b0823ee3SMasahisa Kojima 	val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
324b0823ee3SMasahisa Kojima 	val &= ~(SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_MASK <<
325b0823ee3SMasahisa Kojima 		 SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT);
326b0823ee3SMasahisa Kojima 	val |= ((bpw / 8 - 1) << SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT);
327b0823ee3SMasahisa Kojima 	writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
328b0823ee3SMasahisa Kojima 
329b0823ee3SMasahisa Kojima 	val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
330b0823ee3SMasahisa Kojima 	val &= ~(SYNQUACER_HSSPI_DMTRP_DATA_MASK <<
331b0823ee3SMasahisa Kojima 		 SYNQUACER_HSSPI_DMTRP_DATA_SHIFT);
332b0823ee3SMasahisa Kojima 
333b0823ee3SMasahisa Kojima 	if (xfer->rx_buf)
334b0823ee3SMasahisa Kojima 		val |= (SYNQUACER_HSSPI_DMTRP_DATA_RX <<
335b0823ee3SMasahisa Kojima 			SYNQUACER_HSSPI_DMTRP_DATA_SHIFT);
336b0823ee3SMasahisa Kojima 	else
337b0823ee3SMasahisa Kojima 		val |= (SYNQUACER_HSSPI_DMTRP_DATA_TX <<
338b0823ee3SMasahisa Kojima 			SYNQUACER_HSSPI_DMTRP_DATA_SHIFT);
339b0823ee3SMasahisa Kojima 
340b0823ee3SMasahisa Kojima 	val &= ~(3 << SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT);
341b0823ee3SMasahisa Kojima 	val |= ((bus_width >> 1) << SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT);
342b0823ee3SMasahisa Kojima 	writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
343b0823ee3SMasahisa Kojima 
344b0823ee3SMasahisa Kojima 	sspi->bpw = bpw;
345b0823ee3SMasahisa Kojima 	sspi->mode = mode;
346b0823ee3SMasahisa Kojima 	sspi->speed = speed;
347b0823ee3SMasahisa Kojima 	sspi->cs = spi->chip_select;
348b0823ee3SMasahisa Kojima 	sspi->bus_width = bus_width;
349b0823ee3SMasahisa Kojima 
350b0823ee3SMasahisa Kojima 	return 0;
351b0823ee3SMasahisa Kojima }
352b0823ee3SMasahisa Kojima 
353b0823ee3SMasahisa Kojima static int synquacer_spi_transfer_one(struct spi_master *master,
354b0823ee3SMasahisa Kojima 				      struct spi_device *spi,
355b0823ee3SMasahisa Kojima 				      struct spi_transfer *xfer)
356b0823ee3SMasahisa Kojima {
357b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi = spi_master_get_devdata(master);
358b0823ee3SMasahisa Kojima 	int ret;
359b0823ee3SMasahisa Kojima 	int status = 0;
360b0823ee3SMasahisa Kojima 	u32 words;
361b0823ee3SMasahisa Kojima 	u8 bpw;
362b0823ee3SMasahisa Kojima 	u32 val;
363b0823ee3SMasahisa Kojima 
364b0823ee3SMasahisa Kojima 	val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
365b0823ee3SMasahisa Kojima 	val &= ~SYNQUACER_HSSPI_DMSTOP_STOP;
366b0823ee3SMasahisa Kojima 	writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
367b0823ee3SMasahisa Kojima 
368b0823ee3SMasahisa Kojima 	val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
369b0823ee3SMasahisa Kojima 	val |= SYNQUACER_HSSPI_FIFOCFG_RX_FLUSH;
370b0823ee3SMasahisa Kojima 	val |= SYNQUACER_HSSPI_FIFOCFG_TX_FLUSH;
371b0823ee3SMasahisa Kojima 	writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
372b0823ee3SMasahisa Kojima 
373b0823ee3SMasahisa Kojima 	/*
374b0823ee3SMasahisa Kojima 	 * See if we can transfer 4-bytes as 1 word
375b0823ee3SMasahisa Kojima 	 * to maximize the FIFO buffer efficiency.
376b0823ee3SMasahisa Kojima 	 */
377b0823ee3SMasahisa Kojima 	bpw = xfer->bits_per_word;
378b0823ee3SMasahisa Kojima 	if (bpw == 8 && !(xfer->len % 4) && !(spi->mode & SPI_LSB_FIRST))
379b0823ee3SMasahisa Kojima 		xfer->bits_per_word = 32;
380b0823ee3SMasahisa Kojima 
381b0823ee3SMasahisa Kojima 	ret = synquacer_spi_config(master, spi, xfer);
382b0823ee3SMasahisa Kojima 
383b0823ee3SMasahisa Kojima 	/* restore */
384b0823ee3SMasahisa Kojima 	xfer->bits_per_word = bpw;
385b0823ee3SMasahisa Kojima 
386b0823ee3SMasahisa Kojima 	if (ret)
387b0823ee3SMasahisa Kojima 		return ret;
388b0823ee3SMasahisa Kojima 
389b0823ee3SMasahisa Kojima 	reinit_completion(&sspi->transfer_done);
390b0823ee3SMasahisa Kojima 
391b0823ee3SMasahisa Kojima 	sspi->tx_buf = xfer->tx_buf;
392b0823ee3SMasahisa Kojima 	sspi->rx_buf = xfer->rx_buf;
393b0823ee3SMasahisa Kojima 
394b0823ee3SMasahisa Kojima 	switch (sspi->bpw) {
395b0823ee3SMasahisa Kojima 	case 8:
396b0823ee3SMasahisa Kojima 		words = xfer->len;
397b0823ee3SMasahisa Kojima 		break;
398b0823ee3SMasahisa Kojima 	case 16:
399b0823ee3SMasahisa Kojima 		words = xfer->len / 2;
400b0823ee3SMasahisa Kojima 		break;
401b0823ee3SMasahisa Kojima 	case 24:
402b0823ee3SMasahisa Kojima 		/* fallthrough, should use 32-bits access */
403b0823ee3SMasahisa Kojima 	case 32:
404b0823ee3SMasahisa Kojima 		words = xfer->len / 4;
405b0823ee3SMasahisa Kojima 		break;
406b0823ee3SMasahisa Kojima 	default:
407b0823ee3SMasahisa Kojima 		dev_err(sspi->dev, "unsupported bpw: %d\n", sspi->bpw);
408b0823ee3SMasahisa Kojima 		return -EINVAL;
409b0823ee3SMasahisa Kojima 	}
410b0823ee3SMasahisa Kojima 
411b0823ee3SMasahisa Kojima 	if (xfer->tx_buf)
412b0823ee3SMasahisa Kojima 		sspi->tx_words = words;
413b0823ee3SMasahisa Kojima 	else
414b0823ee3SMasahisa Kojima 		sspi->tx_words = 0;
415b0823ee3SMasahisa Kojima 
416b0823ee3SMasahisa Kojima 	if (xfer->rx_buf)
417b0823ee3SMasahisa Kojima 		sspi->rx_words = words;
418b0823ee3SMasahisa Kojima 	else
419b0823ee3SMasahisa Kojima 		sspi->rx_words = 0;
420b0823ee3SMasahisa Kojima 
421b0823ee3SMasahisa Kojima 	if (xfer->tx_buf) {
422b0823ee3SMasahisa Kojima 		status = write_fifo(sspi);
423b0823ee3SMasahisa Kojima 		if (status < 0) {
424b0823ee3SMasahisa Kojima 			dev_err(sspi->dev, "failed write_fifo. status: 0x%x\n",
425b0823ee3SMasahisa Kojima 				status);
426b0823ee3SMasahisa Kojima 			return status;
427b0823ee3SMasahisa Kojima 		}
428b0823ee3SMasahisa Kojima 	}
429b0823ee3SMasahisa Kojima 
430b0823ee3SMasahisa Kojima 	if (xfer->rx_buf) {
431b0823ee3SMasahisa Kojima 		val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
432b0823ee3SMasahisa Kojima 		val &= ~(SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_MASK <<
433b0823ee3SMasahisa Kojima 			 SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT);
434b0823ee3SMasahisa Kojima 		val |= ((sspi->rx_words > SYNQUACER_HSSPI_FIFO_DEPTH ?
435b0823ee3SMasahisa Kojima 			SYNQUACER_HSSPI_FIFO_RX_THRESHOLD : sspi->rx_words) <<
436b0823ee3SMasahisa Kojima 			SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT);
437b0823ee3SMasahisa Kojima 		writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG);
438b0823ee3SMasahisa Kojima 	}
439b0823ee3SMasahisa Kojima 
440b0823ee3SMasahisa Kojima 	writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_TXC);
441b0823ee3SMasahisa Kojima 	writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_RXC);
442b0823ee3SMasahisa Kojima 
443b0823ee3SMasahisa Kojima 	/* Trigger */
444b0823ee3SMasahisa Kojima 	val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
445b0823ee3SMasahisa Kojima 	val |= SYNQUACER_HSSPI_DMSTART_START;
446b0823ee3SMasahisa Kojima 	writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
447b0823ee3SMasahisa Kojima 
448b0823ee3SMasahisa Kojima 	if (xfer->tx_buf) {
449b0823ee3SMasahisa Kojima 		val = SYNQUACER_HSSPI_TXE_FIFO_EMPTY;
450b0823ee3SMasahisa Kojima 		writel(val, sspi->regs + SYNQUACER_HSSPI_REG_TXE);
451b0823ee3SMasahisa Kojima 		status = wait_for_completion_timeout(&sspi->transfer_done,
452b0823ee3SMasahisa Kojima 			msecs_to_jiffies(SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC));
453b0823ee3SMasahisa Kojima 		writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE);
454b0823ee3SMasahisa Kojima 	}
455b0823ee3SMasahisa Kojima 
456b0823ee3SMasahisa Kojima 	if (xfer->rx_buf) {
457b0823ee3SMasahisa Kojima 		u32 buf[SYNQUACER_HSSPI_FIFO_DEPTH];
458b0823ee3SMasahisa Kojima 
459b0823ee3SMasahisa Kojima 		val = SYNQUACER_HSSPI_RXE_FIFO_MORE_THAN_THRESHOLD |
460b0823ee3SMasahisa Kojima 		      SYNQUACER_HSSPI_RXE_SLAVE_RELEASED;
461b0823ee3SMasahisa Kojima 		writel(val, sspi->regs + SYNQUACER_HSSPI_REG_RXE);
462b0823ee3SMasahisa Kojima 		status = wait_for_completion_timeout(&sspi->transfer_done,
463b0823ee3SMasahisa Kojima 			msecs_to_jiffies(SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC));
464b0823ee3SMasahisa Kojima 		writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE);
465b0823ee3SMasahisa Kojima 
466b0823ee3SMasahisa Kojima 		/* stop RX and clean RXFIFO */
467b0823ee3SMasahisa Kojima 		val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
468b0823ee3SMasahisa Kojima 		val |= SYNQUACER_HSSPI_DMSTOP_STOP;
469b0823ee3SMasahisa Kojima 		writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
470b0823ee3SMasahisa Kojima 		sspi->rx_buf = buf;
471b0823ee3SMasahisa Kojima 		sspi->rx_words = SYNQUACER_HSSPI_FIFO_DEPTH;
472b0823ee3SMasahisa Kojima 		read_fifo(sspi);
473b0823ee3SMasahisa Kojima 	}
474b0823ee3SMasahisa Kojima 
475b0823ee3SMasahisa Kojima 	if (status < 0) {
476b0823ee3SMasahisa Kojima 		dev_err(sspi->dev, "failed to transfer. status: 0x%x\n",
477b0823ee3SMasahisa Kojima 			status);
478b0823ee3SMasahisa Kojima 		return status;
479b0823ee3SMasahisa Kojima 	}
480b0823ee3SMasahisa Kojima 
481b0823ee3SMasahisa Kojima 	return 0;
482b0823ee3SMasahisa Kojima }
483b0823ee3SMasahisa Kojima 
484b0823ee3SMasahisa Kojima static void synquacer_spi_set_cs(struct spi_device *spi, bool enable)
485b0823ee3SMasahisa Kojima {
486b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi = spi_master_get_devdata(spi->master);
487b0823ee3SMasahisa Kojima 	u32 val;
488b0823ee3SMasahisa Kojima 
489b0823ee3SMasahisa Kojima 	val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
490b0823ee3SMasahisa Kojima 	val &= ~(SYNQUACER_HSSPI_DMPSEL_CS_MASK <<
491b0823ee3SMasahisa Kojima 		 SYNQUACER_HSSPI_DMPSEL_CS_SHIFT);
492b0823ee3SMasahisa Kojima 	val |= spi->chip_select << SYNQUACER_HSSPI_DMPSEL_CS_SHIFT;
4931c9f1750SMasahisa Kojima 
4941c9f1750SMasahisa Kojima 	if (!enable)
4951c9f1750SMasahisa Kojima 		val |= SYNQUACER_HSSPI_DMSTOP_STOP;
4961c9f1750SMasahisa Kojima 
497b0823ee3SMasahisa Kojima 	writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
498b0823ee3SMasahisa Kojima }
499b0823ee3SMasahisa Kojima 
500b0823ee3SMasahisa Kojima static int synquacer_spi_wait_status_update(struct synquacer_spi *sspi,
501b0823ee3SMasahisa Kojima 					    bool enable)
502b0823ee3SMasahisa Kojima {
503b0823ee3SMasahisa Kojima 	u32 val;
504b0823ee3SMasahisa Kojima 	unsigned long timeout = jiffies +
505b0823ee3SMasahisa Kojima 		msecs_to_jiffies(SYNQUACER_HSSPI_ENABLE_TMOUT_MSEC);
506b0823ee3SMasahisa Kojima 
507b0823ee3SMasahisa Kojima 	/* wait MES(Module Enable Status) is updated */
508b0823ee3SMasahisa Kojima 	do {
509b0823ee3SMasahisa Kojima 		val = readl(sspi->regs + SYNQUACER_HSSPI_REG_MCTRL) &
510b0823ee3SMasahisa Kojima 		      SYNQUACER_HSSPI_MCTRL_MES;
511b0823ee3SMasahisa Kojima 		if (enable && val)
512b0823ee3SMasahisa Kojima 			return 0;
513b0823ee3SMasahisa Kojima 		if (!enable && !val)
514b0823ee3SMasahisa Kojima 			return 0;
515b0823ee3SMasahisa Kojima 	} while (time_before(jiffies, timeout));
516b0823ee3SMasahisa Kojima 
517b0823ee3SMasahisa Kojima 	dev_err(sspi->dev, "timeout occurs in updating Module Enable Status\n");
518b0823ee3SMasahisa Kojima 	return -EBUSY;
519b0823ee3SMasahisa Kojima }
520b0823ee3SMasahisa Kojima 
521b0823ee3SMasahisa Kojima static int synquacer_spi_enable(struct spi_master *master)
522b0823ee3SMasahisa Kojima {
523b0823ee3SMasahisa Kojima 	u32 val;
524b0823ee3SMasahisa Kojima 	int status;
525b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi = spi_master_get_devdata(master);
526b0823ee3SMasahisa Kojima 
527b0823ee3SMasahisa Kojima 	/* Disable module */
528b0823ee3SMasahisa Kojima 	writel(0, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL);
529b0823ee3SMasahisa Kojima 	status = synquacer_spi_wait_status_update(sspi, false);
530b0823ee3SMasahisa Kojima 	if (status < 0)
531b0823ee3SMasahisa Kojima 		return status;
532b0823ee3SMasahisa Kojima 
533b0823ee3SMasahisa Kojima 	writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE);
534b0823ee3SMasahisa Kojima 	writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE);
535b0823ee3SMasahisa Kojima 	writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_TXC);
536b0823ee3SMasahisa Kojima 	writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_RXC);
537b0823ee3SMasahisa Kojima 	writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_FAULTC);
538b0823ee3SMasahisa Kojima 
539b0823ee3SMasahisa Kojima 	val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMCFG);
540b0823ee3SMasahisa Kojima 	val &= ~SYNQUACER_HSSPI_DMCFG_SSDC;
541b0823ee3SMasahisa Kojima 	val &= ~SYNQUACER_HSSPI_DMCFG_MSTARTEN;
542b0823ee3SMasahisa Kojima 	writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMCFG);
543b0823ee3SMasahisa Kojima 
544b0823ee3SMasahisa Kojima 	val = readl(sspi->regs + SYNQUACER_HSSPI_REG_MCTRL);
545b0823ee3SMasahisa Kojima 	if (sspi->clk_src_type == SYNQUACER_HSSPI_CLOCK_SRC_IPCLK)
546b0823ee3SMasahisa Kojima 		val |= SYNQUACER_HSSPI_MCTRL_CDSS;
547b0823ee3SMasahisa Kojima 	else
548b0823ee3SMasahisa Kojima 		val &= ~SYNQUACER_HSSPI_MCTRL_CDSS;
549b0823ee3SMasahisa Kojima 
550b0823ee3SMasahisa Kojima 	val &= ~SYNQUACER_HSSPI_MCTRL_COMMAND_SEQUENCE_EN;
551b0823ee3SMasahisa Kojima 	val |= SYNQUACER_HSSPI_MCTRL_MEN;
552b0823ee3SMasahisa Kojima 	val |= SYNQUACER_HSSPI_MCTRL_SYNCON;
553b0823ee3SMasahisa Kojima 
554b0823ee3SMasahisa Kojima 	/* Enable module */
555b0823ee3SMasahisa Kojima 	writel(val, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL);
556b0823ee3SMasahisa Kojima 	status = synquacer_spi_wait_status_update(sspi, true);
557b0823ee3SMasahisa Kojima 	if (status < 0)
558b0823ee3SMasahisa Kojima 		return status;
559b0823ee3SMasahisa Kojima 
560b0823ee3SMasahisa Kojima 	return 0;
561b0823ee3SMasahisa Kojima }
562b0823ee3SMasahisa Kojima 
563b0823ee3SMasahisa Kojima static irqreturn_t sq_spi_rx_handler(int irq, void *priv)
564b0823ee3SMasahisa Kojima {
565b0823ee3SMasahisa Kojima 	uint32_t val;
566b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi = priv;
567b0823ee3SMasahisa Kojima 
568b0823ee3SMasahisa Kojima 	val = readl(sspi->regs + SYNQUACER_HSSPI_REG_RXF);
569b0823ee3SMasahisa Kojima 	if ((val & SYNQUACER_HSSPI_RXF_SLAVE_RELEASED) ||
570b0823ee3SMasahisa Kojima 	    (val & SYNQUACER_HSSPI_RXF_FIFO_MORE_THAN_THRESHOLD)) {
571b0823ee3SMasahisa Kojima 		read_fifo(sspi);
572b0823ee3SMasahisa Kojima 
573b0823ee3SMasahisa Kojima 		if (sspi->rx_words == 0) {
574b0823ee3SMasahisa Kojima 			writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE);
575b0823ee3SMasahisa Kojima 			complete(&sspi->transfer_done);
576b0823ee3SMasahisa Kojima 		}
577b0823ee3SMasahisa Kojima 		return IRQ_HANDLED;
578b0823ee3SMasahisa Kojima 	}
579b0823ee3SMasahisa Kojima 
580b0823ee3SMasahisa Kojima 	return IRQ_NONE;
581b0823ee3SMasahisa Kojima }
582b0823ee3SMasahisa Kojima 
583b0823ee3SMasahisa Kojima static irqreturn_t sq_spi_tx_handler(int irq, void *priv)
584b0823ee3SMasahisa Kojima {
585b0823ee3SMasahisa Kojima 	uint32_t val;
586b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi = priv;
587b0823ee3SMasahisa Kojima 
588b0823ee3SMasahisa Kojima 	val = readl(sspi->regs + SYNQUACER_HSSPI_REG_TXF);
589b0823ee3SMasahisa Kojima 	if (val & SYNQUACER_HSSPI_TXF_FIFO_EMPTY) {
590b0823ee3SMasahisa Kojima 		if (sspi->tx_words == 0) {
591b0823ee3SMasahisa Kojima 			writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE);
592b0823ee3SMasahisa Kojima 			complete(&sspi->transfer_done);
593b0823ee3SMasahisa Kojima 		} else {
594b0823ee3SMasahisa Kojima 			write_fifo(sspi);
595b0823ee3SMasahisa Kojima 		}
596b0823ee3SMasahisa Kojima 		return IRQ_HANDLED;
597b0823ee3SMasahisa Kojima 	}
598b0823ee3SMasahisa Kojima 
599b0823ee3SMasahisa Kojima 	return IRQ_NONE;
600b0823ee3SMasahisa Kojima }
601b0823ee3SMasahisa Kojima 
602b0823ee3SMasahisa Kojima static int synquacer_spi_probe(struct platform_device *pdev)
603b0823ee3SMasahisa Kojima {
604b0823ee3SMasahisa Kojima 	struct device_node *np = pdev->dev.of_node;
605b0823ee3SMasahisa Kojima 	struct spi_master *master;
606b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi;
607b0823ee3SMasahisa Kojima 	int ret;
608b0823ee3SMasahisa Kojima 	int rx_irq, tx_irq;
609b0823ee3SMasahisa Kojima 
610b0823ee3SMasahisa Kojima 	master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
611b0823ee3SMasahisa Kojima 	if (!master)
612b0823ee3SMasahisa Kojima 		return -ENOMEM;
613b0823ee3SMasahisa Kojima 
614b0823ee3SMasahisa Kojima 	platform_set_drvdata(pdev, master);
615b0823ee3SMasahisa Kojima 
616b0823ee3SMasahisa Kojima 	sspi = spi_master_get_devdata(master);
617b0823ee3SMasahisa Kojima 	sspi->dev = &pdev->dev;
618b0823ee3SMasahisa Kojima 
619b0823ee3SMasahisa Kojima 	init_completion(&sspi->transfer_done);
620b0823ee3SMasahisa Kojima 
621b0823ee3SMasahisa Kojima 	sspi->regs = devm_platform_ioremap_resource(pdev, 0);
622b0823ee3SMasahisa Kojima 	if (IS_ERR(sspi->regs)) {
623b0823ee3SMasahisa Kojima 		ret = PTR_ERR(sspi->regs);
624b0823ee3SMasahisa Kojima 		goto put_spi;
625b0823ee3SMasahisa Kojima 	}
626b0823ee3SMasahisa Kojima 
627b0823ee3SMasahisa Kojima 	sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; /* Default */
628b0823ee3SMasahisa Kojima 	device_property_read_u32(&pdev->dev, "socionext,ihclk-rate",
629b0823ee3SMasahisa Kojima 				 &master->max_speed_hz); /* for ACPI */
630b0823ee3SMasahisa Kojima 
631b0823ee3SMasahisa Kojima 	if (dev_of_node(&pdev->dev)) {
632b0823ee3SMasahisa Kojima 		if (device_property_match_string(&pdev->dev,
633b0823ee3SMasahisa Kojima 					 "clock-names", "iHCLK") >= 0) {
634b0823ee3SMasahisa Kojima 			sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK;
635b0823ee3SMasahisa Kojima 			sspi->clk = devm_clk_get(sspi->dev, "iHCLK");
636b0823ee3SMasahisa Kojima 		} else if (device_property_match_string(&pdev->dev,
637b0823ee3SMasahisa Kojima 						"clock-names", "iPCLK") >= 0) {
638b0823ee3SMasahisa Kojima 			sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IPCLK;
639b0823ee3SMasahisa Kojima 			sspi->clk = devm_clk_get(sspi->dev, "iPCLK");
640b0823ee3SMasahisa Kojima 		} else {
641b0823ee3SMasahisa Kojima 			dev_err(&pdev->dev, "specified wrong clock source\n");
642b0823ee3SMasahisa Kojima 			ret = -EINVAL;
643b0823ee3SMasahisa Kojima 			goto put_spi;
644b0823ee3SMasahisa Kojima 		}
645b0823ee3SMasahisa Kojima 
646b0823ee3SMasahisa Kojima 		if (IS_ERR(sspi->clk)) {
64774ee6dc1SKrzysztof Kozlowski 			ret = dev_err_probe(&pdev->dev, PTR_ERR(sspi->clk),
64874ee6dc1SKrzysztof Kozlowski 					    "clock not found\n");
649b0823ee3SMasahisa Kojima 			goto put_spi;
650b0823ee3SMasahisa Kojima 		}
651b0823ee3SMasahisa Kojima 
652b0823ee3SMasahisa Kojima 		ret = clk_prepare_enable(sspi->clk);
653b0823ee3SMasahisa Kojima 		if (ret) {
654b0823ee3SMasahisa Kojima 			dev_err(&pdev->dev, "failed to enable clock (%d)\n",
655b0823ee3SMasahisa Kojima 				ret);
656b0823ee3SMasahisa Kojima 			goto put_spi;
657b0823ee3SMasahisa Kojima 		}
658b0823ee3SMasahisa Kojima 
659b0823ee3SMasahisa Kojima 		master->max_speed_hz = clk_get_rate(sspi->clk);
660b0823ee3SMasahisa Kojima 	}
661b0823ee3SMasahisa Kojima 
662b0823ee3SMasahisa Kojima 	if (!master->max_speed_hz) {
663b0823ee3SMasahisa Kojima 		dev_err(&pdev->dev, "missing clock source\n");
6648853b250SLukas Wunner 		ret = -EINVAL;
6658853b250SLukas Wunner 		goto disable_clk;
666b0823ee3SMasahisa Kojima 	}
667b0823ee3SMasahisa Kojima 	master->min_speed_hz = master->max_speed_hz / 254;
668b0823ee3SMasahisa Kojima 
669b0823ee3SMasahisa Kojima 	sspi->aces = device_property_read_bool(&pdev->dev,
670b0823ee3SMasahisa Kojima 					       "socionext,set-aces");
671b0823ee3SMasahisa Kojima 	sspi->rtm = device_property_read_bool(&pdev->dev, "socionext,use-rtm");
672b0823ee3SMasahisa Kojima 
673b0823ee3SMasahisa Kojima 	master->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT;
674b0823ee3SMasahisa Kojima 
675b0823ee3SMasahisa Kojima 	rx_irq = platform_get_irq(pdev, 0);
676b0823ee3SMasahisa Kojima 	if (rx_irq <= 0) {
677b0823ee3SMasahisa Kojima 		ret = rx_irq;
6788853b250SLukas Wunner 		goto disable_clk;
679b0823ee3SMasahisa Kojima 	}
680b0823ee3SMasahisa Kojima 	snprintf(sspi->rx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-rx",
681b0823ee3SMasahisa Kojima 		 dev_name(&pdev->dev));
682b0823ee3SMasahisa Kojima 	ret = devm_request_irq(&pdev->dev, rx_irq, sq_spi_rx_handler,
683b0823ee3SMasahisa Kojima 				0, sspi->rx_irq_name, sspi);
684b0823ee3SMasahisa Kojima 	if (ret) {
685b0823ee3SMasahisa Kojima 		dev_err(&pdev->dev, "request rx_irq failed (%d)\n", ret);
6868853b250SLukas Wunner 		goto disable_clk;
687b0823ee3SMasahisa Kojima 	}
688b0823ee3SMasahisa Kojima 
689b0823ee3SMasahisa Kojima 	tx_irq = platform_get_irq(pdev, 1);
690b0823ee3SMasahisa Kojima 	if (tx_irq <= 0) {
691b0823ee3SMasahisa Kojima 		ret = tx_irq;
6928853b250SLukas Wunner 		goto disable_clk;
693b0823ee3SMasahisa Kojima 	}
694b0823ee3SMasahisa Kojima 	snprintf(sspi->tx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-tx",
695b0823ee3SMasahisa Kojima 		 dev_name(&pdev->dev));
696b0823ee3SMasahisa Kojima 	ret = devm_request_irq(&pdev->dev, tx_irq, sq_spi_tx_handler,
697b0823ee3SMasahisa Kojima 				0, sspi->tx_irq_name, sspi);
698b0823ee3SMasahisa Kojima 	if (ret) {
699b0823ee3SMasahisa Kojima 		dev_err(&pdev->dev, "request tx_irq failed (%d)\n", ret);
7008853b250SLukas Wunner 		goto disable_clk;
701b0823ee3SMasahisa Kojima 	}
702b0823ee3SMasahisa Kojima 
703b0823ee3SMasahisa Kojima 	master->dev.of_node = np;
704b0823ee3SMasahisa Kojima 	master->dev.fwnode = pdev->dev.fwnode;
705b0823ee3SMasahisa Kojima 	master->auto_runtime_pm = true;
706b0823ee3SMasahisa Kojima 	master->bus_num = pdev->id;
707b0823ee3SMasahisa Kojima 
708b0823ee3SMasahisa Kojima 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL |
709b0823ee3SMasahisa Kojima 			    SPI_TX_QUAD | SPI_RX_QUAD;
710b0823ee3SMasahisa Kojima 	master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) |
711b0823ee3SMasahisa Kojima 				     SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
712b0823ee3SMasahisa Kojima 
713b0823ee3SMasahisa Kojima 	master->set_cs = synquacer_spi_set_cs;
714b0823ee3SMasahisa Kojima 	master->transfer_one = synquacer_spi_transfer_one;
715b0823ee3SMasahisa Kojima 
716b0823ee3SMasahisa Kojima 	ret = synquacer_spi_enable(master);
717b0823ee3SMasahisa Kojima 	if (ret)
7188853b250SLukas Wunner 		goto disable_clk;
719b0823ee3SMasahisa Kojima 
720b0823ee3SMasahisa Kojima 	pm_runtime_set_active(sspi->dev);
721b0823ee3SMasahisa Kojima 	pm_runtime_enable(sspi->dev);
722b0823ee3SMasahisa Kojima 
723b0823ee3SMasahisa Kojima 	ret = devm_spi_register_master(sspi->dev, master);
724b0823ee3SMasahisa Kojima 	if (ret)
725b0823ee3SMasahisa Kojima 		goto disable_pm;
726b0823ee3SMasahisa Kojima 
727b0823ee3SMasahisa Kojima 	return 0;
728b0823ee3SMasahisa Kojima 
729b0823ee3SMasahisa Kojima disable_pm:
730b0823ee3SMasahisa Kojima 	pm_runtime_disable(sspi->dev);
7318853b250SLukas Wunner disable_clk:
732b0823ee3SMasahisa Kojima 	clk_disable_unprepare(sspi->clk);
733b0823ee3SMasahisa Kojima put_spi:
734b0823ee3SMasahisa Kojima 	spi_master_put(master);
735b0823ee3SMasahisa Kojima 
736b0823ee3SMasahisa Kojima 	return ret;
737b0823ee3SMasahisa Kojima }
738b0823ee3SMasahisa Kojima 
739b0823ee3SMasahisa Kojima static int synquacer_spi_remove(struct platform_device *pdev)
740b0823ee3SMasahisa Kojima {
741b0823ee3SMasahisa Kojima 	struct spi_master *master = platform_get_drvdata(pdev);
742b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi = spi_master_get_devdata(master);
743b0823ee3SMasahisa Kojima 
744b0823ee3SMasahisa Kojima 	pm_runtime_disable(sspi->dev);
745b0823ee3SMasahisa Kojima 
746b0823ee3SMasahisa Kojima 	clk_disable_unprepare(sspi->clk);
747b0823ee3SMasahisa Kojima 
748b0823ee3SMasahisa Kojima 	return 0;
749b0823ee3SMasahisa Kojima }
750b0823ee3SMasahisa Kojima 
751b0823ee3SMasahisa Kojima static int __maybe_unused synquacer_spi_suspend(struct device *dev)
752b0823ee3SMasahisa Kojima {
753b0823ee3SMasahisa Kojima 	struct spi_master *master = dev_get_drvdata(dev);
754b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi = spi_master_get_devdata(master);
755b0823ee3SMasahisa Kojima 	int ret;
756b0823ee3SMasahisa Kojima 
757b0823ee3SMasahisa Kojima 	ret = spi_master_suspend(master);
758b0823ee3SMasahisa Kojima 	if (ret)
759b0823ee3SMasahisa Kojima 		return ret;
760b0823ee3SMasahisa Kojima 
761b0823ee3SMasahisa Kojima 	if (!pm_runtime_suspended(dev))
762b0823ee3SMasahisa Kojima 		clk_disable_unprepare(sspi->clk);
763b0823ee3SMasahisa Kojima 
764b0823ee3SMasahisa Kojima 	return ret;
765b0823ee3SMasahisa Kojima }
766b0823ee3SMasahisa Kojima 
767b0823ee3SMasahisa Kojima static int __maybe_unused synquacer_spi_resume(struct device *dev)
768b0823ee3SMasahisa Kojima {
769b0823ee3SMasahisa Kojima 	struct spi_master *master = dev_get_drvdata(dev);
770b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi = spi_master_get_devdata(master);
771b0823ee3SMasahisa Kojima 	int ret;
772b0823ee3SMasahisa Kojima 
773b0823ee3SMasahisa Kojima 	if (!pm_runtime_suspended(dev)) {
774b0823ee3SMasahisa Kojima 		/* Ensure reconfigure during next xfer */
775b0823ee3SMasahisa Kojima 		sspi->speed = 0;
776b0823ee3SMasahisa Kojima 
777b0823ee3SMasahisa Kojima 		ret = clk_prepare_enable(sspi->clk);
778b0823ee3SMasahisa Kojima 		if (ret < 0) {
779b0823ee3SMasahisa Kojima 			dev_err(dev, "failed to enable clk (%d)\n",
780b0823ee3SMasahisa Kojima 				ret);
781b0823ee3SMasahisa Kojima 			return ret;
782b0823ee3SMasahisa Kojima 		}
783b0823ee3SMasahisa Kojima 
784b0823ee3SMasahisa Kojima 		ret = synquacer_spi_enable(master);
785b0823ee3SMasahisa Kojima 		if (ret) {
786*917e43deSGuo Mengqi 			clk_disable_unprepare(sspi->clk);
787b0823ee3SMasahisa Kojima 			dev_err(dev, "failed to enable spi (%d)\n", ret);
788b0823ee3SMasahisa Kojima 			return ret;
789b0823ee3SMasahisa Kojima 		}
790b0823ee3SMasahisa Kojima 	}
791b0823ee3SMasahisa Kojima 
792b0823ee3SMasahisa Kojima 	ret = spi_master_resume(master);
793b0823ee3SMasahisa Kojima 	if (ret < 0)
794b0823ee3SMasahisa Kojima 		clk_disable_unprepare(sspi->clk);
795b0823ee3SMasahisa Kojima 
796b0823ee3SMasahisa Kojima 	return ret;
797b0823ee3SMasahisa Kojima }
798b0823ee3SMasahisa Kojima 
799b0823ee3SMasahisa Kojima static SIMPLE_DEV_PM_OPS(synquacer_spi_pm_ops, synquacer_spi_suspend,
800b0823ee3SMasahisa Kojima 			 synquacer_spi_resume);
801b0823ee3SMasahisa Kojima 
802b0823ee3SMasahisa Kojima static const struct of_device_id synquacer_spi_of_match[] = {
803b0823ee3SMasahisa Kojima 	{.compatible = "socionext,synquacer-spi"},
804b0823ee3SMasahisa Kojima 	{}
805b0823ee3SMasahisa Kojima };
806b0823ee3SMasahisa Kojima MODULE_DEVICE_TABLE(of, synquacer_spi_of_match);
807b0823ee3SMasahisa Kojima 
808b0823ee3SMasahisa Kojima #ifdef CONFIG_ACPI
809b0823ee3SMasahisa Kojima static const struct acpi_device_id synquacer_hsspi_acpi_ids[] = {
810b0823ee3SMasahisa Kojima 	{ "SCX0004" },
811b0823ee3SMasahisa Kojima 	{ /* sentinel */ }
812b0823ee3SMasahisa Kojima };
813b0823ee3SMasahisa Kojima MODULE_DEVICE_TABLE(acpi, synquacer_hsspi_acpi_ids);
814b0823ee3SMasahisa Kojima #endif
815b0823ee3SMasahisa Kojima 
816b0823ee3SMasahisa Kojima static struct platform_driver synquacer_spi_driver = {
817b0823ee3SMasahisa Kojima 	.driver = {
818b0823ee3SMasahisa Kojima 		.name = "synquacer-spi",
819b0823ee3SMasahisa Kojima 		.pm = &synquacer_spi_pm_ops,
820b0823ee3SMasahisa Kojima 		.of_match_table = synquacer_spi_of_match,
821b0823ee3SMasahisa Kojima 		.acpi_match_table = ACPI_PTR(synquacer_hsspi_acpi_ids),
822b0823ee3SMasahisa Kojima 	},
823b0823ee3SMasahisa Kojima 	.probe = synquacer_spi_probe,
824b0823ee3SMasahisa Kojima 	.remove = synquacer_spi_remove,
825b0823ee3SMasahisa Kojima };
826b0823ee3SMasahisa Kojima module_platform_driver(synquacer_spi_driver);
827b0823ee3SMasahisa Kojima 
828b0823ee3SMasahisa Kojima MODULE_DESCRIPTION("Socionext Synquacer HS-SPI controller driver");
829b0823ee3SMasahisa Kojima MODULE_AUTHOR("Masahisa Kojima <masahisa.kojima@linaro.org>");
830b0823ee3SMasahisa Kojima MODULE_AUTHOR("Jassi Brar <jaswinder.singh@linaro.org>");
831b0823ee3SMasahisa Kojima MODULE_LICENSE("GPL v2");
832