xref: /openbmc/linux/drivers/spi/spi-synquacer.c (revision 9e264f3f)
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 
read_fifo(struct synquacer_spi * sspi)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 
write_fifo(struct synquacer_spi * sspi)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 
synquacer_spi_config(struct spi_master * master,struct spi_device * spi,struct spi_transfer * xfer)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;
253*9e264f3fSAmit Kumar Mahapatra via Alsa-devel 	cs = spi_get_chipselect(spi, 0);
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;
347*9e264f3fSAmit Kumar Mahapatra via Alsa-devel 	sspi->cs = spi_get_chipselect(spi, 0);
348b0823ee3SMasahisa Kojima 	sspi->bus_width = bus_width;
349b0823ee3SMasahisa Kojima 
350b0823ee3SMasahisa Kojima 	return 0;
351b0823ee3SMasahisa Kojima }
352b0823ee3SMasahisa Kojima 
synquacer_spi_transfer_one(struct spi_master * master,struct spi_device * spi,struct spi_transfer * xfer)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 
475e6a0b671SChristophe JAILLET 	if (status == 0) {
476e6a0b671SChristophe JAILLET 		dev_err(sspi->dev, "failed to transfer. Timeout.\n");
477e6a0b671SChristophe JAILLET 		return -ETIMEDOUT;
478b0823ee3SMasahisa Kojima 	}
479b0823ee3SMasahisa Kojima 
480b0823ee3SMasahisa Kojima 	return 0;
481b0823ee3SMasahisa Kojima }
482b0823ee3SMasahisa Kojima 
synquacer_spi_set_cs(struct spi_device * spi,bool enable)483b0823ee3SMasahisa Kojima static void synquacer_spi_set_cs(struct spi_device *spi, bool enable)
484b0823ee3SMasahisa Kojima {
485b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi = spi_master_get_devdata(spi->master);
486b0823ee3SMasahisa Kojima 	u32 val;
487b0823ee3SMasahisa Kojima 
488b0823ee3SMasahisa Kojima 	val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
489b0823ee3SMasahisa Kojima 	val &= ~(SYNQUACER_HSSPI_DMPSEL_CS_MASK <<
490b0823ee3SMasahisa Kojima 		 SYNQUACER_HSSPI_DMPSEL_CS_SHIFT);
491*9e264f3fSAmit Kumar Mahapatra via Alsa-devel 	val |= spi_get_chipselect(spi, 0) << SYNQUACER_HSSPI_DMPSEL_CS_SHIFT;
4921c9f1750SMasahisa Kojima 
4931c9f1750SMasahisa Kojima 	if (!enable)
4941c9f1750SMasahisa Kojima 		val |= SYNQUACER_HSSPI_DMSTOP_STOP;
4951c9f1750SMasahisa Kojima 
496b0823ee3SMasahisa Kojima 	writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART);
497b0823ee3SMasahisa Kojima }
498b0823ee3SMasahisa Kojima 
synquacer_spi_wait_status_update(struct synquacer_spi * sspi,bool enable)499b0823ee3SMasahisa Kojima static int synquacer_spi_wait_status_update(struct synquacer_spi *sspi,
500b0823ee3SMasahisa Kojima 					    bool enable)
501b0823ee3SMasahisa Kojima {
502b0823ee3SMasahisa Kojima 	u32 val;
503b0823ee3SMasahisa Kojima 	unsigned long timeout = jiffies +
504b0823ee3SMasahisa Kojima 		msecs_to_jiffies(SYNQUACER_HSSPI_ENABLE_TMOUT_MSEC);
505b0823ee3SMasahisa Kojima 
506b0823ee3SMasahisa Kojima 	/* wait MES(Module Enable Status) is updated */
507b0823ee3SMasahisa Kojima 	do {
508b0823ee3SMasahisa Kojima 		val = readl(sspi->regs + SYNQUACER_HSSPI_REG_MCTRL) &
509b0823ee3SMasahisa Kojima 		      SYNQUACER_HSSPI_MCTRL_MES;
510b0823ee3SMasahisa Kojima 		if (enable && val)
511b0823ee3SMasahisa Kojima 			return 0;
512b0823ee3SMasahisa Kojima 		if (!enable && !val)
513b0823ee3SMasahisa Kojima 			return 0;
514b0823ee3SMasahisa Kojima 	} while (time_before(jiffies, timeout));
515b0823ee3SMasahisa Kojima 
516b0823ee3SMasahisa Kojima 	dev_err(sspi->dev, "timeout occurs in updating Module Enable Status\n");
517b0823ee3SMasahisa Kojima 	return -EBUSY;
518b0823ee3SMasahisa Kojima }
519b0823ee3SMasahisa Kojima 
synquacer_spi_enable(struct spi_master * master)520b0823ee3SMasahisa Kojima static int synquacer_spi_enable(struct spi_master *master)
521b0823ee3SMasahisa Kojima {
522b0823ee3SMasahisa Kojima 	u32 val;
523b0823ee3SMasahisa Kojima 	int status;
524b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi = spi_master_get_devdata(master);
525b0823ee3SMasahisa Kojima 
526b0823ee3SMasahisa Kojima 	/* Disable module */
527b0823ee3SMasahisa Kojima 	writel(0, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL);
528b0823ee3SMasahisa Kojima 	status = synquacer_spi_wait_status_update(sspi, false);
529b0823ee3SMasahisa Kojima 	if (status < 0)
530b0823ee3SMasahisa Kojima 		return status;
531b0823ee3SMasahisa Kojima 
532b0823ee3SMasahisa Kojima 	writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE);
533b0823ee3SMasahisa Kojima 	writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE);
534b0823ee3SMasahisa Kojima 	writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_TXC);
535b0823ee3SMasahisa Kojima 	writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_RXC);
536b0823ee3SMasahisa Kojima 	writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_FAULTC);
537b0823ee3SMasahisa Kojima 
538b0823ee3SMasahisa Kojima 	val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMCFG);
539b0823ee3SMasahisa Kojima 	val &= ~SYNQUACER_HSSPI_DMCFG_SSDC;
540b0823ee3SMasahisa Kojima 	val &= ~SYNQUACER_HSSPI_DMCFG_MSTARTEN;
541b0823ee3SMasahisa Kojima 	writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMCFG);
542b0823ee3SMasahisa Kojima 
543b0823ee3SMasahisa Kojima 	val = readl(sspi->regs + SYNQUACER_HSSPI_REG_MCTRL);
544b0823ee3SMasahisa Kojima 	if (sspi->clk_src_type == SYNQUACER_HSSPI_CLOCK_SRC_IPCLK)
545b0823ee3SMasahisa Kojima 		val |= SYNQUACER_HSSPI_MCTRL_CDSS;
546b0823ee3SMasahisa Kojima 	else
547b0823ee3SMasahisa Kojima 		val &= ~SYNQUACER_HSSPI_MCTRL_CDSS;
548b0823ee3SMasahisa Kojima 
549b0823ee3SMasahisa Kojima 	val &= ~SYNQUACER_HSSPI_MCTRL_COMMAND_SEQUENCE_EN;
550b0823ee3SMasahisa Kojima 	val |= SYNQUACER_HSSPI_MCTRL_MEN;
551b0823ee3SMasahisa Kojima 	val |= SYNQUACER_HSSPI_MCTRL_SYNCON;
552b0823ee3SMasahisa Kojima 
553b0823ee3SMasahisa Kojima 	/* Enable module */
554b0823ee3SMasahisa Kojima 	writel(val, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL);
555b0823ee3SMasahisa Kojima 	status = synquacer_spi_wait_status_update(sspi, true);
556b0823ee3SMasahisa Kojima 	if (status < 0)
557b0823ee3SMasahisa Kojima 		return status;
558b0823ee3SMasahisa Kojima 
559b0823ee3SMasahisa Kojima 	return 0;
560b0823ee3SMasahisa Kojima }
561b0823ee3SMasahisa Kojima 
sq_spi_rx_handler(int irq,void * priv)562b0823ee3SMasahisa Kojima static irqreturn_t sq_spi_rx_handler(int irq, void *priv)
563b0823ee3SMasahisa Kojima {
564b0823ee3SMasahisa Kojima 	uint32_t val;
565b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi = priv;
566b0823ee3SMasahisa Kojima 
567b0823ee3SMasahisa Kojima 	val = readl(sspi->regs + SYNQUACER_HSSPI_REG_RXF);
568b0823ee3SMasahisa Kojima 	if ((val & SYNQUACER_HSSPI_RXF_SLAVE_RELEASED) ||
569b0823ee3SMasahisa Kojima 	    (val & SYNQUACER_HSSPI_RXF_FIFO_MORE_THAN_THRESHOLD)) {
570b0823ee3SMasahisa Kojima 		read_fifo(sspi);
571b0823ee3SMasahisa Kojima 
572b0823ee3SMasahisa Kojima 		if (sspi->rx_words == 0) {
573b0823ee3SMasahisa Kojima 			writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE);
574b0823ee3SMasahisa Kojima 			complete(&sspi->transfer_done);
575b0823ee3SMasahisa Kojima 		}
576b0823ee3SMasahisa Kojima 		return IRQ_HANDLED;
577b0823ee3SMasahisa Kojima 	}
578b0823ee3SMasahisa Kojima 
579b0823ee3SMasahisa Kojima 	return IRQ_NONE;
580b0823ee3SMasahisa Kojima }
581b0823ee3SMasahisa Kojima 
sq_spi_tx_handler(int irq,void * priv)582b0823ee3SMasahisa Kojima static irqreturn_t sq_spi_tx_handler(int irq, void *priv)
583b0823ee3SMasahisa Kojima {
584b0823ee3SMasahisa Kojima 	uint32_t val;
585b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi = priv;
586b0823ee3SMasahisa Kojima 
587b0823ee3SMasahisa Kojima 	val = readl(sspi->regs + SYNQUACER_HSSPI_REG_TXF);
588b0823ee3SMasahisa Kojima 	if (val & SYNQUACER_HSSPI_TXF_FIFO_EMPTY) {
589b0823ee3SMasahisa Kojima 		if (sspi->tx_words == 0) {
590b0823ee3SMasahisa Kojima 			writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE);
591b0823ee3SMasahisa Kojima 			complete(&sspi->transfer_done);
592b0823ee3SMasahisa Kojima 		} else {
593b0823ee3SMasahisa Kojima 			write_fifo(sspi);
594b0823ee3SMasahisa Kojima 		}
595b0823ee3SMasahisa Kojima 		return IRQ_HANDLED;
596b0823ee3SMasahisa Kojima 	}
597b0823ee3SMasahisa Kojima 
598b0823ee3SMasahisa Kojima 	return IRQ_NONE;
599b0823ee3SMasahisa Kojima }
600b0823ee3SMasahisa Kojima 
synquacer_spi_probe(struct platform_device * pdev)601b0823ee3SMasahisa Kojima static int synquacer_spi_probe(struct platform_device *pdev)
602b0823ee3SMasahisa Kojima {
603b0823ee3SMasahisa Kojima 	struct device_node *np = pdev->dev.of_node;
604b0823ee3SMasahisa Kojima 	struct spi_master *master;
605b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi;
606b0823ee3SMasahisa Kojima 	int ret;
607b0823ee3SMasahisa Kojima 	int rx_irq, tx_irq;
608b0823ee3SMasahisa Kojima 
609b0823ee3SMasahisa Kojima 	master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
610b0823ee3SMasahisa Kojima 	if (!master)
611b0823ee3SMasahisa Kojima 		return -ENOMEM;
612b0823ee3SMasahisa Kojima 
613b0823ee3SMasahisa Kojima 	platform_set_drvdata(pdev, master);
614b0823ee3SMasahisa Kojima 
615b0823ee3SMasahisa Kojima 	sspi = spi_master_get_devdata(master);
616b0823ee3SMasahisa Kojima 	sspi->dev = &pdev->dev;
617b0823ee3SMasahisa Kojima 
618b0823ee3SMasahisa Kojima 	init_completion(&sspi->transfer_done);
619b0823ee3SMasahisa Kojima 
620b0823ee3SMasahisa Kojima 	sspi->regs = devm_platform_ioremap_resource(pdev, 0);
621b0823ee3SMasahisa Kojima 	if (IS_ERR(sspi->regs)) {
622b0823ee3SMasahisa Kojima 		ret = PTR_ERR(sspi->regs);
623b0823ee3SMasahisa Kojima 		goto put_spi;
624b0823ee3SMasahisa Kojima 	}
625b0823ee3SMasahisa Kojima 
626b0823ee3SMasahisa Kojima 	sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; /* Default */
627b0823ee3SMasahisa Kojima 	device_property_read_u32(&pdev->dev, "socionext,ihclk-rate",
628b0823ee3SMasahisa Kojima 				 &master->max_speed_hz); /* for ACPI */
629b0823ee3SMasahisa Kojima 
630b0823ee3SMasahisa Kojima 	if (dev_of_node(&pdev->dev)) {
631b0823ee3SMasahisa Kojima 		if (device_property_match_string(&pdev->dev,
632b0823ee3SMasahisa Kojima 					 "clock-names", "iHCLK") >= 0) {
633b0823ee3SMasahisa Kojima 			sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK;
634b0823ee3SMasahisa Kojima 			sspi->clk = devm_clk_get(sspi->dev, "iHCLK");
635b0823ee3SMasahisa Kojima 		} else if (device_property_match_string(&pdev->dev,
636b0823ee3SMasahisa Kojima 						"clock-names", "iPCLK") >= 0) {
637b0823ee3SMasahisa Kojima 			sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IPCLK;
638b0823ee3SMasahisa Kojima 			sspi->clk = devm_clk_get(sspi->dev, "iPCLK");
639b0823ee3SMasahisa Kojima 		} else {
640b0823ee3SMasahisa Kojima 			dev_err(&pdev->dev, "specified wrong clock source\n");
641b0823ee3SMasahisa Kojima 			ret = -EINVAL;
642b0823ee3SMasahisa Kojima 			goto put_spi;
643b0823ee3SMasahisa Kojima 		}
644b0823ee3SMasahisa Kojima 
645b0823ee3SMasahisa Kojima 		if (IS_ERR(sspi->clk)) {
64674ee6dc1SKrzysztof Kozlowski 			ret = dev_err_probe(&pdev->dev, PTR_ERR(sspi->clk),
64774ee6dc1SKrzysztof Kozlowski 					    "clock not found\n");
648b0823ee3SMasahisa Kojima 			goto put_spi;
649b0823ee3SMasahisa Kojima 		}
650b0823ee3SMasahisa Kojima 
651b0823ee3SMasahisa Kojima 		ret = clk_prepare_enable(sspi->clk);
652b0823ee3SMasahisa Kojima 		if (ret) {
653b0823ee3SMasahisa Kojima 			dev_err(&pdev->dev, "failed to enable clock (%d)\n",
654b0823ee3SMasahisa Kojima 				ret);
655b0823ee3SMasahisa Kojima 			goto put_spi;
656b0823ee3SMasahisa Kojima 		}
657b0823ee3SMasahisa Kojima 
658b0823ee3SMasahisa Kojima 		master->max_speed_hz = clk_get_rate(sspi->clk);
659b0823ee3SMasahisa Kojima 	}
660b0823ee3SMasahisa Kojima 
661b0823ee3SMasahisa Kojima 	if (!master->max_speed_hz) {
662b0823ee3SMasahisa Kojima 		dev_err(&pdev->dev, "missing clock source\n");
6638853b250SLukas Wunner 		ret = -EINVAL;
6648853b250SLukas Wunner 		goto disable_clk;
665b0823ee3SMasahisa Kojima 	}
666b0823ee3SMasahisa Kojima 	master->min_speed_hz = master->max_speed_hz / 254;
667b0823ee3SMasahisa Kojima 
668b0823ee3SMasahisa Kojima 	sspi->aces = device_property_read_bool(&pdev->dev,
669b0823ee3SMasahisa Kojima 					       "socionext,set-aces");
670b0823ee3SMasahisa Kojima 	sspi->rtm = device_property_read_bool(&pdev->dev, "socionext,use-rtm");
671b0823ee3SMasahisa Kojima 
672b0823ee3SMasahisa Kojima 	master->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT;
673b0823ee3SMasahisa Kojima 
674b0823ee3SMasahisa Kojima 	rx_irq = platform_get_irq(pdev, 0);
675b0823ee3SMasahisa Kojima 	if (rx_irq <= 0) {
676b0823ee3SMasahisa Kojima 		ret = rx_irq;
6778853b250SLukas Wunner 		goto disable_clk;
678b0823ee3SMasahisa Kojima 	}
679b0823ee3SMasahisa Kojima 	snprintf(sspi->rx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-rx",
680b0823ee3SMasahisa Kojima 		 dev_name(&pdev->dev));
681b0823ee3SMasahisa Kojima 	ret = devm_request_irq(&pdev->dev, rx_irq, sq_spi_rx_handler,
682b0823ee3SMasahisa Kojima 				0, sspi->rx_irq_name, sspi);
683b0823ee3SMasahisa Kojima 	if (ret) {
684b0823ee3SMasahisa Kojima 		dev_err(&pdev->dev, "request rx_irq failed (%d)\n", ret);
6858853b250SLukas Wunner 		goto disable_clk;
686b0823ee3SMasahisa Kojima 	}
687b0823ee3SMasahisa Kojima 
688b0823ee3SMasahisa Kojima 	tx_irq = platform_get_irq(pdev, 1);
689b0823ee3SMasahisa Kojima 	if (tx_irq <= 0) {
690b0823ee3SMasahisa Kojima 		ret = tx_irq;
6918853b250SLukas Wunner 		goto disable_clk;
692b0823ee3SMasahisa Kojima 	}
693b0823ee3SMasahisa Kojima 	snprintf(sspi->tx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-tx",
694b0823ee3SMasahisa Kojima 		 dev_name(&pdev->dev));
695b0823ee3SMasahisa Kojima 	ret = devm_request_irq(&pdev->dev, tx_irq, sq_spi_tx_handler,
696b0823ee3SMasahisa Kojima 				0, sspi->tx_irq_name, sspi);
697b0823ee3SMasahisa Kojima 	if (ret) {
698b0823ee3SMasahisa Kojima 		dev_err(&pdev->dev, "request tx_irq failed (%d)\n", ret);
6998853b250SLukas Wunner 		goto disable_clk;
700b0823ee3SMasahisa Kojima 	}
701b0823ee3SMasahisa Kojima 
702b0823ee3SMasahisa Kojima 	master->dev.of_node = np;
703b0823ee3SMasahisa Kojima 	master->dev.fwnode = pdev->dev.fwnode;
704b0823ee3SMasahisa Kojima 	master->auto_runtime_pm = true;
705b0823ee3SMasahisa Kojima 	master->bus_num = pdev->id;
706b0823ee3SMasahisa Kojima 
707b0823ee3SMasahisa Kojima 	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL |
708b0823ee3SMasahisa Kojima 			    SPI_TX_QUAD | SPI_RX_QUAD;
709b0823ee3SMasahisa Kojima 	master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) |
710b0823ee3SMasahisa Kojima 				     SPI_BPW_MASK(16) | SPI_BPW_MASK(8);
711b0823ee3SMasahisa Kojima 
712b0823ee3SMasahisa Kojima 	master->set_cs = synquacer_spi_set_cs;
713b0823ee3SMasahisa Kojima 	master->transfer_one = synquacer_spi_transfer_one;
714b0823ee3SMasahisa Kojima 
715b0823ee3SMasahisa Kojima 	ret = synquacer_spi_enable(master);
716b0823ee3SMasahisa Kojima 	if (ret)
7178853b250SLukas Wunner 		goto disable_clk;
718b0823ee3SMasahisa Kojima 
719b0823ee3SMasahisa Kojima 	pm_runtime_set_active(sspi->dev);
720b0823ee3SMasahisa Kojima 	pm_runtime_enable(sspi->dev);
721b0823ee3SMasahisa Kojima 
722b0823ee3SMasahisa Kojima 	ret = devm_spi_register_master(sspi->dev, master);
723b0823ee3SMasahisa Kojima 	if (ret)
724b0823ee3SMasahisa Kojima 		goto disable_pm;
725b0823ee3SMasahisa Kojima 
726b0823ee3SMasahisa Kojima 	return 0;
727b0823ee3SMasahisa Kojima 
728b0823ee3SMasahisa Kojima disable_pm:
729b0823ee3SMasahisa Kojima 	pm_runtime_disable(sspi->dev);
7308853b250SLukas Wunner disable_clk:
731b0823ee3SMasahisa Kojima 	clk_disable_unprepare(sspi->clk);
732b0823ee3SMasahisa Kojima put_spi:
733b0823ee3SMasahisa Kojima 	spi_master_put(master);
734b0823ee3SMasahisa Kojima 
735b0823ee3SMasahisa Kojima 	return ret;
736b0823ee3SMasahisa Kojima }
737b0823ee3SMasahisa Kojima 
synquacer_spi_remove(struct platform_device * pdev)7381972cdc4SUwe Kleine-König static void synquacer_spi_remove(struct platform_device *pdev)
739b0823ee3SMasahisa Kojima {
740b0823ee3SMasahisa Kojima 	struct spi_master *master = platform_get_drvdata(pdev);
741b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi = spi_master_get_devdata(master);
742b0823ee3SMasahisa Kojima 
743b0823ee3SMasahisa Kojima 	pm_runtime_disable(sspi->dev);
744b0823ee3SMasahisa Kojima 
745b0823ee3SMasahisa Kojima 	clk_disable_unprepare(sspi->clk);
746b0823ee3SMasahisa Kojima }
747b0823ee3SMasahisa Kojima 
synquacer_spi_suspend(struct device * dev)748b0823ee3SMasahisa Kojima static int __maybe_unused synquacer_spi_suspend(struct device *dev)
749b0823ee3SMasahisa Kojima {
750b0823ee3SMasahisa Kojima 	struct spi_master *master = dev_get_drvdata(dev);
751b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi = spi_master_get_devdata(master);
752b0823ee3SMasahisa Kojima 	int ret;
753b0823ee3SMasahisa Kojima 
754b0823ee3SMasahisa Kojima 	ret = spi_master_suspend(master);
755b0823ee3SMasahisa Kojima 	if (ret)
756b0823ee3SMasahisa Kojima 		return ret;
757b0823ee3SMasahisa Kojima 
758b0823ee3SMasahisa Kojima 	if (!pm_runtime_suspended(dev))
759b0823ee3SMasahisa Kojima 		clk_disable_unprepare(sspi->clk);
760b0823ee3SMasahisa Kojima 
761b0823ee3SMasahisa Kojima 	return ret;
762b0823ee3SMasahisa Kojima }
763b0823ee3SMasahisa Kojima 
synquacer_spi_resume(struct device * dev)764b0823ee3SMasahisa Kojima static int __maybe_unused synquacer_spi_resume(struct device *dev)
765b0823ee3SMasahisa Kojima {
766b0823ee3SMasahisa Kojima 	struct spi_master *master = dev_get_drvdata(dev);
767b0823ee3SMasahisa Kojima 	struct synquacer_spi *sspi = spi_master_get_devdata(master);
768b0823ee3SMasahisa Kojima 	int ret;
769b0823ee3SMasahisa Kojima 
770b0823ee3SMasahisa Kojima 	if (!pm_runtime_suspended(dev)) {
771b0823ee3SMasahisa Kojima 		/* Ensure reconfigure during next xfer */
772b0823ee3SMasahisa Kojima 		sspi->speed = 0;
773b0823ee3SMasahisa Kojima 
774b0823ee3SMasahisa Kojima 		ret = clk_prepare_enable(sspi->clk);
775b0823ee3SMasahisa Kojima 		if (ret < 0) {
776b0823ee3SMasahisa Kojima 			dev_err(dev, "failed to enable clk (%d)\n",
777b0823ee3SMasahisa Kojima 				ret);
778b0823ee3SMasahisa Kojima 			return ret;
779b0823ee3SMasahisa Kojima 		}
780b0823ee3SMasahisa Kojima 
781b0823ee3SMasahisa Kojima 		ret = synquacer_spi_enable(master);
782b0823ee3SMasahisa Kojima 		if (ret) {
783917e43deSGuo Mengqi 			clk_disable_unprepare(sspi->clk);
784b0823ee3SMasahisa Kojima 			dev_err(dev, "failed to enable spi (%d)\n", ret);
785b0823ee3SMasahisa Kojima 			return ret;
786b0823ee3SMasahisa Kojima 		}
787b0823ee3SMasahisa Kojima 	}
788b0823ee3SMasahisa Kojima 
789b0823ee3SMasahisa Kojima 	ret = spi_master_resume(master);
790b0823ee3SMasahisa Kojima 	if (ret < 0)
791b0823ee3SMasahisa Kojima 		clk_disable_unprepare(sspi->clk);
792b0823ee3SMasahisa Kojima 
793b0823ee3SMasahisa Kojima 	return ret;
794b0823ee3SMasahisa Kojima }
795b0823ee3SMasahisa Kojima 
796b0823ee3SMasahisa Kojima static SIMPLE_DEV_PM_OPS(synquacer_spi_pm_ops, synquacer_spi_suspend,
797b0823ee3SMasahisa Kojima 			 synquacer_spi_resume);
798b0823ee3SMasahisa Kojima 
799b0823ee3SMasahisa Kojima static const struct of_device_id synquacer_spi_of_match[] = {
800b0823ee3SMasahisa Kojima 	{.compatible = "socionext,synquacer-spi"},
801b0823ee3SMasahisa Kojima 	{}
802b0823ee3SMasahisa Kojima };
803b0823ee3SMasahisa Kojima MODULE_DEVICE_TABLE(of, synquacer_spi_of_match);
804b0823ee3SMasahisa Kojima 
805b0823ee3SMasahisa Kojima #ifdef CONFIG_ACPI
806b0823ee3SMasahisa Kojima static const struct acpi_device_id synquacer_hsspi_acpi_ids[] = {
807b0823ee3SMasahisa Kojima 	{ "SCX0004" },
808b0823ee3SMasahisa Kojima 	{ /* sentinel */ }
809b0823ee3SMasahisa Kojima };
810b0823ee3SMasahisa Kojima MODULE_DEVICE_TABLE(acpi, synquacer_hsspi_acpi_ids);
811b0823ee3SMasahisa Kojima #endif
812b0823ee3SMasahisa Kojima 
813b0823ee3SMasahisa Kojima static struct platform_driver synquacer_spi_driver = {
814b0823ee3SMasahisa Kojima 	.driver = {
815b0823ee3SMasahisa Kojima 		.name = "synquacer-spi",
816b0823ee3SMasahisa Kojima 		.pm = &synquacer_spi_pm_ops,
817b0823ee3SMasahisa Kojima 		.of_match_table = synquacer_spi_of_match,
818b0823ee3SMasahisa Kojima 		.acpi_match_table = ACPI_PTR(synquacer_hsspi_acpi_ids),
819b0823ee3SMasahisa Kojima 	},
820b0823ee3SMasahisa Kojima 	.probe = synquacer_spi_probe,
8211972cdc4SUwe Kleine-König 	.remove_new = synquacer_spi_remove,
822b0823ee3SMasahisa Kojima };
823b0823ee3SMasahisa Kojima module_platform_driver(synquacer_spi_driver);
824b0823ee3SMasahisa Kojima 
825b0823ee3SMasahisa Kojima MODULE_DESCRIPTION("Socionext Synquacer HS-SPI controller driver");
826b0823ee3SMasahisa Kojima MODULE_AUTHOR("Masahisa Kojima <masahisa.kojima@linaro.org>");
827b0823ee3SMasahisa Kojima MODULE_AUTHOR("Jassi Brar <jaswinder.singh@linaro.org>");
828b0823ee3SMasahisa Kojima MODULE_LICENSE("GPL v2");
829