aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/ports/SAMA/LLD/SPIv1
diff options
context:
space:
mode:
Diffstat (limited to 'os/hal/ports/SAMA/LLD/SPIv1')
-rw-r--r--os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c205
-rw-r--r--os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.h300
2 files changed, 397 insertions, 108 deletions
diff --git a/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c b/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c
index ccacf5e70..95625ca07 100644
--- a/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c
+++ b/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c
@@ -56,7 +56,6 @@
spip->SPI_WPMR = SPI_WPMR_WPKEY_PASSWD; \
}
-
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
@@ -114,8 +113,8 @@ SPIDriver FSPID4;
/* Driver local variables and types. */
/*===========================================================================*/
-static const uint8_t dummytx = 0xFFU;
-static uint8_t dummyrx;
+static const CACHE_ALIGNED uint8_t dummytx = 0xFFU;
+CACHE_ALIGNED static uint8_t dummyrx;
/*===========================================================================*/
/* Driver local functions. */
@@ -142,6 +141,13 @@ static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags) {
dmaChannelDisable(spip->dmatx);
dmaChannelDisable(spip->dmarx);
+#if (SAMA_SPI_CACHE_USER_MANAGED == FALSE)
+ /* D-Cache is enabled */
+ /* No operation for dummyrx */
+ if ((uint32_t) spip->rxbuf != (uint32_t) &dummyrx)
+ cacheInvalidateRegion(spip->rxbuf, spip->rxbytes);
+#endif
+
/* Portable SPI ISR code defined in the high level driver, note, it is
a macro.*/
_spi_isr_code(spip);
@@ -156,7 +162,6 @@ static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags) {
static void spi_lld_serve_tx_interrupt(SPIDriver *spip, uint32_t flags) {
/* DMA errors handling.*/
-
#if defined(SAMA_SPI_DMA_ERROR_HOOK)
(void)spip;
if ((flags & (XDMAC_CIS_WBEIS | XDMAC_CIS_ROIS)) != 0) {
@@ -189,6 +194,7 @@ void spi_lld_init(void) {
/* Driver initialization.*/
spiObjectInit(&SPID0);
SPID0.spi = SPI0;
+ SPID0.flexcom = NULL;
SPID0.dmarx = NULL;
SPID0.dmatx = NULL;
SPID0.rxdmamode = XDMAC_CC_TYPE_PER_TRAN |
@@ -222,6 +228,7 @@ void spi_lld_init(void) {
/* Driver initialization.*/
spiObjectInit(&SPID1);
SPID1.spi = SPI1;
+ SPID1.flexcom = NULL;
SPID1.dmarx = NULL;
SPID1.dmatx = NULL;
SPID1.rxdmamode = XDMAC_CC_TYPE_PER_TRAN |
@@ -443,6 +450,15 @@ void spi_lld_start(SPIDriver *spip) {
(sama_dmaisr_t)spi_lld_serve_tx_interrupt,
(void *)spip);
osalDbgAssert(spip->dmatx != NULL, "no channel allocated");
+
+#if SAMA_SPI0_USE_GCLK
+#if SAMA_SPI0_GCLK_DIV > 256
+ #error "SPI0 GCLK divider out of range"
+#endif
+ pmcConfigGclk(ID_SPI0, SAMA_SPI0_GCLK_SOURCE, SAMA_SPI0_GCLK_DIV);
+ pmcEnableGclk(ID_SPI0);
+#endif /* SAMA_SPI0_USE_GCLK */
+
/* Enable SPI0 clock */
pmcEnableSPI0();
}
@@ -458,6 +474,15 @@ void spi_lld_start(SPIDriver *spip) {
(sama_dmaisr_t)spi_lld_serve_tx_interrupt,
(void *)spip);
osalDbgAssert(spip->dmatx != NULL, "no channel allocated");
+
+#if SAMA_SPI1_USE_GCLK
+#if SAMA_SPI1_GCLK_DIV > 256
+ #error "SPI1 GCLK divider out of range"
+#endif
+ pmcConfigGclk(ID_SPI1, SAMA_SPI1_GCLK_SOURCE, SAMA_SPI1_GCLK_DIV);
+ pmcEnableGclk(ID_SPI1);
+#endif /* SAMA_SPI1_USE_GCLK */
+
/* Enable SPI1 clock */
pmcEnableSPI1();
}
@@ -475,6 +500,15 @@ void spi_lld_start(SPIDriver *spip) {
osalDbgAssert(spip->dmatx != NULL, "no channel allocated");
/* Enabling SPI on FLEXCOM */
spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI;
+
+#if SAMA_FSPI0_USE_GCLK
+#if SAMA_FSPI0_GCLK_DIV > 256
+ #error "FSPI0 GCLK divider out of range"
+#endif
+ pmcConfigGclk(ID_FLEXCOM0, SAMA_FSPI0_GCLK_SOURCE, SAMA_FSPI0_GCLK_DIV);
+ pmcEnableGclk(ID_FLEXCOM0);
+#endif /* SAMA_FSPI0_USE_GCLK */
+
/* Enable FLEXCOM0 clock */
pmcEnableFLEXCOM0();
}
@@ -492,6 +526,15 @@ void spi_lld_start(SPIDriver *spip) {
osalDbgAssert(spip->dmatx != NULL, "no channel allocated");
/* Enabling SPI on FLEXCOM */
spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI;
+
+#if SAMA_FSPI1_USE_GCLK
+#if SAMA_FSPI1_GCLK_DIV > 256
+ #error "FSPI1 GCLK divider out of range"
+#endif
+ pmcConfigGclk(ID_FLEXCOM1, SAMA_FSPI1_GCLK_SOURCE, SAMA_FSPI1_GCLK_DIV);
+ pmcEnableGclk(ID_FLEXCOM1);
+#endif /* SAMA_FSPI1_USE_GCLK */
+
/* Enable FLEXCOM1 clock */
pmcEnableFLEXCOM1();
}
@@ -509,6 +552,15 @@ void spi_lld_start(SPIDriver *spip) {
osalDbgAssert(spip->dmatx != NULL, "no channel allocated");
/* Enabling SPI on FLEXCOM */
spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI;
+
+#if SAMA_FSPI2_USE_GCLK
+#if SAMA_FSPI2_GCLK_DIV > 256
+ #error "FSPI2 GCLK divider out of range"
+#endif
+ pmcConfigGclk(ID_FLEXCOM2, SAMA_FSPI2_GCLK_SOURCE, SAMA_FSPI2_GCLK_DIV);
+ pmcEnableGclk(ID_FLEXCOM2);
+#endif /* SAMA_FSPI2_USE_GCLK */
+
/* Enable FLEXCOM2 clock */
pmcEnableFLEXCOM2();
}
@@ -526,6 +578,15 @@ void spi_lld_start(SPIDriver *spip) {
osalDbgAssert(spip->dmatx != NULL, "no channel allocated");
/* Enabling SPI on FLEXCOM */
spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI;
+
+#if SAMA_FSPI3_USE_GCLK
+#if SAMA_FSPI3_GCLK_DIV > 256
+ #error "FSPI3 GCLK divider out of range"
+#endif
+ pmcConfigGclk(ID_FLEXCOM3, SAMA_FSPI3_GCLK_SOURCE, SAMA_FSPI3_GCLK_DIV);
+ pmcEnableGclk(ID_FLEXCOM3);
+#endif /* SAMA_FSPI3_USE_GCLK */
+
/* Enable FLEXCOM3 clock */
pmcEnableFLEXCOM3();
}
@@ -543,7 +604,16 @@ void spi_lld_start(SPIDriver *spip) {
osalDbgAssert(spip->dmatx != NULL, "no channel allocated");
/* Enabling SPI on FLEXCOM */
spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI;
- /* Enable FLEXCOM4 clock */
+
+#if SAMA_FSPI4_USE_GCLK
+#if SAMA_FSPI4_GCLK_DIV > 256
+ #error "FSPI4 GCLK divider out of range"
+#endif
+ pmcConfigGclk(ID_FLEXCOM4, SAMA_FSPI4_GCLK_SOURCE, SAMA_FSPI4_GCLK_DIV);
+ pmcEnableGclk(ID_FLEXCOM4);
+#endif /* SAMA_FSPI4_USE_GCLK */
+
+ /* Enable FLEXCOM4 clock */
pmcEnableFLEXCOM4();
}
#endif /* SAMA_SPI_USE_FLEXCOM4 */
@@ -605,20 +675,32 @@ void spi_lld_stop(SPIDriver *spip) {
if (&SPID0 == spip)
/* Disable SPI0 clock */
pmcDisableSPI0();
+#if SAMA_SPI0_USE_GCLK
+ pmcDisableGclk(ID_SPI0);
+#endif /* SAMA_SPI0_USE_GCLK */
+
+#endif /* SAMA_SPI_USE_SPI0 */
-#endif /* SAMA_SPI_USE_SPI1 */
#if SAMA_SPI_USE_SPI1
if (&SPID1 == spip)
/* Disable SPI1 clock */
pmcDisableSPI1();
-#endif /* SAMA_SPI_USE_FLEXCOM0 */
+#if SAMA_SPI1_USE_GCLK
+ pmcDisableGclk(ID_SPI1);
+#endif /* SAMA_SPI1_USE_GCLK */
+
+#endif /* SAMA_SPI_USE_SPI1 */
#if SAMA_SPI_USE_FLEXCOM0
if (&FSPID0 == spip)
/* Disable FLEXCOM0 clock */
pmcDisableFLEXCOM0();
+#if SAMA_FSPI0_USE_GCLK
+ pmcDisableGclk(ID_FLEXCOM0);
+#endif /* SAMA_FSPI0_USE_GCLK */
+
#endif /* SAMA_SPI_USE_FLEXCOM0 */
#if SAMA_SPI_USE_FLEXCOM1
@@ -626,6 +708,10 @@ void spi_lld_stop(SPIDriver *spip) {
/* Disable FLEXCOM1 clock */
pmcDisableFLEXCOM1();
+#if SAMA_FSPI1_USE_GCLK
+ pmcDisableGclk(ID_FLEXCOM1);
+#endif /* SAMA_FSPI1_USE_GCLK */
+
#endif /* SAMA_SPI_USE_FLEXCOM1 */
#if SAMA_SPI_USE_FLEXCOM2
@@ -633,6 +719,10 @@ void spi_lld_stop(SPIDriver *spip) {
/* Disable FLEXCOM2 clock */
pmcDisableFLEXCOM2();
+#if SAMA_FSPI2_USE_GCLK
+ pmcDisableGclk(ID_FLEXCOM2);
+#endif /* SAMA_FSPI2_USE_GCLK */
+
#endif /* SAMA_SPI_USE_FLEXCOM2 */
#if SAMA_SPI_USE_FLEXCOM3
@@ -640,6 +730,10 @@ void spi_lld_stop(SPIDriver *spip) {
/* Disable FLEXCOM3 clock */
pmcDisableFLEXCOM3();
+#if SAMA_FSPI3_USE_GCLK
+ pmcDisableGclk(ID_FLEXCOM3);
+#endif /* SAMA_FSPI3_USE_GCLK */
+
#endif /* SAMA_SPI_USE_FLEXCOM3 */
#if SAMA_SPI_USE_FLEXCOM4
@@ -647,8 +741,16 @@ void spi_lld_stop(SPIDriver *spip) {
/* Disable FLEXCOM4 clock */
pmcDisableFLEXCOM4();
+#if SAMA_FSPI4_USE_GCLK
+ pmcDisableGclk(ID_FLEXCOM4);
+#endif /* SAMA_FSPI4_USE_GCLK */
+
#endif /* SAMA_SPI_USE_FLEXCOM4 */
}
+
+ spip->txbuf = NULL;
+ spip->rxbuf = NULL;
+ spip->rxbytes = 0;
}
#if (SPI_SELECT_MODE == (SPI_SELECT_MODE_LLD || SPI_SELECT_MODE_PAD || \
@@ -695,12 +797,35 @@ void spi_lld_unselect(SPIDriver *spip) {
void spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf) {
+ spip->txbuf = txbuf;
+ spip->rxbuf = rxbuf;
+ spip->rxbytes = n;
+
+#if (SAMA_SPI_CACHE_USER_MANAGED == FALSE)
+
+ osalDbgAssert(!((uint32_t) txbuf & (L1_CACHE_BYTES - 1)), "txbuf address not cache aligned");
+ osalDbgAssert(!((uint32_t) rxbuf & (L1_CACHE_BYTES - 1)), "rxbuf address not cache aligned");
+
+ /*
+ * If size is not multiple of cache line, clean cache region is required.
+ */
+ if (n & (L1_CACHE_BYTES - 1)) {
+ cacheCleanRegion((uint8_t *) rxbuf, n);
+ }
+ /* Cache is enabled */
+ cacheCleanRegion((uint8_t *) txbuf, n);
+#endif /* SAMA_SPI_CACHE_USER_MANAGED */
+
/* Writing channel */
+ /* Change mode to incremented address for dummytx */
+ dmaChannelSetMode(spip->dmatx, spip->txdmamode | XDMAC_CC_SAM_INCREMENTED_AM);
dmaChannelSetSource(spip->dmatx, txbuf);
dmaChannelSetDestination(spip->dmatx, &spip->spi->SPI_TDR);
dmaChannelSetTransactionSize(spip->dmatx, n);
/* Reading channel */
+ /* Change mode to incremented address */
+ dmaChannelSetMode(spip->dmarx, spip->rxdmamode | XDMAC_CC_DAM_INCREMENTED_AM);
dmaChannelSetSource(spip->dmarx, &spip->spi->SPI_RDR);
dmaChannelSetDestination(spip->dmarx, rxbuf);
dmaChannelSetTransactionSize(spip->dmarx, n);
@@ -724,17 +849,37 @@ void spi_lld_exchange(SPIDriver *spip, size_t n,
*/
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
+ spip->txbuf = txbuf;
+ spip->rxbuf = &dummyrx;
+ spip->rxbytes = n;
+
+#if (SAMA_SPI_CACHE_USER_MANAGED == FALSE)
+
+ osalDbgAssert(!((uint32_t) txbuf & (L1_CACHE_BYTES - 1)), "address not cache aligned");
+
+ /* Cache is enabled */
+ cacheCleanRegion((uint8_t *) txbuf, n);
+#endif /* SAMA_SPI_CACHE_USER_MANAGED */
+
/* Writing channel */
+
+ /* Change mode to incremented address for dummytx */
+ dmaChannelSetMode(spip->dmatx, spip->txdmamode | XDMAC_CC_SAM_INCREMENTED_AM);
+
dmaChannelSetSource(spip->dmatx, txbuf);
dmaChannelSetDestination(spip->dmatx, &spip->spi->SPI_TDR);
dmaChannelSetTransactionSize(spip->dmatx, n);
/* Reading channel */
+
+ /* Change mode from incremented to fixed address for dummyrx */
+ dmaChannelSetMode(spip->dmarx, spip->rxdmamode & ~XDMAC_CC_DAM_INCREMENTED_AM);
+
dmaChannelSetSource(spip->dmarx, &spip->spi->SPI_RDR);
dmaChannelSetDestination(spip->dmarx, &dummyrx);
dmaChannelSetTransactionSize(spip->dmarx, n);
- /* Enable write protection. */
+ /* Enable channel. */
dmaChannelEnable(spip->dmarx);
dmaChannelEnable(spip->dmatx);
@@ -759,12 +904,33 @@ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
*/
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
+ spip->rxbuf = rxbuf;
+ spip->rxbytes = n;
+
+#if (SAMA_SPI_CACHE_USER_MANAGED == FALSE)
+
+ osalDbgAssert(!((uint32_t) rxbuf & (L1_CACHE_BYTES - 1)), "address not cache aligned");
+
+ /*
+ * If size is not multiple of cache line, clean cache region is required.
+ */
+ if (n & (L1_CACHE_BYTES - 1)) {
+ cacheCleanRegion((uint8_t *) rxbuf, n);
+ }
+#endif /* SAMA_SPI_CACHE_USER_MANAGED */
+
/* Writing channel */
+ /* Change mode from incremented to fixed address for dummytx */
+ dmaChannelSetMode(spip->dmatx, spip->txdmamode & ~XDMAC_CC_SAM_INCREMENTED_AM);
+
dmaChannelSetSource(spip->dmatx, &dummytx);
dmaChannelSetDestination(spip->dmatx, &spip->spi->SPI_TDR);
dmaChannelSetTransactionSize(spip->dmatx, n);
/* Reading channel */
+ /* Change mode to incremented address */
+ dmaChannelSetMode(spip->dmarx, spip->rxdmamode | XDMAC_CC_DAM_INCREMENTED_AM);
+
dmaChannelSetSource(spip->dmarx, &spip->spi->SPI_RDR);
dmaChannelSetDestination(spip->dmarx, rxbuf);
dmaChannelSetTransactionSize(spip->dmarx, n);
@@ -773,6 +939,29 @@ void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
dmaChannelEnable(spip->dmatx);
}
+/**
+ * @brief Exchanges one frame using a polled wait.
+ * @details This synchronous function exchanges one frame using a polled
+ * synchronization method. This function is useful when exchanging
+ * small amount of data on high speed channels, usually in this
+ * situation is much more efficient just wait for completion using
+ * polling than suspending the thread waiting for an interrupt.
+ *
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] frame the data frame to send over the SPI bus
+ * @return The received data frame from the SPI bus.
+ */
+uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) {
+
+ while((spip->spi->SPI_SR & SPI_SR_TXEMPTY) == 1);
+
+ spip->spi->SPI_TDR = (uint8_t) frame;
+
+ while((spip->spi->SPI_SR & SPI_SR_RDRF) == 0);
+
+ return (uint16_t) spip->spi->SPI_RDR;
+}
+
#endif /* HAL_USE_SPI */
/** @} */
diff --git a/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.h b/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.h
index f9be8bdee..df448eaec 100644
--- a/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.h
+++ b/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.h
@@ -25,7 +25,7 @@
#ifndef HAL_SPI_LLD_H
#define HAL_SPI_LLD_H
-#if HAL_USE_SPI || defined(__DOXYGEN__)
+#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
@@ -53,15 +53,58 @@
#endif
/**
+ * @brief SPI0 Generic clock enable.
+ * @details If set to @p TRUE the support for GCLK SPI0 is included.
+ */
+#if !defined(SAMA_SPI0_USE_GCLK) || defined(__DOXYGEN__)
+#define SAMA_SPI0_USE_GCLK FALSE
+#endif
+
+/**
+ * @brief SPI0 Generic clock source.
+ */
+#if !defined(SAMA_SPI0_GCLK_SOURCE) || defined(__DOXYGEN__)
+#define SAMA_SPI0_GCLK_SOURCE SAMA_GCLK_MCK_CLK
+#endif
+
+/**
+ * @brief SPI0 Generic clock div.
+ */
+#if !defined(SAMA_SPI0_GCLK_DIV) || defined(__DOXYGEN__)
+#define SAMA_SPI0_GCLK_DIV 21
+#endif
+
+/**
* @brief SPI1 driver enable switch.
* @details If set to @p TRUE the support for SPI1 is included.
- * @note The default is @p FALSE.
*/
#if !defined(SAMA_SPI_USE_SPI1) || defined(__DOXYGEN__)
#define SAMA_SPI_USE_SPI1 FALSE
#endif
/**
+ * @brief SPI1 Generic clock enable.
+ * @details If set to @p TRUE the support for GCLK SPI1 is included.
+ */
+#if !defined(SAMA_SPI1_USE_GCLK) || defined(__DOXYGEN__)
+#define SAMA_SPI1_USE_GCLK FALSE
+#endif
+
+/**
+ * @brief SPI1 Generic clock source.
+ */
+#if !defined(SAMA_SPI1_GCLK_SOURCE) || defined(__DOXYGEN__)
+#define SAMA_SPI1_GCLK_SOURCE SAMA_GCLK_MCK_CLK
+#endif
+
+/**
+ * @brief SPI1 Generic clock div.
+ */
+#if !defined(SAMA_SPI1_GCLK_DIV) || defined(__DOXYGEN__)
+#define SAMA_SPI1_GCLK_DIV 21
+#endif
+
+/**
* @brief SPI FLEXCOM0 driver enable switch.
* @details If set to @p TRUE the support for FLEXCOM0 is included.
*/
@@ -70,6 +113,28 @@
#endif
/**
+ * @brief FSPI0 Generic clock enable.
+ * @details If set to @p TRUE the support for GCLK FSPI0 is included.
+ */
+#if !defined(SAMA_FSPI0_USE_GCLK) || defined(__DOXYGEN__)
+#define SAMA_FSPI0_USE_GCLK FALSE
+#endif
+
+/**
+ * @brief FSPI0 Generic clock source.
+ */
+#if !defined(SAMA_FSPI0_GCLK_SOURCE) || defined(__DOXYGEN__)
+#define SAMA_FSPI0_GCLK_SOURCE SAMA_GCLK_MCK_CLK
+#endif
+
+/**
+ * @brief FSPI0 Generic clock div.
+ */
+#if !defined(SAMA_FSPI0_GCLK_DIV) || defined(__DOXYGEN__)
+#define SAMA_FSPI0_GCLK_DIV 21
+#endif
+
+/**
* @brief SPI FLEXCOM1 driver enable switch.
* @details If set to @p TRUE the support for FLEXCOM1 is included.
*/
@@ -78,6 +143,28 @@
#endif
/**
+ * @brief FSPI1 Generic clock enable.
+ * @details If set to @p TRUE the support for GCLK FSPI1 is included.
+ */
+#if !defined(SAMA_FSPI1_USE_GCLK) || defined(__DOXYGEN__)
+#define SAMA_FSPI1_USE_GCLK FALSE
+#endif
+
+/**
+ * @brief FSPI1 Generic clock source.
+ */
+#if !defined(SAMA_FSPI1_GCLK_SOURCE) || defined(__DOXYGEN__)
+#define SAMA_FSPI1_GCLK_SOURCE SAMA_GCLK_MCK_CLK
+#endif
+
+/**
+ * @brief FSPI1 Generic clock div.
+ */
+#if !defined(SAMA_FSPI1_GCLK_DIV) || defined(__DOXYGEN__)
+#define SAMA_FSPI1_GCLK_DIV 21
+#endif
+
+/**
* @brief SPI FLEXCOM2 driver enable switch.
* @details If set to @p TRUE the support for FLEXCOM2 is included.
*/
@@ -86,6 +173,28 @@
#endif
/**
+ * @brief FSPI2 Generic clock enable.
+ * @details If set to @p TRUE the support for GCLK FSPI2 is included.
+ */
+#if !defined(SAMA_FSPI2_USE_GCLK) || defined(__DOXYGEN__)
+#define SAMA_FSPI2_USE_GCLK FALSE
+#endif
+
+/**
+ * @brief FSPI2 Generic clock source.
+ */
+#if !defined(SAMA_FSPI2_GCLK_SOURCE) || defined(__DOXYGEN__)
+#define SAMA_FSPI2_GCLK_SOURCE SAMA_GCLK_MCK_CLK
+#endif
+
+/**
+ * @brief FSPI2 Generic clock div.
+ */
+#if !defined(SAMA_FSPI2_GCLK_DIV) || defined(__DOXYGEN__)
+#define SAMA_FSPI2_GCLK_DIV 21
+#endif
+
+/**
* @brief SPI FLEXCOM3 driver enable switch.
* @details If set to @p TRUE the support for FLEXCOM3 is included.
*/
@@ -94,6 +203,28 @@
#endif
/**
+ * @brief FSPI3 Generic clock enable.
+ * @details If set to @p TRUE the support for GCLK FSPI3 is included.
+ */
+#if !defined(SAMA_FSPI3_USE_GCLK) || defined(__DOXYGEN__)
+#define SAMA_FSPI3_USE_GCLK FALSE
+#endif
+
+/**
+ * @brief FSPI3 Generic clock source.
+ */
+#if !defined(SAMA_FSPI3_GCLK_SOURCE) || defined(__DOXYGEN__)
+#define SAMA_FSPI3_GCLK_SOURCE SAMA_GCLK_MCK_CLK
+#endif
+
+/**
+ * @brief FSPI3 Generic clock div.
+ */
+#if !defined(SAMA_FSPI3_GCLK_DIV) || defined(__DOXYGEN__)
+#define SAMA_FSPI3_GCLK_DIV 21
+#endif
+
+/**
* @brief SPI FLEXCOM4 driver enable switch.
* @details If set to @p TRUE the support for FLEXCOM4 is included.
*/
@@ -102,6 +233,28 @@
#endif
/**
+ * @brief FSPI4 Generic clock enable.
+ * @details If set to @p TRUE the support for GCLK FSPI4 is included.
+ */
+#if !defined(SAMA_FSPI4_USE_GCLK) || defined(__DOXYGEN__)
+#define SAMA_FSPI4_USE_GCLK FALSE
+#endif
+
+/**
+ * @brief FSPI4 Generic clock source.
+ */
+#if !defined(SAMA_FSPI4_GCLK_SOURCE) || defined(__DOXYGEN__)
+#define SAMA_FSPI4_GCLK_SOURCE SAMA_GCLK_MCK_CLK
+#endif
+
+/**
+ * @brief FSPI4 Generic clock div.
+ */
+#if !defined(SAMA_FSPI4_GCLK_DIV) || defined(__DOXYGEN__)
+#define SAMA_FSPI4_GCLK_DIV 21
+#endif
+
+/**
* @brief SPI0 DMA interrupt priority level setting.
*/
#if !defined(SAMA_SPI_SPI0_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
@@ -151,6 +304,22 @@
#endif
/** @} */
+/**
+ * @brief SPI DMA error hook.
+ * @note The default action for DMA errors is a system halt because DMA
+ * error can only happen because programming errors.
+ */
+#if !defined(SAMA_SPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define SAMA_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure")
+#endif
+
+/**
+ * @brief SPI cache managing.
+ */
+#if !defined(SAMA_SPI_CACHE_USER_MANAGED) || defined(__DOXYGEN__)
+#define SAMA_SPI_CACHE_USER_MANAGED FALSE
+#endif
+
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
@@ -230,106 +399,36 @@
/* Driver data structures and types. */
/*===========================================================================*/
-/**
- * @brief Type of a structure representing an SPI driver.
- */
-typedef struct SPIDriver SPIDriver;
+#define spi_lld_driver_fields \
+ /* Pointer to the SPIx registers block.*/ \
+ Spi *spi; \
+ /* Pointer to the FLEXCOMx registers block.*/ \
+ Flexcom *flexcom; \
+ /* Receive DMA stream.*/ \
+ sama_dma_channel_t *dmarx; \
+ /* Transmit DMA stream.*/ \
+ sama_dma_channel_t *dmatx; \
+ /* RX DMA mode bit mask.*/ \
+ uint32_t rxdmamode; \
+ /* TX DMA mode bit mask.*/ \
+ uint32_t txdmamode; \
+ /* Pointer to the TX buffer location.*/ \
+ const uint8_t *txbuf; \
+ /* Pointer to the RX buffer location.*/ \
+ uint8_t *rxbuf; \
+ /* Number of bytes in RX phase.*/ \
+ size_t rxbytes;
/**
- * @brief SPI notification callback type.
- *
- * @param[in] spip pointer to the @p SPIDriver object triggering the
- * callback
- */
-typedef void (*spicallback_t)(SPIDriver *spip);
-
-/**
- * @brief Driver configuration structure.
- */
-typedef struct {
-#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__)
- /**
- * @brief Enables the circular buffer mode.
- */
- bool circular;
-#endif
- /**
- * @brief Operation complete callback or @p NULL.
- */
- spicallback_t end_cb;
- /* End of the mandatory fields.*/
- /**
- * @brief The chip select line number.
- */
- uint16_t npcs;
- /**
- * @brief SPI MR register initialization data.
- */
- uint32_t mr;
- /**
- * @brief SPI CSR register initialization data.
- */
+ * @brief Low level fields of the SPI configuration structure.
+ */
+#define spi_lld_config_fields \
+ /* The chip select line number.*/ \
+ uint8_t npcs; \
+ /* SPI MR register initialization data.*/ \
+ uint32_t mr; \
+ /* SPI CSR register initialization data.*/ \
uint32_t csr;
-} SPIConfig;
-
-/**
- * @brief Structure representing an SPI driver.
- * @note Implementations may extend this structure to contain more,
- * architecture dependent, fields.
- */
-struct SPIDriver {
- /**
- * @brief Driver state.
- */
- spistate_t state;
- /**
- * @brief Current configuration data.
- */
- const SPIConfig *config;
-#if SPI_USE_WAIT || defined(__DOXYGEN__)
- /**
- * @brief Waiting thread.
- */
- thread_reference_t thread;
-#endif /* SPI_USE_WAIT */
-#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
- /**
- * @brief Mutex protecting the bus.
- */
- mutex_t mutex;
-#endif /* SPI_USE_MUTUAL_EXCLUSION */
-#if defined(SPI_DRIVER_EXT_FIELDS)
- SPI_DRIVER_EXT_FIELDS
-#endif
- /* End of the mandatory fields.*/
- /**
- * @brief Pointer to the SPIx registers block.
- */
- Spi *spi;
-#if SAMA_SPI_USE_FLEXCOM
- /**
- * @brief Pointer to the FLEXCOMx registers block.
- */
- Flexcom *flexcom;
-#endif
- /**
- * @brief Receive DMA stream.
- */
- sama_dma_channel_t *dmarx;
- /**
- * @brief Transmit DMA stream.
- */
- sama_dma_channel_t *dmatx;
- /**
- * @brief RX DMA mode bit mask.
- */
- uint32_t rxdmamode;
- /**
- * @brief TX DMA mode bit mask.
- */
- uint32_t txdmamode;
-};
-
/*===========================================================================*/
/* Driver macros. */
@@ -371,7 +470,7 @@ extern SPIDriver FSPID4;
#ifdef __cplusplus
extern "C" {
#endif
-void spi_lld_init(void);
+ void spi_lld_init(void);
void spi_lld_start(SPIDriver *spip);
void spi_lld_stop(SPIDriver *spip);
void spi_lld_select(SPIDriver *spip);
@@ -381,6 +480,7 @@ void spi_lld_init(void);
const void *txbuf, void *rxbuf);
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf);
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf);
+ uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame);
#ifdef __cplusplus
}