STM32F7, STM32H7, and STM32L4: Port Dave Marples STM32 fix to other STM32 spi drivers

This commit is contained in:
Gregory Nutt 2018-12-03 13:14:00 -06:00
parent ee058683c6
commit 8983f1c82e
3 changed files with 300 additions and 15 deletions

View File

@ -153,6 +153,10 @@ struct stm32_spidev_s
#ifdef CONFIG_STM32F7_SPI_DMA
volatile uint8_t rxresult; /* Result of the RX DMA */
volatile uint8_t txresult; /* Result of the RX DMA */
#ifdef CONFIG_SPI_TRIGGER
bool defertrig; /* Flag indicating that trigger should be deferred */
bool trigarmed; /* Flag indicating that the trigger is armed */
#endif
uint8_t rxch; /* The RX DMA channel number */
uint8_t txch; /* The TX DMA channel number */
DMA_HANDLE rxdma; /* DMA channel handle for RX transfers */
@ -216,6 +220,9 @@ static int spi_hwfeatures(FAR struct spi_dev_s *dev,
static uint16_t spi_send(FAR struct spi_dev_s *dev, uint16_t wd);
static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
FAR void *rxbuffer, size_t nwords);
#ifdef CONFIG_SPI_TRIGGER
static int spi_trigger(FAR struct spi_dev_s *dev);
#endif
#ifndef CONFIG_SPI_EXCHANGE
static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
size_t nwords);
@ -260,6 +267,9 @@ static const struct spi_ops_s g_sp1iops =
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
#endif
#ifdef CONFIG_SPI_TRIGGER
.trigger = spi_trigger,
#endif
#ifdef CONFIG_SPI_CALLBACK
.registercallback = stm32_spi1register, /* Provided externally */
#else
@ -307,6 +317,9 @@ static const struct spi_ops_s g_sp2iops =
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
#endif
#ifdef CONFIG_SPI_TRIGGER
.trigger = spi_trigger,
#endif
#ifdef CONFIG_SPI_CALLBACK
.registercallback = stm32_spi2register, /* provided externally */
#else
@ -354,6 +367,9 @@ static const struct spi_ops_s g_sp3iops =
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
#endif
#ifdef CONFIG_SPI_TRIGGER
.trigger = spi_trigger,
#endif
#ifdef CONFIG_SPI_CALLBACK
.registercallback = stm32_spi3register, /* provided externally */
#else
@ -401,6 +417,9 @@ static const struct spi_ops_s g_sp4iops =
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
#endif
#ifdef CONFIG_SPI_TRIGGER
.trigger = spi_trigger,
#endif
#ifdef CONFIG_SPI_CALLBACK
.registercallback = stm32_spi4register, /* provided externally */
#else
@ -448,6 +467,9 @@ static const struct spi_ops_s g_sp5iops =
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
#endif
#ifdef CONFIG_SPI_TRIGGER
.trigger = spi_trigger,
#endif
#ifdef CONFIG_SPI_CALLBACK
.registercallback = stm32_spi5register, /* provided externally */
#else
@ -495,6 +517,9 @@ static const struct spi_ops_s g_sp6iops =
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
#endif
#ifdef CONFIG_SPI_TRIGGER
.trigger = spi_trigger,
#endif
#ifdef CONFIG_SPI_CALLBACK
.registercallback = stm32_spi6register, /* provided externally */
#else
@ -1380,8 +1405,11 @@ static void spi_setbits(FAR struct spi_dev_s *dev, int nbits)
#ifdef CONFIG_SPI_HWFEATURES
static int spi_hwfeatures(FAR struct spi_dev_s *dev, spi_hwfeatures_t features)
{
#ifdef CONFIG_SPI_BITORDER
#if defined(CONFIG_SPI_BITORDER) || defined(CONFIG_SPI_TRIGGER)
FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)dev;
#endif
#ifdef CONFIG_SPI_BITORDER
uint16_t setbitscr1;
uint16_t clrbitscr1;
uint16_t setbitscr2;
@ -1407,12 +1435,23 @@ static int spi_hwfeatures(FAR struct spi_dev_s *dev, spi_hwfeatures_t features)
spi_modifycr1(priv, setbits, clrbits);
spi_modifycr1(priv, SPI_CR1_SPE, 0);
features &= ~HWFEAT_LSBFIRST;
#endif
#ifdef CONFIG_SPI_TRIGGER
/* Turn deferred trigger mode on or off. Only applicable for DMA mode. If a
* transfer is deferred then the DMA will not actually be triggered until a
* subsequent call to SPI_TRIGGER to set it off. The thread will be waiting
* on the transfer completing as normal.
*/
priv->defertrig = ((features & HWFEAT_TRIGGER) != 0);
features &= ~HWFEAT_TRIGGER;
#endif
/* Other H/W features are not supported */
return ((features & ~HWFEAT_LSBFIRST) == 0) ? OK : -ENOSYS;
#else
return -ENOSYS;
#endif
return (features == 0) ? OK : -ENOSYS;
}
#endif
@ -1644,16 +1683,38 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
arch_flush_dcache((uintptr_t)txbuffer, (uintptr_t)txbuffer + buflen);
}
#ifdef CONFIG_SPI_TRIGGER
/* Is deferred triggering in effect? */
if (!priv->defertrig)
{
/* No.. Start the DMAs */
spi_dmarxstart(priv);
spi_dmatxstart(priv);
}
else
{
/* Yes.. indicated that we are ready to be started */
priv->trigarmed = true;
}
#else
/* Start the DMAs */
spi_dmarxstart(priv);
spi_dmatxstart(priv);
#endif
/* Then wait for each to complete */
spi_dmarxwait(priv);
spi_dmatxwait(priv);
#ifdef CONFIG_SPI_TRIGGER
priv->trigarmed = false;
#endif
/* Force RAM re-read */
if (rxbuffer)
@ -1670,6 +1731,43 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
}
#endif /* CONFIG_STM32F7_SPI_DMA */
/****************************************************************************
* Name: spi_trigger
*
* Description:
* Trigger a previously configured DMA transfer.
*
* Input Parameters:
* dev - Device-specific state data
*
* Returned Value:
* OK - Trigger was fired
* ENOTSUP - Trigger not fired due to lack of DMA support
* EIO - Trigger not fired because not previously primed
*
****************************************************************************/
#ifdef CONFIG_SPI_TRIGGER
static int spi_trigger(FAR struct spi_dev_s *dev)
{
#ifdef CONFIG_STM32F7_SPI_DMA
FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)dev;
if (!priv->trigarmed)
{
return -EIO;
}
spi_dmarxstart(priv);
spi_dmatxstart(priv);
return OK;
#else
return -ENOSYS;
#endif
}
#endif
/****************************************************************************
* Name: spi_sndblock
*

View File

@ -196,6 +196,10 @@ struct stm32_spidev_s
#ifdef CONFIG_STM32H7_SPI_DMA
volatile uint8_t rxresult; /* Result of the RX DMA */
volatile uint8_t txresult; /* Result of the RX DMA */
#ifdef CONFIG_SPI_TRIGGER
bool defertrig; /* Flag indicating that trigger should be deferred */
bool trigarmed; /* Flag indicating that the trigger is armed */
#endif
uint8_t rxch; /* The RX DMA channel number */
uint8_t txch; /* The TX DMA channel number */
DMA_HANDLE rxdma; /* DMA channel handle for RX transfers */
@ -262,6 +266,9 @@ static int spi_hwfeatures(FAR struct spi_dev_s *dev,
static uint16_t spi_send(FAR struct spi_dev_s *dev, uint16_t wd);
static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
FAR void *rxbuffer, size_t nwords);
#ifdef CONFIG_SPI_TRIGGER
static int spi_trigger(FAR struct spi_dev_s *dev);
#endif
#ifndef CONFIG_SPI_EXCHANGE
static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
size_t nwords);
@ -306,6 +313,9 @@ static const struct spi_ops_s g_sp1iops =
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
#endif
#ifdef CONFIG_SPI_TRIGGER
.trigger = spi_trigger,
#endif
#ifdef CONFIG_SPI_CALLBACK
.registercallback = stm32_spi1register, /* Provided externally */
#else
@ -353,6 +363,9 @@ static const struct spi_ops_s g_sp2iops =
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
#endif
#ifdef CONFIG_SPI_TRIGGER
.trigger = spi_trigger,
#endif
#ifdef CONFIG_SPI_CALLBACK
.registercallback = stm32_spi2register, /* provided externally */
#else
@ -400,6 +413,9 @@ static const struct spi_ops_s g_sp3iops =
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
#endif
#ifdef CONFIG_SPI_TRIGGER
.trigger = spi_trigger,
#endif
#ifdef CONFIG_SPI_CALLBACK
.registercallback = stm32_spi3register, /* provided externally */
#else
@ -447,6 +463,9 @@ static const struct spi_ops_s g_sp4iops =
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
#endif
#ifdef CONFIG_SPI_TRIGGER
.trigger = spi_trigger,
#endif
#ifdef CONFIG_SPI_CALLBACK
.registercallback = stm32_spi4register, /* provided externally */
#else
@ -494,6 +513,9 @@ static const struct spi_ops_s g_sp5iops =
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
#endif
#ifdef CONFIG_SPI_TRIGGER
.trigger = spi_trigger,
#endif
#ifdef CONFIG_SPI_CALLBACK
.registercallback = stm32_spi5register, /* provided externally */
#else
@ -541,6 +563,9 @@ static const struct spi_ops_s g_sp6iops =
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
#endif
#ifdef CONFIG_SPI_TRIGGER
.trigger = spi_trigger,
#endif
#ifdef CONFIG_SPI_CALLBACK
.registercallback = stm32_spi6register, /* provided externally */
#else
@ -1424,8 +1449,11 @@ static void spi_setbits(FAR struct spi_dev_s *dev, int nbits)
#ifdef CONFIG_SPI_HWFEATURES
static int spi_hwfeatures(FAR struct spi_dev_s *dev, spi_hwfeatures_t features)
{
#ifdef CONFIG_SPI_BITORDER
#if defined(CONFIG_SPI_BITORDER) || defined(CONFIG_SPI_TRIGGER)
FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)dev;
#endif
#ifdef CONFIG_SPI_BITORDER
uint32_t setbits = 0;
uint32_t clrbits = 0;
@ -1448,12 +1476,23 @@ static int spi_hwfeatures(FAR struct spi_dev_s *dev, spi_hwfeatures_t features)
spi_modifyreg(priv, STM32_SPI_CFG2_OFFSET, clrbits, setbits);
spi_enable(priv, true);
features &= ~HWFEAT_LSBFIRST;
#endif
#ifdef CONFIG_SPI_TRIGGER
/* Turn deferred trigger mode on or off. Only applicable for DMA mode. If a
* transfer is deferred then the DMA will not actually be triggered until a
* subsequent call to SPI_TRIGGER to set it off. The thread will be waiting
* on the transfer completing as normal.
*/
priv->defertrig = ((features & HWFEAT_TRIGGER) != 0);
features &= ~HWFEAT_TRIGGER;
#endif
/* Other H/W features are not supported */
return ((features & ~HWFEAT_LSBFIRST) == 0) ? OK : -ENOSYS;
#else
return -ENOSYS;
#endif
return (features == 0) ? OK : -ENOSYS;
}
#endif
@ -1700,16 +1739,38 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
arch_flush_dcache((uintptr_t)txbuffer, (uintptr_t)txbuffer + buflen);
}
#ifdef CONFIG_SPI_TRIGGER
/* Is deferred triggering in effect? */
if (!priv->defertrig)
{
/* No.. Start the DMAs */
spi_dmarxstart(priv);
spi_dmatxstart(priv);
}
else
{
/* Yes.. indicated that we are ready to be started */
priv->trigarmed = true;
}
#else
/* Start the DMAs */
spi_dmarxstart(priv);
spi_dmatxstart(priv);
#endif
/* Then wait for each to complete */
spi_dmarxwait(priv);
spi_dmatxwait(priv);
#ifdef CONFIG_SPI_TRIGGER
priv->trigarmed = false;
#endif
/* Force RAM re-read */
if (rxbuffer)
@ -1726,6 +1787,43 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
}
#endif /* CONFIG_STM32H7_SPI_DMA */
/****************************************************************************
* Name: spi_trigger
*
* Description:
* Trigger a previously configured DMA transfer.
*
* Input Parameters:
* dev - Device-specific state data
*
* Returned Value:
* OK - Trigger was fired
* ENOTSUP - Trigger not fired due to lack of DMA support
* EIO - Trigger not fired because not previously primed
*
****************************************************************************/
#ifdef CONFIG_SPI_TRIGGER
static int spi_trigger(FAR struct spi_dev_s *dev)
{
#ifdef CONFIG_STM32H7_SPI_DMA
FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)dev;
if (!priv->trigarmed)
{
return -EIO;
}
spi_dmarxstart(priv);
spi_dmatxstart(priv);
return OK;
#else
return -ENOSYS;
#endif
}
#endif
/****************************************************************************
* Name: spi_sndblock
*

View File

@ -154,6 +154,10 @@ struct stm32l4_spidev_s
#ifdef CONFIG_STM32L4_SPI_DMA
volatile uint8_t rxresult; /* Result of the RX DMA */
volatile uint8_t txresult; /* Result of the RX DMA */
#ifdef CONFIG_SPI_TRIGGER
bool defertrig; /* Flag indicating that trigger should be deferred */
bool trigarmed; /* Flag indicating that the trigger is armed */
#endif
uint16_t rxch; /* The RX DMA channel number */
uint16_t txch; /* The TX DMA channel number */
DMA_HANDLE rxdma; /* DMA channel handle for RX transfers */
@ -217,6 +221,9 @@ static int spi_hwfeatures(FAR struct spi_dev_s *dev,
static uint16_t spi_send(FAR struct spi_dev_s *dev, uint16_t wd);
static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
FAR void *rxbuffer, size_t nwords);
#ifdef CONFIG_SPI_TRIGGER
static int spi_trigger(FAR struct spi_dev_s *dev);
#endif
#ifndef CONFIG_SPI_EXCHANGE
static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
size_t nwords);
@ -261,6 +268,9 @@ static const struct spi_ops_s g_spi1ops =
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
#endif
#ifdef CONFIG_SPI_TRIGGER
.trigger = spi_trigger,
#endif
#ifdef CONFIG_SPI_CALLBACK
.registercallback = stm32l4_spi1register, /* Provided externally */
#else
@ -309,6 +319,9 @@ static const struct spi_ops_s g_spi2ops =
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
#endif
#ifdef CONFIG_SPI_TRIGGER
.trigger = spi_trigger,
#endif
#ifdef CONFIG_SPI_CALLBACK
.registercallback = stm32l4_spi2register, /* provided externally */
#else
@ -356,6 +369,9 @@ static const struct spi_ops_s g_spi3ops =
.sndblock = spi_sndblock,
.recvblock = spi_recvblock,
#endif
#ifdef CONFIG_SPI_TRIGGER
.trigger = spi_trigger,
#endif
#ifdef CONFIG_SPI_CALLBACK
.registercallback = stm32l4_spi3register, /* provided externally */
#else
@ -1185,8 +1201,11 @@ static void spi_setbits(FAR struct spi_dev_s *dev, int nbits)
#ifdef CONFIG_SPI_HWFEATURES
static int spi_hwfeatures(FAR struct spi_dev_s *dev, spi_hwfeatures_t features)
{
#ifdef CONFIG_SPI_BITORDER
#if defined(CONFIG_SPI_BITORDER) || defined(CONFIG_SPI_TRIGGER)
FAR struct stm32l4_spidev_s *priv = (FAR struct stm32l4_spidev_s *)dev;
#endif
#ifdef CONFIG_SPI_BITORDER
uint16_t setbits;
uint16_t clrbits;
@ -1209,12 +1228,23 @@ static int spi_hwfeatures(FAR struct spi_dev_s *dev, spi_hwfeatures_t features)
spi_modifycr(STM32L4_SPI_CR1_OFFSET, priv, setbits, clrbits);
spi_modifycr(STM32L4_SPI_CR1_OFFSET, priv, SPI_CR1_SPE, 0);
features &= ~HWFEAT_LSBFIRST;
#endif
#ifdef CONFIG_SPI_TRIGGER
/* Turn deferred trigger mode on or off. Only applicable for DMA mode. If a
* transfer is deferred then the DMA will not actually be triggered until a
* subsequent call to SPI_TRIGGER to set it off. The thread will be waiting
* on the transfer completing as normal.
*/
priv->defertrig = ((features & HWFEAT_TRIGGER) != 0);
features &= ~HWFEAT_TRIGGER;
#endif
/* Other H/W features are not supported */
return ((features & ~HWFEAT_LSBFIRST) == 0) ? OK : -ENOSYS;
#else
return -ENOSYS;
#endif
return (features == 0) ? OK : -ENOSYS;
}
#endif
@ -1430,19 +1460,78 @@ static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
spi_dmarxsetup(priv, rxbuffer, &rxdummy, nwords);
spi_dmatxsetup(priv, txbuffer, &txdummy, nwords);
#ifdef CONFIG_SPI_TRIGGER
/* Is deferred triggering in effect? */
if (!priv->defertrig)
{
/* No.. Start the DMAs */
spi_dmarxstart(priv);
spi_dmatxstart(priv);
}
else
{
/* Yes.. indicated that we are ready to be started */
priv->trigarmed = true;
}
#else
/* Start the DMAs */
spi_dmarxstart(priv);
spi_dmatxstart(priv);
#endif
/* Then wait for each to complete */
spi_dmarxwait(priv);
spi_dmatxwait(priv);
#ifdef CONFIG_SPI_TRIGGER
priv->trigarmed = false;
#endif
}
}
#endif /* CONFIG_STM32L4_SPI_DMA */
/****************************************************************************
* Name: spi_trigger
*
* Description:
* Trigger a previously configured DMA transfer.
*
* Input Parameters:
* dev - Device-specific state data
*
* Returned Value:
* OK - Trigger was fired
* ENOTSUP - Trigger not fired due to lack of DMA support
* EIO - Trigger not fired because not previously primed
*
****************************************************************************/
#ifdef CONFIG_SPI_TRIGGER
static int spi_trigger(FAR struct spi_dev_s *dev)
{
#ifdef CONFIG_STM32L4_SPI_DMA
FAR struct stm32_spidev_s *priv = (FAR struct stm32_spidev_s *)dev;
if (!priv->trigarmed)
{
return -EIO;
}
spi_dmarxstart(priv);
spi_dmatxstart(priv);
return OK;
#else
return -ENOSYS;
#endif
}
#endif
/****************************************************************************
* Name: spi_sndblock
*