1 /*
2  * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #pragma once
8 
9 #include "soc/soc_caps.h"
10 #if SOC_SDMMC_HOST_SUPPORTED
11 
12 #include <stdint.h>
13 #include <stddef.h>
14 #include "esp_err.h"
15 #include "sdmmc_types.h"
16 #include "driver/gpio.h"
17 
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21 
22 #define SDMMC_HOST_SLOT_0     0     ///< SDMMC slot 0
23 #define SDMMC_HOST_SLOT_1     1     ///< SDMMC slot 1
24 
25 /**
26  * @brief Default sdmmc_host_t structure initializer for SDMMC peripheral
27  *
28  * Uses SDMMC peripheral, with 4-bit mode enabled, and max frequency set to 20MHz
29  */
30 #define SDMMC_HOST_DEFAULT() {\
31     .flags = SDMMC_HOST_FLAG_8BIT | \
32              SDMMC_HOST_FLAG_4BIT | \
33              SDMMC_HOST_FLAG_1BIT | \
34              SDMMC_HOST_FLAG_DDR, \
35     .slot = SDMMC_HOST_SLOT_1, \
36     .max_freq_khz = SDMMC_FREQ_DEFAULT, \
37     .io_voltage = 3.3f, \
38     .init = &sdmmc_host_init, \
39     .set_bus_width = &sdmmc_host_set_bus_width, \
40     .get_bus_width = &sdmmc_host_get_slot_width, \
41     .set_bus_ddr_mode = &sdmmc_host_set_bus_ddr_mode, \
42     .set_card_clk = &sdmmc_host_set_card_clk, \
43     .do_transaction = &sdmmc_host_do_transaction, \
44     .deinit = &sdmmc_host_deinit, \
45     .io_int_enable = sdmmc_host_io_int_enable, \
46     .io_int_wait = sdmmc_host_io_int_wait, \
47     .command_timeout_ms = 0, \
48 }
49 
50 /**
51  * Extra configuration for SDMMC peripheral slot
52  */
53 typedef struct {
54 #ifdef SOC_SDMMC_USE_GPIO_MATRIX
55     gpio_num_t clk;         ///< GPIO number of CLK signal.
56     gpio_num_t cmd;         ///< GPIO number of CMD signal.
57     gpio_num_t d0;          ///< GPIO number of D0 signal.
58     gpio_num_t d1;          ///< GPIO number of D1 signal.
59     gpio_num_t d2;          ///< GPIO number of D2 signal.
60     gpio_num_t d3;          ///< GPIO number of D3 signal.
61     gpio_num_t d4;          ///< GPIO number of D4 signal. Ignored in 1- or 4- line mode.
62     gpio_num_t d5;          ///< GPIO number of D5 signal. Ignored in 1- or 4- line mode.
63     gpio_num_t d6;          ///< GPIO number of D6 signal. Ignored in 1- or 4- line mode.
64     gpio_num_t d7;          ///< GPIO number of D7 signal. Ignored in 1- or 4- line mode.
65 #endif // SOC_SDMMC_USE_GPIO_MATRIX
66     union {
67         gpio_num_t gpio_cd;     ///< GPIO number of card detect signal
68         gpio_num_t cd;          ///< GPIO number of card detect signal; shorter name.
69     };
70     union {
71         gpio_num_t gpio_wp;     ///< GPIO number of write protect signal
72         gpio_num_t wp;          ///< GPIO number of write protect signal; shorter name.
73     };
74     uint8_t width;          ///< Bus width used by the slot (might be less than the max width supported)
75     uint32_t flags;         ///< Features used by this slot
76 #define SDMMC_SLOT_FLAG_INTERNAL_PULLUP  BIT(0)
77         /**< Enable internal pullups on enabled pins. The internal pullups
78          are insufficient however, please make sure external pullups are
79          connected on the bus. This is for debug / example purpose only.
80          */
81 } sdmmc_slot_config_t;
82 
83 #define SDMMC_SLOT_NO_CD      GPIO_NUM_NC     ///< indicates that card detect line is not used
84 #define SDMMC_SLOT_NO_WP      GPIO_NUM_NC     ///< indicates that write protect line is not used
85 #define SDMMC_SLOT_WIDTH_DEFAULT 0 ///< use the maximum possible width for the slot
86 
87 #ifdef SOC_SDMMC_USE_GPIO_MATRIX
88 
89 /**
90  * Macro defining default configuration of SDMMC host slot
91  */
92 #define SDMMC_SLOT_CONFIG_DEFAULT() {\
93     .clk = GPIO_NUM_14, \
94     .cmd = GPIO_NUM_15, \
95     .d0 = GPIO_NUM_2, \
96     .d1 = GPIO_NUM_4, \
97     .d2 = GPIO_NUM_12, \
98     .d3 = GPIO_NUM_13, \
99     .d4 = GPIO_NUM_33, \
100     .d5 = GPIO_NUM_34, \
101     .d6 = GPIO_NUM_35, \
102     .d7 = GPIO_NUM_36, \
103     .cd = SDMMC_SLOT_NO_CD, \
104     .wp = SDMMC_SLOT_NO_WP, \
105     .width   = SDMMC_SLOT_WIDTH_DEFAULT, \
106     .flags = 0, \
107 }
108 
109 #else // SOC_SDMMC_USE_GPIO_MATRIX
110 
111 /**
112  * Macro defining default configuration of SDMMC host slot
113  */
114 #define SDMMC_SLOT_CONFIG_DEFAULT() {\
115     .cd = SDMMC_SLOT_NO_CD, \
116     .wp = SDMMC_SLOT_NO_WP, \
117     .width   = SDMMC_SLOT_WIDTH_DEFAULT, \
118     .flags = 0, \
119 }
120 
121 #endif // SOC_SDMMC_USE_GPIO_MATRIX
122 
123 /**
124  * @brief Initialize SDMMC host peripheral
125  *
126  * @note This function is not thread safe
127  *
128  * @return
129  *      - ESP_OK on success
130  *      - ESP_ERR_INVALID_STATE if sdmmc_host_init was already called
131  *      - ESP_ERR_NO_MEM if memory can not be allocated
132  */
133 esp_err_t sdmmc_host_init(void);
134 
135 /**
136  * @brief Initialize given slot of SDMMC peripheral
137  *
138  * On the ESP32, SDMMC peripheral has two slots:
139  *  - Slot 0: 8-bit wide, maps to HS1_* signals in PIN MUX
140  *  - Slot 1: 4-bit wide, maps to HS2_* signals in PIN MUX
141  *
142  * Card detect and write protect signals can be routed to
143  * arbitrary GPIOs using GPIO matrix.
144  *
145  * @note This function is not thread safe
146  *
147  * @param slot  slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
148  * @param slot_config  additional configuration for the slot
149  * @return
150  *      - ESP_OK on success
151  *      - ESP_ERR_INVALID_STATE if host has not been initialized using sdmmc_host_init
152  */
153 esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t* slot_config);
154 
155 /**
156  * @brief Select bus width to be used for data transfer
157  *
158  * SD/MMC card must be initialized prior to this command, and a command to set
159  * bus width has to be sent to the card (e.g. SD_APP_SET_BUS_WIDTH)
160  *
161  * @note This function is not thread safe
162  *
163  * @param slot  slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
164  * @param width  bus width (1, 4, or 8 for slot 0; 1 or 4 for slot 1)
165  * @return
166  *      - ESP_OK on success
167  *      - ESP_ERR_INVALID_ARG if slot number or width is not valid
168  */
169 esp_err_t sdmmc_host_set_bus_width(int slot, size_t width);
170 
171 /**
172  * @brief Get bus width configured in ``sdmmc_host_init_slot`` to be used for data transfer
173  *
174  * @param slot  slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
175  * @return configured bus width of the specified slot.
176  */
177 size_t sdmmc_host_get_slot_width(int slot);
178 
179 /**
180  * @brief Set card clock frequency
181  *
182  * Currently only integer fractions of 40MHz clock can be used.
183  * For High Speed cards, 40MHz can be used.
184  * For Default Speed cards, 20MHz can be used.
185  *
186  * @note This function is not thread safe
187  *
188  * @param slot  slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
189  * @param freq_khz  card clock frequency, in kHz
190  * @return
191  *      - ESP_OK on success
192  *      - other error codes may be returned in the future
193  */
194 esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz);
195 
196 /**
197  * @brief Enable or disable DDR mode of SD interface
198  * @param slot  slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
199  * @param ddr_enabled  enable or disable DDR mode
200  * @return
201  *      - ESP_OK on success
202  *      - ESP_ERR_NOT_SUPPORTED if DDR mode is not supported on this slot
203  */
204 esp_err_t sdmmc_host_set_bus_ddr_mode(int slot, bool ddr_enabled);
205 
206 /**
207  * @brief Send command to the card and get response
208  *
209  * This function returns when command is sent and response is received,
210  * or data is transferred, or timeout occurs.
211  *
212  * @note This function is not thread safe w.r.t. init/deinit functions,
213  *       and bus width/clock speed configuration functions. Multiple tasks
214  *       can call sdmmc_host_do_transaction as long as other sdmmc_host_*
215  *       functions are not called.
216  *
217  * @attention Data buffer passed in cmdinfo->data must be in DMA capable memory
218  *
219  * @param slot  slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
220  * @param cmdinfo   pointer to structure describing command and data to transfer
221  * @return
222  *      - ESP_OK on success
223  *      - ESP_ERR_TIMEOUT if response or data transfer has timed out
224  *      - ESP_ERR_INVALID_CRC if response or data transfer CRC check has failed
225  *      - ESP_ERR_INVALID_RESPONSE if the card has sent an invalid response
226  *      - ESP_ERR_INVALID_SIZE if the size of data transfer is not valid in SD protocol
227  *      - ESP_ERR_INVALID_ARG if the data buffer is not in DMA capable memory
228  */
229 esp_err_t sdmmc_host_do_transaction(int slot, sdmmc_command_t* cmdinfo);
230 
231 /**
232  * @brief Enable IO interrupts
233  *
234  * This function configures the host to accept SDIO interrupts.
235  *
236  * @param slot  slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
237  * @return returns ESP_OK, other errors possible in the future
238  */
239 esp_err_t sdmmc_host_io_int_enable(int slot);
240 
241 /**
242  * @brief Block until an SDIO interrupt is received, or timeout occurs
243  * @param slot  slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1)
244  * @param timeout_ticks  number of RTOS ticks to wait for the interrupt
245  * @return
246  *  - ESP_OK on success (interrupt received)
247  *  - ESP_ERR_TIMEOUT if the interrupt did not occur within timeout_ticks
248  */
249 esp_err_t sdmmc_host_io_int_wait(int slot, TickType_t timeout_ticks);
250 
251 /**
252  * @brief Disable SDMMC host and release allocated resources
253  *
254  * @note This function is not thread safe
255  *
256  * @return
257  *      - ESP_OK on success
258  *      - ESP_ERR_INVALID_STATE if sdmmc_host_init function has not been called
259  */
260 esp_err_t sdmmc_host_deinit(void);
261 
262 /**
263  * @brief Enable the pull-ups of sd pins.
264  *
265  * This function is deprecated. Please set SDMMC_SLOT_FLAG_INTERNAL_PULLUP flag in
266  * sdmmc_slot_config_t::flags instead.
267  *
268  * @note You should always place actual pullups on the lines instead of using
269  * this function. Internal pullup resistance are high and not sufficient, may
270  * cause instability in products. This is for debug or examples only.
271  *
272  * @param slot Slot to use, normally set it to 1.
273  * @param width Bit width of your configuration, 1 or 4.
274  *
275  * @return
276  *      - ESP_OK: if success
277  *      - ESP_ERR_INVALID_ARG: if configured width larger than maximum the slot can
278  *              support
279  */
280 esp_err_t sdmmc_host_pullup_en(int slot, int width) __attribute__((deprecated));
281 
282 #ifdef __cplusplus
283 }
284 #endif
285 
286 #endif //SOC_SDMMC_HOST_SUPPORTED
287