1c770d863SJay Fang // SPDX-License-Identifier: GPL-2.0-only
2c770d863SJay Fang //
3c770d863SJay Fang // HiSilicon SPI Controller Driver for Kunpeng SoCs
4c770d863SJay Fang //
5c770d863SJay Fang // Copyright (c) 2021 HiSilicon Technologies Co., Ltd.
6c770d863SJay Fang // Author: Jay Fang <f.fangjian@huawei.com>
7c770d863SJay Fang //
8c770d863SJay Fang // This code is based on spi-dw-core.c.
9c770d863SJay Fang 
10c770d863SJay Fang #include <linux/acpi.h>
11c770d863SJay Fang #include <linux/bitfield.h>
122b2142f2SJay Fang #include <linux/debugfs.h>
13c770d863SJay Fang #include <linux/delay.h>
14c770d863SJay Fang #include <linux/err.h>
15c770d863SJay Fang #include <linux/interrupt.h>
16c770d863SJay Fang #include <linux/module.h>
17c770d863SJay Fang #include <linux/property.h>
18c770d863SJay Fang #include <linux/platform_device.h>
19c770d863SJay Fang #include <linux/slab.h>
20c770d863SJay Fang #include <linux/spi/spi.h>
21c770d863SJay Fang 
22c770d863SJay Fang /* Register offsets */
23c770d863SJay Fang #define HISI_SPI_CSCR		0x00	/* cs control register */
24c770d863SJay Fang #define HISI_SPI_CR		0x04	/* spi common control register */
25c770d863SJay Fang #define HISI_SPI_ENR		0x08	/* spi enable register */
26c770d863SJay Fang #define HISI_SPI_FIFOC		0x0c	/* fifo level control register */
27c770d863SJay Fang #define HISI_SPI_IMR		0x10	/* interrupt mask register */
28c770d863SJay Fang #define HISI_SPI_DIN		0x14	/* data in register */
29c770d863SJay Fang #define HISI_SPI_DOUT		0x18	/* data out register */
30c770d863SJay Fang #define HISI_SPI_SR		0x1c	/* status register */
31c770d863SJay Fang #define HISI_SPI_RISR		0x20	/* raw interrupt status register */
32c770d863SJay Fang #define HISI_SPI_ISR		0x24	/* interrupt status register */
33c770d863SJay Fang #define HISI_SPI_ICR		0x28	/* interrupt clear register */
34c770d863SJay Fang #define HISI_SPI_VERSION	0xe0	/* version register */
35c770d863SJay Fang 
36c770d863SJay Fang /* Bit fields in HISI_SPI_CR */
37c770d863SJay Fang #define CR_LOOP_MASK		GENMASK(1, 1)
38c770d863SJay Fang #define CR_CPOL_MASK		GENMASK(2, 2)
39c770d863SJay Fang #define CR_CPHA_MASK		GENMASK(3, 3)
40c770d863SJay Fang #define CR_DIV_PRE_MASK		GENMASK(11, 4)
41c770d863SJay Fang #define CR_DIV_POST_MASK	GENMASK(19, 12)
42c770d863SJay Fang #define CR_BPW_MASK		GENMASK(24, 20)
43c770d863SJay Fang #define CR_SPD_MODE_MASK	GENMASK(25, 25)
44c770d863SJay Fang 
45c770d863SJay Fang /* Bit fields in HISI_SPI_FIFOC */
46c770d863SJay Fang #define FIFOC_TX_MASK		GENMASK(5, 3)
47c770d863SJay Fang #define FIFOC_RX_MASK		GENMASK(11, 9)
48c770d863SJay Fang 
49c770d863SJay Fang /* Bit fields in HISI_SPI_IMR, 4 bits */
50c770d863SJay Fang #define IMR_RXOF		BIT(0)		/* Receive Overflow */
51c770d863SJay Fang #define IMR_RXTO		BIT(1)		/* Receive Timeout */
52c770d863SJay Fang #define IMR_RX			BIT(2)		/* Receive */
53c770d863SJay Fang #define IMR_TX			BIT(3)		/* Transmit */
54c770d863SJay Fang #define IMR_MASK		(IMR_RXOF | IMR_RXTO | IMR_RX | IMR_TX)
55c770d863SJay Fang 
56c770d863SJay Fang /* Bit fields in HISI_SPI_SR, 5 bits */
57c770d863SJay Fang #define SR_TXE			BIT(0)		/* Transmit FIFO empty */
58c770d863SJay Fang #define SR_TXNF			BIT(1)		/* Transmit FIFO not full */
59c770d863SJay Fang #define SR_RXNE			BIT(2)		/* Receive FIFO not empty */
60c770d863SJay Fang #define SR_RXF			BIT(3)		/* Receive FIFO full */
61c770d863SJay Fang #define SR_BUSY			BIT(4)		/* Busy Flag */
62c770d863SJay Fang 
63c770d863SJay Fang /* Bit fields in HISI_SPI_ISR, 4 bits */
64c770d863SJay Fang #define ISR_RXOF		BIT(0)		/* Receive Overflow */
65c770d863SJay Fang #define ISR_RXTO		BIT(1)		/* Receive Timeout */
66c770d863SJay Fang #define ISR_RX			BIT(2)		/* Receive */
67c770d863SJay Fang #define ISR_TX			BIT(3)		/* Transmit */
68c770d863SJay Fang #define ISR_MASK		(ISR_RXOF | ISR_RXTO | ISR_RX | ISR_TX)
69c770d863SJay Fang 
70c770d863SJay Fang /* Bit fields in HISI_SPI_ICR, 2 bits */
71c770d863SJay Fang #define ICR_RXOF		BIT(0)		/* Receive Overflow */
72c770d863SJay Fang #define ICR_RXTO		BIT(1)		/* Receive Timeout */
73c770d863SJay Fang #define ICR_MASK		(ICR_RXOF | ICR_RXTO)
74c770d863SJay Fang 
75c770d863SJay Fang #define DIV_POST_MAX		0xFF
76c770d863SJay Fang #define DIV_POST_MIN		0x00
77c770d863SJay Fang #define DIV_PRE_MAX		0xFE
78c770d863SJay Fang #define DIV_PRE_MIN		0x02
79c770d863SJay Fang #define CLK_DIV_MAX		((1 + DIV_POST_MAX) * DIV_PRE_MAX)
80c770d863SJay Fang #define CLK_DIV_MIN		((1 + DIV_POST_MIN) * DIV_PRE_MIN)
81c770d863SJay Fang 
82c770d863SJay Fang #define DEFAULT_NUM_CS		1
83c770d863SJay Fang 
84c770d863SJay Fang #define HISI_SPI_WAIT_TIMEOUT_MS	10UL
85c770d863SJay Fang 
86c770d863SJay Fang enum hisi_spi_rx_level_trig {
87c770d863SJay Fang 	HISI_SPI_RX_1,
88c770d863SJay Fang 	HISI_SPI_RX_4,
89c770d863SJay Fang 	HISI_SPI_RX_8,
90c770d863SJay Fang 	HISI_SPI_RX_16,
91c770d863SJay Fang 	HISI_SPI_RX_32,
92c770d863SJay Fang 	HISI_SPI_RX_64,
93c770d863SJay Fang 	HISI_SPI_RX_128
94c770d863SJay Fang };
95c770d863SJay Fang 
96c770d863SJay Fang enum hisi_spi_tx_level_trig {
97c770d863SJay Fang 	HISI_SPI_TX_1_OR_LESS,
98c770d863SJay Fang 	HISI_SPI_TX_4_OR_LESS,
99c770d863SJay Fang 	HISI_SPI_TX_8_OR_LESS,
100c770d863SJay Fang 	HISI_SPI_TX_16_OR_LESS,
101c770d863SJay Fang 	HISI_SPI_TX_32_OR_LESS,
102c770d863SJay Fang 	HISI_SPI_TX_64_OR_LESS,
103c770d863SJay Fang 	HISI_SPI_TX_128_OR_LESS
104c770d863SJay Fang };
105c770d863SJay Fang 
106c770d863SJay Fang enum hisi_spi_frame_n_bytes {
107c770d863SJay Fang 	HISI_SPI_N_BYTES_NULL,
108c770d863SJay Fang 	HISI_SPI_N_BYTES_U8,
109c770d863SJay Fang 	HISI_SPI_N_BYTES_U16,
110c770d863SJay Fang 	HISI_SPI_N_BYTES_U32 = 4
111c770d863SJay Fang };
112c770d863SJay Fang 
113c770d863SJay Fang /* Slave spi_dev related */
114c770d863SJay Fang struct hisi_chip_data {
115c770d863SJay Fang 	u32 cr;
116c770d863SJay Fang 	u32 speed_hz;	/* baud rate */
117c770d863SJay Fang 	u16 clk_div;	/* baud rate divider */
118c770d863SJay Fang 
119c770d863SJay Fang 	/* clk_div = (1 + div_post) * div_pre */
120c770d863SJay Fang 	u8 div_post;	/* value from 0 to 255 */
121c770d863SJay Fang 	u8 div_pre;	/* value from 2 to 254 (even only!) */
122c770d863SJay Fang };
123c770d863SJay Fang 
124c770d863SJay Fang struct hisi_spi {
125c770d863SJay Fang 	struct device		*dev;
126c770d863SJay Fang 
127c770d863SJay Fang 	void __iomem		*regs;
128c770d863SJay Fang 	int			irq;
129c770d863SJay Fang 	u32			fifo_len; /* depth of the FIFO buffer */
130c770d863SJay Fang 
131c770d863SJay Fang 	/* Current message transfer state info */
132c770d863SJay Fang 	const void		*tx;
133c770d863SJay Fang 	unsigned int		tx_len;
134c770d863SJay Fang 	void			*rx;
135c770d863SJay Fang 	unsigned int		rx_len;
136c770d863SJay Fang 	u8			n_bytes; /* current is a 1/2/4 bytes op */
1372b2142f2SJay Fang 
1382b2142f2SJay Fang 	struct dentry *debugfs;
1392b2142f2SJay Fang 	struct debugfs_regset32 regset;
140c770d863SJay Fang };
141c770d863SJay Fang 
1422b2142f2SJay Fang #define HISI_SPI_DBGFS_REG(_name, _off)	\
1432b2142f2SJay Fang {					\
1442b2142f2SJay Fang 	.name = _name,			\
1452b2142f2SJay Fang 	.offset = _off,			\
1462b2142f2SJay Fang }
1472b2142f2SJay Fang 
1482b2142f2SJay Fang static const struct debugfs_reg32 hisi_spi_regs[] = {
1492b2142f2SJay Fang 	HISI_SPI_DBGFS_REG("CSCR", HISI_SPI_CSCR),
1502b2142f2SJay Fang 	HISI_SPI_DBGFS_REG("CR", HISI_SPI_CR),
1512b2142f2SJay Fang 	HISI_SPI_DBGFS_REG("ENR", HISI_SPI_ENR),
1522b2142f2SJay Fang 	HISI_SPI_DBGFS_REG("FIFOC", HISI_SPI_FIFOC),
1532b2142f2SJay Fang 	HISI_SPI_DBGFS_REG("IMR", HISI_SPI_IMR),
1542b2142f2SJay Fang 	HISI_SPI_DBGFS_REG("SR", HISI_SPI_SR),
1552b2142f2SJay Fang 	HISI_SPI_DBGFS_REG("RISR", HISI_SPI_RISR),
1562b2142f2SJay Fang 	HISI_SPI_DBGFS_REG("ISR", HISI_SPI_ISR),
1572b2142f2SJay Fang 	HISI_SPI_DBGFS_REG("ICR", HISI_SPI_ICR),
1582b2142f2SJay Fang 	HISI_SPI_DBGFS_REG("VERSION", HISI_SPI_VERSION),
1592b2142f2SJay Fang };
1602b2142f2SJay Fang 
hisi_spi_debugfs_init(struct hisi_spi * hs)1612b2142f2SJay Fang static int hisi_spi_debugfs_init(struct hisi_spi *hs)
1622b2142f2SJay Fang {
1632b2142f2SJay Fang 	char name[32];
1642b2142f2SJay Fang 
165*9f589046SYang Yingliang 	struct spi_controller *host;
16640fafc8eSoujiefeng 
167*9f589046SYang Yingliang 	host = container_of(hs->dev, struct spi_controller, dev);
168*9f589046SYang Yingliang 	snprintf(name, 32, "hisi_spi%d", host->bus_num);
1692b2142f2SJay Fang 	hs->debugfs = debugfs_create_dir(name, NULL);
170120e1aa2SYeqi Fu 	if (IS_ERR(hs->debugfs))
1712b2142f2SJay Fang 		return -ENOMEM;
1722b2142f2SJay Fang 
1732b2142f2SJay Fang 	hs->regset.regs = hisi_spi_regs;
1742b2142f2SJay Fang 	hs->regset.nregs = ARRAY_SIZE(hisi_spi_regs);
1752b2142f2SJay Fang 	hs->regset.base = hs->regs;
1762b2142f2SJay Fang 	debugfs_create_regset32("registers", 0400, hs->debugfs, &hs->regset);
1772b2142f2SJay Fang 
1782b2142f2SJay Fang 	return 0;
1792b2142f2SJay Fang }
1802b2142f2SJay Fang 
hisi_spi_busy(struct hisi_spi * hs)181c770d863SJay Fang static u32 hisi_spi_busy(struct hisi_spi *hs)
182c770d863SJay Fang {
183c770d863SJay Fang 	return readl(hs->regs + HISI_SPI_SR) & SR_BUSY;
184c770d863SJay Fang }
185c770d863SJay Fang 
hisi_spi_rx_not_empty(struct hisi_spi * hs)186c770d863SJay Fang static u32 hisi_spi_rx_not_empty(struct hisi_spi *hs)
187c770d863SJay Fang {
188c770d863SJay Fang 	return readl(hs->regs + HISI_SPI_SR) & SR_RXNE;
189c770d863SJay Fang }
190c770d863SJay Fang 
hisi_spi_tx_not_full(struct hisi_spi * hs)191c770d863SJay Fang static u32 hisi_spi_tx_not_full(struct hisi_spi *hs)
192c770d863SJay Fang {
193c770d863SJay Fang 	return readl(hs->regs + HISI_SPI_SR) & SR_TXNF;
194c770d863SJay Fang }
195c770d863SJay Fang 
hisi_spi_flush_fifo(struct hisi_spi * hs)196c770d863SJay Fang static void hisi_spi_flush_fifo(struct hisi_spi *hs)
197c770d863SJay Fang {
198c770d863SJay Fang 	unsigned long limit = loops_per_jiffy << 1;
199c770d863SJay Fang 
200c770d863SJay Fang 	do {
201c770d863SJay Fang 		while (hisi_spi_rx_not_empty(hs))
202c770d863SJay Fang 			readl(hs->regs + HISI_SPI_DOUT);
203c770d863SJay Fang 	} while (hisi_spi_busy(hs) && limit--);
204c770d863SJay Fang }
205c770d863SJay Fang 
206c770d863SJay Fang /* Disable the controller and all interrupts */
hisi_spi_disable(struct hisi_spi * hs)207c770d863SJay Fang static void hisi_spi_disable(struct hisi_spi *hs)
208c770d863SJay Fang {
209c770d863SJay Fang 	writel(0, hs->regs + HISI_SPI_ENR);
210c770d863SJay Fang 	writel(IMR_MASK, hs->regs + HISI_SPI_IMR);
211c770d863SJay Fang 	writel(ICR_MASK, hs->regs + HISI_SPI_ICR);
212c770d863SJay Fang }
213c770d863SJay Fang 
hisi_spi_n_bytes(struct spi_transfer * transfer)214c770d863SJay Fang static u8 hisi_spi_n_bytes(struct spi_transfer *transfer)
215c770d863SJay Fang {
216c770d863SJay Fang 	if (transfer->bits_per_word <= 8)
217c770d863SJay Fang 		return HISI_SPI_N_BYTES_U8;
218c770d863SJay Fang 	else if (transfer->bits_per_word <= 16)
219c770d863SJay Fang 		return HISI_SPI_N_BYTES_U16;
220c770d863SJay Fang 	else
221c770d863SJay Fang 		return HISI_SPI_N_BYTES_U32;
222c770d863SJay Fang }
223c770d863SJay Fang 
hisi_spi_reader(struct hisi_spi * hs)224c770d863SJay Fang static void hisi_spi_reader(struct hisi_spi *hs)
225c770d863SJay Fang {
226c770d863SJay Fang 	u32 max = min_t(u32, hs->rx_len, hs->fifo_len);
227c770d863SJay Fang 	u32 rxw;
228c770d863SJay Fang 
229c770d863SJay Fang 	while (hisi_spi_rx_not_empty(hs) && max--) {
230c770d863SJay Fang 		rxw = readl(hs->regs + HISI_SPI_DOUT);
231c770d863SJay Fang 		/* Check the transfer's original "rx" is not null */
232c770d863SJay Fang 		if (hs->rx) {
233c770d863SJay Fang 			switch (hs->n_bytes) {
234c770d863SJay Fang 			case HISI_SPI_N_BYTES_U8:
235c770d863SJay Fang 				*(u8 *)(hs->rx) = rxw;
236c770d863SJay Fang 				break;
237c770d863SJay Fang 			case HISI_SPI_N_BYTES_U16:
238c770d863SJay Fang 				*(u16 *)(hs->rx) = rxw;
239c770d863SJay Fang 				break;
240c770d863SJay Fang 			case HISI_SPI_N_BYTES_U32:
241c770d863SJay Fang 				*(u32 *)(hs->rx) = rxw;
242c770d863SJay Fang 				break;
243c770d863SJay Fang 			}
244c770d863SJay Fang 			hs->rx += hs->n_bytes;
245c770d863SJay Fang 		}
246c770d863SJay Fang 		--hs->rx_len;
247c770d863SJay Fang 	}
248c770d863SJay Fang }
249c770d863SJay Fang 
hisi_spi_writer(struct hisi_spi * hs)250c770d863SJay Fang static void hisi_spi_writer(struct hisi_spi *hs)
251c770d863SJay Fang {
252c770d863SJay Fang 	u32 max = min_t(u32, hs->tx_len, hs->fifo_len);
253c770d863SJay Fang 	u32 txw = 0;
254c770d863SJay Fang 
255c770d863SJay Fang 	while (hisi_spi_tx_not_full(hs) && max--) {
256c770d863SJay Fang 		/* Check the transfer's original "tx" is not null */
257c770d863SJay Fang 		if (hs->tx) {
258c770d863SJay Fang 			switch (hs->n_bytes) {
259c770d863SJay Fang 			case HISI_SPI_N_BYTES_U8:
260c770d863SJay Fang 				txw = *(u8 *)(hs->tx);
261c770d863SJay Fang 				break;
262c770d863SJay Fang 			case HISI_SPI_N_BYTES_U16:
263c770d863SJay Fang 				txw = *(u16 *)(hs->tx);
264c770d863SJay Fang 				break;
265c770d863SJay Fang 			case HISI_SPI_N_BYTES_U32:
266c770d863SJay Fang 				txw = *(u32 *)(hs->tx);
267c770d863SJay Fang 				break;
268c770d863SJay Fang 			}
269c770d863SJay Fang 			hs->tx += hs->n_bytes;
270c770d863SJay Fang 		}
271c770d863SJay Fang 		writel(txw, hs->regs + HISI_SPI_DIN);
272c770d863SJay Fang 		--hs->tx_len;
273c770d863SJay Fang 	}
274c770d863SJay Fang }
275c770d863SJay Fang 
__hisi_calc_div_reg(struct hisi_chip_data * chip)276c770d863SJay Fang static void __hisi_calc_div_reg(struct hisi_chip_data *chip)
277c770d863SJay Fang {
278c770d863SJay Fang 	chip->div_pre = DIV_PRE_MAX;
279c770d863SJay Fang 	while (chip->div_pre >= DIV_PRE_MIN) {
280c770d863SJay Fang 		if (chip->clk_div % chip->div_pre == 0)
281c770d863SJay Fang 			break;
282c770d863SJay Fang 
283c770d863SJay Fang 		chip->div_pre -= 2;
284c770d863SJay Fang 	}
285c770d863SJay Fang 
286c770d863SJay Fang 	if (chip->div_pre > chip->clk_div)
287c770d863SJay Fang 		chip->div_pre = chip->clk_div;
288c770d863SJay Fang 
289c770d863SJay Fang 	chip->div_post = (chip->clk_div / chip->div_pre) - 1;
290c770d863SJay Fang }
291c770d863SJay Fang 
hisi_calc_effective_speed(struct spi_controller * host,struct hisi_chip_data * chip,u32 speed_hz)292*9f589046SYang Yingliang static u32 hisi_calc_effective_speed(struct spi_controller *host,
293c770d863SJay Fang 			struct hisi_chip_data *chip, u32 speed_hz)
294c770d863SJay Fang {
295c770d863SJay Fang 	u32 effective_speed;
296c770d863SJay Fang 
297c770d863SJay Fang 	/* Note clock divider doesn't support odd numbers */
298*9f589046SYang Yingliang 	chip->clk_div = DIV_ROUND_UP(host->max_speed_hz, speed_hz) + 1;
299c770d863SJay Fang 	chip->clk_div &= 0xfffe;
300c770d863SJay Fang 	if (chip->clk_div > CLK_DIV_MAX)
301c770d863SJay Fang 		chip->clk_div = CLK_DIV_MAX;
302c770d863SJay Fang 
303*9f589046SYang Yingliang 	effective_speed = host->max_speed_hz / chip->clk_div;
304c770d863SJay Fang 	if (chip->speed_hz != effective_speed) {
305c770d863SJay Fang 		__hisi_calc_div_reg(chip);
306c770d863SJay Fang 		chip->speed_hz = effective_speed;
307c770d863SJay Fang 	}
308c770d863SJay Fang 
309c770d863SJay Fang 	return effective_speed;
310c770d863SJay Fang }
311c770d863SJay Fang 
hisi_spi_prepare_cr(struct spi_device * spi)312c770d863SJay Fang static u32 hisi_spi_prepare_cr(struct spi_device *spi)
313c770d863SJay Fang {
314c770d863SJay Fang 	u32 cr = FIELD_PREP(CR_SPD_MODE_MASK, 1);
315c770d863SJay Fang 
316c770d863SJay Fang 	cr |= FIELD_PREP(CR_CPHA_MASK, (spi->mode & SPI_CPHA) ? 1 : 0);
317c770d863SJay Fang 	cr |= FIELD_PREP(CR_CPOL_MASK, (spi->mode & SPI_CPOL) ? 1 : 0);
318c770d863SJay Fang 	cr |= FIELD_PREP(CR_LOOP_MASK, (spi->mode & SPI_LOOP) ? 1 : 0);
319c770d863SJay Fang 
320c770d863SJay Fang 	return cr;
321c770d863SJay Fang }
322c770d863SJay Fang 
hisi_spi_hw_init(struct hisi_spi * hs)323c770d863SJay Fang static void hisi_spi_hw_init(struct hisi_spi *hs)
324c770d863SJay Fang {
325c770d863SJay Fang 	hisi_spi_disable(hs);
326c770d863SJay Fang 
327c770d863SJay Fang 	/* FIFO default config */
328c770d863SJay Fang 	writel(FIELD_PREP(FIFOC_TX_MASK, HISI_SPI_TX_64_OR_LESS) |
329c770d863SJay Fang 		FIELD_PREP(FIFOC_RX_MASK, HISI_SPI_RX_16),
330c770d863SJay Fang 		hs->regs + HISI_SPI_FIFOC);
331c770d863SJay Fang 
332c770d863SJay Fang 	hs->fifo_len = 256;
333c770d863SJay Fang }
334c770d863SJay Fang 
hisi_spi_irq(int irq,void * dev_id)335c770d863SJay Fang static irqreturn_t hisi_spi_irq(int irq, void *dev_id)
336c770d863SJay Fang {
337*9f589046SYang Yingliang 	struct spi_controller *host = dev_id;
338*9f589046SYang Yingliang 	struct hisi_spi *hs = spi_controller_get_devdata(host);
339c770d863SJay Fang 	u32 irq_status = readl(hs->regs + HISI_SPI_ISR) & ISR_MASK;
340c770d863SJay Fang 
341c770d863SJay Fang 	if (!irq_status)
342c770d863SJay Fang 		return IRQ_NONE;
343c770d863SJay Fang 
344*9f589046SYang Yingliang 	if (!host->cur_msg)
345c770d863SJay Fang 		return IRQ_HANDLED;
346c770d863SJay Fang 
347c770d863SJay Fang 	/* Error handling */
348c770d863SJay Fang 	if (irq_status & ISR_RXOF) {
349c770d863SJay Fang 		dev_err(hs->dev, "interrupt_transfer: fifo overflow\n");
350*9f589046SYang Yingliang 		host->cur_msg->status = -EIO;
351c770d863SJay Fang 		goto finalize_transfer;
352c770d863SJay Fang 	}
353c770d863SJay Fang 
354c770d863SJay Fang 	/*
355c770d863SJay Fang 	 * Read data from the Rx FIFO every time. If there is
356c770d863SJay Fang 	 * nothing left to receive, finalize the transfer.
357c770d863SJay Fang 	 */
358c770d863SJay Fang 	hisi_spi_reader(hs);
359c770d863SJay Fang 	if (!hs->rx_len)
360c770d863SJay Fang 		goto finalize_transfer;
361c770d863SJay Fang 
362c770d863SJay Fang 	/* Send data out when Tx FIFO IRQ triggered */
363c770d863SJay Fang 	if (irq_status & ISR_TX)
364c770d863SJay Fang 		hisi_spi_writer(hs);
365c770d863SJay Fang 
366c770d863SJay Fang 	return IRQ_HANDLED;
367c770d863SJay Fang 
368c770d863SJay Fang finalize_transfer:
369c770d863SJay Fang 	hisi_spi_disable(hs);
370*9f589046SYang Yingliang 	spi_finalize_current_transfer(host);
371c770d863SJay Fang 	return IRQ_HANDLED;
372c770d863SJay Fang }
373c770d863SJay Fang 
hisi_spi_transfer_one(struct spi_controller * host,struct spi_device * spi,struct spi_transfer * transfer)374*9f589046SYang Yingliang static int hisi_spi_transfer_one(struct spi_controller *host,
375c770d863SJay Fang 		struct spi_device *spi, struct spi_transfer *transfer)
376c770d863SJay Fang {
377*9f589046SYang Yingliang 	struct hisi_spi *hs = spi_controller_get_devdata(host);
378c770d863SJay Fang 	struct hisi_chip_data *chip = spi_get_ctldata(spi);
379c770d863SJay Fang 	u32 cr = chip->cr;
380c770d863SJay Fang 
381c770d863SJay Fang 	/* Update per transfer options for speed and bpw */
382c770d863SJay Fang 	transfer->effective_speed_hz =
383*9f589046SYang Yingliang 		hisi_calc_effective_speed(host, chip, transfer->speed_hz);
384c770d863SJay Fang 	cr |= FIELD_PREP(CR_DIV_PRE_MASK, chip->div_pre);
385c770d863SJay Fang 	cr |= FIELD_PREP(CR_DIV_POST_MASK, chip->div_post);
386c770d863SJay Fang 	cr |= FIELD_PREP(CR_BPW_MASK, transfer->bits_per_word - 1);
387c770d863SJay Fang 	writel(cr, hs->regs + HISI_SPI_CR);
388c770d863SJay Fang 
389c770d863SJay Fang 	hisi_spi_flush_fifo(hs);
390c770d863SJay Fang 
391c770d863SJay Fang 	hs->n_bytes = hisi_spi_n_bytes(transfer);
392c770d863SJay Fang 	hs->tx = transfer->tx_buf;
393c770d863SJay Fang 	hs->tx_len = transfer->len / hs->n_bytes;
394c770d863SJay Fang 	hs->rx = transfer->rx_buf;
395c770d863SJay Fang 	hs->rx_len = hs->tx_len;
396c770d863SJay Fang 
397c770d863SJay Fang 	/*
398c770d863SJay Fang 	 * Ensure that the transfer data above has been updated
399c770d863SJay Fang 	 * before the interrupt to start.
400c770d863SJay Fang 	 */
401c770d863SJay Fang 	smp_mb();
402c770d863SJay Fang 
403c770d863SJay Fang 	/* Enable all interrupts and the controller */
4049a446cf9SJay Fang 	writel(~(u32)IMR_MASK, hs->regs + HISI_SPI_IMR);
405c770d863SJay Fang 	writel(1, hs->regs + HISI_SPI_ENR);
406c770d863SJay Fang 
407c770d863SJay Fang 	return 1;
408c770d863SJay Fang }
409c770d863SJay Fang 
hisi_spi_handle_err(struct spi_controller * host,struct spi_message * msg)410*9f589046SYang Yingliang static void hisi_spi_handle_err(struct spi_controller *host,
411c770d863SJay Fang 		struct spi_message *msg)
412c770d863SJay Fang {
413*9f589046SYang Yingliang 	struct hisi_spi *hs = spi_controller_get_devdata(host);
414c770d863SJay Fang 
415c770d863SJay Fang 	hisi_spi_disable(hs);
416c770d863SJay Fang 
417c770d863SJay Fang 	/*
418c770d863SJay Fang 	 * Wait for interrupt handler that is
419c770d863SJay Fang 	 * already in timeout to complete.
420c770d863SJay Fang 	 */
421c770d863SJay Fang 	msleep(HISI_SPI_WAIT_TIMEOUT_MS);
422c770d863SJay Fang }
423c770d863SJay Fang 
hisi_spi_setup(struct spi_device * spi)424c770d863SJay Fang static int hisi_spi_setup(struct spi_device *spi)
425c770d863SJay Fang {
426c770d863SJay Fang 	struct hisi_chip_data *chip;
427c770d863SJay Fang 
428c770d863SJay Fang 	/* Only alloc on first setup */
429c770d863SJay Fang 	chip = spi_get_ctldata(spi);
430c770d863SJay Fang 	if (!chip) {
431c770d863SJay Fang 		chip = kzalloc(sizeof(*chip), GFP_KERNEL);
432c770d863SJay Fang 		if (!chip)
433c770d863SJay Fang 			return -ENOMEM;
434c770d863SJay Fang 		spi_set_ctldata(spi, chip);
435c770d863SJay Fang 	}
436c770d863SJay Fang 
437c770d863SJay Fang 	chip->cr = hisi_spi_prepare_cr(spi);
438c770d863SJay Fang 
439c770d863SJay Fang 	return 0;
440c770d863SJay Fang }
441c770d863SJay Fang 
hisi_spi_cleanup(struct spi_device * spi)442c770d863SJay Fang static void hisi_spi_cleanup(struct spi_device *spi)
443c770d863SJay Fang {
444c770d863SJay Fang 	struct hisi_chip_data *chip = spi_get_ctldata(spi);
445c770d863SJay Fang 
446c770d863SJay Fang 	kfree(chip);
447c770d863SJay Fang 	spi_set_ctldata(spi, NULL);
448c770d863SJay Fang }
449c770d863SJay Fang 
hisi_spi_probe(struct platform_device * pdev)450c770d863SJay Fang static int hisi_spi_probe(struct platform_device *pdev)
451c770d863SJay Fang {
452c770d863SJay Fang 	struct device *dev = &pdev->dev;
453*9f589046SYang Yingliang 	struct spi_controller *host;
454c770d863SJay Fang 	struct hisi_spi *hs;
455c770d863SJay Fang 	int ret, irq;
456c770d863SJay Fang 
457c770d863SJay Fang 	irq = platform_get_irq(pdev, 0);
458c770d863SJay Fang 	if (irq < 0)
459c770d863SJay Fang 		return irq;
460c770d863SJay Fang 
461*9f589046SYang Yingliang 	host = devm_spi_alloc_host(dev, sizeof(*hs));
462*9f589046SYang Yingliang 	if (!host)
463c770d863SJay Fang 		return -ENOMEM;
464c770d863SJay Fang 
465*9f589046SYang Yingliang 	platform_set_drvdata(pdev, host);
466c770d863SJay Fang 
467*9f589046SYang Yingliang 	hs = spi_controller_get_devdata(host);
468c770d863SJay Fang 	hs->dev = dev;
469c770d863SJay Fang 	hs->irq = irq;
470c770d863SJay Fang 
471c770d863SJay Fang 	hs->regs = devm_platform_ioremap_resource(pdev, 0);
472c770d863SJay Fang 	if (IS_ERR(hs->regs))
473c770d863SJay Fang 		return PTR_ERR(hs->regs);
474c770d863SJay Fang 
475*9f589046SYang Yingliang 	/* Specify maximum SPI clocking speed (host only) by firmware */
476c770d863SJay Fang 	ret = device_property_read_u32(dev, "spi-max-frequency",
477*9f589046SYang Yingliang 					&host->max_speed_hz);
478c770d863SJay Fang 	if (ret) {
479c770d863SJay Fang 		dev_err(dev, "failed to get max SPI clocking speed, ret=%d\n",
480c770d863SJay Fang 			ret);
481c770d863SJay Fang 		return -EINVAL;
482c770d863SJay Fang 	}
483c770d863SJay Fang 
484c770d863SJay Fang 	ret = device_property_read_u16(dev, "num-cs",
485*9f589046SYang Yingliang 					&host->num_chipselect);
486c770d863SJay Fang 	if (ret)
487*9f589046SYang Yingliang 		host->num_chipselect = DEFAULT_NUM_CS;
488c770d863SJay Fang 
489*9f589046SYang Yingliang 	host->use_gpio_descriptors = true;
490*9f589046SYang Yingliang 	host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
491*9f589046SYang Yingliang 	host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
492*9f589046SYang Yingliang 	host->bus_num = pdev->id;
493*9f589046SYang Yingliang 	host->setup = hisi_spi_setup;
494*9f589046SYang Yingliang 	host->cleanup = hisi_spi_cleanup;
495*9f589046SYang Yingliang 	host->transfer_one = hisi_spi_transfer_one;
496*9f589046SYang Yingliang 	host->handle_err = hisi_spi_handle_err;
497*9f589046SYang Yingliang 	host->dev.fwnode = dev->fwnode;
498c770d863SJay Fang 
499c770d863SJay Fang 	hisi_spi_hw_init(hs);
500c770d863SJay Fang 
501c770d863SJay Fang 	ret = devm_request_irq(dev, hs->irq, hisi_spi_irq, 0, dev_name(dev),
502*9f589046SYang Yingliang 			       host);
503c770d863SJay Fang 	if (ret < 0) {
504c770d863SJay Fang 		dev_err(dev, "failed to get IRQ=%d, ret=%d\n", hs->irq, ret);
505c770d863SJay Fang 		return ret;
506c770d863SJay Fang 	}
507c770d863SJay Fang 
508*9f589046SYang Yingliang 	ret = spi_register_controller(host);
509c770d863SJay Fang 	if (ret) {
510*9f589046SYang Yingliang 		dev_err(dev, "failed to register spi host, ret=%d\n", ret);
511c770d863SJay Fang 		return ret;
512c770d863SJay Fang 	}
513c770d863SJay Fang 
51440fafc8eSoujiefeng 	if (hisi_spi_debugfs_init(hs))
51540fafc8eSoujiefeng 		dev_info(dev, "failed to create debugfs dir\n");
51640fafc8eSoujiefeng 
517c770d863SJay Fang 	dev_info(dev, "hw version:0x%x max-freq:%u kHz\n",
518c770d863SJay Fang 		readl(hs->regs + HISI_SPI_VERSION),
519*9f589046SYang Yingliang 		host->max_speed_hz / 1000);
520c770d863SJay Fang 
521c770d863SJay Fang 	return 0;
522c770d863SJay Fang }
523c770d863SJay Fang 
hisi_spi_remove(struct platform_device * pdev)524e77ccdfeSUwe Kleine-König static void hisi_spi_remove(struct platform_device *pdev)
525c770d863SJay Fang {
526*9f589046SYang Yingliang 	struct spi_controller *host = platform_get_drvdata(pdev);
527*9f589046SYang Yingliang 	struct hisi_spi *hs = spi_controller_get_devdata(host);
528c770d863SJay Fang 
5292b2142f2SJay Fang 	debugfs_remove_recursive(hs->debugfs);
530*9f589046SYang Yingliang 	spi_unregister_controller(host);
531c770d863SJay Fang }
532c770d863SJay Fang 
533c770d863SJay Fang static const struct acpi_device_id hisi_spi_acpi_match[] = {
534c770d863SJay Fang 	{"HISI03E1", 0},
535c770d863SJay Fang 	{}
536c770d863SJay Fang };
537c770d863SJay Fang MODULE_DEVICE_TABLE(acpi, hisi_spi_acpi_match);
538c770d863SJay Fang 
539c770d863SJay Fang static struct platform_driver hisi_spi_driver = {
540c770d863SJay Fang 	.probe		= hisi_spi_probe,
541e77ccdfeSUwe Kleine-König 	.remove_new	= hisi_spi_remove,
542c770d863SJay Fang 	.driver		= {
543c770d863SJay Fang 		.name	= "hisi-kunpeng-spi",
544c770d863SJay Fang 		.acpi_match_table = hisi_spi_acpi_match,
545c770d863SJay Fang 	},
546c770d863SJay Fang };
547c770d863SJay Fang module_platform_driver(hisi_spi_driver);
548c770d863SJay Fang 
549c770d863SJay Fang MODULE_AUTHOR("Jay Fang <f.fangjian@huawei.com>");
550c770d863SJay Fang MODULE_DESCRIPTION("HiSilicon SPI Controller Driver for Kunpeng SoCs");
551c770d863SJay Fang MODULE_LICENSE("GPL v2");
552