Lines Matching +full:spi +full:- +full:clk
1 // SPDX-License-Identifier: GPL-2.0+
2 // Loongson SPI Support
5 #include <linux/clk.h>
15 #include <linux/spi/spi.h>
17 #include "spi-loongson.h"
19 static inline void loongson_spi_write_reg(struct loongson_spi *spi, unsigned char reg, in loongson_spi_write_reg() argument
22 writeb(data, spi->base + reg); in loongson_spi_write_reg()
25 static inline char loongson_spi_read_reg(struct loongson_spi *spi, unsigned char reg) in loongson_spi_read_reg() argument
27 return readb(spi->base + reg); in loongson_spi_read_reg()
30 static void loongson_spi_set_cs(struct spi_device *spi, bool en) in loongson_spi_set_cs() argument
33 unsigned char mask = (BIT(4) | BIT(0)) << spi_get_chipselect(spi, 0); in loongson_spi_set_cs()
34 unsigned char val = en ? mask : (BIT(0) << spi_get_chipselect(spi, 0)); in loongson_spi_set_cs()
35 struct loongson_spi *loongson_spi = spi_controller_get_devdata(spi->controller); in loongson_spi_set_cs()
47 div = clamp_val(DIV_ROUND_UP_ULL(loongson_spi->clk_rate, hz), 2, 4096); in loongson_spi_set_clk()
48 div_tmp = rdiv[fls(div - 1)]; in loongson_spi_set_clk()
49 loongson_spi->spcr = (div_tmp & GENMASK(1, 0)) >> 0; in loongson_spi_set_clk()
50 loongson_spi->sper = (div_tmp & GENMASK(3, 2)) >> 2; in loongson_spi_set_clk()
54 loongson_spi->spcr); in loongson_spi_set_clk()
58 loongson_spi->sper); in loongson_spi_set_clk()
59 loongson_spi->hz = hz; in loongson_spi_set_clk()
63 struct spi_device *spi) in loongson_spi_set_mode() argument
69 if (spi->mode & SPI_CPOL) in loongson_spi_set_mode()
71 if (spi->mode & SPI_CPHA) in loongson_spi_set_mode()
75 loongson_spi->mode |= spi->mode; in loongson_spi_set_mode()
79 struct spi_device *spi, struct spi_transfer *t) in loongson_spi_update_state() argument
81 if (t && loongson_spi->hz != t->speed_hz) in loongson_spi_update_state()
82 loongson_spi_set_clk(loongson_spi, t->speed_hz); in loongson_spi_update_state()
84 if ((spi->mode ^ loongson_spi->mode) & SPI_MODE_X_MASK) in loongson_spi_update_state()
85 loongson_spi_set_mode(loongson_spi, spi); in loongson_spi_update_state()
90 static int loongson_spi_setup(struct spi_device *spi) in loongson_spi_setup() argument
94 loongson_spi = spi_controller_get_devdata(spi->controller); in loongson_spi_setup()
95 if (spi->bits_per_word % 8) in loongson_spi_setup()
96 return -EINVAL; in loongson_spi_setup()
98 if (spi_get_chipselect(spi, 0) >= spi->controller->num_chipselect) in loongson_spi_setup()
99 return -EINVAL; in loongson_spi_setup()
101 loongson_spi->hz = 0; in loongson_spi_setup()
102 loongson_spi_set_cs(spi, true); in loongson_spi_setup()
107 static int loongson_spi_write_read_8bit(struct spi_device *spi, const u8 **tx_buf, in loongson_spi_write_read_8bit() argument
111 struct loongson_spi *loongson_spi = spi_controller_get_devdata(spi->controller); in loongson_spi_write_read_8bit()
118 ret = readb_poll_timeout(loongson_spi->base + LOONGSON_SPI_SPSR_REG, in loongson_spi_write_read_8bit()
119 loongson_spi->spsr, (loongson_spi->spsr & in loongson_spi_write_read_8bit()
131 static int loongson_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) in loongson_spi_write_read() argument
135 const u8 *tx = xfer->tx_buf; in loongson_spi_write_read()
136 u8 *rx = xfer->rx_buf; in loongson_spi_write_read()
138 count = xfer->len; in loongson_spi_write_read()
140 ret = loongson_spi_write_read_8bit(spi, &tx, &rx, count); in loongson_spi_write_read()
143 } while (--count); in loongson_spi_write_read()
152 loongson_spi->para = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_PARA_REG); in loongson_spi_prepare_message()
153 loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_PARA_REG, loongson_spi->para & in loongson_spi_prepare_message()
159 static int loongson_spi_transfer_one(struct spi_controller *ctrl, struct spi_device *spi, in loongson_spi_transfer_one() argument
162 struct loongson_spi *loongson_spi = spi_controller_get_devdata(spi->controller); in loongson_spi_transfer_one()
164 loongson_spi_update_state(loongson_spi, spi, xfer); in loongson_spi_transfer_one()
165 if (xfer->len) in loongson_spi_transfer_one()
166 return loongson_spi_write_read(spi, xfer); in loongson_spi_transfer_one()
175 loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_PARA_REG, loongson_spi->para); in loongson_spi_unprepare_message()
199 struct loongson_spi *spi; in loongson_spi_init_controller() local
200 struct clk *clk; in loongson_spi_init_controller() local
204 return -ENOMEM; in loongson_spi_init_controller()
206 controller->mode_bits = SPI_MODE_X_MASK | SPI_CS_HIGH; in loongson_spi_init_controller()
207 controller->setup = loongson_spi_setup; in loongson_spi_init_controller()
208 controller->prepare_message = loongson_spi_prepare_message; in loongson_spi_init_controller()
209 controller->transfer_one = loongson_spi_transfer_one; in loongson_spi_init_controller()
210 controller->unprepare_message = loongson_spi_unprepare_message; in loongson_spi_init_controller()
211 controller->set_cs = loongson_spi_set_cs; in loongson_spi_init_controller()
212 controller->num_chipselect = 4; in loongson_spi_init_controller()
213 device_set_node(&controller->dev, dev_fwnode(dev)); in loongson_spi_init_controller()
216 spi = spi_controller_get_devdata(controller); in loongson_spi_init_controller()
217 spi->base = regs; in loongson_spi_init_controller()
218 spi->controller = controller; in loongson_spi_init_controller()
220 clk = devm_clk_get_optional(dev, NULL); in loongson_spi_init_controller()
221 if (IS_ERR(clk)) in loongson_spi_init_controller()
222 return dev_err_probe(dev, PTR_ERR(clk), "unable to get clock\n"); in loongson_spi_init_controller()
224 spi->clk_rate = clk_get_rate(clk); in loongson_spi_init_controller()
225 loongson_spi_reginit(spi); in loongson_spi_init_controller()
227 spi->mode = 0; in loongson_spi_init_controller()
243 loongson_spi->spcr = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SPCR_REG); in loongson_spi_suspend()
244 loongson_spi->sper = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SPER_REG); in loongson_spi_suspend()
245 loongson_spi->spsr = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SPSR_REG); in loongson_spi_suspend()
246 loongson_spi->para = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_PARA_REG); in loongson_spi_suspend()
247 loongson_spi->sfcs = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_SFCS_REG); in loongson_spi_suspend()
248 loongson_spi->timi = loongson_spi_read_reg(loongson_spi, LOONGSON_SPI_TIMI_REG); in loongson_spi_suspend()
261 loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SPCR_REG, loongson_spi->spcr); in loongson_spi_resume()
262 loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SPER_REG, loongson_spi->sper); in loongson_spi_resume()
263 loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SPSR_REG, loongson_spi->spsr); in loongson_spi_resume()
264 loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_PARA_REG, loongson_spi->para); in loongson_spi_resume()
265 loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_SFCS_REG, loongson_spi->sfcs); in loongson_spi_resume()
266 loongson_spi_write_reg(loongson_spi, LOONGSON_SPI_TIMI_REG, loongson_spi->timi); in loongson_spi_resume()
279 MODULE_DESCRIPTION("Loongson SPI core driver");