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