1 /*
2  * Copyright (c) 2016 BayLibre, SAS
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_DRIVERS_SPI_SPI_LL_STM32_H_
8 #define ZEPHYR_DRIVERS_SPI_SPI_LL_STM32_H_
9 
10 #include "spi_context.h"
11 
12 typedef void (*irq_config_func_t)(const struct device *port);
13 
14 /* This symbol takes the value 1 if one of the device instances */
15 /* is configured in dts with a domain clock */
16 #if STM32_DT_INST_DEV_DOMAIN_CLOCK_SUPPORT
17 #define STM32_SPI_DOMAIN_CLOCK_SUPPORT 1
18 #else
19 #define STM32_SPI_DOMAIN_CLOCK_SUPPORT 0
20 #endif
21 
22 struct spi_stm32_config {
23 	SPI_TypeDef *spi;
24 	const struct pinctrl_dev_config *pcfg;
25 #ifdef CONFIG_SPI_STM32_INTERRUPT
26 	irq_config_func_t irq_config;
27 #endif
28 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_subghz)
29 	bool use_subghzspi_nss;
30 #endif
31 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
32 	int midi_clocks;
33 	int mssi_clocks;
34 #endif
35 	size_t pclk_len;
36 	const struct stm32_pclken *pclken;
37 	bool fifo_enabled;
38 };
39 
40 #ifdef CONFIG_SPI_STM32_DMA
41 
42 #define SPI_STM32_DMA_ERROR_FLAG	0x01
43 #define SPI_STM32_DMA_RX_DONE_FLAG	0x02
44 #define SPI_STM32_DMA_TX_DONE_FLAG	0x04
45 #define SPI_STM32_DMA_DONE_FLAG	\
46 	(SPI_STM32_DMA_RX_DONE_FLAG | SPI_STM32_DMA_TX_DONE_FLAG)
47 
48 #define SPI_STM32_DMA_TX	0x01
49 #define SPI_STM32_DMA_RX	0x02
50 
51 struct stream {
52 	const struct device *dma_dev;
53 	uint32_t channel; /* stores the channel for dma or mux */
54 	struct dma_config dma_cfg;
55 	struct dma_block_config dma_blk_cfg;
56 	uint8_t priority;
57 	bool src_addr_increment;
58 	bool dst_addr_increment;
59 	int fifo_threshold;
60 };
61 #endif
62 
63 struct spi_stm32_data {
64 	struct spi_context ctx;
65 #ifdef CONFIG_SPI_STM32_DMA
66 	struct k_sem status_sem;
67 	volatile uint32_t status_flags;
68 	struct stream dma_rx;
69 	struct stream dma_tx;
70 #endif /* CONFIG_SPI_STM32_DMA */
71 	bool pm_policy_state_on;
72 };
73 
74 #ifdef CONFIG_SPI_STM32_DMA
ll_func_dma_get_reg_addr(SPI_TypeDef * spi,uint32_t location)75 static inline uint32_t ll_func_dma_get_reg_addr(SPI_TypeDef *spi, uint32_t location)
76 {
77 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
78 	if (location == SPI_STM32_DMA_TX) {
79 		/* use direct register location until the LL_SPI_DMA_GetTxRegAddr exists */
80 		return (uint32_t)&(spi->TXDR);
81 	}
82 	/* use direct register location until the LL_SPI_DMA_GetRxRegAddr exists */
83 	return (uint32_t)&(spi->RXDR);
84 #else
85 	ARG_UNUSED(location);
86 	return (uint32_t)LL_SPI_DMA_GetRegAddr(spi);
87 #endif /* st_stm32h7_spi */
88 }
89 
90 /* checks that DMA Tx packet is fully transmitted over the SPI */
ll_func_spi_dma_busy(SPI_TypeDef * spi)91 static inline uint32_t ll_func_spi_dma_busy(SPI_TypeDef *spi)
92 {
93 #ifdef LL_SPI_SR_TXC
94 	return LL_SPI_IsActiveFlag_TXC(spi);
95 #else
96 	/* the SPI Tx empty and busy flags are needed */
97 	return (LL_SPI_IsActiveFlag_TXE(spi) &&
98 		!LL_SPI_IsActiveFlag_BSY(spi));
99 #endif /* LL_SPI_SR_TXC */
100 }
101 #endif /* CONFIG_SPI_STM32_DMA */
102 
ll_func_tx_is_not_full(SPI_TypeDef * spi)103 static inline uint32_t ll_func_tx_is_not_full(SPI_TypeDef *spi)
104 {
105 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
106 	return LL_SPI_IsActiveFlag_TXP(spi);
107 #else
108 	return LL_SPI_IsActiveFlag_TXE(spi);
109 #endif /* st_stm32h7_spi */
110 }
111 
ll_func_rx_is_not_empty(SPI_TypeDef * spi)112 static inline uint32_t ll_func_rx_is_not_empty(SPI_TypeDef *spi)
113 {
114 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
115 	return LL_SPI_IsActiveFlag_RXP(spi);
116 #else
117 	return LL_SPI_IsActiveFlag_RXNE(spi);
118 #endif /* st_stm32h7_spi */
119 }
120 
ll_func_enable_int_tx_empty(SPI_TypeDef * spi)121 static inline void ll_func_enable_int_tx_empty(SPI_TypeDef *spi)
122 {
123 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
124 	LL_SPI_EnableIT_TXP(spi);
125 #else
126 	LL_SPI_EnableIT_TXE(spi);
127 #endif /* st_stm32h7_spi */
128 }
129 
ll_func_enable_int_rx_not_empty(SPI_TypeDef * spi)130 static inline void ll_func_enable_int_rx_not_empty(SPI_TypeDef *spi)
131 {
132 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
133 	LL_SPI_EnableIT_RXP(spi);
134 #else
135 	LL_SPI_EnableIT_RXNE(spi);
136 #endif /* st_stm32h7_spi */
137 }
138 
ll_func_enable_int_errors(SPI_TypeDef * spi)139 static inline void ll_func_enable_int_errors(SPI_TypeDef *spi)
140 {
141 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
142 	LL_SPI_EnableIT_UDR(spi);
143 	LL_SPI_EnableIT_OVR(spi);
144 	LL_SPI_EnableIT_CRCERR(spi);
145 	LL_SPI_EnableIT_FRE(spi);
146 	LL_SPI_EnableIT_MODF(spi);
147 #else
148 	LL_SPI_EnableIT_ERR(spi);
149 #endif /* st_stm32h7_spi */
150 }
151 
ll_func_disable_int_tx_empty(SPI_TypeDef * spi)152 static inline void ll_func_disable_int_tx_empty(SPI_TypeDef *spi)
153 {
154 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
155 	LL_SPI_DisableIT_TXP(spi);
156 #else
157 	LL_SPI_DisableIT_TXE(spi);
158 #endif /* st_stm32h7_spi */
159 }
160 
ll_func_disable_int_rx_not_empty(SPI_TypeDef * spi)161 static inline void ll_func_disable_int_rx_not_empty(SPI_TypeDef *spi)
162 {
163 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
164 	LL_SPI_DisableIT_RXP(spi);
165 #else
166 	LL_SPI_DisableIT_RXNE(spi);
167 #endif /* st_stm32h7_spi */
168 }
169 
ll_func_disable_int_errors(SPI_TypeDef * spi)170 static inline void ll_func_disable_int_errors(SPI_TypeDef *spi)
171 {
172 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
173 	LL_SPI_DisableIT_UDR(spi);
174 	LL_SPI_DisableIT_OVR(spi);
175 	LL_SPI_DisableIT_CRCERR(spi);
176 	LL_SPI_DisableIT_FRE(spi);
177 	LL_SPI_DisableIT_MODF(spi);
178 #else
179 	LL_SPI_DisableIT_ERR(spi);
180 #endif /* st_stm32h7_spi */
181 }
182 
ll_func_spi_is_busy(SPI_TypeDef * spi)183 static inline uint32_t ll_func_spi_is_busy(SPI_TypeDef *spi)
184 {
185 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
186 	if (LL_SPI_GetTransferSize(spi) == 0) {
187 		return LL_SPI_IsActiveFlag_TXC(spi) == 0;
188 	} else {
189 		return LL_SPI_IsActiveFlag_EOT(spi) == 0;
190 	}
191 #else
192 	return LL_SPI_IsActiveFlag_BSY(spi);
193 #endif /* st_stm32h7_spi */
194 }
195 
196 /* Header is compiled first, this switch avoid the compiler to lookup for
197  * non-existing LL FIFO functions for SoC without SPI FIFO
198  */
199 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_fifo)
ll_func_set_fifo_threshold_8bit(SPI_TypeDef * spi)200 static inline void ll_func_set_fifo_threshold_8bit(SPI_TypeDef *spi)
201 {
202 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
203 	LL_SPI_SetFIFOThreshold(spi, LL_SPI_FIFO_TH_01DATA);
204 #else
205 	LL_SPI_SetRxFIFOThreshold(spi, LL_SPI_RX_FIFO_TH_QUARTER);
206 #endif /* st_stm32h7_spi */
207 }
208 
ll_func_set_fifo_threshold_16bit(SPI_TypeDef * spi)209 static inline void ll_func_set_fifo_threshold_16bit(SPI_TypeDef *spi)
210 {
211 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32h7_spi)
212 	LL_SPI_SetFIFOThreshold(spi, LL_SPI_FIFO_TH_02DATA);
213 #else
214 	LL_SPI_SetRxFIFOThreshold(spi, LL_SPI_RX_FIFO_TH_HALF);
215 #endif /* st_stm32h7_spi */
216 }
217 #endif /* st_stm32_spi_fifo */
218 
ll_func_disable_spi(SPI_TypeDef * spi)219 static inline void ll_func_disable_spi(SPI_TypeDef *spi)
220 {
221 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_fifo)
222 	/* Flush RX buffer */
223 	while (ll_func_rx_is_not_empty(spi)) {
224 		(void) LL_SPI_ReceiveData8(spi);
225 	}
226 #endif /* DT_HAS_COMPAT_STATUS_OKAY(st_stm32_spi_fifo) */
227 
228 	LL_SPI_Disable(spi);
229 
230 	while (LL_SPI_IsEnabled(spi)) {
231 		/* NOP */
232 	}
233 }
234 
235 #endif	/* ZEPHYR_DRIVERS_SPI_SPI_LL_STM32_H_ */
236