1 /*
2 * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7
8 #include <string.h>
9 #include "sdkconfig.h"
10 #include "stdatomic.h"
11 #include "esp_types.h"
12 #include "esp_attr.h"
13 #include "esp_check.h"
14 #include "esp_rom_gpio.h"
15 #include "esp_heap_caps.h"
16 #include "soc/lldesc.h"
17 #include "soc/spi_periph.h"
18 #include "driver/gpio.h"
19 #include "driver/spi_master.h"
20 #include "esp_private/periph_ctrl.h"
21 #include "esp_private/spi_common_internal.h"
22 #include "hal/spi_hal.h"
23 #include "hal/gpio_hal.h"
24 #if CONFIG_IDF_TARGET_ESP32
25 #include "soc/dport_reg.h"
26 #endif
27 #if SOC_GDMA_SUPPORTED
28 #include "esp_private/gdma.h"
29 #endif
30
31 static const char *SPI_TAG = "spi";
32
33 #define SPI_CHECK(a, str, ret_val) ESP_RETURN_ON_FALSE(a, ret_val, SPI_TAG, str)
34
35 #define SPI_CHECK_PIN(pin_num, pin_name, check_output) if (check_output) { \
36 SPI_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(pin_num), pin_name" not valid", ESP_ERR_INVALID_ARG); \
37 } else { \
38 SPI_CHECK(GPIO_IS_VALID_GPIO(pin_num), pin_name" not valid", ESP_ERR_INVALID_ARG); \
39 }
40
41 #define SPI_MAIN_BUS_DEFAULT() { \
42 .host_id = 0, \
43 .bus_attr = { \
44 .tx_dma_chan = 0, \
45 .rx_dma_chan = 0, \
46 .max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE, \
47 .dma_desc_num= 0, \
48 }, \
49 }
50
51 #define FUNC_GPIO PIN_FUNC_GPIO
52
53
54 typedef struct {
55 int host_id;
56 spi_destroy_func_t destroy_func;
57 void* destroy_arg;
58 spi_bus_attr_t bus_attr;
59 #if SOC_GDMA_SUPPORTED
60 gdma_channel_handle_t tx_channel;
61 gdma_channel_handle_t rx_channel;
62 #endif
63 } spicommon_bus_context_t;
64
65 //Periph 1 is 'claimed' by SPI flash code.
66 static atomic_bool spi_periph_claimed[SOC_SPI_PERIPH_NUM] = { ATOMIC_VAR_INIT(true), ATOMIC_VAR_INIT(false),
67 #if (SOC_SPI_PERIPH_NUM >= 3)
68 ATOMIC_VAR_INIT(false),
69 #endif
70 #if (SOC_SPI_PERIPH_NUM >= 4)
71 ATOMIC_VAR_INIT(false),
72 #endif
73 };
74
75 static const char* spi_claiming_func[3] = {NULL, NULL, NULL};
76 static spicommon_bus_context_t s_mainbus = SPI_MAIN_BUS_DEFAULT();
77 static spicommon_bus_context_t* bus_ctx[SOC_SPI_PERIPH_NUM] = {&s_mainbus};
78
79 #if !SOC_GDMA_SUPPORTED
80 //Each bit stands for 1 dma channel, BIT(0) should be used for SPI1
81 static uint8_t spi_dma_chan_enabled = 0;
82 static portMUX_TYPE spi_dma_spinlock = portMUX_INITIALIZER_UNLOCKED;
83 #endif //#if !SOC_GDMA_SUPPORTED
84
85
is_valid_host(spi_host_device_t host)86 static inline bool is_valid_host(spi_host_device_t host)
87 {
88 #if (SOC_SPI_PERIPH_NUM == 2)
89 return host >= SPI1_HOST && host <= SPI2_HOST;
90 #elif (SOC_SPI_PERIPH_NUM == 3)
91 return host >= SPI1_HOST && host <= SPI3_HOST;
92 #endif
93 }
94
95 //----------------------------------------------------------alloc spi periph-------------------------------------------------------//
96 //Returns true if this peripheral is successfully claimed, false if otherwise.
spicommon_periph_claim(spi_host_device_t host,const char * source)97 bool spicommon_periph_claim(spi_host_device_t host, const char* source)
98 {
99 bool false_var = false;
100 bool ret = atomic_compare_exchange_strong(&spi_periph_claimed[host], &false_var, true);
101 if (ret) {
102 spi_claiming_func[host] = source;
103 periph_module_enable(spi_periph_signal[host].module);
104 } else {
105 ESP_EARLY_LOGE(SPI_TAG, "SPI%d already claimed by %s.", host+1, spi_claiming_func[host]);
106 }
107 return ret;
108 }
109
spicommon_periph_in_use(spi_host_device_t host)110 bool spicommon_periph_in_use(spi_host_device_t host)
111 {
112 return atomic_load(&spi_periph_claimed[host]);
113 }
114
115 //Returns true if this peripheral is successfully freed, false if otherwise.
spicommon_periph_free(spi_host_device_t host)116 bool spicommon_periph_free(spi_host_device_t host)
117 {
118 bool true_var = true;
119 bool ret = atomic_compare_exchange_strong(&spi_periph_claimed[host], &true_var, false);
120 if (ret) periph_module_disable(spi_periph_signal[host].module);
121 return ret;
122 }
123
spicommon_irqsource_for_host(spi_host_device_t host)124 int spicommon_irqsource_for_host(spi_host_device_t host)
125 {
126 return spi_periph_signal[host].irq;
127 }
128
spicommon_irqdma_source_for_host(spi_host_device_t host)129 int spicommon_irqdma_source_for_host(spi_host_device_t host)
130 {
131 return spi_periph_signal[host].irq_dma;
132 }
133
134 //----------------------------------------------------------alloc dma periph-------------------------------------------------------//
135 #if !SOC_GDMA_SUPPORTED
get_dma_periph(int dma_chan)136 static inline periph_module_t get_dma_periph(int dma_chan)
137 {
138 assert(dma_chan >= 1 && dma_chan <= SOC_SPI_DMA_CHAN_NUM);
139 #if CONFIG_IDF_TARGET_ESP32S2
140 if (dma_chan == 1) {
141 return PERIPH_SPI2_DMA_MODULE;
142 } else if (dma_chan == 2) {
143 return PERIPH_SPI3_DMA_MODULE;
144 } else {
145 abort();
146 }
147 #elif CONFIG_IDF_TARGET_ESP32
148 return PERIPH_SPI_DMA_MODULE;
149 #endif
150 }
151
claim_dma_chan(int dma_chan,uint32_t * out_actual_dma_chan)152 static bool claim_dma_chan(int dma_chan, uint32_t *out_actual_dma_chan)
153 {
154 bool ret = false;
155
156 portENTER_CRITICAL(&spi_dma_spinlock);
157 bool is_used = (BIT(dma_chan) & spi_dma_chan_enabled);
158 if (!is_used) {
159 spi_dma_chan_enabled |= BIT(dma_chan);
160 periph_module_enable(get_dma_periph(dma_chan));
161 *out_actual_dma_chan = dma_chan;
162 ret = true;
163 }
164 portEXIT_CRITICAL(&spi_dma_spinlock);
165
166 return ret;
167 }
168
connect_spi_and_dma(spi_host_device_t host,int dma_chan)169 static void connect_spi_and_dma(spi_host_device_t host, int dma_chan)
170 {
171 #if CONFIG_IDF_TARGET_ESP32
172 DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, dma_chan, (host * 2));
173 #elif CONFIG_IDF_TARGET_ESP32S2
174 //On ESP32S2, each SPI controller has its own DMA channel. So there is no need to connect them.
175 #endif
176 }
177
alloc_dma_chan(spi_host_device_t host_id,spi_dma_chan_t dma_chan,uint32_t * out_actual_tx_dma_chan,uint32_t * out_actual_rx_dma_chan)178 static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_chan, uint32_t *out_actual_tx_dma_chan, uint32_t *out_actual_rx_dma_chan)
179 {
180 assert(is_valid_host(host_id));
181 #if CONFIG_IDF_TARGET_ESP32
182 assert(dma_chan > SPI_DMA_DISABLED && dma_chan <= SPI_DMA_CH_AUTO);
183 #elif CONFIG_IDF_TARGET_ESP32S2
184 assert(dma_chan == (int)host_id || dma_chan == SPI_DMA_CH_AUTO);
185 #endif
186
187 esp_err_t ret = ESP_OK;
188 bool success = false;
189 uint32_t actual_dma_chan = 0;
190
191 if (dma_chan == SPI_DMA_CH_AUTO) {
192 #if CONFIG_IDF_TARGET_ESP32
193 for (int i = 1; i < SOC_SPI_DMA_CHAN_NUM+1; i++) {
194 success = claim_dma_chan(i, &actual_dma_chan);
195 if (success) {
196 break;
197 }
198 }
199 #elif CONFIG_IDF_TARGET_ESP32S2
200 //On ESP32S2, each SPI controller has its own DMA channel
201 success = claim_dma_chan(host_id, &actual_dma_chan);
202 #endif //#if CONFIG_IDF_TARGET_XXX
203 } else {
204 success = claim_dma_chan((int)dma_chan, &actual_dma_chan);
205 }
206
207 //On ESP32 and ESP32S2, actual_tx_dma_chan and actual_rx_dma_chan are always same
208 *out_actual_tx_dma_chan = actual_dma_chan;
209 *out_actual_rx_dma_chan = actual_dma_chan;
210
211 if (!success) {
212 SPI_CHECK(false, "no available dma channel", ESP_ERR_NOT_FOUND);
213 }
214
215 connect_spi_and_dma(host_id, *out_actual_tx_dma_chan);
216
217 return ret;
218 }
219
220 #else //SOC_GDMA_SUPPORTED
alloc_dma_chan(spi_host_device_t host_id,spi_dma_chan_t dma_chan,uint32_t * out_actual_tx_dma_chan,uint32_t * out_actual_rx_dma_chan)221 static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_chan, uint32_t *out_actual_tx_dma_chan, uint32_t *out_actual_rx_dma_chan)
222 {
223 assert(is_valid_host(host_id));
224 assert(dma_chan == SPI_DMA_CH_AUTO);
225
226 esp_err_t ret = ESP_OK;
227 spicommon_bus_context_t *ctx = bus_ctx[host_id];
228
229 if (dma_chan == SPI_DMA_CH_AUTO) {
230 gdma_channel_alloc_config_t tx_alloc_config = {
231 .flags.reserve_sibling = 1,
232 .direction = GDMA_CHANNEL_DIRECTION_TX,
233 };
234 ret = gdma_new_channel(&tx_alloc_config, &ctx->tx_channel);
235 if (ret != ESP_OK) {
236 return ret;
237 }
238
239 gdma_channel_alloc_config_t rx_alloc_config = {
240 .direction = GDMA_CHANNEL_DIRECTION_RX,
241 .sibling_chan = ctx->tx_channel,
242 };
243 ret = gdma_new_channel(&rx_alloc_config, &ctx->rx_channel);
244 if (ret != ESP_OK) {
245 return ret;
246 }
247
248 if (host_id == SPI2_HOST) {
249 gdma_connect(ctx->rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 2));
250 gdma_connect(ctx->tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 2));
251 }
252 #if (SOC_SPI_PERIPH_NUM >= 3)
253 else if (host_id == SPI3_HOST) {
254 gdma_connect(ctx->rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 3));
255 gdma_connect(ctx->tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 3));
256 }
257 #endif
258 gdma_get_channel_id(ctx->tx_channel, (int *)out_actual_tx_dma_chan);
259 gdma_get_channel_id(ctx->rx_channel, (int *)out_actual_rx_dma_chan);
260 }
261
262 return ret;
263 }
264 #endif //#if !SOC_GDMA_SUPPORTED
265
spicommon_dma_chan_alloc(spi_host_device_t host_id,spi_dma_chan_t dma_chan,uint32_t * out_actual_tx_dma_chan,uint32_t * out_actual_rx_dma_chan)266 esp_err_t spicommon_dma_chan_alloc(spi_host_device_t host_id, spi_dma_chan_t dma_chan, uint32_t *out_actual_tx_dma_chan, uint32_t *out_actual_rx_dma_chan)
267 {
268 assert(is_valid_host(host_id));
269 #if CONFIG_IDF_TARGET_ESP32
270 assert(dma_chan > SPI_DMA_DISABLED && dma_chan <= SPI_DMA_CH_AUTO);
271 #elif CONFIG_IDF_TARGET_ESP32S2
272 assert(dma_chan == (int)host_id || dma_chan == SPI_DMA_CH_AUTO);
273 #endif
274
275 esp_err_t ret = ESP_OK;
276 uint32_t actual_tx_dma_chan = 0;
277 uint32_t actual_rx_dma_chan = 0;
278 spicommon_bus_context_t *ctx = (spicommon_bus_context_t *)calloc(1, sizeof(spicommon_bus_context_t));
279 if (!ctx) {
280 ret = ESP_ERR_NO_MEM;
281 goto cleanup;
282 }
283 bus_ctx[host_id] = ctx;
284 ctx->host_id = host_id;
285
286 ret = alloc_dma_chan(host_id, dma_chan, &actual_tx_dma_chan, &actual_rx_dma_chan);
287 if (ret != ESP_OK) {
288 goto cleanup;
289 }
290 ctx->bus_attr.tx_dma_chan = actual_tx_dma_chan;
291 ctx->bus_attr.rx_dma_chan = actual_rx_dma_chan;
292 *out_actual_tx_dma_chan = actual_tx_dma_chan;
293 *out_actual_rx_dma_chan = actual_rx_dma_chan;
294
295 return ret;
296
297 cleanup:
298 free(ctx);
299 ctx = NULL;
300 return ret;
301 }
302
303 #if SOC_GDMA_SUPPORTED
spicommon_gdma_get_handle(spi_host_device_t host_id,gdma_channel_handle_t * gdma_handle,gdma_channel_direction_t gdma_direction)304 esp_err_t spicommon_gdma_get_handle(spi_host_device_t host_id, gdma_channel_handle_t *gdma_handle, gdma_channel_direction_t gdma_direction)
305 {
306 assert(is_valid_host(host_id));
307 ESP_RETURN_ON_FALSE((gdma_direction == GDMA_CHANNEL_DIRECTION_TX) || \
308 (gdma_direction == GDMA_CHANNEL_DIRECTION_RX), \
309 ESP_ERR_INVALID_ARG, SPI_TAG, "GDMA Direction not supported!");
310
311
312 if (gdma_direction == GDMA_CHANNEL_DIRECTION_TX) {
313 *gdma_handle = bus_ctx[host_id]->tx_channel;
314 }
315 if (gdma_direction == GDMA_CHANNEL_DIRECTION_RX) {
316 *gdma_handle = bus_ctx[host_id]->rx_channel;
317 }
318 return ESP_OK;
319 }
320 #endif // SOC_GDMA_SUPPORTED
321
322 //----------------------------------------------------------free dma periph-------------------------------------------------------//
dma_chan_free(spi_host_device_t host_id)323 static esp_err_t dma_chan_free(spi_host_device_t host_id)
324 {
325 assert(is_valid_host(host_id));
326
327 spicommon_bus_context_t *ctx = bus_ctx[host_id];
328 #if !SOC_GDMA_SUPPORTED
329 //On ESP32S2, each SPI controller has its own DMA channel
330 int dma_chan = ctx->bus_attr.tx_dma_chan;
331 assert(spi_dma_chan_enabled & BIT(dma_chan));
332
333 portENTER_CRITICAL(&spi_dma_spinlock);
334 spi_dma_chan_enabled &= ~BIT(dma_chan);
335 periph_module_disable(get_dma_periph(dma_chan));
336 portEXIT_CRITICAL(&spi_dma_spinlock);
337
338 #else //SOC_GDMA_SUPPORTED
339 if (ctx->rx_channel) {
340 gdma_disconnect(ctx->rx_channel);
341 gdma_del_channel(ctx->rx_channel);
342 }
343 if (ctx->tx_channel) {
344 gdma_disconnect(ctx->tx_channel);
345 gdma_del_channel(ctx->tx_channel);
346 }
347 #endif
348
349 return ESP_OK;
350 }
351
spicommon_dma_chan_free(spi_host_device_t host_id)352 esp_err_t spicommon_dma_chan_free(spi_host_device_t host_id)
353 {
354 assert(is_valid_host(host_id));
355
356 esp_err_t ret = dma_chan_free(host_id);
357 free(bus_ctx[host_id]);
358 bus_ctx[host_id] = NULL;
359
360 return ret;
361 }
362
363 //----------------------------------------------------------IO general-------------------------------------------------------//
364 #if SOC_SPI_SUPPORT_OCT
check_iomux_pins_oct(spi_host_device_t host,const spi_bus_config_t * bus_config)365 static bool check_iomux_pins_oct(spi_host_device_t host, const spi_bus_config_t* bus_config)
366 {
367 if (host != SPI2_HOST) {
368 return false;
369 }
370 int io_nums[] = {bus_config->data0_io_num, bus_config->data1_io_num, bus_config->data2_io_num, bus_config->data3_io_num,
371 bus_config->sclk_io_num, bus_config->data4_io_num, bus_config->data5_io_num, bus_config->data6_io_num, bus_config->data7_io_num};
372 int io_mux_nums[] = {SPI2_IOMUX_PIN_NUM_MOSI_OCT, SPI2_IOMUX_PIN_NUM_MISO_OCT, SPI2_IOMUX_PIN_NUM_WP_OCT, SPI2_IOMUX_PIN_NUM_HD_OCT,
373 SPI2_IOMUX_PIN_NUM_CLK_OCT, SPI2_IOMUX_PIN_NUM_IO4_OCT, SPI2_IOMUX_PIN_NUM_IO5_OCT, SPI2_IOMUX_PIN_NUM_IO6_OCT, SPI2_IOMUX_PIN_NUM_IO7_OCT};
374 for (size_t i = 0; i < sizeof(io_nums)/sizeof(io_nums[0]); i++) {
375 if (io_nums[i] >= 0 && io_nums[i] != io_mux_nums[i]) {
376 return false;
377 }
378 }
379 return true;
380 }
381 #endif
382
check_iomux_pins_quad(spi_host_device_t host,const spi_bus_config_t * bus_config)383 static bool check_iomux_pins_quad(spi_host_device_t host, const spi_bus_config_t* bus_config)
384 {
385 if (bus_config->sclk_io_num>=0 &&
386 bus_config->sclk_io_num != spi_periph_signal[host].spiclk_iomux_pin) {
387 return false;
388 }
389 if (bus_config->quadwp_io_num>=0 &&
390 bus_config->quadwp_io_num != spi_periph_signal[host].spiwp_iomux_pin) {
391 return false;
392 }
393 if (bus_config->quadhd_io_num>=0 &&
394 bus_config->quadhd_io_num != spi_periph_signal[host].spihd_iomux_pin) {
395 return false;
396 }
397 if (bus_config->mosi_io_num >= 0 &&
398 bus_config->mosi_io_num != spi_periph_signal[host].spid_iomux_pin) {
399 return false;
400 }
401 if (bus_config->miso_io_num>=0 &&
402 bus_config->miso_io_num != spi_periph_signal[host].spiq_iomux_pin) {
403 return false;
404 }
405 return true;
406 }
407
bus_uses_iomux_pins(spi_host_device_t host,const spi_bus_config_t * bus_config)408 static bool bus_uses_iomux_pins(spi_host_device_t host, const spi_bus_config_t* bus_config)
409 {
410 //Check if SPI pins could be routed to iomux.
411 #if SOC_SPI_SUPPORT_OCT
412 //The io mux pins available for Octal mode is not the same as the ones we use for non-Octal mode.
413 if ((bus_config->flags & SPICOMMON_BUSFLAG_OCTAL) == SPICOMMON_BUSFLAG_OCTAL) {
414 return check_iomux_pins_oct(host, bus_config);
415 }
416 #endif
417 return check_iomux_pins_quad(host, bus_config);
418 }
419
420 #if SOC_SPI_SUPPORT_OCT
bus_iomux_pins_set_oct(spi_host_device_t host,const spi_bus_config_t * bus_config)421 static void bus_iomux_pins_set_oct(spi_host_device_t host, const spi_bus_config_t* bus_config)
422 {
423 assert(host == SPI2_HOST);
424 int io_nums[] = {bus_config->data0_io_num, bus_config->data1_io_num, bus_config->data2_io_num, bus_config->data3_io_num,
425 bus_config->sclk_io_num, bus_config->data4_io_num, bus_config->data5_io_num, bus_config->data6_io_num, bus_config->data7_io_num};
426 int io_signals[] = {spi_periph_signal[host].spid_in, spi_periph_signal[host].spiq_in, spi_periph_signal[host].spiwp_in,
427 spi_periph_signal[host].spihd_in,spi_periph_signal[host].spiclk_in, spi_periph_signal[host].spid4_out,
428 spi_periph_signal[host].spid5_out, spi_periph_signal[host].spid6_out, spi_periph_signal[host].spid7_out};
429 for (size_t i = 0; i < sizeof(io_nums)/sizeof(io_nums[0]); i++) {
430 if (io_nums[i] > 0) {
431 gpio_iomux_in(io_nums[i], io_signals[i]);
432 // In Octal mode use function channel 2
433 gpio_iomux_out(io_nums[i], SPI2_FUNC_NUM_OCT, false);
434 }
435 }
436 }
437 #endif //SOC_SPI_SUPPORT_OCT
438
bus_iomux_pins_set_quad(spi_host_device_t host,const spi_bus_config_t * bus_config)439 static void bus_iomux_pins_set_quad(spi_host_device_t host, const spi_bus_config_t* bus_config)
440 {
441 if (bus_config->mosi_io_num >= 0) {
442 gpio_iomux_in(bus_config->mosi_io_num, spi_periph_signal[host].spid_in);
443 gpio_iomux_out(bus_config->mosi_io_num, spi_periph_signal[host].func, false);
444 }
445 if (bus_config->miso_io_num >= 0) {
446 gpio_iomux_in(bus_config->miso_io_num, spi_periph_signal[host].spiq_in);
447 gpio_iomux_out(bus_config->miso_io_num, spi_periph_signal[host].func, false);
448 }
449 if (bus_config->quadwp_io_num >= 0) {
450 gpio_iomux_in(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_in);
451 gpio_iomux_out(bus_config->quadwp_io_num, spi_periph_signal[host].func, false);
452 }
453 if (bus_config->quadhd_io_num >= 0) {
454 gpio_iomux_in(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_in);
455 gpio_iomux_out(bus_config->quadhd_io_num, spi_periph_signal[host].func, false);
456 }
457 if (bus_config->sclk_io_num >= 0) {
458 gpio_iomux_in(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_in);
459 gpio_iomux_out(bus_config->sclk_io_num, spi_periph_signal[host].func, false);
460 }
461 }
462
bus_iomux_pins_set(spi_host_device_t host,const spi_bus_config_t * bus_config)463 static void bus_iomux_pins_set(spi_host_device_t host, const spi_bus_config_t* bus_config)
464 {
465 #if SOC_SPI_SUPPORT_OCT
466 if ((bus_config->flags & SPICOMMON_BUSFLAG_OCTAL) == SPICOMMON_BUSFLAG_OCTAL) {
467 bus_iomux_pins_set_oct(host, bus_config);
468 return;
469 }
470 #endif
471 bus_iomux_pins_set_quad(host, bus_config);
472 }
473
474 /*
475 Do the common stuff to hook up a SPI host to a bus defined by a bunch of GPIO pins. Feed it a host number and a
476 bus config struct and it'll set up the GPIO matrix and enable the device. If a pin is set to non-negative value,
477 it should be able to be initialized.
478 */
spicommon_bus_initialize_io(spi_host_device_t host,const spi_bus_config_t * bus_config,uint32_t flags,uint32_t * flags_o)479 esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, uint32_t flags, uint32_t* flags_o)
480 {
481 #if SOC_SPI_SUPPORT_OCT
482 // In the driver of previous version, spi data4 ~ spi data7 are not in spi_bus_config_t struct. So the new-added pins come as 0
483 // if they are not really set. Add this boolean variable to check if the user has set spi data4 ~spi data7 pins .
484 bool io4_7_is_blank = !bus_config->data4_io_num && !bus_config->data5_io_num && !bus_config->data6_io_num && !bus_config->data7_io_num;
485 // This boolean variable specifies if user sets pins used for octal mode (users can set spi data4 ~ spi data7 to -1).
486 bool io4_7_enabled = !io4_7_is_blank && bus_config->data4_io_num >= 0 && bus_config->data5_io_num >= 0 &&
487 bus_config->data6_io_num >= 0 && bus_config->data7_io_num >= 0;
488 SPI_CHECK((flags & SPICOMMON_BUSFLAG_MASTER) || !((flags & SPICOMMON_BUSFLAG_OCTAL) == SPICOMMON_BUSFLAG_OCTAL), "Octal SPI mode / OPI mode only works when SPI is used as Master", ESP_ERR_INVALID_ARG);
489 SPI_CHECK(host == SPI2_HOST || !((flags & SPICOMMON_BUSFLAG_OCTAL) == SPICOMMON_BUSFLAG_OCTAL), "Only SPI2 supports Octal SPI mode / OPI mode", ESP_ERR_INVALID_ARG);
490 #endif //SOC_SPI_SUPPORT_OCT
491
492 uint32_t temp_flag = 0;
493
494 bool miso_need_output;
495 bool mosi_need_output;
496 bool sclk_need_output;
497 if ((flags&SPICOMMON_BUSFLAG_MASTER) != 0) {
498 //initial for master
499 miso_need_output = ((flags&SPICOMMON_BUSFLAG_DUAL) != 0) ? true : false;
500 mosi_need_output = true;
501 sclk_need_output = true;
502 } else {
503 //initial for slave
504 miso_need_output = true;
505 mosi_need_output = ((flags&SPICOMMON_BUSFLAG_DUAL) != 0) ? true : false;
506 sclk_need_output = false;
507 }
508
509 const bool wp_need_output = true;
510 const bool hd_need_output = true;
511
512 //check pin capabilities
513 if (bus_config->sclk_io_num>=0) {
514 temp_flag |= SPICOMMON_BUSFLAG_SCLK;
515 SPI_CHECK_PIN(bus_config->sclk_io_num, "sclk", sclk_need_output);
516 }
517 if (bus_config->quadwp_io_num>=0) {
518 SPI_CHECK_PIN(bus_config->quadwp_io_num, "wp", wp_need_output);
519 }
520 if (bus_config->quadhd_io_num>=0) {
521 SPI_CHECK_PIN(bus_config->quadhd_io_num, "hd", hd_need_output);
522 }
523 #if SOC_SPI_SUPPORT_OCT
524 const bool io4_need_output = true;
525 const bool io5_need_output = true;
526 const bool io6_need_output = true;
527 const bool io7_need_output = true;
528 // set flags for OCTAL mode according to the existence of spi data4 ~ spi data7
529 if (io4_7_enabled) {
530 temp_flag |= SPICOMMON_BUSFLAG_IO4_IO7;
531 if (bus_config->data4_io_num >= 0) {
532 SPI_CHECK_PIN(bus_config->data4_io_num, "spi data4", io4_need_output);
533 }
534 if (bus_config->data5_io_num >= 0) {
535 SPI_CHECK_PIN(bus_config->data5_io_num, "spi data5", io5_need_output);
536 }
537 if (bus_config->data6_io_num >= 0) {
538 SPI_CHECK_PIN(bus_config->data6_io_num, "spi data6", io6_need_output);
539 }
540 if (bus_config->data7_io_num >= 0) {
541 SPI_CHECK_PIN(bus_config->data7_io_num, "spi data7", io7_need_output);
542 }
543 }
544 #endif //SOC_SPI_SUPPORT_OCT
545
546 //set flags for QUAD mode according to the existence of wp and hd
547 if (bus_config->quadhd_io_num >= 0 && bus_config->quadwp_io_num >= 0) temp_flag |= SPICOMMON_BUSFLAG_WPHD;
548 if (bus_config->mosi_io_num >= 0) {
549 temp_flag |= SPICOMMON_BUSFLAG_MOSI;
550 SPI_CHECK_PIN(bus_config->mosi_io_num, "mosi", mosi_need_output);
551 }
552 if (bus_config->miso_io_num >= 0) {
553 temp_flag |= SPICOMMON_BUSFLAG_MISO;
554 SPI_CHECK_PIN(bus_config->miso_io_num, "miso", miso_need_output);
555 }
556 //set flags for DUAL mode according to output-capability of MOSI and MISO pins.
557 if ( (bus_config->mosi_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num)) &&
558 (bus_config->miso_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->miso_io_num)) ) {
559 temp_flag |= SPICOMMON_BUSFLAG_DUAL;
560 }
561
562 //check if the selected pins correspond to the iomux pins of the peripheral
563 bool use_iomux = !(flags & SPICOMMON_BUSFLAG_GPIO_PINS) && bus_uses_iomux_pins(host, bus_config);
564 if (use_iomux) {
565 temp_flag |= SPICOMMON_BUSFLAG_IOMUX_PINS;
566 } else {
567 temp_flag |= SPICOMMON_BUSFLAG_GPIO_PINS;
568 }
569
570 uint32_t missing_flag = flags & ~temp_flag;
571 missing_flag &= ~SPICOMMON_BUSFLAG_MASTER;//don't check this flag
572
573 if (missing_flag != 0) {
574 //check pins existence
575 if (missing_flag & SPICOMMON_BUSFLAG_SCLK) {
576 ESP_LOGE(SPI_TAG, "sclk pin required.");
577 }
578 if (missing_flag & SPICOMMON_BUSFLAG_MOSI) {
579 ESP_LOGE(SPI_TAG, "mosi pin required.");
580 }
581 if (missing_flag & SPICOMMON_BUSFLAG_MISO) {
582 ESP_LOGE(SPI_TAG, "miso pin required.");
583 }
584 if (missing_flag & SPICOMMON_BUSFLAG_DUAL) {
585 ESP_LOGE(SPI_TAG, "not both mosi and miso output capable");
586 }
587 if (missing_flag & SPICOMMON_BUSFLAG_WPHD) {
588 ESP_LOGE(SPI_TAG, "both wp and hd required.");
589 }
590 if (missing_flag & SPICOMMON_BUSFLAG_IOMUX_PINS) {
591 ESP_LOGE(SPI_TAG, "not using iomux pins");
592 }
593 #if SOC_SPI_SUPPORT_OCT
594 if (missing_flag & SPICOMMON_BUSFLAG_IO4_IO7) {
595 ESP_LOGE(SPI_TAG, "spi data4 ~ spi data7 are required.");
596 }
597 #endif
598 SPI_CHECK(missing_flag == 0, "not all required capabilities satisfied.", ESP_ERR_INVALID_ARG);
599 }
600
601 if (use_iomux) {
602 //All SPI iomux pin selections resolve to 1, so we put that here instead of trying to figure
603 //out which FUNC_GPIOx_xSPIxx to grab; they all are defined to 1 anyway.
604 ESP_LOGD(SPI_TAG, "SPI%d use iomux pins.", host+1);
605 bus_iomux_pins_set(host, bus_config);
606 } else {
607 //Use GPIO matrix
608 ESP_LOGD(SPI_TAG, "SPI%d use gpio matrix.", host+1);
609 if (bus_config->mosi_io_num >= 0) {
610 if (mosi_need_output || (temp_flag&SPICOMMON_BUSFLAG_DUAL)) {
611 gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_INPUT_OUTPUT);
612 esp_rom_gpio_connect_out_signal(bus_config->mosi_io_num, spi_periph_signal[host].spid_out, false, false);
613 } else {
614 gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_INPUT);
615 }
616 esp_rom_gpio_connect_in_signal(bus_config->mosi_io_num, spi_periph_signal[host].spid_in, false);
617 #if CONFIG_IDF_TARGET_ESP32S2
618 PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->mosi_io_num]);
619 #endif
620 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->mosi_io_num], FUNC_GPIO);
621 }
622 if (bus_config->miso_io_num >= 0) {
623 if (miso_need_output || (temp_flag&SPICOMMON_BUSFLAG_DUAL)) {
624 gpio_set_direction(bus_config->miso_io_num, GPIO_MODE_INPUT_OUTPUT);
625 esp_rom_gpio_connect_out_signal(bus_config->miso_io_num, spi_periph_signal[host].spiq_out, false, false);
626 } else {
627 gpio_set_direction(bus_config->miso_io_num, GPIO_MODE_INPUT);
628 }
629 esp_rom_gpio_connect_in_signal(bus_config->miso_io_num, spi_periph_signal[host].spiq_in, false);
630 #if CONFIG_IDF_TARGET_ESP32S2
631 PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->miso_io_num]);
632 #endif
633 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->miso_io_num], FUNC_GPIO);
634 }
635 if (bus_config->quadwp_io_num >= 0) {
636 gpio_set_direction(bus_config->quadwp_io_num, GPIO_MODE_INPUT_OUTPUT);
637 esp_rom_gpio_connect_out_signal(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_out, false, false);
638 esp_rom_gpio_connect_in_signal(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_in, false);
639 #if CONFIG_IDF_TARGET_ESP32S2
640 PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num]);
641 #endif
642 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num], FUNC_GPIO);
643 }
644 if (bus_config->quadhd_io_num >= 0) {
645 gpio_set_direction(bus_config->quadhd_io_num, GPIO_MODE_INPUT_OUTPUT);
646 esp_rom_gpio_connect_out_signal(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_out, false, false);
647 esp_rom_gpio_connect_in_signal(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_in, false);
648 #if CONFIG_IDF_TARGET_ESP32S2
649 PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num]);
650 #endif
651 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num], FUNC_GPIO);
652 }
653 if (bus_config->sclk_io_num >= 0) {
654 if (sclk_need_output) {
655 gpio_set_direction(bus_config->sclk_io_num, GPIO_MODE_INPUT_OUTPUT);
656 esp_rom_gpio_connect_out_signal(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_out, false, false);
657 } else {
658 gpio_set_direction(bus_config->sclk_io_num, GPIO_MODE_INPUT);
659 }
660 esp_rom_gpio_connect_in_signal(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_in, false);
661 #if CONFIG_IDF_TARGET_ESP32S2
662 PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->sclk_io_num]);
663 #endif
664 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], FUNC_GPIO);
665 }
666 #if SOC_SPI_SUPPORT_OCT
667 if ((flags & SPICOMMON_BUSFLAG_OCTAL) == SPICOMMON_BUSFLAG_OCTAL) {
668 int io_nums[] = {bus_config->data4_io_num, bus_config->data5_io_num, bus_config->data6_io_num, bus_config->data7_io_num};
669 uint8_t io_signals[4][2] = {{spi_periph_signal[host].spid4_out, spi_periph_signal[host].spid4_in},
670 {spi_periph_signal[host].spid5_out, spi_periph_signal[host].spid5_in},
671 {spi_periph_signal[host].spid6_out, spi_periph_signal[host].spid6_in},
672 {spi_periph_signal[host].spid7_out, spi_periph_signal[host].spid7_in}};
673 for (size_t i = 0; i < sizeof(io_nums) / sizeof(io_nums[0]); i++) {
674 if (io_nums[i] >= 0) {
675 gpio_set_direction(io_nums[i], GPIO_MODE_INPUT_OUTPUT);
676 esp_rom_gpio_connect_out_signal(io_nums[i], io_signals[i][0], false, false);
677 esp_rom_gpio_connect_in_signal(io_nums[i], io_signals[i][1], false);
678 #if CONFIG_IDF_TARGET_ESP32S2
679 PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[io_nums[i]]);
680 #endif
681 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[io_nums[i]], FUNC_GPIO);
682 }
683 }
684 }
685 #endif //SOC_SPI_SUPPORT_OCT
686 }
687
688 if (flags_o) *flags_o = temp_flag;
689 return ESP_OK;
690 }
691
spicommon_bus_free_io_cfg(const spi_bus_config_t * bus_cfg)692 esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg)
693 {
694 int pin_array[] = {
695 bus_cfg->mosi_io_num,
696 bus_cfg->miso_io_num,
697 bus_cfg->sclk_io_num,
698 bus_cfg->quadwp_io_num,
699 bus_cfg->quadhd_io_num,
700 };
701 for (int i = 0; i < sizeof(pin_array)/sizeof(int); i ++) {
702 const int io = pin_array[i];
703 if (GPIO_IS_VALID_GPIO(io)) {
704 gpio_reset_pin(io);
705 }
706 }
707 return ESP_OK;
708 }
709
spicommon_cs_initialize(spi_host_device_t host,int cs_io_num,int cs_num,int force_gpio_matrix)710 void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, int force_gpio_matrix)
711 {
712 if (!force_gpio_matrix && cs_io_num == spi_periph_signal[host].spics0_iomux_pin && cs_num == 0) {
713 //The cs0s for all SPI peripherals map to pin mux source 1, so we use that instead of a define.
714 gpio_iomux_in(cs_io_num, spi_periph_signal[host].spics_in);
715 gpio_iomux_out(cs_io_num, spi_periph_signal[host].func, false);
716 } else {
717 //Use GPIO matrix
718 if (GPIO_IS_VALID_OUTPUT_GPIO(cs_io_num)) {
719 gpio_set_direction(cs_io_num, GPIO_MODE_INPUT_OUTPUT);
720 esp_rom_gpio_connect_out_signal(cs_io_num, spi_periph_signal[host].spics_out[cs_num], false, false);
721 } else {
722 gpio_set_direction(cs_io_num, GPIO_MODE_INPUT);
723 }
724 if (cs_num == 0) esp_rom_gpio_connect_in_signal(cs_io_num, spi_periph_signal[host].spics_in, false);
725 PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[cs_io_num]);
726 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[cs_io_num], FUNC_GPIO);
727 }
728 }
729
spicommon_cs_free_io(int cs_gpio_num)730 void spicommon_cs_free_io(int cs_gpio_num)
731 {
732 assert(GPIO_IS_VALID_GPIO(cs_gpio_num));
733 gpio_reset_pin(cs_gpio_num);
734 }
735
spicommon_bus_using_iomux(spi_host_device_t host)736 bool spicommon_bus_using_iomux(spi_host_device_t host)
737 {
738 #define CHECK_IOMUX_PIN(HOST, PIN_NAME) if (GPIO.func_in_sel_cfg[spi_periph_signal[(HOST)].PIN_NAME##_in].sig_in_sel) return false
739
740 CHECK_IOMUX_PIN(host, spid);
741 CHECK_IOMUX_PIN(host, spiq);
742 CHECK_IOMUX_PIN(host, spiwp);
743 CHECK_IOMUX_PIN(host, spihd);
744 return true;
745 }
746
747
spi_bus_main_set_lock(spi_bus_lock_handle_t lock)748 void spi_bus_main_set_lock(spi_bus_lock_handle_t lock)
749 {
750 bus_ctx[0]->bus_attr.lock = lock;
751 }
752
spi_bus_lock_get_by_id(spi_host_device_t host_id)753 spi_bus_lock_handle_t spi_bus_lock_get_by_id(spi_host_device_t host_id)
754 {
755 return bus_ctx[host_id]->bus_attr.lock;
756 }
757
758 //----------------------------------------------------------master bus init-------------------------------------------------------//
spi_bus_initialize(spi_host_device_t host_id,const spi_bus_config_t * bus_config,spi_dma_chan_t dma_chan)759 esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *bus_config, spi_dma_chan_t dma_chan)
760 {
761 esp_err_t err = ESP_OK;
762 spicommon_bus_context_t *ctx = NULL;
763 spi_bus_attr_t *bus_attr = NULL;
764 uint32_t actual_tx_dma_chan = 0;
765 uint32_t actual_rx_dma_chan = 0;
766
767 SPI_CHECK(is_valid_host(host_id), "invalid host_id", ESP_ERR_INVALID_ARG);
768 SPI_CHECK(bus_ctx[host_id] == NULL, "SPI bus already initialized.", ESP_ERR_INVALID_STATE);
769 #ifdef CONFIG_IDF_TARGET_ESP32
770 SPI_CHECK(dma_chan >= SPI_DMA_DISABLED && dma_chan <= SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG );
771 #elif CONFIG_IDF_TARGET_ESP32S2
772 SPI_CHECK( dma_chan == SPI_DMA_DISABLED || dma_chan == (int)host_id || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel", ESP_ERR_INVALID_ARG );
773 #elif SOC_GDMA_SUPPORTED
774 SPI_CHECK( dma_chan == SPI_DMA_DISABLED || dma_chan == SPI_DMA_CH_AUTO, "invalid dma channel, chip only support spi dma channel auto-alloc", ESP_ERR_INVALID_ARG );
775 #endif
776 SPI_CHECK((bus_config->intr_flags & (ESP_INTR_FLAG_HIGH|ESP_INTR_FLAG_EDGE|ESP_INTR_FLAG_INTRDISABLED))==0, "intr flag not allowed", ESP_ERR_INVALID_ARG);
777 #ifndef CONFIG_SPI_MASTER_ISR_IN_IRAM
778 SPI_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM)==0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_MASTER_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
779 #endif
780
781 bool spi_chan_claimed = spicommon_periph_claim(host_id, "spi master");
782 SPI_CHECK(spi_chan_claimed, "host_id already in use", ESP_ERR_INVALID_STATE);
783
784 //clean and initialize the context
785 ctx = (spicommon_bus_context_t *)calloc(1, sizeof(spicommon_bus_context_t));
786 if (!ctx) {
787 err = ESP_ERR_NO_MEM;
788 goto cleanup;
789 }
790 bus_ctx[host_id] = ctx;
791 ctx->host_id = host_id;
792 bus_attr = &ctx->bus_attr;
793 bus_attr->bus_cfg = *bus_config;
794
795 if (dma_chan != SPI_DMA_DISABLED) {
796 bus_attr->dma_enabled = 1;
797
798 err = alloc_dma_chan(host_id, dma_chan, &actual_tx_dma_chan, &actual_rx_dma_chan);
799 if (err != ESP_OK) {
800 goto cleanup;
801 }
802 bus_attr->tx_dma_chan = actual_tx_dma_chan;
803 bus_attr->rx_dma_chan = actual_rx_dma_chan;
804
805 int dma_desc_ct = lldesc_get_required_num(bus_config->max_transfer_sz);
806 if (dma_desc_ct == 0) dma_desc_ct = 1; //default to 4k when max is not given
807
808 bus_attr->max_transfer_sz = dma_desc_ct * LLDESC_MAX_NUM_PER_DESC;
809 bus_attr->dmadesc_tx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA);
810 bus_attr->dmadesc_rx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA);
811 if (bus_attr->dmadesc_tx == NULL || bus_attr->dmadesc_rx == NULL) {
812 err = ESP_ERR_NO_MEM;
813 goto cleanup;
814 }
815 bus_attr->dma_desc_num = dma_desc_ct;
816 } else {
817 bus_attr->dma_enabled = 0;
818 bus_attr->max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE;
819 bus_attr->dma_desc_num = 0;
820 }
821
822 spi_bus_lock_config_t lock_config = {
823 .host_id = host_id,
824 .cs_num = SOC_SPI_PERIPH_CS_NUM(host_id),
825 };
826 err = spi_bus_init_lock(&bus_attr->lock, &lock_config);
827 if (err != ESP_OK) {
828 goto cleanup;
829 }
830
831 #ifdef CONFIG_PM_ENABLE
832 err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_master",
833 &bus_attr->pm_lock);
834 if (err != ESP_OK) {
835 goto cleanup;
836 }
837 #endif //CONFIG_PM_ENABLE
838
839 err = spicommon_bus_initialize_io(host_id, bus_config, SPICOMMON_BUSFLAG_MASTER | bus_config->flags, &bus_attr->flags);
840 if (err != ESP_OK) {
841 goto cleanup;
842 }
843
844 return ESP_OK;
845
846 cleanup:
847 if (bus_attr) {
848 #ifdef CONFIG_PM_ENABLE
849 esp_pm_lock_delete(bus_attr->pm_lock);
850 #endif
851 if (bus_attr->lock) {
852 spi_bus_deinit_lock(bus_attr->lock);
853 }
854 free(bus_attr->dmadesc_tx);
855 free(bus_attr->dmadesc_rx);
856 bus_attr->dmadesc_tx = NULL;
857 bus_attr->dmadesc_rx = NULL;
858 if (bus_attr->dma_enabled) {
859 dma_chan_free(host_id);
860 }
861 }
862 spicommon_periph_free(host_id);
863 free(bus_ctx[host_id]);
864 bus_ctx[host_id] = NULL;
865 return err;
866 }
867
spi_bus_get_attr(spi_host_device_t host_id)868 const spi_bus_attr_t* spi_bus_get_attr(spi_host_device_t host_id)
869 {
870 if (bus_ctx[host_id] == NULL) return NULL;
871
872 return &bus_ctx[host_id]->bus_attr;
873 }
874
spi_bus_free(spi_host_device_t host_id)875 esp_err_t spi_bus_free(spi_host_device_t host_id)
876 {
877 if (bus_ctx[host_id] == NULL) {
878 return ESP_ERR_INVALID_STATE;
879 }
880
881 esp_err_t err = ESP_OK;
882 spicommon_bus_context_t* ctx = bus_ctx[host_id];
883 spi_bus_attr_t* bus_attr = &ctx->bus_attr;
884
885 if (ctx->destroy_func) {
886 err = ctx->destroy_func(ctx->destroy_arg);
887 }
888
889 spicommon_bus_free_io_cfg(&bus_attr->bus_cfg);
890
891 #ifdef CONFIG_PM_ENABLE
892 esp_pm_lock_delete(bus_attr->pm_lock);
893 #endif
894 spi_bus_deinit_lock(bus_attr->lock);
895 free(bus_attr->dmadesc_rx);
896 free(bus_attr->dmadesc_tx);
897 bus_attr->dmadesc_tx = NULL;
898 bus_attr->dmadesc_rx = NULL;
899 if (bus_attr->dma_enabled > 0) {
900 dma_chan_free(host_id);
901 }
902 spicommon_periph_free(host_id);
903 free(ctx);
904 bus_ctx[host_id] = NULL;
905 return err;
906 }
907
spi_bus_register_destroy_func(spi_host_device_t host_id,spi_destroy_func_t f,void * arg)908 esp_err_t spi_bus_register_destroy_func(spi_host_device_t host_id,
909 spi_destroy_func_t f, void *arg)
910 {
911 bus_ctx[host_id]->destroy_func = f;
912 bus_ctx[host_id]->destroy_arg = arg;
913 return ESP_OK;
914 }
915
916
917 /*
918 Code for workaround for DMA issue in ESP32 v0/v1 silicon
919 */
920 #if CONFIG_IDF_TARGET_ESP32
921 static volatile int dmaworkaround_channels_busy[2] = {0, 0};
922 static dmaworkaround_cb_t dmaworkaround_cb;
923 static void *dmaworkaround_cb_arg;
924 static portMUX_TYPE dmaworkaround_mux = portMUX_INITIALIZER_UNLOCKED;
925 static int dmaworkaround_waiting_for_chan = 0;
926
spicommon_dmaworkaround_req_reset(int dmachan,dmaworkaround_cb_t cb,void * arg)927 bool IRAM_ATTR spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void *arg)
928 {
929
930 int otherchan = (dmachan == 1) ? 2 : 1;
931 bool ret;
932 portENTER_CRITICAL_ISR(&dmaworkaround_mux);
933 if (dmaworkaround_channels_busy[otherchan-1]) {
934 //Other channel is busy. Call back when it's done.
935 dmaworkaround_cb = cb;
936 dmaworkaround_cb_arg = arg;
937 dmaworkaround_waiting_for_chan = otherchan;
938 ret = false;
939 } else {
940 //Reset DMA
941 periph_module_reset( PERIPH_SPI_DMA_MODULE );
942 ret = true;
943 }
944 portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
945 return ret;
946 }
947
spicommon_dmaworkaround_reset_in_progress(void)948 bool IRAM_ATTR spicommon_dmaworkaround_reset_in_progress(void)
949 {
950 return (dmaworkaround_waiting_for_chan != 0);
951 }
952
spicommon_dmaworkaround_idle(int dmachan)953 void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan)
954 {
955 portENTER_CRITICAL_ISR(&dmaworkaround_mux);
956 dmaworkaround_channels_busy[dmachan-1] = 0;
957 if (dmaworkaround_waiting_for_chan == dmachan) {
958 //Reset DMA
959 periph_module_reset( PERIPH_SPI_DMA_MODULE );
960 dmaworkaround_waiting_for_chan = 0;
961 //Call callback
962 dmaworkaround_cb(dmaworkaround_cb_arg);
963
964 }
965 portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
966 }
967
spicommon_dmaworkaround_transfer_active(int dmachan)968 void IRAM_ATTR spicommon_dmaworkaround_transfer_active(int dmachan)
969 {
970 portENTER_CRITICAL_ISR(&dmaworkaround_mux);
971 dmaworkaround_channels_busy[dmachan-1] = 1;
972 portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
973 }
974 #endif //#if CONFIG_IDF_TARGET_ESP32
975