diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2025-12-04 11:24:24 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2025-12-04 11:24:24 -0800 |
| commit | fa5ef105618ae9b5aaa51b3f09e41d88d4514207 (patch) | |
| tree | 30780efabf844cc55a8d27082e6a7810d311d68b /drivers/spi/spi-cadence.c | |
| parent | 0a9431fa74ac9b744bff5b65082ff96fd3d80297 (diff) | |
| parent | cb5c2eb459f4c98d584eaf3d3ea7c3612385d081 (diff) | |
Merge tag 'spi-v6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
Pull spi updates from Mark Brown:
"This release is almost entirely new drivers, with a couple of small
changes in generic code.
The biggest individual update is a rename of the existing Microchip
driver and the addition of a new driver for the silicon SPI controller
in their PolarFire SoCs. The overlap between the soft IP supported by
the current driver and this new one is regrettably all in the IP and
not in the register interface offered to software.
- Add a time offset parameter for offloads, allowing them to be
defined in relation to each other. This is useful for IIO type
applcations where you trigger an operation then read the result
after a delay.
- Add a tracepoint for flash exec_ops, bringing the flash support
more in line with the debuggability of vanilla SPI.
- Support for Airoha EN7523, Arduino MCUs, Aspeed AST2700, Microchip
PolarFire SPI controllers, NXP i.MX51 ECSPI target mode, Qualcomm
IPQ5414 and IPQ5332, Renesas RZ/T2H, RZ/V2N and RZ/2NH and SpacemiT
K1 QuadSPI.
There's also a small set of ASoC cleanups that I mistakenly applied to
the SPI tree and then put more stuff on top of before it was brought
to my attention, sorry about that"
* tag 'spi-v6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi: (80 commits)
spi: microchip-core: Refactor FIFO read and write handlers
spi: ch341: fix out-of-bounds memory access in ch341_transfer_one
spi: microchip-core: Remove unneeded PM related macro
spi: microchip-core: Use SPI_MODE_X_MASK
spi: microchip-core: Utilise temporary variable for struct device
spi: microchip-core: Replace dead code (-ENOMEM error message)
spi: microchip-core: use min() instead of min_t()
spi: dt-bindings: airoha: add compatible for EN7523
spi: airoha-snfi: en7523: workaround flash damaging if UART_TXD was short to GND
spi: dt-bindings: renesas,rzv2h-rspi: Document RZ/V2N SoC support
spi: dt-bindings: renesas,rzv2h-rspi: Document RZ/V2N SoC support
spi: microchip: Enable compile-testing for FPGA SPI controllers
spi: Fix potential uninitialized variable in probe()
spi: rzv2h-rspi: add support for RZ/T2H and RZ/N2H
spi: dt-bindings: renesas,rzv2h-rspi: document RZ/T2H and RZ/N2H
spi: rzv2h-rspi: add support for loopback mode
spi: rzv2h-rspi: add support for variable transfer clock
spi: rzv2h-rspi: add support for using PCLK for transfer clock
spi: rzv2h-rspi: make transfer clock rate finding chip-specific
spi: rzv2h-rspi: avoid recomputing transfer frequency
...
Diffstat (limited to 'drivers/spi/spi-cadence.c')
| -rw-r--r-- | drivers/spi/spi-cadence.c | 106 |
1 files changed, 93 insertions, 13 deletions
diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c index 5ae09b21d23a..47054da630d0 100644 --- a/drivers/spi/spi-cadence.c +++ b/drivers/spi/spi-cadence.c @@ -109,6 +109,7 @@ * @rxbuf: Pointer to the RX buffer * @tx_bytes: Number of bytes left to transfer * @rx_bytes: Number of bytes requested + * @n_bytes: Number of bytes per word * @dev_busy: Device busy flag * @is_decoded_cs: Flag for decoder property set or not * @tx_fifo_depth: Depth of the TX FIFO @@ -120,16 +121,24 @@ struct cdns_spi { struct clk *pclk; unsigned int clk_rate; u32 speed_hz; - const u8 *txbuf; - u8 *rxbuf; + const void *txbuf; + void *rxbuf; int tx_bytes; int rx_bytes; + u8 n_bytes; u8 dev_busy; u32 is_decoded_cs; unsigned int tx_fifo_depth; struct reset_control *rstc; }; +enum cdns_spi_frame_n_bytes { + CDNS_SPI_N_BYTES_NULL = 0, + CDNS_SPI_N_BYTES_U8 = 1, + CDNS_SPI_N_BYTES_U16 = 2, + CDNS_SPI_N_BYTES_U32 = 4 +}; + /* Macros for the SPI controller read/write */ static inline u32 cdns_spi_read(struct cdns_spi *xspi, u32 offset) { @@ -305,6 +314,78 @@ static int cdns_spi_setup_transfer(struct spi_device *spi, return 0; } +static u8 cdns_spi_n_bytes(struct spi_transfer *transfer) +{ + if (transfer->bits_per_word <= 8) + return CDNS_SPI_N_BYTES_U8; + else if (transfer->bits_per_word <= 16) + return CDNS_SPI_N_BYTES_U16; + else + return CDNS_SPI_N_BYTES_U32; +} + +static inline void cdns_spi_reader(struct cdns_spi *xspi) +{ + u32 rxw = 0; + + if (xspi->rxbuf && !IS_ALIGNED((uintptr_t)xspi->rxbuf, xspi->n_bytes)) { + pr_err("%s: rxbuf address is not aligned for %d bytes\n", + __func__, xspi->n_bytes); + return; + } + + rxw = cdns_spi_read(xspi, CDNS_SPI_RXD); + if (xspi->rxbuf) { + switch (xspi->n_bytes) { + case CDNS_SPI_N_BYTES_U8: + *(u8 *)xspi->rxbuf = rxw; + break; + case CDNS_SPI_N_BYTES_U16: + *(u16 *)xspi->rxbuf = rxw; + break; + case CDNS_SPI_N_BYTES_U32: + *(u32 *)xspi->rxbuf = rxw; + break; + default: + pr_err("%s invalid n_bytes %d\n", __func__, + xspi->n_bytes); + return; + } + xspi->rxbuf = (u8 *)xspi->rxbuf + xspi->n_bytes; + } +} + +static inline void cdns_spi_writer(struct cdns_spi *xspi) +{ + u32 txw = 0; + + if (xspi->txbuf && !IS_ALIGNED((uintptr_t)xspi->txbuf, xspi->n_bytes)) { + pr_err("%s: txbuf address is not aligned for %d bytes\n", + __func__, xspi->n_bytes); + return; + } + + if (xspi->txbuf) { + switch (xspi->n_bytes) { + case CDNS_SPI_N_BYTES_U8: + txw = *(u8 *)xspi->txbuf; + break; + case CDNS_SPI_N_BYTES_U16: + txw = *(u16 *)xspi->txbuf; + break; + case CDNS_SPI_N_BYTES_U32: + txw = *(u32 *)xspi->txbuf; + break; + default: + pr_err("%s invalid n_bytes %d\n", __func__, + xspi->n_bytes); + return; + } + cdns_spi_write(xspi, CDNS_SPI_TXD, txw); + xspi->txbuf = (u8 *)xspi->txbuf + xspi->n_bytes; + } +} + /** * cdns_spi_process_fifo - Fills the TX FIFO, and drain the RX FIFO * @xspi: Pointer to the cdns_spi structure @@ -321,23 +402,14 @@ static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx) while (ntx || nrx) { if (nrx) { - u8 data = cdns_spi_read(xspi, CDNS_SPI_RXD); - - if (xspi->rxbuf) - *xspi->rxbuf++ = data; - + cdns_spi_reader(xspi); nrx--; } if (ntx) { - if (xspi->txbuf) - cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++); - else - cdns_spi_write(xspi, CDNS_SPI_TXD, 0); - + cdns_spi_writer(xspi); ntx--; } - } } @@ -454,6 +526,10 @@ static int cdns_transfer_one(struct spi_controller *ctlr, if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL) udelay(10); + xspi->n_bytes = cdns_spi_n_bytes(transfer); + xspi->tx_bytes = DIV_ROUND_UP(xspi->tx_bytes, xspi->n_bytes); + xspi->rx_bytes = DIV_ROUND_UP(xspi->rx_bytes, xspi->n_bytes); + cdns_spi_process_fifo(xspi, xspi->tx_fifo_depth, 0); cdns_spi_write(xspi, CDNS_SPI_IER, CDNS_SPI_IXR_DEFAULT); @@ -654,6 +730,9 @@ static int cdns_spi_probe(struct platform_device *pdev) ctlr->mode_bits = SPI_CPOL | SPI_CPHA; ctlr->bits_per_word_mask = SPI_BPW_MASK(8); + if (of_device_is_compatible(pdev->dev.of_node, "cix,sky1-spi-r1p6")) + ctlr->bits_per_word_mask |= SPI_BPW_MASK(16) | SPI_BPW_MASK(32); + if (!spi_controller_is_target(ctlr)) { ctlr->mode_bits |= SPI_CS_HIGH; ctlr->set_cs = cdns_spi_chipselect; @@ -797,6 +876,7 @@ static const struct dev_pm_ops cdns_spi_dev_pm_ops = { static const struct of_device_id cdns_spi_of_match[] = { { .compatible = "xlnx,zynq-spi-r1p6" }, + { .compatible = "cix,sky1-spi-r1p6" }, { .compatible = "cdns,spi-r1p6" }, { /* end of table */ } }; |