Skip to content

Commit 22fd98c

Browse files
swilkins-raymarinebroonie
authored andcommitted
spi: microchip-core: defer asserting chip select until just before write to TX FIFO
Setting up many of the registers for a new SPI transfer requires the SPI controller to be disabled after set_cs() has been called to assert the chip select line. However, disabling the controller results in the SCLK and MOSI output pins being tristate, which can cause clock transitions to be seen by a slave device whilst SS is active. To fix this, the CS is only set to inactive inline, whilst setting it active is deferred until all registers are set up and the any controller disables have been completed. Fixes: 9ac8d17 ("spi: add support for microchip fpga spi controllers") Signed-off-by: Steve Wilkins <[email protected]> Signed-off-by: Conor Dooley <[email protected]> Link: https://patch.msgid.link/20240715-sanitizer-recant-dd96b7a97048@wendy Signed-off-by: Mark Brown <[email protected]>
1 parent 502a582 commit 22fd98c

File tree

1 file changed

+17
-2
lines changed

1 file changed

+17
-2
lines changed

drivers/spi/spi-microchip-core.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ struct mchp_corespi {
103103
u8 *rx_buf;
104104
u32 clk_gen; /* divider for spi output clock generated by the controller */
105105
u32 clk_mode;
106+
u32 pending_slave_select;
106107
int irq;
107108
int tx_len;
108109
int rx_len;
@@ -249,8 +250,18 @@ static void mchp_corespi_set_cs(struct spi_device *spi, bool disable)
249250
reg = mchp_corespi_read(corespi, REG_SLAVE_SELECT);
250251
reg &= ~BIT(spi_get_chipselect(spi, 0));
251252
reg |= !disable << spi_get_chipselect(spi, 0);
253+
corespi->pending_slave_select = reg;
252254

253-
mchp_corespi_write(corespi, REG_SLAVE_SELECT, reg);
255+
/*
256+
* Only deassert chip select immediately. Writing to some registers
257+
* requires the controller to be disabled, which results in the
258+
* output pins being tristated and can cause the SCLK and MOSI lines
259+
* to transition. Therefore asserting the chip select is deferred
260+
* until just before writing to the TX FIFO, to ensure the device
261+
* doesn't see any spurious clock transitions whilst CS is enabled.
262+
*/
263+
if (((spi->mode & SPI_CS_HIGH) == 0) == disable)
264+
mchp_corespi_write(corespi, REG_SLAVE_SELECT, reg);
254265
}
255266

256267
static int mchp_corespi_setup(struct spi_device *spi)
@@ -269,6 +280,7 @@ static int mchp_corespi_setup(struct spi_device *spi)
269280
if (spi->mode & SPI_CS_HIGH) {
270281
reg = mchp_corespi_read(corespi, REG_SLAVE_SELECT);
271282
reg |= BIT(spi_get_chipselect(spi, 0));
283+
corespi->pending_slave_select = reg;
272284
mchp_corespi_write(corespi, REG_SLAVE_SELECT, reg);
273285
}
274286
return 0;
@@ -310,7 +322,8 @@ static void mchp_corespi_init(struct spi_controller *host, struct mchp_corespi *
310322
* select is relinquished to the hardware. SSELOUT is enabled too so we
311323
* can deal with active high targets.
312324
*/
313-
mchp_corespi_write(spi, REG_SLAVE_SELECT, SSELOUT | SSEL_DIRECT);
325+
spi->pending_slave_select = SSELOUT | SSEL_DIRECT;
326+
mchp_corespi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select);
314327

315328
control = mchp_corespi_read(spi, REG_CONTROL);
316329

@@ -479,6 +492,8 @@ static int mchp_corespi_transfer_one(struct spi_controller *host,
479492
mchp_corespi_set_xfer_size(spi, (spi->tx_len > FIFO_DEPTH)
480493
? FIFO_DEPTH : spi->tx_len);
481494

495+
mchp_corespi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select);
496+
482497
while (spi->tx_len)
483498
mchp_corespi_write_fifo(spi);
484499

0 commit comments

Comments
 (0)