drivers: spi: stm32: add error checking to IRQ mode
Now that struct spi_context supports passing errors from interrupt-driven I/O handlers to waiting threads, we can enable error interrupts and propagate errors to spi_transceive() callers. To make it easier for users to debug SPI-related issues, log any error bits set in SR when failures occur. A subsequent patch will add error checking to polled mode as well, but other cleanups and fixes will go in first to make this easier. Note that this breaks the spi_loopback test on some targets, but it's not a regression, as it wasn't working properly anyway. Subsequent patches the bugs that this error checking has exposed. Signed-off-by: Marti Bolivar <marti.bolivar@linaro.org>
This commit is contained in:
parent
6c717095b8
commit
69bc5ebdf3
1 changed files with 58 additions and 22 deletions
|
@ -25,16 +25,64 @@
|
|||
#define CONFIG_DATA(cfg) \
|
||||
((struct spi_stm32_data * const)(cfg)->dev->driver_data)
|
||||
|
||||
#ifdef LL_SPI_SR_UDR
|
||||
#define SPI_STM32_ERR_MSK (LL_SPI_SR_UDR | LL_SPI_SR_CRCERR | LL_SPI_SR_MODF | \
|
||||
LL_SPI_SR_OVR | LL_SPI_SR_FRE)
|
||||
#else
|
||||
#define SPI_STM32_ERR_MSK (LL_SPI_SR_CRCERR | LL_SPI_SR_MODF | \
|
||||
LL_SPI_SR_OVR | LL_SPI_SR_FRE)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPI_STM32_INTERRUPT
|
||||
static void spi_stm32_transmit(SPI_TypeDef *spi, struct spi_stm32_data *data);
|
||||
static void spi_stm32_receive(SPI_TypeDef *spi, struct spi_stm32_data *data);
|
||||
|
||||
static int spi_stm32_get_err(SPI_TypeDef *spi)
|
||||
{
|
||||
u32_t sr = LL_SPI_ReadReg(spi, SR);
|
||||
|
||||
return (int)(sr & SPI_STM32_ERR_MSK);
|
||||
}
|
||||
|
||||
static void spi_stm32_complete(struct spi_stm32_data *data, SPI_TypeDef *spi,
|
||||
int status)
|
||||
{
|
||||
LL_SPI_DisableIT_TXE(spi);
|
||||
LL_SPI_DisableIT_RXNE(spi);
|
||||
LL_SPI_DisableIT_ERR(spi);
|
||||
|
||||
spi_context_cs_control(&data->ctx, false);
|
||||
|
||||
#if defined(CONFIG_SOC_SERIES_STM32L4X) || defined(CONFIG_SOC_SERIES_STM32F3X)
|
||||
/* Flush RX buffer */
|
||||
while (LL_SPI_IsActiveFlag_RXNE(spi)) {
|
||||
(void) LL_SPI_ReceiveData8(spi);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (LL_SPI_GetMode(spi) == LL_SPI_MODE_MASTER) {
|
||||
while (LL_SPI_IsActiveFlag_BSY(spi)) {
|
||||
/* NOP */
|
||||
}
|
||||
LL_SPI_Disable(spi);
|
||||
}
|
||||
|
||||
spi_context_complete(&data->ctx, status);
|
||||
}
|
||||
|
||||
static void spi_stm32_isr(void *arg)
|
||||
{
|
||||
struct device * const dev = (struct device *) arg;
|
||||
const struct spi_stm32_config *cfg = dev->config->config_info;
|
||||
struct spi_stm32_data *data = dev->driver_data;
|
||||
SPI_TypeDef *spi = cfg->spi;
|
||||
int err;
|
||||
|
||||
err = spi_stm32_get_err(spi);
|
||||
if (err) {
|
||||
spi_stm32_complete(data, spi, err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LL_SPI_IsActiveFlag_TXE(spi) &&
|
||||
(spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx))) {
|
||||
|
@ -51,26 +99,7 @@ static void spi_stm32_isr(void *arg)
|
|||
|
||||
if (!spi_context_tx_on(&data->ctx) &&
|
||||
!spi_context_rx_on(&data->ctx)) {
|
||||
LL_SPI_DisableIT_TXE(spi);
|
||||
LL_SPI_DisableIT_RXNE(spi);
|
||||
|
||||
spi_context_cs_control(&data->ctx, false);
|
||||
|
||||
#if defined(CONFIG_SOC_SERIES_STM32L4X) || defined(CONFIG_SOC_SERIES_STM32F3X)
|
||||
/* Flush RX buffer */
|
||||
while (LL_SPI_IsActiveFlag_RXNE(spi)) {
|
||||
(void) LL_SPI_ReceiveData8(spi);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (LL_SPI_GetMode(spi) == LL_SPI_MODE_MASTER) {
|
||||
while (LL_SPI_IsActiveFlag_BSY(spi)) {
|
||||
/* NOP */
|
||||
}
|
||||
LL_SPI_Disable(spi);
|
||||
}
|
||||
|
||||
spi_context_complete(&data->ctx, 0);
|
||||
spi_stm32_complete(data, spi, spi_stm32_get_err(spi));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -263,14 +292,17 @@ static int transceive(struct spi_config *config,
|
|||
spi_context_cs_control(&data->ctx, true);
|
||||
|
||||
#ifdef CONFIG_SPI_STM32_INTERRUPT
|
||||
LL_SPI_EnableIT_ERR(spi);
|
||||
|
||||
if (rx_bufs) {
|
||||
LL_SPI_EnableIT_RXNE(spi);
|
||||
}
|
||||
|
||||
LL_SPI_EnableIT_TXE(spi);
|
||||
|
||||
spi_context_wait_for_completion(&data->ctx);
|
||||
ret = spi_context_wait_for_completion(&data->ctx);
|
||||
#else
|
||||
ret = 0; /* FIXME: add error checking. */
|
||||
do {
|
||||
/* Keep transmitting NOP data until RX data left */
|
||||
if ((spi_context_tx_on(&data->ctx) ||
|
||||
|
@ -305,7 +337,11 @@ static int transceive(struct spi_config *config,
|
|||
|
||||
spi_context_release(&data->ctx, 0);
|
||||
|
||||
return 0;
|
||||
if (ret) {
|
||||
SYS_LOG_ERR("error mask 0x%x", ret);
|
||||
}
|
||||
|
||||
return ret ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int spi_stm32_transceive(struct spi_config *config,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue