1 // SPDX-License-Identifier: GPL-2.0+
2 // Loongson SPI Support
3 // Copyright (C) 2023 Loongson Technology Corporation Limited
6 #include <linux/delay.h>
8 #include <linux/init.h>
9 #include <linux/interrupt.h>
11 #include <linux/iopoll.h>
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/spi/spi.h>
16 #include "spi-loongson.h"
18 static inline void loongson_spi_write_reg(struct loongson_spi
*spi
, unsigned char reg
,
21 writeb(data
, spi
->base
+ reg
);
24 static inline char loongson_spi_read_reg(struct loongson_spi
*spi
, unsigned char reg
)
26 return readb(spi
->base
+ reg
);
29 static void loongson_spi_set_cs(struct spi_device
*spi
, bool en
)
32 unsigned char mask
= (BIT(4) | BIT(0)) << spi_get_chipselect(spi
, 0);
33 unsigned char val
= en
? mask
: (BIT(0) << spi_get_chipselect(spi
, 0));
34 struct loongson_spi
*loongson_spi
= spi_controller_get_devdata(spi
->controller
);
36 cs
= loongson_spi_read_reg(loongson_spi
, LOONGSON_SPI_SFCS_REG
) & ~mask
;
37 loongson_spi_write_reg(loongson_spi
, LOONGSON_SPI_SFCS_REG
, val
| cs
);
40 static void loongson_spi_set_clk(struct loongson_spi
*loongson_spi
, unsigned int hz
)
43 unsigned int div
, div_tmp
;
44 static const char rdiv
[12] = {0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10, 11};
46 div
= clamp_val(DIV_ROUND_UP_ULL(loongson_spi
->clk_rate
, hz
), 2, 4096);
47 div_tmp
= rdiv
[fls(div
- 1)];
48 loongson_spi
->spcr
= (div_tmp
& GENMASK(1, 0)) >> 0;
49 loongson_spi
->sper
= (div_tmp
& GENMASK(3, 2)) >> 2;
50 val
= loongson_spi_read_reg(loongson_spi
, LOONGSON_SPI_SPCR_REG
);
51 val
&= ~GENMASK(1, 0);
52 loongson_spi_write_reg(loongson_spi
, LOONGSON_SPI_SPCR_REG
, val
|
54 val
= loongson_spi_read_reg(loongson_spi
, LOONGSON_SPI_SPER_REG
);
55 val
&= ~GENMASK(1, 0);
56 loongson_spi_write_reg(loongson_spi
, LOONGSON_SPI_SPER_REG
, val
|
58 loongson_spi
->hz
= hz
;
61 static void loongson_spi_set_mode(struct loongson_spi
*loongson_spi
,
62 struct spi_device
*spi
)
66 val
= loongson_spi_read_reg(loongson_spi
, LOONGSON_SPI_SPCR_REG
);
67 val
&= ~(LOONGSON_SPI_SPCR_CPOL
| LOONGSON_SPI_SPCR_CPHA
);
68 if (spi
->mode
& SPI_CPOL
)
69 val
|= LOONGSON_SPI_SPCR_CPOL
;
70 if (spi
->mode
& SPI_CPHA
)
71 val
|= LOONGSON_SPI_SPCR_CPHA
;
73 loongson_spi_write_reg(loongson_spi
, LOONGSON_SPI_SPCR_REG
, val
);
74 loongson_spi
->mode
|= spi
->mode
;
77 static int loongson_spi_update_state(struct loongson_spi
*loongson_spi
,
78 struct spi_device
*spi
, struct spi_transfer
*t
)
80 if (t
&& loongson_spi
->hz
!= t
->speed_hz
)
81 loongson_spi_set_clk(loongson_spi
, t
->speed_hz
);
83 if ((spi
->mode
^ loongson_spi
->mode
) & SPI_MODE_X_MASK
)
84 loongson_spi_set_mode(loongson_spi
, spi
);
89 static int loongson_spi_setup(struct spi_device
*spi
)
91 struct loongson_spi
*loongson_spi
;
93 loongson_spi
= spi_controller_get_devdata(spi
->controller
);
94 if (spi
->bits_per_word
% 8)
97 if (spi_get_chipselect(spi
, 0) >= spi
->controller
->num_chipselect
)
100 loongson_spi
->hz
= 0;
101 loongson_spi_set_cs(spi
, true);
106 static int loongson_spi_write_read_8bit(struct spi_device
*spi
, const u8
**tx_buf
,
107 u8
**rx_buf
, unsigned int num
)
110 struct loongson_spi
*loongson_spi
= spi_controller_get_devdata(spi
->controller
);
112 if (tx_buf
&& *tx_buf
)
113 loongson_spi_write_reg(loongson_spi
, LOONGSON_SPI_FIFO_REG
, *((*tx_buf
)++));
115 loongson_spi_write_reg(loongson_spi
, LOONGSON_SPI_FIFO_REG
, 0);
117 ret
= readb_poll_timeout(loongson_spi
->base
+ LOONGSON_SPI_SPSR_REG
,
118 loongson_spi
->spsr
, (loongson_spi
->spsr
&
119 LOONGSON_SPI_SPSR_RFEMPTY
) != LOONGSON_SPI_SPSR_RFEMPTY
,
122 if (rx_buf
&& *rx_buf
)
123 *(*rx_buf
)++ = loongson_spi_read_reg(loongson_spi
, LOONGSON_SPI_FIFO_REG
);
125 loongson_spi_read_reg(loongson_spi
, LOONGSON_SPI_FIFO_REG
);
130 static int loongson_spi_write_read(struct spi_device
*spi
, struct spi_transfer
*xfer
)
134 const u8
*tx
= xfer
->tx_buf
;
135 u8
*rx
= xfer
->rx_buf
;
139 ret
= loongson_spi_write_read_8bit(spi
, &tx
, &rx
, count
);
147 static int loongson_spi_prepare_message(struct spi_controller
*ctlr
, struct spi_message
*m
)
149 struct loongson_spi
*loongson_spi
= spi_controller_get_devdata(ctlr
);
151 loongson_spi
->para
= loongson_spi_read_reg(loongson_spi
, LOONGSON_SPI_PARA_REG
);
152 loongson_spi_write_reg(loongson_spi
, LOONGSON_SPI_PARA_REG
, loongson_spi
->para
&
153 ~LOONGSON_SPI_PARA_MEM_EN
);
158 static int loongson_spi_transfer_one(struct spi_controller
*ctrl
, struct spi_device
*spi
,
159 struct spi_transfer
*xfer
)
161 struct loongson_spi
*loongson_spi
= spi_controller_get_devdata(spi
->controller
);
163 loongson_spi_update_state(loongson_spi
, spi
, xfer
);
165 return loongson_spi_write_read(spi
, xfer
);
170 static int loongson_spi_unprepare_message(struct spi_controller
*ctrl
, struct spi_message
*m
)
172 struct loongson_spi
*loongson_spi
= spi_controller_get_devdata(ctrl
);
174 loongson_spi_write_reg(loongson_spi
, LOONGSON_SPI_PARA_REG
, loongson_spi
->para
);
179 static void loongson_spi_reginit(struct loongson_spi
*loongson_spi_dev
)
183 val
= loongson_spi_read_reg(loongson_spi_dev
, LOONGSON_SPI_SPCR_REG
);
184 val
&= ~LOONGSON_SPI_SPCR_SPE
;
185 loongson_spi_write_reg(loongson_spi_dev
, LOONGSON_SPI_SPCR_REG
, val
);
187 loongson_spi_write_reg(loongson_spi_dev
, LOONGSON_SPI_SPSR_REG
,
188 (LOONGSON_SPI_SPSR_SPIF
| LOONGSON_SPI_SPSR_WCOL
));
190 val
= loongson_spi_read_reg(loongson_spi_dev
, LOONGSON_SPI_SPCR_REG
);
191 val
|= LOONGSON_SPI_SPCR_SPE
;
192 loongson_spi_write_reg(loongson_spi_dev
, LOONGSON_SPI_SPCR_REG
, val
);
195 int loongson_spi_init_controller(struct device
*dev
, void __iomem
*regs
)
197 struct spi_controller
*controller
;
198 struct loongson_spi
*spi
;
201 controller
= devm_spi_alloc_host(dev
, sizeof(struct loongson_spi
));
202 if (controller
== NULL
)
205 controller
->mode_bits
= SPI_MODE_X_MASK
| SPI_CS_HIGH
;
206 controller
->setup
= loongson_spi_setup
;
207 controller
->prepare_message
= loongson_spi_prepare_message
;
208 controller
->transfer_one
= loongson_spi_transfer_one
;
209 controller
->unprepare_message
= loongson_spi_unprepare_message
;
210 controller
->set_cs
= loongson_spi_set_cs
;
211 controller
->num_chipselect
= 4;
212 device_set_node(&controller
->dev
, dev_fwnode(dev
));
213 dev_set_drvdata(dev
, controller
);
215 spi
= spi_controller_get_devdata(controller
);
217 spi
->controller
= controller
;
219 clk
= devm_clk_get_optional(dev
, NULL
);
221 return dev_err_probe(dev
, PTR_ERR(clk
), "unable to get clock\n");
223 spi
->clk_rate
= clk_get_rate(clk
);
224 loongson_spi_reginit(spi
);
228 return devm_spi_register_controller(dev
, controller
);
230 EXPORT_SYMBOL_NS_GPL(loongson_spi_init_controller
, "SPI_LOONGSON_CORE");
232 static int __maybe_unused
loongson_spi_suspend(struct device
*dev
)
234 struct loongson_spi
*loongson_spi
;
235 struct spi_controller
*controller
;
237 controller
= dev_get_drvdata(dev
);
238 spi_controller_suspend(controller
);
240 loongson_spi
= spi_controller_get_devdata(controller
);
242 loongson_spi
->spcr
= loongson_spi_read_reg(loongson_spi
, LOONGSON_SPI_SPCR_REG
);
243 loongson_spi
->sper
= loongson_spi_read_reg(loongson_spi
, LOONGSON_SPI_SPER_REG
);
244 loongson_spi
->spsr
= loongson_spi_read_reg(loongson_spi
, LOONGSON_SPI_SPSR_REG
);
245 loongson_spi
->para
= loongson_spi_read_reg(loongson_spi
, LOONGSON_SPI_PARA_REG
);
246 loongson_spi
->sfcs
= loongson_spi_read_reg(loongson_spi
, LOONGSON_SPI_SFCS_REG
);
247 loongson_spi
->timi
= loongson_spi_read_reg(loongson_spi
, LOONGSON_SPI_TIMI_REG
);
252 static int __maybe_unused
loongson_spi_resume(struct device
*dev
)
254 struct loongson_spi
*loongson_spi
;
255 struct spi_controller
*controller
;
257 controller
= dev_get_drvdata(dev
);
258 loongson_spi
= spi_controller_get_devdata(controller
);
260 loongson_spi_write_reg(loongson_spi
, LOONGSON_SPI_SPCR_REG
, loongson_spi
->spcr
);
261 loongson_spi_write_reg(loongson_spi
, LOONGSON_SPI_SPER_REG
, loongson_spi
->sper
);
262 loongson_spi_write_reg(loongson_spi
, LOONGSON_SPI_SPSR_REG
, loongson_spi
->spsr
);
263 loongson_spi_write_reg(loongson_spi
, LOONGSON_SPI_PARA_REG
, loongson_spi
->para
);
264 loongson_spi_write_reg(loongson_spi
, LOONGSON_SPI_SFCS_REG
, loongson_spi
->sfcs
);
265 loongson_spi_write_reg(loongson_spi
, LOONGSON_SPI_TIMI_REG
, loongson_spi
->timi
);
267 spi_controller_resume(controller
);
272 const struct dev_pm_ops loongson_spi_dev_pm_ops
= {
273 .suspend
= loongson_spi_suspend
,
274 .resume
= loongson_spi_resume
,
276 EXPORT_SYMBOL_NS_GPL(loongson_spi_dev_pm_ops
, "SPI_LOONGSON_CORE");
278 MODULE_DESCRIPTION("Loongson SPI core driver");
279 MODULE_LICENSE("GPL");