Skip to content

Commit 0fe4960

Browse files
swilkins-raymarinegregkh
authored andcommitted
spi: microchip-core: defer asserting chip select until just before write to TX FIFO
[ Upstream commit 22fd98c ] 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 <steve.wilkins@raymarine.com> Signed-off-by: Conor Dooley <conor.dooley@microchip.com> Link: https://patch.msgid.link/20240715-sanitizer-recant-dd96b7a97048@wendy Signed-off-by: Mark Brown <broonie@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent 1504fb5 commit 0fe4960

1 file changed

Lines changed: 17 additions & 2 deletions

File tree

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)
@@ -266,6 +277,7 @@ static int mchp_corespi_setup(struct spi_device *spi)
266277
if (spi->mode & SPI_CS_HIGH) {
267278
reg = mchp_corespi_read(corespi, REG_SLAVE_SELECT);
268279
reg |= BIT(spi_get_chipselect(spi, 0));
280+
corespi->pending_slave_select = reg;
269281
mchp_corespi_write(corespi, REG_SLAVE_SELECT, reg);
270282
}
271283
return 0;
@@ -307,7 +319,8 @@ static void mchp_corespi_init(struct spi_controller *host, struct mchp_corespi *
307319
* select is relinquished to the hardware. SSELOUT is enabled too so we
308320
* can deal with active high targets.
309321
*/
310-
mchp_corespi_write(spi, REG_SLAVE_SELECT, SSELOUT | SSEL_DIRECT);
322+
spi->pending_slave_select = SSELOUT | SSEL_DIRECT;
323+
mchp_corespi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select);
311324

312325
control = mchp_corespi_read(spi, REG_CONTROL);
313326

@@ -476,6 +489,8 @@ static int mchp_corespi_transfer_one(struct spi_controller *host,
476489
mchp_corespi_set_xfer_size(spi, (spi->tx_len > FIFO_DEPTH)
477490
? FIFO_DEPTH : spi->tx_len);
478491

492+
mchp_corespi_write(spi, REG_SLAVE_SELECT, spi->pending_slave_select);
493+
479494
while (spi->tx_len)
480495
mchp_corespi_write_fifo(spi);
481496

0 commit comments

Comments
 (0)