Lines Matching +full:axi +full:- +full:spi +full:- +full:engine +full:- +full:1
1 // SPDX-License-Identifier: GPL-2.0-only
3 * SPI-Engine SPI controller driver
5 * Author: Lars-Peter Clausen <lars@metafoo.de>
10 #include <linux/fpga/adi-axi-common.h>
17 #include <linux/spi/spi.h>
18 #include <trace/events/spi.h>
38 #define SPI_ENGINE_INT_SDO_ALMOST_EMPTY BIT(1)
43 #define SPI_ENGINE_CONFIG_CPOL BIT(1)
63 /* Arbitrary sync ID for use by host->cur_msg */
88 * struct spi_engine_message_state - SPI engine per-message state
126 p->length++; in spi_engine_program_add_cmd()
129 p->instructions[p->length - 1] = cmd; in spi_engine_program_add_cmd()
132 static unsigned int spi_engine_get_config(struct spi_device *spi) in spi_engine_get_config() argument
136 if (spi->mode & SPI_CPOL) in spi_engine_get_config()
138 if (spi->mode & SPI_CPHA) in spi_engine_get_config()
140 if (spi->mode & SPI_3WIRE) in spi_engine_get_config()
142 if (spi->mode & SPI_MOSI_IDLE_HIGH) in spi_engine_get_config()
144 if (spi->mode & SPI_MOSI_IDLE_LOW) in spi_engine_get_config()
155 if (xfer->bits_per_word <= 8) in spi_engine_gen_xfer()
156 len = xfer->len; in spi_engine_gen_xfer()
157 else if (xfer->bits_per_word <= 16) in spi_engine_gen_xfer()
158 len = xfer->len / 2; in spi_engine_gen_xfer()
160 len = xfer->len / 4; in spi_engine_gen_xfer()
166 if (xfer->tx_buf) in spi_engine_gen_xfer()
168 if (xfer->rx_buf) in spi_engine_gen_xfer()
172 SPI_ENGINE_CMD_TRANSFER(flags, n - 1)); in spi_engine_gen_xfer()
173 len -= n; in spi_engine_gen_xfer()
191 t = DIV_ROUND_UP_ULL((u64)(delay_ns - inst_ns) * sclk_hz, NSEC_PER_SEC); in spi_engine_gen_sleep()
195 spi_engine_program_add_cmd(p, dry, SPI_ENGINE_CMD_SLEEP(n - 1)); in spi_engine_gen_sleep()
196 t -= n; in spi_engine_gen_sleep()
201 struct spi_device *spi, bool assert) in spi_engine_gen_cs() argument
206 mask ^= BIT(spi_get_chipselect(spi, 0)); in spi_engine_gen_cs()
214 * The SPI core does most of the message/transfer validation and filling in
219 * is called twice and would otherwise result in double-evaluation.
223 unsigned int clk_div, max_hz = msg->spi->controller->max_speed_hz; in spi_engine_precompile_message()
226 list_for_each_entry(xfer, &msg->transfers, transfer_list) { in spi_engine_precompile_message()
227 clk_div = DIV_ROUND_UP(max_hz, xfer->speed_hz); in spi_engine_precompile_message()
228 xfer->effective_speed_hz = max_hz / min(clk_div, 256U); in spi_engine_precompile_message()
235 struct spi_device *spi = msg->spi; in spi_engine_compile_message() local
236 struct spi_controller *host = spi->controller; in spi_engine_compile_message()
246 inst_ns = DIV_ROUND_UP(NSEC_PER_SEC, host->max_speed_hz); in spi_engine_compile_message()
248 clk_div = 1; in spi_engine_compile_message()
252 spi_engine_get_config(spi))); in spi_engine_compile_message()
254 xfer = list_first_entry(&msg->transfers, struct spi_transfer, transfer_list); in spi_engine_compile_message()
255 spi_engine_gen_cs(p, dry, spi, !xfer->cs_off); in spi_engine_compile_message()
257 list_for_each_entry(xfer, &msg->transfers, transfer_list) { in spi_engine_compile_message()
258 new_clk_div = host->max_speed_hz / xfer->effective_speed_hz; in spi_engine_compile_message()
261 /* actual divider used is register value + 1 */ in spi_engine_compile_message()
264 clk_div - 1)); in spi_engine_compile_message()
267 if (bits_per_word != xfer->bits_per_word && xfer->len) { in spi_engine_compile_message()
268 bits_per_word = xfer->bits_per_word; in spi_engine_compile_message()
275 spi_engine_gen_sleep(p, dry, spi_delay_to_ns(&xfer->delay, xfer), in spi_engine_compile_message()
276 inst_ns, xfer->effective_speed_hz); in spi_engine_compile_message()
278 if (xfer->cs_change) { in spi_engine_compile_message()
279 if (list_is_last(&xfer->transfer_list, &msg->transfers)) { in spi_engine_compile_message()
282 if (!xfer->cs_off) in spi_engine_compile_message()
283 spi_engine_gen_cs(p, dry, spi, false); in spi_engine_compile_message()
286 &xfer->cs_change_delay, xfer), inst_ns, in spi_engine_compile_message()
287 xfer->effective_speed_hz); in spi_engine_compile_message()
289 if (!list_next_entry(xfer, transfer_list)->cs_off) in spi_engine_compile_message()
290 spi_engine_gen_cs(p, dry, spi, true); in spi_engine_compile_message()
292 } else if (!list_is_last(&xfer->transfer_list, &msg->transfers) && in spi_engine_compile_message()
293 xfer->cs_off != list_next_entry(xfer, transfer_list)->cs_off) { in spi_engine_compile_message()
294 spi_engine_gen_cs(p, dry, spi, xfer->cs_off); in spi_engine_compile_message()
299 spi_engine_gen_cs(p, dry, spi, false); in spi_engine_compile_message()
305 if (clk_div != 1) in spi_engine_compile_message()
316 xfer = list_first_entry(&msg->transfers, in spi_engine_xfer_next()
318 } else if (list_is_last(&xfer->transfer_list, &msg->transfers)) { in spi_engine_xfer_next()
329 struct spi_engine_message_state *st = msg->state; in spi_engine_tx_next()
330 struct spi_transfer *xfer = st->tx_xfer; in spi_engine_tx_next()
334 } while (xfer && !xfer->tx_buf); in spi_engine_tx_next()
336 st->tx_xfer = xfer; in spi_engine_tx_next()
338 st->tx_length = xfer->len; in spi_engine_tx_next()
339 st->tx_buf = xfer->tx_buf; in spi_engine_tx_next()
341 st->tx_buf = NULL; in spi_engine_tx_next()
347 struct spi_engine_message_state *st = msg->state; in spi_engine_rx_next()
348 struct spi_transfer *xfer = st->rx_xfer; in spi_engine_rx_next()
352 } while (xfer && !xfer->rx_buf); in spi_engine_rx_next()
354 st->rx_xfer = xfer; in spi_engine_rx_next()
356 st->rx_length = xfer->len; in spi_engine_rx_next()
357 st->rx_buf = xfer->rx_buf; in spi_engine_rx_next()
359 st->rx_buf = NULL; in spi_engine_rx_next()
366 void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_CMD_FIFO; in spi_engine_write_cmd_fifo()
367 struct spi_engine_message_state *st = msg->state; in spi_engine_write_cmd_fifo()
371 n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_CMD_FIFO_ROOM); in spi_engine_write_cmd_fifo()
372 while (n && st->cmd_length) { in spi_engine_write_cmd_fifo()
373 m = min(n, st->cmd_length); in spi_engine_write_cmd_fifo()
374 buf = st->cmd_buf; in spi_engine_write_cmd_fifo()
377 st->cmd_buf += m; in spi_engine_write_cmd_fifo()
378 st->cmd_length -= m; in spi_engine_write_cmd_fifo()
379 n -= m; in spi_engine_write_cmd_fifo()
382 return st->cmd_length != 0; in spi_engine_write_cmd_fifo()
388 void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_SDO_DATA_FIFO; in spi_engine_write_tx_fifo()
389 struct spi_engine_message_state *st = msg->state; in spi_engine_write_tx_fifo()
392 n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_SDO_FIFO_ROOM); in spi_engine_write_tx_fifo()
393 while (n && st->tx_length) { in spi_engine_write_tx_fifo()
394 if (st->tx_xfer->bits_per_word <= 8) { in spi_engine_write_tx_fifo()
395 const u8 *buf = st->tx_buf; in spi_engine_write_tx_fifo()
397 m = min(n, st->tx_length); in spi_engine_write_tx_fifo()
400 st->tx_buf += m; in spi_engine_write_tx_fifo()
401 st->tx_length -= m; in spi_engine_write_tx_fifo()
402 } else if (st->tx_xfer->bits_per_word <= 16) { in spi_engine_write_tx_fifo()
403 const u16 *buf = (const u16 *)st->tx_buf; in spi_engine_write_tx_fifo()
405 m = min(n, st->tx_length / 2); in spi_engine_write_tx_fifo()
408 st->tx_buf += m * 2; in spi_engine_write_tx_fifo()
409 st->tx_length -= m * 2; in spi_engine_write_tx_fifo()
411 const u32 *buf = (const u32 *)st->tx_buf; in spi_engine_write_tx_fifo()
413 m = min(n, st->tx_length / 4); in spi_engine_write_tx_fifo()
416 st->tx_buf += m * 4; in spi_engine_write_tx_fifo()
417 st->tx_length -= m * 4; in spi_engine_write_tx_fifo()
419 n -= m; in spi_engine_write_tx_fifo()
420 if (st->tx_length == 0) in spi_engine_write_tx_fifo()
424 return st->tx_length != 0; in spi_engine_write_tx_fifo()
430 void __iomem *addr = spi_engine->base + SPI_ENGINE_REG_SDI_DATA_FIFO; in spi_engine_read_rx_fifo()
431 struct spi_engine_message_state *st = msg->state; in spi_engine_read_rx_fifo()
434 n = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_SDI_FIFO_LEVEL); in spi_engine_read_rx_fifo()
435 while (n && st->rx_length) { in spi_engine_read_rx_fifo()
436 if (st->rx_xfer->bits_per_word <= 8) { in spi_engine_read_rx_fifo()
437 u8 *buf = st->rx_buf; in spi_engine_read_rx_fifo()
439 m = min(n, st->rx_length); in spi_engine_read_rx_fifo()
442 st->rx_buf += m; in spi_engine_read_rx_fifo()
443 st->rx_length -= m; in spi_engine_read_rx_fifo()
444 } else if (st->rx_xfer->bits_per_word <= 16) { in spi_engine_read_rx_fifo()
445 u16 *buf = (u16 *)st->rx_buf; in spi_engine_read_rx_fifo()
447 m = min(n, st->rx_length / 2); in spi_engine_read_rx_fifo()
450 st->rx_buf += m * 2; in spi_engine_read_rx_fifo()
451 st->rx_length -= m * 2; in spi_engine_read_rx_fifo()
453 u32 *buf = (u32 *)st->rx_buf; in spi_engine_read_rx_fifo()
455 m = min(n, st->rx_length / 4); in spi_engine_read_rx_fifo()
458 st->rx_buf += m * 4; in spi_engine_read_rx_fifo()
459 st->rx_length -= m * 4; in spi_engine_read_rx_fifo()
461 n -= m; in spi_engine_read_rx_fifo()
462 if (st->rx_length == 0) in spi_engine_read_rx_fifo()
466 return st->rx_length != 0; in spi_engine_read_rx_fifo()
472 struct spi_message *msg = host->cur_msg; in spi_engine_irq()
476 int completed_id = -1; in spi_engine_irq()
478 pending = readl_relaxed(spi_engine->base + SPI_ENGINE_REG_INT_PENDING); in spi_engine_irq()
482 spi_engine->base + SPI_ENGINE_REG_INT_PENDING); in spi_engine_irq()
484 spi_engine->base + SPI_ENGINE_REG_SYNC_ID); in spi_engine_irq()
487 spin_lock(&spi_engine->lock); in spi_engine_irq()
506 msg->status = 0; in spi_engine_irq()
507 msg->actual_length = msg->frame_length; in spi_engine_irq()
508 complete(&spi_engine->msg_complete); in spi_engine_irq()
514 spi_engine->int_enable &= ~disable_int; in spi_engine_irq()
515 writel_relaxed(spi_engine->int_enable, in spi_engine_irq()
516 spi_engine->base + SPI_ENGINE_REG_INT_ENABLE); in spi_engine_irq()
519 spin_unlock(&spi_engine->lock); in spi_engine_irq()
533 p = kzalloc(struct_size(p, instructions, p_dry.length + 1), GFP_KERNEL); in spi_engine_optimize_message()
535 return -ENOMEM; in spi_engine_optimize_message()
542 msg->opt_state = p; in spi_engine_optimize_message()
549 kfree(msg->opt_state); in spi_engine_unoptimize_message()
556 struct spi_controller *host = device->controller; in spi_engine_setup()
559 if (device->mode & SPI_CS_HIGH) in spi_engine_setup()
560 spi_engine->cs_inv |= BIT(spi_get_chipselect(device, 0)); in spi_engine_setup()
562 spi_engine->cs_inv &= ~BIT(spi_get_chipselect(device, 0)); in spi_engine_setup()
564 writel_relaxed(SPI_ENGINE_CMD_CS_INV(spi_engine->cs_inv), in spi_engine_setup()
565 spi_engine->base + SPI_ENGINE_REG_CMD_FIFO); in spi_engine_setup()
572 spi_engine->base + SPI_ENGINE_REG_CMD_FIFO); in spi_engine_setup()
581 struct spi_engine_message_state *st = &spi_engine->msg_state; in spi_engine_transfer_one_message()
582 struct spi_engine_program *p = msg->opt_state; in spi_engine_transfer_one_message()
588 st->cmd_buf = p->instructions; in spi_engine_transfer_one_message()
589 st->cmd_length = p->length; in spi_engine_transfer_one_message()
590 msg->state = st; in spi_engine_transfer_one_message()
592 reinit_completion(&spi_engine->msg_complete); in spi_engine_transfer_one_message()
597 list_for_each_entry(xfer, &msg->transfers, transfer_list) in spi_engine_transfer_one_message()
601 spin_lock_irqsave(&spi_engine->lock, flags); in spi_engine_transfer_one_message()
611 if (st->rx_length != 0) in spi_engine_transfer_one_message()
617 spi_engine->base + SPI_ENGINE_REG_INT_ENABLE); in spi_engine_transfer_one_message()
618 spi_engine->int_enable = int_enable; in spi_engine_transfer_one_message()
619 spin_unlock_irqrestore(&spi_engine->lock, flags); in spi_engine_transfer_one_message()
621 if (!wait_for_completion_timeout(&spi_engine->msg_complete, in spi_engine_transfer_one_message()
623 dev_err(&host->dev, in spi_engine_transfer_one_message()
625 msg->status = -ETIMEDOUT; in spi_engine_transfer_one_message()
631 list_for_each_entry(xfer, &msg->transfers, transfer_list) in spi_engine_transfer_one_message()
637 return msg->status; in spi_engine_transfer_one_message()
644 writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING); in spi_engine_release_hw()
645 writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE); in spi_engine_release_hw()
646 writel_relaxed(0x01, spi_engine->base + SPI_ENGINE_REG_RESET); in spi_engine_release_hw()
661 host = devm_spi_alloc_host(&pdev->dev, sizeof(*spi_engine)); in spi_engine_probe()
663 return -ENOMEM; in spi_engine_probe()
667 spin_lock_init(&spi_engine->lock); in spi_engine_probe()
668 init_completion(&spi_engine->msg_complete); in spi_engine_probe()
670 spi_engine->clk = devm_clk_get_enabled(&pdev->dev, "s_axi_aclk"); in spi_engine_probe()
671 if (IS_ERR(spi_engine->clk)) in spi_engine_probe()
672 return PTR_ERR(spi_engine->clk); in spi_engine_probe()
674 spi_engine->ref_clk = devm_clk_get_enabled(&pdev->dev, "spi_clk"); in spi_engine_probe()
675 if (IS_ERR(spi_engine->ref_clk)) in spi_engine_probe()
676 return PTR_ERR(spi_engine->ref_clk); in spi_engine_probe()
678 spi_engine->base = devm_platform_ioremap_resource(pdev, 0); in spi_engine_probe()
679 if (IS_ERR(spi_engine->base)) in spi_engine_probe()
680 return PTR_ERR(spi_engine->base); in spi_engine_probe()
682 version = readl(spi_engine->base + ADI_AXI_REG_VERSION); in spi_engine_probe()
683 if (ADI_AXI_PCORE_VER_MAJOR(version) != 1) { in spi_engine_probe()
684 dev_err(&pdev->dev, "Unsupported peripheral version %u.%u.%u\n", in spi_engine_probe()
688 return -ENODEV; in spi_engine_probe()
691 writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_RESET); in spi_engine_probe()
692 writel_relaxed(0xff, spi_engine->base + SPI_ENGINE_REG_INT_PENDING); in spi_engine_probe()
693 writel_relaxed(0x00, spi_engine->base + SPI_ENGINE_REG_INT_ENABLE); in spi_engine_probe()
695 ret = devm_add_action_or_reset(&pdev->dev, spi_engine_release_hw, in spi_engine_probe()
700 ret = devm_request_irq(&pdev->dev, irq, spi_engine_irq, 0, pdev->name, in spi_engine_probe()
705 host->dev.of_node = pdev->dev.of_node; in spi_engine_probe()
706 host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_3WIRE; in spi_engine_probe()
707 host->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); in spi_engine_probe()
708 host->max_speed_hz = clk_get_rate(spi_engine->ref_clk) / 2; in spi_engine_probe()
709 host->transfer_one_message = spi_engine_transfer_one_message; in spi_engine_probe()
710 host->optimize_message = spi_engine_optimize_message; in spi_engine_probe()
711 host->unoptimize_message = spi_engine_unoptimize_message; in spi_engine_probe()
712 host->num_chipselect = 8; in spi_engine_probe()
715 if (ADI_AXI_PCORE_VER_MAJOR(version) >= 1) { in spi_engine_probe()
717 host->mode_bits |= SPI_CS_HIGH; in spi_engine_probe()
718 host->setup = spi_engine_setup; in spi_engine_probe()
721 host->mode_bits |= SPI_MOSI_IDLE_LOW | SPI_MOSI_IDLE_HIGH; in spi_engine_probe()
724 if (host->max_speed_hz == 0) in spi_engine_probe()
725 return dev_err_probe(&pdev->dev, -EINVAL, "spi_clk rate is 0"); in spi_engine_probe()
727 return devm_spi_register_controller(&pdev->dev, host); in spi_engine_probe()
731 { .compatible = "adi,axi-spi-engine-1.00.a" },
739 .name = "spi-engine",
745 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
746 MODULE_DESCRIPTION("Analog Devices SPI engine peripheral driver");