Lines Matching +full:mpfs +full:- +full:spi

1 // SPDX-License-Identifier: (GPL-2.0)
3 * Microchip CoreSPI SPI controller driver
5 * Copyright (c) 2018-2022 Microchip Technology Inc. and its subsidiaries
21 #include <linux/spi/spi.h>
104 u32 clk_gen; /* divider for spi output clock generated by the controller */
112 static inline u32 mchp_corespi_read(struct mchp_corespi *spi, unsigned int reg) in mchp_corespi_read() argument
114 return readl(spi->regs + reg); in mchp_corespi_read()
117 static inline void mchp_corespi_write(struct mchp_corespi *spi, unsigned int reg, u32 val) in mchp_corespi_write() argument
119 writel(val, spi->regs + reg); in mchp_corespi_write()
122 static inline void mchp_corespi_disable(struct mchp_corespi *spi) in mchp_corespi_disable() argument
124 u32 control = mchp_corespi_read(spi, REG_CONTROL); in mchp_corespi_disable()
128 mchp_corespi_write(spi, REG_CONTROL, control); in mchp_corespi_disable()
131 static inline void mchp_corespi_read_fifo(struct mchp_corespi *spi) in mchp_corespi_read_fifo() argument
136 fifo_max = min(spi->rx_len, FIFO_DEPTH); in mchp_corespi_read_fifo()
138 while ((i < fifo_max) && !(mchp_corespi_read(spi, REG_STATUS) & STATUS_RXFIFO_EMPTY)) { in mchp_corespi_read_fifo()
139 data = mchp_corespi_read(spi, REG_RX_DATA); in mchp_corespi_read_fifo()
141 if (spi->rx_buf) in mchp_corespi_read_fifo()
142 *spi->rx_buf++ = data; in mchp_corespi_read_fifo()
145 spi->rx_len -= i; in mchp_corespi_read_fifo()
146 spi->pending -= i; in mchp_corespi_read_fifo()
149 static void mchp_corespi_enable_ints(struct mchp_corespi *spi) in mchp_corespi_enable_ints() argument
153 mchp_corespi_disable(spi); in mchp_corespi_enable_ints()
155 control = mchp_corespi_read(spi, REG_CONTROL); in mchp_corespi_enable_ints()
158 mchp_corespi_write(spi, REG_CONTROL, control); in mchp_corespi_enable_ints()
161 mchp_corespi_write(spi, REG_CONTROL, control); in mchp_corespi_enable_ints()
164 static void mchp_corespi_disable_ints(struct mchp_corespi *spi) in mchp_corespi_disable_ints() argument
168 mchp_corespi_disable(spi); in mchp_corespi_disable_ints()
170 control = mchp_corespi_read(spi, REG_CONTROL); in mchp_corespi_disable_ints()
172 mchp_corespi_write(spi, REG_CONTROL, control); in mchp_corespi_disable_ints()
175 mchp_corespi_write(spi, REG_CONTROL, control); in mchp_corespi_disable_ints()
178 static inline void mchp_corespi_set_xfer_size(struct mchp_corespi *spi, int len) in mchp_corespi_set_xfer_size() argument
184 * Disable the SPI controller. Writes to transfer length have in mchp_corespi_set_xfer_size()
187 mchp_corespi_disable(spi); in mchp_corespi_set_xfer_size()
197 control = mchp_corespi_read(spi, REG_CONTROL); in mchp_corespi_set_xfer_size()
200 mchp_corespi_write(spi, REG_CONTROL, control); in mchp_corespi_set_xfer_size()
203 mchp_corespi_write(spi, REG_FRAMESUP, lenpart); in mchp_corespi_set_xfer_size()
206 mchp_corespi_write(spi, REG_CONTROL, control); in mchp_corespi_set_xfer_size()
209 static inline void mchp_corespi_write_fifo(struct mchp_corespi *spi) in mchp_corespi_write_fifo() argument
214 fifo_max = min(spi->tx_len, FIFO_DEPTH); in mchp_corespi_write_fifo()
215 mchp_corespi_set_xfer_size(spi, fifo_max); in mchp_corespi_write_fifo()
217 while ((i < fifo_max) && !(mchp_corespi_read(spi, REG_STATUS) & STATUS_TXFIFO_FULL)) { in mchp_corespi_write_fifo()
218 byte = spi->tx_buf ? *spi->tx_buf++ : 0xaa; in mchp_corespi_write_fifo()
219 mchp_corespi_write(spi, REG_TX_DATA, byte); in mchp_corespi_write_fifo()
223 spi->tx_len -= i; in mchp_corespi_write_fifo()
224 spi->pending += i; in mchp_corespi_write_fifo()
227 static inline void mchp_corespi_set_framesize(struct mchp_corespi *spi, int bt) in mchp_corespi_set_framesize() argument
232 * Disable the SPI controller. Writes to the frame size have in mchp_corespi_set_framesize()
235 mchp_corespi_disable(spi); in mchp_corespi_set_framesize()
237 mchp_corespi_write(spi, REG_FRAME_SIZE, bt); in mchp_corespi_set_framesize()
239 control = mchp_corespi_read(spi, REG_CONTROL); in mchp_corespi_set_framesize()
241 mchp_corespi_write(spi, REG_CONTROL, control); in mchp_corespi_set_framesize()
244 static void mchp_corespi_set_cs(struct spi_device *spi, bool disable) in mchp_corespi_set_cs() argument
247 struct mchp_corespi *corespi = spi_controller_get_devdata(spi->controller); in mchp_corespi_set_cs()
250 reg &= ~BIT(spi_get_chipselect(spi, 0)); in mchp_corespi_set_cs()
251 reg |= !disable << spi_get_chipselect(spi, 0); in mchp_corespi_set_cs()
256 static int mchp_corespi_setup(struct spi_device *spi) in mchp_corespi_setup() argument
258 struct mchp_corespi *corespi = spi_controller_get_devdata(spi->controller); in mchp_corespi_setup()
266 if (spi->mode & SPI_CS_HIGH) { in mchp_corespi_setup()
268 reg |= BIT(spi_get_chipselect(spi, 0)); in mchp_corespi_setup()
274 static void mchp_corespi_init(struct spi_controller *host, struct mchp_corespi *spi) in mchp_corespi_init() argument
277 u32 control = mchp_corespi_read(spi, REG_CONTROL); in mchp_corespi_init()
284 mchp_corespi_set_framesize(spi, DEFAULT_FRAMESIZE); in mchp_corespi_init()
286 /* max. possible spi clock rate is the apb clock rate */ in mchp_corespi_init()
287 clk_hz = clk_get_rate(spi->clk); in mchp_corespi_init()
288 host->max_speed_hz = clk_hz; in mchp_corespi_init()
298 control = mchp_corespi_read(spi, REG_CONTROL); in mchp_corespi_init()
301 mchp_corespi_write(spi, REG_CONTROL, control); in mchp_corespi_init()
303 mchp_corespi_enable_ints(spi); in mchp_corespi_init()
310 mchp_corespi_write(spi, REG_SLAVE_SELECT, SSELOUT | SSEL_DIRECT); in mchp_corespi_init()
312 control = mchp_corespi_read(spi, REG_CONTROL); in mchp_corespi_init()
317 mchp_corespi_write(spi, REG_CONTROL, control); in mchp_corespi_init()
320 static inline void mchp_corespi_set_clk_gen(struct mchp_corespi *spi) in mchp_corespi_set_clk_gen() argument
324 mchp_corespi_disable(spi); in mchp_corespi_set_clk_gen()
326 control = mchp_corespi_read(spi, REG_CONTROL); in mchp_corespi_set_clk_gen()
327 if (spi->clk_mode) in mchp_corespi_set_clk_gen()
332 mchp_corespi_write(spi, REG_CLK_GEN, spi->clk_gen); in mchp_corespi_set_clk_gen()
333 mchp_corespi_write(spi, REG_CONTROL, control); in mchp_corespi_set_clk_gen()
334 mchp_corespi_write(spi, REG_CONTROL, control | CONTROL_ENABLE); in mchp_corespi_set_clk_gen()
337 static inline void mchp_corespi_set_mode(struct mchp_corespi *spi, unsigned int mode) in mchp_corespi_set_mode() argument
357 * Disable the SPI controller. Writes to the frame size have in mchp_corespi_set_mode()
360 mchp_corespi_disable(spi); in mchp_corespi_set_mode()
362 control = mchp_corespi_read(spi, REG_CONTROL); in mchp_corespi_set_mode()
366 mchp_corespi_write(spi, REG_CONTROL, control); in mchp_corespi_set_mode()
369 mchp_corespi_write(spi, REG_CONTROL, control); in mchp_corespi_set_mode()
375 struct mchp_corespi *spi = spi_controller_get_devdata(host); in mchp_corespi_interrupt() local
376 u32 intfield = mchp_corespi_read(spi, REG_MIS) & 0xf; in mchp_corespi_interrupt()
384 mchp_corespi_write(spi, REG_INT_CLEAR, INT_TXDONE); in mchp_corespi_interrupt()
386 if (spi->rx_len) in mchp_corespi_interrupt()
387 mchp_corespi_read_fifo(spi); in mchp_corespi_interrupt()
389 if (spi->tx_len) in mchp_corespi_interrupt()
390 mchp_corespi_write_fifo(spi); in mchp_corespi_interrupt()
392 if (!spi->rx_len) in mchp_corespi_interrupt()
397 mchp_corespi_write(spi, REG_INT_CLEAR, INT_RXRDY); in mchp_corespi_interrupt()
400 mchp_corespi_write(spi, REG_INT_CLEAR, INT_RX_CHANNEL_OVERFLOW); in mchp_corespi_interrupt()
402 dev_err(&host->dev, in mchp_corespi_interrupt()
404 spi->rx_len, spi->tx_len); in mchp_corespi_interrupt()
408 mchp_corespi_write(spi, REG_INT_CLEAR, INT_TX_CHANNEL_UNDERRUN); in mchp_corespi_interrupt()
410 dev_err(&host->dev, in mchp_corespi_interrupt()
412 spi->rx_len, spi->tx_len); in mchp_corespi_interrupt()
421 static int mchp_corespi_calculate_clkgen(struct mchp_corespi *spi, in mchp_corespi_calculate_clkgen() argument
426 clk_hz = clk_get_rate(spi->clk); in mchp_corespi_calculate_clkgen()
428 return -EINVAL; in mchp_corespi_calculate_clkgen()
439 * clk_gen is the register name for the clock divider on MPFS. in mchp_corespi_calculate_clkgen()
441 clk_gen = DIV_ROUND_UP(clk_hz, 2 * spi_hz) - 1; in mchp_corespi_calculate_clkgen()
444 clk_gen = fls(clk_gen) - 1; in mchp_corespi_calculate_clkgen()
447 return -EINVAL; in mchp_corespi_calculate_clkgen()
449 spi->clk_mode = 0; in mchp_corespi_calculate_clkgen()
451 spi->clk_mode = 1; in mchp_corespi_calculate_clkgen()
454 spi->clk_gen = clk_gen; in mchp_corespi_calculate_clkgen()
462 struct mchp_corespi *spi = spi_controller_get_devdata(host); in mchp_corespi_transfer_one() local
465 ret = mchp_corespi_calculate_clkgen(spi, (unsigned long)xfer->speed_hz); in mchp_corespi_transfer_one()
467 dev_err(&host->dev, "failed to set clk_gen for target %u Hz\n", xfer->speed_hz); in mchp_corespi_transfer_one()
471 mchp_corespi_set_clk_gen(spi); in mchp_corespi_transfer_one()
473 spi->tx_buf = xfer->tx_buf; in mchp_corespi_transfer_one()
474 spi->rx_buf = xfer->rx_buf; in mchp_corespi_transfer_one()
475 spi->tx_len = xfer->len; in mchp_corespi_transfer_one()
476 spi->rx_len = xfer->len; in mchp_corespi_transfer_one()
477 spi->pending = 0; in mchp_corespi_transfer_one()
479 mchp_corespi_set_xfer_size(spi, (spi->tx_len > FIFO_DEPTH) in mchp_corespi_transfer_one()
480 ? FIFO_DEPTH : spi->tx_len); in mchp_corespi_transfer_one()
482 if (spi->tx_len) in mchp_corespi_transfer_one()
483 mchp_corespi_write_fifo(spi); in mchp_corespi_transfer_one()
490 struct spi_device *spi_dev = msg->spi; in mchp_corespi_prepare_message()
491 struct mchp_corespi *spi = spi_controller_get_devdata(host); in mchp_corespi_prepare_message() local
493 mchp_corespi_set_framesize(spi, DEFAULT_FRAMESIZE); in mchp_corespi_prepare_message()
494 mchp_corespi_set_mode(spi, spi_dev->mode); in mchp_corespi_prepare_message()
502 struct mchp_corespi *spi; in mchp_corespi_probe() local
507 host = devm_spi_alloc_host(&pdev->dev, sizeof(*spi)); in mchp_corespi_probe()
509 return dev_err_probe(&pdev->dev, -ENOMEM, in mchp_corespi_probe()
510 "unable to allocate host for SPI controller\n"); in mchp_corespi_probe()
514 if (of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs)) in mchp_corespi_probe()
517 host->num_chipselect = num_cs; in mchp_corespi_probe()
518 host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; in mchp_corespi_probe()
519 host->setup = mchp_corespi_setup; in mchp_corespi_probe()
520 host->bits_per_word_mask = SPI_BPW_MASK(8); in mchp_corespi_probe()
521 host->transfer_one = mchp_corespi_transfer_one; in mchp_corespi_probe()
522 host->prepare_message = mchp_corespi_prepare_message; in mchp_corespi_probe()
523 host->set_cs = mchp_corespi_set_cs; in mchp_corespi_probe()
524 host->dev.of_node = pdev->dev.of_node; in mchp_corespi_probe()
526 spi = spi_controller_get_devdata(host); in mchp_corespi_probe()
528 spi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); in mchp_corespi_probe()
529 if (IS_ERR(spi->regs)) in mchp_corespi_probe()
530 return PTR_ERR(spi->regs); in mchp_corespi_probe()
532 spi->irq = platform_get_irq(pdev, 0); in mchp_corespi_probe()
533 if (spi->irq < 0) in mchp_corespi_probe()
534 return spi->irq; in mchp_corespi_probe()
536 ret = devm_request_irq(&pdev->dev, spi->irq, mchp_corespi_interrupt, in mchp_corespi_probe()
537 IRQF_SHARED, dev_name(&pdev->dev), host); in mchp_corespi_probe()
539 return dev_err_probe(&pdev->dev, ret, in mchp_corespi_probe()
542 spi->clk = devm_clk_get_enabled(&pdev->dev, NULL); in mchp_corespi_probe()
543 if (IS_ERR(spi->clk)) in mchp_corespi_probe()
544 return dev_err_probe(&pdev->dev, PTR_ERR(spi->clk), in mchp_corespi_probe()
547 mchp_corespi_init(host, spi); in mchp_corespi_probe()
549 ret = devm_spi_register_controller(&pdev->dev, host); in mchp_corespi_probe()
551 mchp_corespi_disable(spi); in mchp_corespi_probe()
552 return dev_err_probe(&pdev->dev, ret, in mchp_corespi_probe()
553 "unable to register host for SPI controller\n"); in mchp_corespi_probe()
556 dev_info(&pdev->dev, "Registered SPI controller %d\n", host->bus_num); in mchp_corespi_probe()
564 struct mchp_corespi *spi = spi_controller_get_devdata(host); in mchp_corespi_remove() local
566 mchp_corespi_disable_ints(spi); in mchp_corespi_remove()
567 mchp_corespi_disable(spi); in mchp_corespi_remove()
578 { .compatible = "microchip,mpfs-spi" },
587 .name = "microchip-corespi",
594 MODULE_DESCRIPTION("Microchip coreSPI SPI controller driver");