From: dillon min <redacted>
in l3gd20 driver startup, there is a setup failed error return from
stm32 spi driver
"
[ 2.687630] st-gyro-spi spi0.0: supply vdd not found, using dummy
regulator
[ 2.696869] st-gyro-spi spi0.0: supply vddio not found, using dummy
regulator
[ 2.706707] spi_stm32 40015000.spi: SPI transfer setup failed
[ 2.713741] st-gyro-spi spi0.0: SPI transfer failed: -22
[ 2.721096] spi_master spi0: failed to transfer one message from queue
[ 2.729268] iio iio:device0: failed to read Who-Am-I register.
[ 2.737504] st-gyro-spi: probe of spi0.0 failed with error -22
"
after debug into spi-stm32 driver, st-gyro-spi split two steps to read
l3gd20 id
first: send command to l3gd20 with read id command in tx_buf, rx_buf
is null.
second: read id with tx_buf is null, rx_buf not null.
so, for second step, stm32 driver recongise this process is SPI_SIMPLE_RX
from stm32_spi_communication_type, but there is no related process for this
type in stm32f4_spi_set_mode, then we get error from
stm32_spi_transfer_one_setup.
we can use two method to fix this bug.
1, use stm32 spi's "In unidirectional receive-only mode (BIDIMODE=0 and
RXONLY=1)". but as our code running in sdram, the read latency is too large
to get so many receive overrun error in interrupts handler.
2, use stm32 spi's "In full-duplex (BIDIMODE=0 and RXONLY=0)", as tx_buf is
null, we must add dummy data sent out before read data.
so, add stm32f4_spi_tx_dummy to handle this situation.
Signed-off-by: dillon min <redacted>
---
drivers/spi/spi-stm32.c | 29 +++++++++++++++++++++++++----
1 file changed, 25 insertions(+), 4 deletions(-)
@@ -388,6 +388,13 @@ static int stm32h7_spi_get_fifo_size(struct stm32_spi *spi)returncount;}+staticvoidstm32f4_spi_tx_dummy(structstm32_spi*spi)+{+if(spi->cur_bpw==16)+writew_relaxed(0x5555,spi->base+STM32F4_SPI_DR);+else+writeb_relaxed(0x55,spi->base+STM32F4_SPI_DR);+}/***stm32f4_spi_get_bpw_mask-Returnbitsperwordmask*@spi:pointertothespicontrollerdatastructure
@@ -811,7 +818,9 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)mask|=STM32F4_SPI_SR_TXE;}-if(!spi->cur_usedma&&spi->cur_comm==SPI_FULL_DUPLEX){+if(!spi->cur_usedma&&(spi->cur_comm==SPI_FULL_DUPLEX||+spi->cur_comm==SPI_SIMPLEX_RX||+spi->cur_comm==SPI_3WIRE_RX)){/* TXE flag is set and is handled when RXNE flag occurs */sr&=~STM32F4_SPI_SR_TXE;mask|=STM32F4_SPI_SR_RXNE|STM32F4_SPI_SR_OVR;
@@ -850,8 +859,10 @@ static irqreturn_t stm32f4_spi_irq_event(int irq, void *dev_id)stm32f4_spi_read_rx(spi);if(spi->rx_len==0)end=true;-else/* Load data for discontinuous mode */+elseif(spi->tx_buf)/* Load data for discontinuous mode */stm32f4_spi_write_tx(spi);+elseif(spi->cur_comm==SPI_SIMPLEX_RX)+stm32f4_spi_tx_dummy(spi);}end_irq:
@@ -1151,7 +1162,9 @@ static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi)/* Enable the interrupts relative to the current communication mode */if(spi->cur_comm==SPI_SIMPLEX_TX||spi->cur_comm==SPI_3WIRE_TX){cr2|=STM32F4_SPI_CR2_TXEIE;-}elseif(spi->cur_comm==SPI_FULL_DUPLEX){+}elseif(spi->cur_comm==SPI_FULL_DUPLEX||+spi->cur_comm==SPI_SIMPLEX_RX||+spi->cur_comm==SPI_3WIRE_RX){/* In transmit-only mode, the OVR flag is set in the SR register*sincethereceiveddataareneverread.ThereforesetOVR*interruptonlywhenrxbufferisavailable.
@@ -1170,6 +1183,8 @@ static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi)/* starting data transfer when buffer is loaded */if(spi->tx_buf)stm32f4_spi_write_tx(spi);+elseif(spi->cur_comm==SPI_SIMPLEX_RX)+stm32f4_spi_tx_dummy(spi);spin_unlock_irqrestore(&spi->lock,flags);
@@ -1462,10 +1477,16 @@ static int stm32f4_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type)stm32_spi_set_bits(spi,STM32F4_SPI_CR1,STM32F4_SPI_CR1_BIDIMODE|STM32F4_SPI_CR1_BIDIOE);-}elseif(comm_type==SPI_FULL_DUPLEX){+}elseif(comm_type==SPI_FULL_DUPLEX||+comm_type==SPI_SIMPLEX_RX){stm32_spi_clr_bits(spi,STM32F4_SPI_CR1,STM32F4_SPI_CR1_BIDIMODE|STM32F4_SPI_CR1_BIDIOE);+}elseif(comm_type==SPI_3WIRE_RX){+stm32_spi_set_bits(spi,STM32F4_SPI_CR1,+STM32F4_SPI_CR1_BIDIMODE);+stm32_spi_clr_bits(spi,STM32F4_SPI_CR1,+STM32F4_SPI_CR1_BIDIOE);}else{return-EINVAL;}