arch/arm/src/stm32h7: Add support for spi simplex configurations

Signed-off-by: Jukka Laitinen <jukka.laitinen@intel.com>
This commit is contained in:
Jukka Laitinen 2019-09-11 16:21:28 +03:00 committed by patacongo
parent 574b2593e6
commit e989147119
2 changed files with 206 additions and 12 deletions

View File

@ -826,6 +826,13 @@ config STM32H7_SPI1_DMA_BUFFER
---help---
Add a properly aligned DMA buffer for RX and TX DMA for SPI1.
config STM32H7_SPI1_COMMTYPE
int "SPI1 Operation mode"
default 0
depends on STM32H7_SPI1
---help---
Select full-duplex (0), simplex tx (1), simplex rx (2) or half-duplex (3)
config STM32H7_SPI2_DMA
bool "SPI2 DMA"
default n
@ -840,6 +847,13 @@ config STM32H7_SPI2_DMA_BUFFER
---help---
Add a properly aligned DMA buffer for RX and TX DMA for SPI2.
config STM32H7_SPI2_COMMTYPE
int "SPI2 Operation mode"
default 0
depends on STM32H7_SPI2
---help---
Select full-duplex (0), simplex tx (1), simplex rx (2) or half-duplex (3)
config STM32H7_SPI3_DMA
bool "SPI3 DMA"
default n
@ -854,6 +868,13 @@ config STM32H7_SPI3_DMA_BUFFER
---help---
Add a properly aligned DMA buffer for RX and TX DMA for SPI3.
config STM32H7_SPI3_COMMTYPE
int "SPI3 Operation mode"
default 0
depends on STM32H7_SPI3
---help---
Select full-duplex (0), simplex tx (1), simplex rx (2) or half-duplex (3)
config STM32H7_SPI4_DMA
bool "SPI4 DMA"
default n
@ -868,6 +889,13 @@ config STM32H7_SPI4_DMA_BUFFER
---help---
Add a properly aligned DMA buffer for RX and TX DMA for SPI4.
config STM32H7_SPI4_COMMTYPE
int "SPI4 Operation mode"
default 0
depends on STM32H7_SPI4
---help---
Select full-duplex (0), simplex tx (1), simplex rx (2) or half-duplex (3)
config STM32H7_SPI5_DMA
bool "SPI5 DMA"
default n
@ -882,6 +910,13 @@ config STM32H7_SPI5_DMA_BUFFER
---help---
Add a properly aligned DMA buffer for RX and TX DMA for SPI5.
config STM32H7_SPI5_COMMTYPE
int "SPI5 Operation mode"
default 0
depends on STM32H7_SPI5
---help---
Select full-duplex (0), simplex tx (1), simplex rx (2) or half-duplex (3)
config STM32H7_SPI6_DMA
bool "SPI6 DMA"
default n
@ -896,6 +931,13 @@ config STM32H7_SPI6_DMA_BUFFER
---help---
Add a properly aligned DMA buffer for RX and TX DMA for SPI6.
config STM32H7_SPI6_COMMTYPE
int "SPI6 Operation mode"
default 0
depends on STM32H7_SPI6
---help---
Select full-duplex (0), simplex tx (1), simplex rx (2) or half-duplex (3)
endmenu # "SPI Configuration"
menu "U[S]ART Configuration"

View File

@ -221,6 +221,14 @@
* Private Types
****************************************************************************/
enum spi_config_e
{
FULL_DUPLEX = 0,
SIMPLEX_TX,
SIMPLEX_RX,
HALF_DUPLEX
};
struct stm32_spidev_s
{
struct spi_dev_s spidev; /* Externally visible part of the SPI interface */
@ -257,6 +265,7 @@ struct stm32_spidev_s
#ifdef CONFIG_PM
struct pm_callback_s pm_cb; /* PM callbacks */
#endif
enum spi_config_e config; /* full/half duplex, simplex transmit/read only */
};
/****************************************************************************
@ -402,6 +411,11 @@ static struct stm32_spidev_s g_spi1dev =
#ifdef CONFIG_PM
.pm_cb.prepare = spi_pm_prepare,
#endif
#ifdef CONFIG_STM32H7_SPI1_COMMTYPE
.config = CONFIG_STM32H7_SPI1_COMMTYPE,
#else
.config = FULL_DUPLEX,
#endif
};
#endif /* CONFIG_STM32H7_SPI1 */
@ -465,6 +479,11 @@ static struct stm32_spidev_s g_spi2dev =
#ifdef CONFIG_PM
.pm_cb.prepare = spi_pm_prepare,
#endif
#ifdef CONFIG_STM32H7_SPI2_COMMTYPE
.config = CONFIG_STM32H7_SPI2_COMMTYPE,
#else
.config = FULL_DUPLEX,
#endif
};
#endif /* CONFIG_STM32H7_SPI2 */
@ -528,6 +547,11 @@ static struct stm32_spidev_s g_spi3dev =
#ifdef CONFIG_PM
.pm_cb.prepare = spi_pm_prepare,
#endif
#ifdef CONFIG_STM32H7_SPI3_COMMTYPE
.config = CONFIG_STM32H7_SPI3_COMMTYPE,
#else
.config = FULL_DUPLEX,
#endif
};
#endif /* CONFIG_STM32H7_SPI3 */
@ -591,6 +615,11 @@ static struct stm32_spidev_s g_spi4dev =
#ifdef CONFIG_PM
.pm_cb.prepare = spi_pm_prepare,
#endif
#ifdef CONFIG_STM32H7_SPI4_COMMTYPE
.config = CONFIG_STM32H7_SPI4_COMMTYPE,
#else
.config = FULL_DUPLEX,
#endif
};
#endif /* CONFIG_STM32H7_SPI4 */
@ -654,6 +683,11 @@ static struct stm32_spidev_s g_spi5dev =
#ifdef CONFIG_PM
.pm_cb.prepare = spi_pm_prepare,
#endif
#ifdef CONFIG_STM32H7_SPI5_COMMTYPE
.config = CONFIG_STM32H7_SPI5_COMMTYPE,
#else
.config = FULL_DUPLEX,
#endif
};
#endif /* CONFIG_STM32H7_SPI5 */
@ -717,6 +751,11 @@ static struct stm32_spidev_s g_spi6dev =
#ifdef CONFIG_PM
.pm_cb.prepare = spi_pm_prepare,
#endif
#ifdef CONFIG_STM32H7_SPI6_COMMTYPE
.config = CONFIG_STM32H7_SPI6_COMMTYPE,
#else
.config = FULL_DUPLEX,
#endif
};
#endif /* CONFIG_STM32H7_SPI6 */
@ -823,6 +862,13 @@ static inline void spi_putreg(FAR struct stm32_spidev_s *priv,
static inline uint32_t spi_readword(FAR struct stm32_spidev_s *priv)
{
/* Can't receive in tx only mode */
if (priv->config == SIMPLEX_TX)
{
return 0;
}
/* Wait until the receive buffer is not empty */
while ((spi_getreg(priv, STM32_SPI_SR_OFFSET) & SPI_SR_RXP) == 0);
@ -850,6 +896,13 @@ static inline uint32_t spi_readword(FAR struct stm32_spidev_s *priv)
static inline void spi_writeword(FAR struct stm32_spidev_s *priv,
uint32_t word)
{
/* Can't transmit in rx only mode */
if (priv->config == SIMPLEX_RX)
{
return;
}
/* Wait until the transmit buffer is empty */
while ((spi_getreg(priv, STM32_SPI_SR_OFFSET) & SPI_SR_TXP) == 0);
@ -875,6 +928,13 @@ static inline void spi_writeword(FAR struct stm32_spidev_s *priv,
static inline uint8_t spi_readbyte(FAR struct stm32_spidev_s *priv)
{
/* Can't receive in tx only mode */
if (priv->config == SIMPLEX_TX)
{
return 0;
}
/* Wait until the receive buffer is not empty */
while ((spi_getreg(priv, STM32_SPI_SR_OFFSET) & SPI_SR_RXP) == 0);
@ -902,6 +962,13 @@ static inline uint8_t spi_readbyte(FAR struct stm32_spidev_s *priv)
static inline void spi_writebyte(FAR struct stm32_spidev_s *priv,
uint8_t byte)
{
/* Can't transmit in rx only mode */
if (priv->config == SIMPLEX_RX)
{
return;
}
/* Wait until the transmit buffer is empty */
while ((spi_getreg(priv, STM32_SPI_SR_OFFSET) & SPI_SR_TXP) == 0);
@ -942,6 +1009,13 @@ static int spi_dmarxwait(FAR struct stm32_spidev_s *priv)
{
int ret;
/* Don't wait in tx only mode */
if (priv->config == SIMPLEX_TX)
{
return OK;
}
/* Take the semaphore (perhaps waiting). If the result is zero, then the
* DMA must not really have completed???
*/
@ -975,6 +1049,13 @@ static int spi_dmatxwait(FAR struct stm32_spidev_s *priv)
{
int ret;
/* Don't wait in rx only mode */
if (priv->config == SIMPLEX_RX)
{
return OK;
}
/* Take the semaphore (perhaps waiting). If the result is zero, then the
* DMA must not really have completed???
*/
@ -1078,6 +1159,14 @@ static void spi_dmarxsetup(FAR struct stm32_spidev_s *priv,
FAR void *rxbuffer, FAR void *rxdummy,
size_t nwords, stm32_dmacfg_t *dmacfg)
{
/* Can't receive in tx only mode */
if (priv->config == SIMPLEX_TX)
{
priv->rxccr = 0;
return;
}
/* 8- or 16-bit mode? */
if (priv->nbits > 8)
@ -1132,6 +1221,14 @@ static void spi_dmatxsetup(FAR struct stm32_spidev_s *priv,
FAR const void *txbuffer, FAR const void *txdummy,
size_t nwords, stm32_dmacfg_t *dmacfg)
{
/* Can't transmit in rx only mode */
if (priv->config == SIMPLEX_RX)
{
priv->txccr = 0;
return;
}
/* 8- or 16-bit mode? */
if (priv->nbits > 8)
@ -1182,6 +1279,13 @@ static void spi_dmatxsetup(FAR struct stm32_spidev_s *priv,
#ifdef CONFIG_STM32H7_SPI_DMA
static void spi_dmarxstart(FAR struct stm32_spidev_s *priv)
{
/* Can't receive in tx only mode */
if (priv->config == SIMPLEX_TX)
{
return;
}
priv->rxresult = 0;
stm32_dmastart(priv->rxdma, spi_dmarxcallback, priv, false);
}
@ -1198,6 +1302,13 @@ static void spi_dmarxstart(FAR struct stm32_spidev_s *priv)
#ifdef CONFIG_STM32H7_SPI_DMA
static void spi_dmatxstart(FAR struct stm32_spidev_s *priv)
{
/* Can't transmit in rx only mode */
if (priv->config == SIMPLEX_RX)
{
return;
}
priv->txresult = 0;
stm32_dmastart(priv->txdma, spi_dmatxcallback, priv, false);
}
@ -1624,7 +1735,10 @@ static uint32_t spi_send(FAR struct spi_dev_s *dev, uint32_t wd)
/* Master transfer start */
if (priv->config != SIMPLEX_RX)
{
spi_modifyreg(priv, STM32_SPI_CR1_OFFSET, 0, SPI_CR1_CSTART);
}
/* According to the number of bits, access data register as word or byte
* This is absolutely required because of packing. With nbits <=8 bit
@ -1829,7 +1943,8 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
}
#endif
if ((priv->rxdma == NULL) || (priv->txdma == NULL) ||
if ((priv->config != SIMPLEX_TX && priv->rxdma == NULL) ||
(priv->config != SIMPLEX_RX && priv->txdma == NULL) ||
up_interrupt_context())
{
/* Invalid DMA channels, or interrupt context, fall
@ -1870,8 +1985,10 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
rxbuffer = rxbuffer ? priv->rxbuf : rxbuffer;
}
if (!stm32_dmacapable(priv->txdma, &txdmacfg) ||
!stm32_dmacapable(priv->rxdma, &rxdmacfg))
if ((priv->config != SIMPLEX_RX &&
!stm32_dmacapable(priv->txdma, &txdmacfg)) ||
(priv->config != SIMPLEX_TX &&
!stm32_dmacapable(priv->rxdma, &rxdmacfg)))
{
/* Unsupported memory region fall back to non-DMA method. */
@ -1901,8 +2018,16 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
DEBUGASSERT(priv->spibase != 0);
/* Setup the DMA */
if (priv->config != SIMPLEX_RX)
{
stm32_dmasetup(priv->txdma, &txdmacfg);
}
if (priv->config != SIMPLEX_TX)
{
stm32_dmasetup(priv->rxdma, &rxdmacfg);
}
spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, 0, SPI_CFG1_TXDMAEN |
SPI_CFG1_RXDMAEN);
@ -2187,6 +2312,7 @@ static void spi_bus_initialize(struct stm32_spidev_s *priv)
clrbits = SPI_CR1_SPE;
setbits = SPI_CR1_SSI;
spi_modifyreg(priv, STM32_SPI_CR1_OFFSET, clrbits, setbits);
/* CFG1 */
@ -2200,6 +2326,24 @@ static void spi_bus_initialize(struct stm32_spidev_s *priv)
clrbits = SPI_CFG2_CPHA | SPI_CFG2_CPOL | SPI_CFG2_LSBFRST |
SPI_CFG2_COMM_MASK;
setbits = SPI_CFG2_MASTER | SPI_CFG2_SSM;
switch (priv->config)
{
default:
case FULL_DUPLEX:
setbits |= SPI_CFG2_COMM_FULL;
break;
case SIMPLEX_TX:
setbits |= SPI_CFG2_COMM_STX;
break;
case SIMPLEX_RX:
setbits |= SPI_CFG2_COMM_SRX;
break;
case HALF_DUPLEX:
setbits |= SPI_CFG2_COMM_HALF;
break;
}
spi_modifyreg(priv, STM32_SPI_CFG2_OFFSET, clrbits, setbits);
priv->frequency = 0;
@ -2238,12 +2382,21 @@ static void spi_bus_initialize(struct stm32_spidev_s *priv)
* forever in this function! Don't let your design do that!
*/
priv->rxdma = NULL;
priv->txdma = NULL;
if (priv->config != SIMPLEX_TX)
{
priv->rxdma = stm32_dmachannel(priv->rxch);
priv->txdma = stm32_dmachannel(priv->txch);
DEBUGASSERT(priv->rxdma && priv->txdma);
DEBUGASSERT(priv->rxdma);
spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, 0, SPI_CFG1_RXDMAEN);
}
spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, 0,
SPI_CFG1_RXDMAEN | SPI_CFG1_TXDMAEN);
if (priv->config != SIMPLEX_RX)
{
priv->txdma = stm32_dmachannel(priv->txch);
DEBUGASSERT(priv->txdma);
spi_modifyreg(priv, STM32_SPI_CFG1_OFFSET, 0, SPI_CFG1_TXDMAEN);
}
#endif
/* Enable SPI */
@ -2288,7 +2441,6 @@ FAR struct spi_dev_s *stm32_spibus_initialize(int bus)
FAR struct stm32_spidev_s *priv = NULL;
irqstate_t flags = enter_critical_section();
#ifdef CONFIG_STM32H7_SPI1
if (bus == 1)
{