/ components / driver / spi_common.c
spi_common.c
  1  // Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
  2  //
  3  // Licensed under the Apache License, Version 2.0 (the "License");
  4  // you may not use this file except in compliance with the License.
  5  // You may obtain a copy of the License at
  6  //
  7  //     http://www.apache.org/licenses/LICENSE-2.0
  8  //
  9  // Unless required by applicable law or agreed to in writing, software
 10  // distributed under the License is distributed on an "AS IS" BASIS,
 11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12  // See the License for the specific language governing permissions and
 13  // limitations under the License.
 14  
 15  
 16  #include <string.h>
 17  #include "sdkconfig.h"
 18  #include "driver/spi_master.h"
 19  #include "soc/spi_periph.h"
 20  #include "esp_types.h"
 21  #include "esp_attr.h"
 22  #include "esp_log.h"
 23  #include "esp_err.h"
 24  #include "soc/soc.h"
 25  #include "soc/soc_caps.h"
 26  #include "soc/dport_reg.h"
 27  #include "soc/lldesc.h"
 28  #include "driver/gpio.h"
 29  #include "driver/periph_ctrl.h"
 30  #include "esp_heap_caps.h"
 31  #include "driver/spi_common_internal.h"
 32  #include "stdatomic.h"
 33  #include "hal/spi_hal.h"
 34  #include "esp_rom_gpio.h"
 35  
 36  //This GDMA related part will be introduced by GDMA dedicated APIs in the future. Here we temporarily use macros.
 37  #if SOC_GDMA_SUPPORTED
 38  #include "hal/gdma_ll.h"
 39  
 40  #define spi_dma_set_rx_channel_priority(gdma_chan, priority)       gdma_ll_rx_set_priority(&GDMA, gdma_chan, priority);
 41  #define spi_dma_set_tx_channel_priority(gdma_chan, priority)       gdma_ll_tx_set_priority(&GDMA, gdma_chan, priority);
 42  #define spi_dma_connect_rx_channel_to_periph(gdma_chan, periph_id) gdma_ll_rx_connect_to_periph(&GDMA, gdma_chan, periph_id);
 43  #define spi_dma_connect_tx_channel_to_periph(gdma_chan, periph_id) gdma_ll_tx_connect_to_periph(&GDMA, gdma_chan, periph_id);
 44  #endif
 45  
 46  static const char *SPI_TAG = "spi";
 47  
 48  #define SPI_CHECK(a, str, ret_val) do { \
 49      if (!(a)) { \
 50          ESP_LOGE(SPI_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \
 51          return (ret_val); \
 52      } \
 53      } while(0)
 54  
 55  #define SPI_CHECK_PIN(pin_num, pin_name, check_output) if (check_output) { \
 56              SPI_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(pin_num), pin_name" not valid", ESP_ERR_INVALID_ARG); \
 57          } else { \
 58              SPI_CHECK(GPIO_IS_VALID_GPIO(pin_num), pin_name" not valid", ESP_ERR_INVALID_ARG); \
 59          }
 60  
 61  
 62  typedef struct spi_device_t spi_device_t;
 63  
 64  #define FUNC_GPIO   PIN_FUNC_GPIO
 65  
 66  #define DMA_CHANNEL_ENABLED(dma_chan)    (BIT(dma_chan-1))
 67  
 68  
 69  typedef struct {
 70      int host_id;
 71      spi_destroy_func_t destroy_func;
 72      void* destroy_arg;
 73      spi_bus_attr_t bus_attr;
 74  } spicommon_bus_context_t;
 75  
 76  #define MAIN_BUS_DEFAULT() { \
 77          .host_id = 0, \
 78          .bus_attr = { \
 79              .dma_chan = 0, \
 80              .max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE, \
 81              .dma_desc_num= 0, \
 82          }, \
 83      }
 84  
 85  //Periph 1 is 'claimed' by SPI flash code.
 86  static atomic_bool spi_periph_claimed[SOC_SPI_PERIPH_NUM] = { ATOMIC_VAR_INIT(true), ATOMIC_VAR_INIT(false), ATOMIC_VAR_INIT(false),
 87  #if SOC_SPI_PERIPH_NUM >= 4
 88          ATOMIC_VAR_INIT(false),
 89  #endif
 90  };
 91  static const char* spi_claiming_func[3] = {NULL, NULL, NULL};
 92  static uint8_t spi_dma_chan_enabled = 0;
 93  static portMUX_TYPE spi_dma_spinlock = portMUX_INITIALIZER_UNLOCKED;
 94  
 95  static spicommon_bus_context_t s_mainbus = MAIN_BUS_DEFAULT();
 96  static spicommon_bus_context_t* bus_ctx[SOC_SPI_PERIPH_NUM] = {&s_mainbus};
 97  
 98  
 99  //Returns true if this peripheral is successfully claimed, false if otherwise.
100  bool spicommon_periph_claim(spi_host_device_t host, const char* source)
101  {
102      bool false_var = false;
103      bool ret = atomic_compare_exchange_strong(&spi_periph_claimed[host], &false_var, true);
104      if (ret) {
105          spi_claiming_func[host] = source;
106          periph_module_enable(spi_periph_signal[host].module);
107      } else {
108          ESP_EARLY_LOGE(SPI_TAG, "SPI%d already claimed by %s.", host+1, spi_claiming_func[host]);
109      }
110      return ret;
111  }
112  
113  bool spicommon_periph_in_use(spi_host_device_t host)
114  {
115      return atomic_load(&spi_periph_claimed[host]);
116  }
117  
118  //Returns true if this peripheral is successfully freed, false if otherwise.
119  bool spicommon_periph_free(spi_host_device_t host)
120  {
121      bool true_var = true;
122      bool ret = atomic_compare_exchange_strong(&spi_periph_claimed[host], &true_var, false);
123      if (ret) periph_module_disable(spi_periph_signal[host].module);
124      return ret;
125  }
126  
127  int spicommon_irqsource_for_host(spi_host_device_t host)
128  {
129      return spi_periph_signal[host].irq;
130  }
131  
132  int spicommon_irqdma_source_for_host(spi_host_device_t host)
133  {
134      return spi_periph_signal[host].irq_dma;
135  }
136  
137  static inline uint32_t get_dma_periph(int dma_chan)
138  {
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          return -1;
147      }
148  #elif CONFIG_IDF_TARGET_ESP32
149      return PERIPH_SPI_DMA_MODULE;
150  #else
151      return 0;
152  #endif
153  }
154  
155  bool spicommon_dma_chan_claim(int dma_chan)
156  {
157      bool ret = false;
158      assert(dma_chan >= 1 && dma_chan <= SOC_SPI_DMA_CHAN_NUM);
159  
160      portENTER_CRITICAL(&spi_dma_spinlock);
161      if ( !(spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan)) ) {
162          // get the channel only when it's not claimed yet.
163          spi_dma_chan_enabled |= DMA_CHANNEL_ENABLED(dma_chan);
164          ret = true;
165      }
166  
167  #if CONFIG_IDF_TARGET_ESP32
168      periph_module_enable(get_dma_periph(dma_chan));
169  #elif CONFIG_IDF_TARGET_ESP32S2
170      if (dma_chan==1) {
171          periph_module_enable(PERIPH_SPI2_DMA_MODULE);
172      } else if (dma_chan==2) {
173          periph_module_enable(PERIPH_SPI3_DMA_MODULE);
174      }
175  #elif SOC_GDMA_SUPPORTED
176      periph_module_enable(PERIPH_GDMA_MODULE);
177  #endif
178      portEXIT_CRITICAL(&spi_dma_spinlock);
179  
180      return ret;
181  }
182  
183  bool spicommon_dma_chan_in_use(int dma_chan)
184  {
185      assert(dma_chan ==1 || dma_chan == 2);
186      return spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan);
187  }
188  
189  bool spicommon_dma_chan_free(int dma_chan)
190  {
191      assert( dma_chan == 1 || dma_chan == 2 );
192      assert( spi_dma_chan_enabled & DMA_CHANNEL_ENABLED(dma_chan) );
193  
194      portENTER_CRITICAL(&spi_dma_spinlock);
195      spi_dma_chan_enabled &= ~DMA_CHANNEL_ENABLED(dma_chan);
196  #if CONFIG_IDF_TARGET_ESP32
197      if ( spi_dma_chan_enabled == 0 ) {
198          //disable the DMA only when all the channels are freed.
199          periph_module_disable(get_dma_periph(dma_chan));
200      }
201  #elif CONFIG_IDF_TARGET_ESP32S2
202      if (dma_chan==1) {
203          periph_module_disable(PERIPH_SPI2_DMA_MODULE);
204      } else if (dma_chan==2) {
205          periph_module_disable(PERIPH_SPI3_DMA_MODULE);
206      }
207  #elif SOC_GDMA_SUPPORTED
208      periph_module_disable(PERIPH_GDMA_MODULE);
209  #endif
210      portEXIT_CRITICAL(&spi_dma_spinlock);
211  
212      return true;
213  }
214  
215  void spicommon_connect_spi_and_dma(spi_host_device_t host, int dma_chan)
216  {
217  #if CONFIG_IDF_TARGET_ESP32
218      DPORT_SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, dma_chan, (host * 2));
219  #elif CONFIG_IDF_TARGET_ESP32S2
220      //On ESP32S2, each SPI controller has its own DMA channel. So there is no need to connect them.
221  #elif SOC_GDMA_SUPPORTED
222      int gdma_chan, periph_id;
223      if (dma_chan == 1) {
224          gdma_chan = SOC_GDMA_SPI2_DMA_CHANNEL;
225          periph_id = GDMA_LL_TRIG_SRC_SPI2;
226      } else if (dma_chan == 2) {
227          gdma_chan = SOC_GDMA_SPI3_DMA_CHANNEL;
228          periph_id = GDMA_LL_TRIG_SRC_SPI3;
229      } else {
230          abort();
231      }
232  
233      spi_dma_connect_rx_channel_to_periph(gdma_chan, periph_id);
234      spi_dma_connect_tx_channel_to_periph(gdma_chan, periph_id);
235      spi_dma_set_rx_channel_priority(gdma_chan, 1);
236      spi_dma_set_tx_channel_priority(gdma_chan, 1);
237  #endif
238  }
239  
240  static bool bus_uses_iomux_pins(spi_host_device_t host, const spi_bus_config_t* bus_config)
241  {
242      if (bus_config->sclk_io_num>=0 &&
243          bus_config->sclk_io_num != spi_periph_signal[host].spiclk_iomux_pin) return false;
244      if (bus_config->quadwp_io_num>=0 &&
245          bus_config->quadwp_io_num != spi_periph_signal[host].spiwp_iomux_pin) return false;
246      if (bus_config->quadhd_io_num>=0 &&
247          bus_config->quadhd_io_num != spi_periph_signal[host].spihd_iomux_pin) return false;
248      if (bus_config->mosi_io_num >= 0 &&
249          bus_config->mosi_io_num != spi_periph_signal[host].spid_iomux_pin) return false;
250      if (bus_config->miso_io_num>=0 &&
251          bus_config->miso_io_num != spi_periph_signal[host].spiq_iomux_pin) return false;
252  
253      return true;
254  }
255  
256  /*
257  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
258  bus config struct and it'll set up the GPIO matrix and enable the device. If a pin is set to non-negative value,
259  it should be able to be initialized.
260  */
261  esp_err_t spicommon_bus_initialize_io(spi_host_device_t host, const spi_bus_config_t *bus_config, int dma_chan, uint32_t flags, uint32_t* flags_o)
262  {
263      uint32_t temp_flag = 0;
264  
265      bool miso_need_output;
266      bool mosi_need_output;
267      bool sclk_need_output;
268      if ((flags&SPICOMMON_BUSFLAG_MASTER) != 0) {
269          //initial for master
270          miso_need_output = ((flags&SPICOMMON_BUSFLAG_DUAL) != 0) ? true : false;
271          mosi_need_output = true;
272          sclk_need_output = true;
273      } else {
274          //initial for slave
275          miso_need_output = true;
276          mosi_need_output = ((flags&SPICOMMON_BUSFLAG_DUAL) != 0) ? true : false;
277          sclk_need_output = false;
278      }
279  
280      const bool wp_need_output = true;
281      const bool hd_need_output = true;
282  
283      //check pin capabilities
284      if (bus_config->sclk_io_num>=0) {
285          temp_flag |= SPICOMMON_BUSFLAG_SCLK;
286          SPI_CHECK_PIN(bus_config->sclk_io_num, "sclk", sclk_need_output);
287      }
288      if (bus_config->quadwp_io_num>=0) {
289          SPI_CHECK_PIN(bus_config->quadwp_io_num, "wp", wp_need_output);
290      }
291      if (bus_config->quadhd_io_num>=0) {
292          SPI_CHECK_PIN(bus_config->quadhd_io_num, "hd", hd_need_output);
293      }
294      //set flags for QUAD mode according to the existence of wp and hd
295      if (bus_config->quadhd_io_num >= 0 && bus_config->quadwp_io_num >= 0) temp_flag |= SPICOMMON_BUSFLAG_WPHD;
296      if (bus_config->mosi_io_num >= 0) {
297          temp_flag |= SPICOMMON_BUSFLAG_MOSI;
298          SPI_CHECK_PIN(bus_config->mosi_io_num, "mosi", mosi_need_output);
299      }
300      if (bus_config->miso_io_num>=0) {
301          temp_flag |= SPICOMMON_BUSFLAG_MISO;
302          SPI_CHECK_PIN(bus_config->miso_io_num, "miso", miso_need_output);
303      }
304      //set flags for DUAL mode according to output-capability of MOSI and MISO pins.
305      if ( (bus_config->mosi_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num)) &&
306          (bus_config->miso_io_num < 0 || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->miso_io_num)) ) {
307          temp_flag |= SPICOMMON_BUSFLAG_DUAL;
308      }
309  
310      //check if the selected pins correspond to the iomux pins of the peripheral
311      bool use_iomux = !(flags & SPICOMMON_BUSFLAG_GPIO_PINS) && bus_uses_iomux_pins(host, bus_config);
312      if (use_iomux) {
313          temp_flag |= SPICOMMON_BUSFLAG_IOMUX_PINS;
314      } else {
315          temp_flag |= SPICOMMON_BUSFLAG_GPIO_PINS;
316      }
317  
318      uint32_t missing_flag = flags & ~temp_flag;
319      missing_flag &= ~SPICOMMON_BUSFLAG_MASTER;//don't check this flag
320  
321      if (missing_flag != 0) {
322      //check pins existence
323          if (missing_flag & SPICOMMON_BUSFLAG_SCLK) ESP_LOGE(SPI_TAG, "sclk pin required.");
324          if (missing_flag & SPICOMMON_BUSFLAG_MOSI) ESP_LOGE(SPI_TAG, "mosi pin required.");
325          if (missing_flag & SPICOMMON_BUSFLAG_MISO) ESP_LOGE(SPI_TAG, "miso pin required.");
326          if (missing_flag & SPICOMMON_BUSFLAG_DUAL) ESP_LOGE(SPI_TAG, "not both mosi and miso output capable");
327          if (missing_flag & SPICOMMON_BUSFLAG_WPHD) ESP_LOGE(SPI_TAG, "both wp and hd required.");
328          if (missing_flag & SPICOMMON_BUSFLAG_IOMUX_PINS) ESP_LOGE(SPI_TAG, "not using iomux pins");
329          SPI_CHECK(missing_flag == 0, "not all required capabilities satisfied.", ESP_ERR_INVALID_ARG);
330      }
331  
332      if (use_iomux) {
333          //All SPI iomux pin selections resolve to 1, so we put that here instead of trying to figure
334          //out which FUNC_GPIOx_xSPIxx to grab; they all are defined to 1 anyway.
335          ESP_LOGD(SPI_TAG, "SPI%d use iomux pins.", host+1);
336          if (bus_config->mosi_io_num >= 0) {
337              gpio_iomux_in(bus_config->mosi_io_num, spi_periph_signal[host].spid_in);
338              gpio_iomux_out(bus_config->mosi_io_num, spi_periph_signal[host].func, false);
339          }
340          if (bus_config->miso_io_num >= 0) {
341              gpio_iomux_in(bus_config->miso_io_num, spi_periph_signal[host].spiq_in);
342              gpio_iomux_out(bus_config->miso_io_num, spi_periph_signal[host].func, false);
343          }
344          if (bus_config->quadwp_io_num >= 0) {
345              gpio_iomux_in(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_in);
346              gpio_iomux_out(bus_config->quadwp_io_num, spi_periph_signal[host].func, false);
347          }
348          if (bus_config->quadhd_io_num >= 0) {
349              gpio_iomux_in(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_in);
350              gpio_iomux_out(bus_config->quadhd_io_num, spi_periph_signal[host].func, false);
351          }
352          if (bus_config->sclk_io_num >= 0) {
353              gpio_iomux_in(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_in);
354              gpio_iomux_out(bus_config->sclk_io_num, spi_periph_signal[host].func, false);
355          }
356          temp_flag |= SPICOMMON_BUSFLAG_IOMUX_PINS;
357      } else {
358          //Use GPIO matrix
359          ESP_LOGD(SPI_TAG, "SPI%d use gpio matrix.", host+1);
360          if (bus_config->mosi_io_num >= 0) {
361              if (mosi_need_output || (temp_flag&SPICOMMON_BUSFLAG_DUAL)) {
362                  gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_INPUT_OUTPUT);
363                  esp_rom_gpio_connect_out_signal(bus_config->mosi_io_num, spi_periph_signal[host].spid_out, false, false);
364              } else {
365                  gpio_set_direction(bus_config->mosi_io_num, GPIO_MODE_INPUT);
366              }
367              esp_rom_gpio_connect_in_signal(bus_config->mosi_io_num, spi_periph_signal[host].spid_in, false);
368  #if CONFIG_IDF_TARGET_ESP32S2
369              PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->mosi_io_num]);
370  #endif
371              PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->mosi_io_num], FUNC_GPIO);
372          }
373          if (bus_config->miso_io_num >= 0) {
374              if (miso_need_output || (temp_flag&SPICOMMON_BUSFLAG_DUAL)) {
375                  gpio_set_direction(bus_config->miso_io_num, GPIO_MODE_INPUT_OUTPUT);
376                  esp_rom_gpio_connect_out_signal(bus_config->miso_io_num, spi_periph_signal[host].spiq_out, false, false);
377              } else {
378                  gpio_set_direction(bus_config->miso_io_num, GPIO_MODE_INPUT);
379              }
380              esp_rom_gpio_connect_in_signal(bus_config->miso_io_num, spi_periph_signal[host].spiq_in, false);
381  #if CONFIG_IDF_TARGET_ESP32S2
382              PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->miso_io_num]);
383  #endif
384              PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->miso_io_num], FUNC_GPIO);
385          }
386          if (bus_config->quadwp_io_num >= 0) {
387              gpio_set_direction(bus_config->quadwp_io_num, GPIO_MODE_INPUT_OUTPUT);
388              esp_rom_gpio_connect_out_signal(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_out, false, false);
389              esp_rom_gpio_connect_in_signal(bus_config->quadwp_io_num, spi_periph_signal[host].spiwp_in, false);
390  #if CONFIG_IDF_TARGET_ESP32S2
391              PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num]);
392  #endif
393              PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadwp_io_num], FUNC_GPIO);
394          }
395          if (bus_config->quadhd_io_num >= 0) {
396              gpio_set_direction(bus_config->quadhd_io_num, GPIO_MODE_INPUT_OUTPUT);
397              esp_rom_gpio_connect_out_signal(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_out, false, false);
398              esp_rom_gpio_connect_in_signal(bus_config->quadhd_io_num, spi_periph_signal[host].spihd_in, false);
399  #if CONFIG_IDF_TARGET_ESP32S2
400              PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num]);
401  #endif
402              PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->quadhd_io_num], FUNC_GPIO);
403          }
404          if (bus_config->sclk_io_num >= 0) {
405              if (sclk_need_output) {
406                  gpio_set_direction(bus_config->sclk_io_num, GPIO_MODE_INPUT_OUTPUT);
407                  esp_rom_gpio_connect_out_signal(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_out, false, false);
408              } else {
409                  gpio_set_direction(bus_config->sclk_io_num, GPIO_MODE_INPUT);
410              }
411              esp_rom_gpio_connect_in_signal(bus_config->sclk_io_num, spi_periph_signal[host].spiclk_in, false);
412  #if CONFIG_IDF_TARGET_ESP32S2
413              PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[bus_config->sclk_io_num]);
414  #endif
415              PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[bus_config->sclk_io_num], FUNC_GPIO);
416          }
417      }
418  
419      if (flags_o) *flags_o = temp_flag;
420      return ESP_OK;
421  }
422  
423  esp_err_t spicommon_bus_free_io_cfg(const spi_bus_config_t *bus_cfg)
424  {
425      int pin_array[] = {
426          bus_cfg->mosi_io_num,
427          bus_cfg->miso_io_num,
428          bus_cfg->sclk_io_num,
429          bus_cfg->quadwp_io_num,
430          bus_cfg->quadhd_io_num,
431      };
432      for (int i = 0; i < sizeof(pin_array)/sizeof(int); i ++) {
433          const int io = pin_array[i];
434          if (io >= 0 && GPIO_IS_VALID_GPIO(io)) gpio_reset_pin(io);
435      }
436      return ESP_OK;
437  }
438  
439  void spicommon_cs_initialize(spi_host_device_t host, int cs_io_num, int cs_num, int force_gpio_matrix)
440  {
441      if (!force_gpio_matrix && cs_io_num == spi_periph_signal[host].spics0_iomux_pin && cs_num == 0) {
442          //The cs0s for all SPI peripherals map to pin mux source 1, so we use that instead of a define.
443          gpio_iomux_in(cs_io_num, spi_periph_signal[host].spics_in);
444  #if CONFIG_IDF_TARGET_ESP32
445          gpio_iomux_out(cs_io_num, spi_periph_signal[host].func, false);
446  #elif CONFIG_IDF_TARGET_ESP32S2
447          gpio_iomux_out(cs_io_num, spi_periph_signal[host].func, false);
448  #endif
449      } else {
450          //Use GPIO matrix
451          if (GPIO_IS_VALID_OUTPUT_GPIO(cs_io_num)) {
452              gpio_set_direction(cs_io_num, GPIO_MODE_INPUT_OUTPUT);
453              esp_rom_gpio_connect_out_signal(cs_io_num, spi_periph_signal[host].spics_out[cs_num], false, false);
454          } else {
455              gpio_set_direction(cs_io_num, GPIO_MODE_INPUT);
456          }
457          if (cs_num == 0) esp_rom_gpio_connect_in_signal(cs_io_num, spi_periph_signal[host].spics_in, false);
458          PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[cs_io_num]);
459          PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[cs_io_num], FUNC_GPIO);
460      }
461  }
462  
463  void spicommon_cs_free_io(int cs_gpio_num)
464  {
465      assert(cs_gpio_num>=0 && GPIO_IS_VALID_GPIO(cs_gpio_num));
466      gpio_reset_pin(cs_gpio_num);
467  }
468  
469  bool spicommon_bus_using_iomux(spi_host_device_t host)
470  {
471  #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
472  
473      CHECK_IOMUX_PIN(host, spid);
474      CHECK_IOMUX_PIN(host, spiq);
475      CHECK_IOMUX_PIN(host, spiwp);
476      CHECK_IOMUX_PIN(host, spihd);
477      return true;
478  }
479  
480  
481  void spi_bus_main_set_lock(spi_bus_lock_handle_t lock)
482  {
483      bus_ctx[0]->bus_attr.lock = lock;
484  }
485  
486  spi_bus_lock_handle_t spi_bus_lock_get_by_id(spi_host_device_t host_id)
487  {
488      return bus_ctx[host_id]->bus_attr.lock;
489  }
490  
491  static inline bool is_valid_host(spi_host_device_t host)
492  {
493      return host >= SPI1_HOST && host <= SPI3_HOST;
494  }
495  
496  esp_err_t spi_bus_initialize(spi_host_device_t host_id, const spi_bus_config_t *bus_config, int dma_chan)
497  {
498      esp_err_t err = ESP_OK;
499      spicommon_bus_context_t *ctx = NULL;
500      spi_bus_attr_t *bus_attr = NULL;
501      SPI_CHECK(is_valid_host(host_id), "invalid host_id", ESP_ERR_INVALID_ARG);
502      SPI_CHECK(bus_ctx[host_id] == NULL, "SPI bus already initialized.", ESP_ERR_INVALID_STATE);
503  #ifdef CONFIG_IDF_TARGET_ESP32
504      SPI_CHECK( dma_chan >= 0 && dma_chan <= 2, "invalid dma channel", ESP_ERR_INVALID_ARG );
505  #elif CONFIG_IDF_TARGET_ESP32S2
506      SPI_CHECK( dma_chan == 0 || dma_chan == host_id, "invalid dma channel", ESP_ERR_INVALID_ARG );
507  #endif
508      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);
509  #ifndef CONFIG_SPI_MASTER_ISR_IN_IRAM
510      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);
511  #endif
512  
513      bool spi_chan_claimed = spicommon_periph_claim(host_id, "spi master");
514      SPI_CHECK(spi_chan_claimed, "host_id already in use", ESP_ERR_INVALID_STATE);
515  
516      if (dma_chan != 0) {
517          bool dma_chan_claimed = spicommon_dma_chan_claim(dma_chan);
518          if (!dma_chan_claimed) {
519              spicommon_periph_free(host_id);
520              SPI_CHECK(false, "dma channel already in use", ESP_ERR_INVALID_STATE);
521          }
522  
523          spicommon_connect_spi_and_dma(host_id, dma_chan);
524      }
525  
526      //clean and initialize the context
527      ctx = (spicommon_bus_context_t*)malloc(sizeof(spicommon_bus_context_t));
528      if (!ctx) {
529          err = ESP_ERR_NO_MEM;
530          goto cleanup;
531      }
532      *ctx = (spicommon_bus_context_t) {
533          .host_id = host_id,
534          .bus_attr = {
535              .bus_cfg = *bus_config,
536              .dma_chan = dma_chan,
537          },
538      };
539  
540      bus_attr = &ctx->bus_attr;
541      if (dma_chan == 0) {
542          bus_attr->max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE;
543          bus_attr->dma_desc_num = 0;
544      } else {
545          //See how many dma descriptors we need and allocate them
546          int dma_desc_ct = lldesc_get_required_num(bus_config->max_transfer_sz);
547          if (dma_desc_ct == 0) dma_desc_ct = 1; //default to 4k when max is not given
548  
549          bus_attr->max_transfer_sz = dma_desc_ct * LLDESC_MAX_NUM_PER_DESC;
550          bus_attr->dmadesc_tx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA);
551          bus_attr->dmadesc_rx = heap_caps_malloc(sizeof(lldesc_t) * dma_desc_ct, MALLOC_CAP_DMA);
552          if (bus_attr->dmadesc_tx == NULL || bus_attr->dmadesc_rx == NULL) {
553              err = ESP_ERR_NO_MEM;
554              goto cleanup;
555          }
556          bus_attr->dma_desc_num = dma_desc_ct;
557      }
558  
559      spi_bus_lock_config_t lock_config = {
560          .host_id = host_id,
561          .cs_num = SOC_SPI_PERIPH_CS_NUM(host_id),
562      };
563      err = spi_bus_init_lock(&bus_attr->lock, &lock_config);
564      if (err != ESP_OK) {
565          goto cleanup;
566      }
567  
568  #ifdef CONFIG_PM_ENABLE
569      err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "spi_master",
570              &bus_attr->pm_lock);
571      if (err != ESP_OK) {
572          goto cleanup;
573      }
574  #endif //CONFIG_PM_ENABLE
575  
576      err = spicommon_bus_initialize_io(host_id, bus_config, dma_chan, SPICOMMON_BUSFLAG_MASTER | bus_config->flags, &bus_attr->flags);
577      if (err != ESP_OK) {
578          goto cleanup;
579      }
580  
581      bus_ctx[host_id] = ctx;
582      return ESP_OK;
583  
584  cleanup:
585      if (bus_attr) {
586  #ifdef CONFIG_PM_ENABLE
587          esp_pm_lock_delete(bus_attr->pm_lock);
588  #endif
589          if (bus_attr->lock) {
590              spi_bus_deinit_lock(bus_attr->lock);
591          }
592          free(bus_attr->dmadesc_tx);
593          free(bus_attr->dmadesc_rx);
594      }
595      free(ctx);
596      if (dma_chan) {
597          spicommon_dma_chan_free(dma_chan);
598      }
599      spicommon_periph_free(host_id);
600      return err;
601  }
602  
603  const spi_bus_attr_t* spi_bus_get_attr(spi_host_device_t host_id)
604  {
605      if (bus_ctx[host_id] == NULL) return NULL;
606  
607      return &bus_ctx[host_id]->bus_attr;
608  }
609  
610  esp_err_t spi_bus_free(spi_host_device_t host_id)
611  {
612      esp_err_t err = ESP_OK;
613      spicommon_bus_context_t* ctx = bus_ctx[host_id];
614      spi_bus_attr_t* bus_attr = &ctx->bus_attr;
615  
616      if (ctx->destroy_func) {
617          err = ctx->destroy_func(ctx->destroy_arg);
618      }
619  
620      spicommon_bus_free_io_cfg(&bus_attr->bus_cfg);
621  
622  #ifdef CONFIG_PM_ENABLE
623      esp_pm_lock_delete(bus_attr->pm_lock);
624  #endif
625      spi_bus_deinit_lock(bus_attr->lock);
626  
627      free(bus_attr->dmadesc_rx);
628      free(bus_attr->dmadesc_tx);
629  
630      if (bus_attr->dma_chan > 0) {
631          spicommon_dma_chan_free (bus_attr->dma_chan);
632      }
633      spicommon_periph_free(host_id);
634  
635      free(ctx);
636      bus_ctx[host_id] = NULL;
637      return err;
638  }
639  
640  esp_err_t spi_bus_register_destroy_func(spi_host_device_t host_id,
641                                          spi_destroy_func_t f, void *arg)
642  {
643      bus_ctx[host_id]->destroy_func = f;
644      bus_ctx[host_id]->destroy_arg = arg;
645      return ESP_OK;
646  }
647  
648  
649  /*
650  Code for workaround for DMA issue in ESP32 v0/v1 silicon
651  */
652  #if CONFIG_IDF_TARGET_ESP32
653  static volatile int dmaworkaround_channels_busy[2] = {0, 0};
654  static dmaworkaround_cb_t dmaworkaround_cb;
655  static void *dmaworkaround_cb_arg;
656  static portMUX_TYPE dmaworkaround_mux = portMUX_INITIALIZER_UNLOCKED;
657  static int dmaworkaround_waiting_for_chan = 0;
658  #endif
659  
660  bool IRAM_ATTR spicommon_dmaworkaround_req_reset(int dmachan, dmaworkaround_cb_t cb, void *arg)
661  {
662  #if CONFIG_IDF_TARGET_ESP32
663      int otherchan = (dmachan == 1) ? 2 : 1;
664      bool ret;
665      portENTER_CRITICAL_ISR(&dmaworkaround_mux);
666      if (dmaworkaround_channels_busy[otherchan-1]) {
667          //Other channel is busy. Call back when it's done.
668          dmaworkaround_cb = cb;
669          dmaworkaround_cb_arg = arg;
670          dmaworkaround_waiting_for_chan = otherchan;
671          ret = false;
672      } else {
673          //Reset DMA
674          periph_module_reset( PERIPH_SPI_DMA_MODULE );
675          ret = true;
676      }
677      portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
678      return ret;
679  #else
680      //no need to reset
681      return true;
682  #endif
683  }
684  
685  bool IRAM_ATTR spicommon_dmaworkaround_reset_in_progress(void)
686  {
687  #if CONFIG_IDF_TARGET_ESP32
688      return (dmaworkaround_waiting_for_chan != 0);
689  #else
690      return false;
691  #endif
692  }
693  
694  void IRAM_ATTR spicommon_dmaworkaround_idle(int dmachan)
695  {
696  #if CONFIG_IDF_TARGET_ESP32
697      portENTER_CRITICAL_ISR(&dmaworkaround_mux);
698      dmaworkaround_channels_busy[dmachan-1] = 0;
699      if (dmaworkaround_waiting_for_chan == dmachan) {
700          //Reset DMA
701          periph_module_reset( PERIPH_SPI_DMA_MODULE );
702          dmaworkaround_waiting_for_chan = 0;
703          //Call callback
704          dmaworkaround_cb(dmaworkaround_cb_arg);
705  
706      }
707      portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
708  #endif
709  }
710  
711  void IRAM_ATTR spicommon_dmaworkaround_transfer_active(int dmachan)
712  {
713  #if CONFIG_IDF_TARGET_ESP32
714      portENTER_CRITICAL_ISR(&dmaworkaround_mux);
715      dmaworkaround_channels_busy[dmachan-1] = 1;
716      portEXIT_CRITICAL_ISR(&dmaworkaround_mux);
717  #endif
718  }