blob: f37f0b465648147457d69d8a5d6d139521bb72f4 [file] [log] [blame]
/*
* Copyright (c) 2016 BayLibre, SAS
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_DRIVERS_SPI_SPI_LL_STM32_H_
#define ZEPHYR_DRIVERS_SPI_SPI_LL_STM32_H_
#include "spi_context.h"
typedef void (*irq_config_func_t)(const struct device *port);
/* This symbol takes the value 1 if one of the device instances */
/* is configured in dts with a domain clock */
#if STM32_DT_INST_DEV_DOMAIN_CLOCK_SUPPORT
#define STM32_SPI_DOMAIN_CLOCK_SUPPORT 1
#else
#define STM32_SPI_DOMAIN_CLOCK_SUPPORT 0
#endif
struct spi_stm32_config {
SPI_TypeDef *spi;
const struct pinctrl_dev_config *pcfg;
#ifdef CONFIG_SPI_STM32_INTERRUPT
irq_config_func_t irq_config;
#endif
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_subghz)
bool use_subghzspi_nss;
#endif
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
int midi_clocks;
int mssi_clocks;
#endif
size_t pclk_len;
const struct stm32_pclken *pclken;
bool fifo_enabled;
};
#ifdef CONFIG_SPI_STM32_DMA
#define SPI_STM32_DMA_ERROR_FLAG 0x01
#define SPI_STM32_DMA_RX_DONE_FLAG 0x02
#define SPI_STM32_DMA_TX_DONE_FLAG 0x04
#define SPI_STM32_DMA_DONE_FLAG \
(SPI_STM32_DMA_RX_DONE_FLAG | SPI_STM32_DMA_TX_DONE_FLAG)
#define SPI_STM32_DMA_TX 0x01
#define SPI_STM32_DMA_RX 0x02
struct stream {
const struct device *dma_dev;
uint32_t channel; /* stores the channel for dma or mux */
struct dma_config dma_cfg;
struct dma_block_config dma_blk_cfg;
uint8_t priority;
bool src_addr_increment;
bool dst_addr_increment;
int fifo_threshold;
};
#endif
struct spi_stm32_data {
struct spi_context ctx;
#ifdef CONFIG_SPI_STM32_DMA
struct k_sem status_sem;
volatile uint32_t status_flags;
struct stream dma_rx;
struct stream dma_tx;
#endif /* CONFIG_SPI_STM32_DMA */
bool pm_policy_state_on;
};
#ifdef CONFIG_SPI_STM32_DMA
static inline uint32_t ll_func_dma_get_reg_addr(SPI_TypeDef *spi, uint32_t location)
{
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
if (location == SPI_STM32_DMA_TX) {
/* use direct register location until the LL_SPI_DMA_GetTxRegAddr exists */
return (uint32_t)&(spi->TXDR);
}
/* use direct register location until the LL_SPI_DMA_GetRxRegAddr exists */
return (uint32_t)&(spi->RXDR);
#else
ARG_UNUSED(location);
return (uint32_t)LL_SPI_DMA_GetRegAddr(spi);
#endif /* st_stm32h7_spi */
}
/* checks that DMA Tx packet is fully transmitted over the SPI */
static inline uint32_t ll_func_spi_dma_busy(SPI_TypeDef *spi)
{
#ifdef LL_SPI_SR_TXC
return LL_SPI_IsActiveFlag_TXC(spi);
#else
/* the SPI Tx empty and busy flags are needed */
return (LL_SPI_IsActiveFlag_TXE(spi) &&
!LL_SPI_IsActiveFlag_BSY(spi));
#endif /* LL_SPI_SR_TXC */
}
#endif /* CONFIG_SPI_STM32_DMA */
static inline uint32_t ll_func_tx_is_not_full(SPI_TypeDef *spi)
{
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
return LL_SPI_IsActiveFlag_TXP(spi);
#else
return LL_SPI_IsActiveFlag_TXE(spi);
#endif /* st_stm32h7_spi */
}
static inline uint32_t ll_func_rx_is_not_empty(SPI_TypeDef *spi)
{
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
return LL_SPI_IsActiveFlag_RXP(spi);
#else
return LL_SPI_IsActiveFlag_RXNE(spi);
#endif /* st_stm32h7_spi */
}
static inline void ll_func_enable_int_tx_empty(SPI_TypeDef *spi)
{
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
LL_SPI_EnableIT_TXP(spi);
#else
LL_SPI_EnableIT_TXE(spi);
#endif /* st_stm32h7_spi */
}
static inline void ll_func_enable_int_rx_not_empty(SPI_TypeDef *spi)
{
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
LL_SPI_EnableIT_RXP(spi);
#else
LL_SPI_EnableIT_RXNE(spi);
#endif /* st_stm32h7_spi */
}
static inline void ll_func_enable_int_errors(SPI_TypeDef *spi)
{
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
LL_SPI_EnableIT_UDR(spi);
LL_SPI_EnableIT_OVR(spi);
LL_SPI_EnableIT_CRCERR(spi);
LL_SPI_EnableIT_FRE(spi);
LL_SPI_EnableIT_MODF(spi);
#else
LL_SPI_EnableIT_ERR(spi);
#endif /* st_stm32h7_spi */
}
static inline void ll_func_disable_int_tx_empty(SPI_TypeDef *spi)
{
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
LL_SPI_DisableIT_TXP(spi);
#else
LL_SPI_DisableIT_TXE(spi);
#endif /* st_stm32h7_spi */
}
static inline void ll_func_disable_int_rx_not_empty(SPI_TypeDef *spi)
{
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
LL_SPI_DisableIT_RXP(spi);
#else
LL_SPI_DisableIT_RXNE(spi);
#endif /* st_stm32h7_spi */
}
static inline void ll_func_disable_int_errors(SPI_TypeDef *spi)
{
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
LL_SPI_DisableIT_UDR(spi);
LL_SPI_DisableIT_OVR(spi);
LL_SPI_DisableIT_CRCERR(spi);
LL_SPI_DisableIT_FRE(spi);
LL_SPI_DisableIT_MODF(spi);
#else
LL_SPI_DisableIT_ERR(spi);
#endif /* st_stm32h7_spi */
}
static inline uint32_t ll_func_spi_is_busy(SPI_TypeDef *spi)
{
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
if (LL_SPI_GetTransferSize(spi) == 0) {
return LL_SPI_IsActiveFlag_TXC(spi) == 0;
} else {
return LL_SPI_IsActiveFlag_EOT(spi) == 0;
}
#else
return LL_SPI_IsActiveFlag_BSY(spi);
#endif /* st_stm32h7_spi */
}
/* Header is compiled first, this switch avoid the compiler to lookup for
* non-existing LL FIFO functions for SoC without SPI FIFO
*/
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_fifo)
static inline void ll_func_set_fifo_threshold_8bit(SPI_TypeDef *spi)
{
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
LL_SPI_SetFIFOThreshold(spi, LL_SPI_FIFO_TH_01DATA);
#else
LL_SPI_SetRxFIFOThreshold(spi, LL_SPI_RX_FIFO_TH_QUARTER);
#endif /* st_stm32h7_spi */
}
static inline void ll_func_set_fifo_threshold_16bit(SPI_TypeDef *spi)
{
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
LL_SPI_SetFIFOThreshold(spi, LL_SPI_FIFO_TH_02DATA);
#else
LL_SPI_SetRxFIFOThreshold(spi, LL_SPI_RX_FIFO_TH_HALF);
#endif /* st_stm32h7_spi */
}
#endif /* st_stm32_spi_fifo */
static inline void ll_func_disable_spi(SPI_TypeDef *spi)
{
#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_fifo)
/* Flush RX buffer */
while (ll_func_rx_is_not_empty(spi)) {
(void) LL_SPI_ReceiveData8(spi);
}
#endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_fifo) */
LL_SPI_Disable(spi);
while (LL_SPI_IsEnabled(spi)) {
/* NOP */
}
}
#endif /* ZEPHYR_DRIVERS_SPI_SPI_LL_STM32_H_ */