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
1659f589046SYang Yingliang struct spi_controller *host;
16640fafc8eSoujiefeng
1679f589046SYang Yingliang host = container_of(hs->dev, struct spi_controller, dev);
1689f589046SYang 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)2929f589046SYang 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 */
2989f589046SYang 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
3039f589046SYang 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 {
3379f589046SYang Yingliang struct spi_controller *host = dev_id;
3389f589046SYang 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
3449f589046SYang 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");
3509f589046SYang 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);
3709f589046SYang 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)3749f589046SYang Yingliang static int hisi_spi_transfer_one(struct spi_controller *host,
375c770d863SJay Fang struct spi_device *spi, struct spi_transfer *transfer)
376c770d863SJay Fang {
3779f589046SYang 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 =
3839f589046SYang 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)4109f589046SYang Yingliang static void hisi_spi_handle_err(struct spi_controller *host,
411c770d863SJay Fang struct spi_message *msg)
412c770d863SJay Fang {
4139f589046SYang 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;
4539f589046SYang 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
4619f589046SYang Yingliang host = devm_spi_alloc_host(dev, sizeof(*hs));
4629f589046SYang Yingliang if (!host)
463c770d863SJay Fang return -ENOMEM;
464c770d863SJay Fang
4659f589046SYang Yingliang platform_set_drvdata(pdev, host);
466c770d863SJay Fang
4679f589046SYang 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
4759f589046SYang Yingliang /* Specify maximum SPI clocking speed (host only) by firmware */
476c770d863SJay Fang ret = device_property_read_u32(dev, "spi-max-frequency",
4779f589046SYang 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
484*16ccaf58SDevyn Liu if (host->max_speed_hz == 0)
485*16ccaf58SDevyn Liu return dev_err_probe(dev, -EINVAL, "spi-max-frequency can't be 0\n");
486*16ccaf58SDevyn Liu
487c770d863SJay Fang ret = device_property_read_u16(dev, "num-cs",
4889f589046SYang Yingliang &host->num_chipselect);
489c770d863SJay Fang if (ret)
4909f589046SYang Yingliang host->num_chipselect = DEFAULT_NUM_CS;
491c770d863SJay Fang
4929f589046SYang Yingliang host->use_gpio_descriptors = true;
4939f589046SYang Yingliang host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
4949f589046SYang Yingliang host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
4959f589046SYang Yingliang host->bus_num = pdev->id;
4969f589046SYang Yingliang host->setup = hisi_spi_setup;
4979f589046SYang Yingliang host->cleanup = hisi_spi_cleanup;
4989f589046SYang Yingliang host->transfer_one = hisi_spi_transfer_one;
4999f589046SYang Yingliang host->handle_err = hisi_spi_handle_err;
5009f589046SYang Yingliang host->dev.fwnode = dev->fwnode;
5018b28f8c5SDevyn Liu host->min_speed_hz = DIV_ROUND_UP(host->max_speed_hz, CLK_DIV_MAX);
502c770d863SJay Fang
503c770d863SJay Fang hisi_spi_hw_init(hs);
504c770d863SJay Fang
505c770d863SJay Fang ret = devm_request_irq(dev, hs->irq, hisi_spi_irq, 0, dev_name(dev),
5069f589046SYang Yingliang host);
507c770d863SJay Fang if (ret < 0) {
508c770d863SJay Fang dev_err(dev, "failed to get IRQ=%d, ret=%d\n", hs->irq, ret);
509c770d863SJay Fang return ret;
510c770d863SJay Fang }
511c770d863SJay Fang
5129f589046SYang Yingliang ret = spi_register_controller(host);
513c770d863SJay Fang if (ret) {
5149f589046SYang Yingliang dev_err(dev, "failed to register spi host, ret=%d\n", ret);
515c770d863SJay Fang return ret;
516c770d863SJay Fang }
517c770d863SJay Fang
51840fafc8eSoujiefeng if (hisi_spi_debugfs_init(hs))
51940fafc8eSoujiefeng dev_info(dev, "failed to create debugfs dir\n");
52040fafc8eSoujiefeng
521c770d863SJay Fang dev_info(dev, "hw version:0x%x max-freq:%u kHz\n",
522c770d863SJay Fang readl(hs->regs + HISI_SPI_VERSION),
5239f589046SYang Yingliang host->max_speed_hz / 1000);
524c770d863SJay Fang
525c770d863SJay Fang return 0;
526c770d863SJay Fang }
527c770d863SJay Fang
hisi_spi_remove(struct platform_device * pdev)528e77ccdfeSUwe Kleine-König static void hisi_spi_remove(struct platform_device *pdev)
529c770d863SJay Fang {
5309f589046SYang Yingliang struct spi_controller *host = platform_get_drvdata(pdev);
5319f589046SYang Yingliang struct hisi_spi *hs = spi_controller_get_devdata(host);
532c770d863SJay Fang
5332b2142f2SJay Fang debugfs_remove_recursive(hs->debugfs);
5349f589046SYang Yingliang spi_unregister_controller(host);
535c770d863SJay Fang }
536c770d863SJay Fang
537c770d863SJay Fang static const struct acpi_device_id hisi_spi_acpi_match[] = {
538c770d863SJay Fang {"HISI03E1", 0},
539c770d863SJay Fang {}
540c770d863SJay Fang };
541c770d863SJay Fang MODULE_DEVICE_TABLE(acpi, hisi_spi_acpi_match);
542c770d863SJay Fang
543c770d863SJay Fang static struct platform_driver hisi_spi_driver = {
544c770d863SJay Fang .probe = hisi_spi_probe,
545e77ccdfeSUwe Kleine-König .remove_new = hisi_spi_remove,
546c770d863SJay Fang .driver = {
547c770d863SJay Fang .name = "hisi-kunpeng-spi",
548c770d863SJay Fang .acpi_match_table = hisi_spi_acpi_match,
549c770d863SJay Fang },
550c770d863SJay Fang };
551c770d863SJay Fang module_platform_driver(hisi_spi_driver);
552c770d863SJay Fang
553c770d863SJay Fang MODULE_AUTHOR("Jay Fang <f.fangjian@huawei.com>");
554c770d863SJay Fang MODULE_DESCRIPTION("HiSilicon SPI Controller Driver for Kunpeng SoCs");
555c770d863SJay Fang MODULE_LICENSE("GPL v2");
556