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