mirror of https://github.com/torvalds/linux.git
spi: spi-cadence: supports transmission with bits_per_word of 16 and 32
The default FIFO data width of the Cadence SPI IP is 8 bits, but the hardware supports configurations of 16 bits and 32 bits. This patch enhances the driver to support communication with both 16-bits and 32-bits FIFO data widths. Signed-off-by: Jun Guo <jun.guo@cixtech.com> Link: https://patch.msgid.link/20251031073003.3289573-3-jun.guo@cixtech.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
55b5d192ba
commit
4e00135b2d
|
|
@ -109,6 +109,7 @@
|
||||||
* @rxbuf: Pointer to the RX buffer
|
* @rxbuf: Pointer to the RX buffer
|
||||||
* @tx_bytes: Number of bytes left to transfer
|
* @tx_bytes: Number of bytes left to transfer
|
||||||
* @rx_bytes: Number of bytes requested
|
* @rx_bytes: Number of bytes requested
|
||||||
|
* @n_bytes: Number of bytes per word
|
||||||
* @dev_busy: Device busy flag
|
* @dev_busy: Device busy flag
|
||||||
* @is_decoded_cs: Flag for decoder property set or not
|
* @is_decoded_cs: Flag for decoder property set or not
|
||||||
* @tx_fifo_depth: Depth of the TX FIFO
|
* @tx_fifo_depth: Depth of the TX FIFO
|
||||||
|
|
@ -120,16 +121,24 @@ struct cdns_spi {
|
||||||
struct clk *pclk;
|
struct clk *pclk;
|
||||||
unsigned int clk_rate;
|
unsigned int clk_rate;
|
||||||
u32 speed_hz;
|
u32 speed_hz;
|
||||||
const u8 *txbuf;
|
const void *txbuf;
|
||||||
u8 *rxbuf;
|
void *rxbuf;
|
||||||
int tx_bytes;
|
int tx_bytes;
|
||||||
int rx_bytes;
|
int rx_bytes;
|
||||||
|
u8 n_bytes;
|
||||||
u8 dev_busy;
|
u8 dev_busy;
|
||||||
u32 is_decoded_cs;
|
u32 is_decoded_cs;
|
||||||
unsigned int tx_fifo_depth;
|
unsigned int tx_fifo_depth;
|
||||||
struct reset_control *rstc;
|
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 */
|
/* Macros for the SPI controller read/write */
|
||||||
static inline u32 cdns_spi_read(struct cdns_spi *xspi, u32 offset)
|
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;
|
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
|
* cdns_spi_process_fifo - Fills the TX FIFO, and drain the RX FIFO
|
||||||
* @xspi: Pointer to the cdns_spi structure
|
* @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) {
|
while (ntx || nrx) {
|
||||||
if (nrx) {
|
if (nrx) {
|
||||||
u8 data = cdns_spi_read(xspi, CDNS_SPI_RXD);
|
cdns_spi_reader(xspi);
|
||||||
|
|
||||||
if (xspi->rxbuf)
|
|
||||||
*xspi->rxbuf++ = data;
|
|
||||||
|
|
||||||
nrx--;
|
nrx--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ntx) {
|
if (ntx) {
|
||||||
if (xspi->txbuf)
|
cdns_spi_writer(xspi);
|
||||||
cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++);
|
|
||||||
else
|
|
||||||
cdns_spi_write(xspi, CDNS_SPI_TXD, 0);
|
|
||||||
|
|
||||||
ntx--;
|
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)
|
if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL)
|
||||||
udelay(10);
|
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_process_fifo(xspi, xspi->tx_fifo_depth, 0);
|
||||||
|
|
||||||
cdns_spi_write(xspi, CDNS_SPI_IER, CDNS_SPI_IXR_DEFAULT);
|
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->mode_bits = SPI_CPOL | SPI_CPHA;
|
||||||
ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
|
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)) {
|
if (!spi_controller_is_target(ctlr)) {
|
||||||
ctlr->mode_bits |= SPI_CS_HIGH;
|
ctlr->mode_bits |= SPI_CS_HIGH;
|
||||||
ctlr->set_cs = cdns_spi_chipselect;
|
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[] = {
|
static const struct of_device_id cdns_spi_of_match[] = {
|
||||||
{ .compatible = "xlnx,zynq-spi-r1p6" },
|
{ .compatible = "xlnx,zynq-spi-r1p6" },
|
||||||
|
{ .compatible = "cix,sky1-spi-r1p6" },
|
||||||
{ .compatible = "cdns,spi-r1p6" },
|
{ .compatible = "cdns,spi-r1p6" },
|
||||||
{ /* end of table */ }
|
{ /* end of table */ }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue