1 Star 1 Fork 0

提子麦子/esp8089_sdio_driver

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
esp_io.c 15.69 KB
一键复制 编辑 原始数据 按行查看 历史
Rockchip 提交于 2014-12-08 13:49 . wifi->esp8089:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
/*
* Copyright (c) 2009 - 2014 Espressif System.
* IO interface
* - sdio/spi common i/f driver
* - target sdio hal
*/
#include <linux/mmc/sdio_func.h>
#include "esp_sif.h"
#include "slc_host_register.h"
#include "esp_debug.h"
#ifdef SIF_DEBUG_DSR_DUMP_REG
static void dump_slc_regs(struct slc_host_regs *regs);
#endif /* SIF_DEBUG_DSR_DUMP_REG */
int esp_common_read(struct esp_pub *epub, u8 *buf, u32 len, int sync, bool noround)
{
if (sync) {
#ifdef ESP_USE_SDIO
return sif_lldesc_read_sync(epub, buf, len);
#endif
#ifdef ESP_USE_SPI
return sif_spi_read_sync(epub, buf, len, NOT_DUMMYMODE);
#endif
} else {
#ifdef ESP_USE_SDIO
return sif_lldesc_read_raw(epub, buf, len, noround);
#endif
#ifdef ESP_USE_SPI
return sif_spi_read_nosync(epub, buf, len, NOT_DUMMYMODE, noround);
#endif
}
}
int esp_common_write(struct esp_pub *epub, u8 *buf, u32 len, int sync)
{
if (sync) {
#ifdef ESP_USE_SDIO
return sif_lldesc_write_sync(epub, buf, len);
#endif
#ifdef ESP_USE_SPI
return sif_spi_write_sync(epub, buf, len, NOT_DUMMYMODE);
#endif
} else {
#ifdef ESP_USE_SDIO
return sif_lldesc_write_raw(epub, buf, len);
#endif
#ifdef ESP_USE_SPI
return sif_spi_write_nosync(epub, buf, len, NOT_DUMMYMODE);
#endif
}
}
int esp_common_read_with_addr(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, int sync)
{
if (sync) {
#ifdef ESP_USE_SDIO
return sif_io_sync(epub, addr, buf, len, SIF_FROM_DEVICE | SIF_SYNC | SIF_BYTE_BASIS | SIF_INC_ADDR);
#endif
#ifdef ESP_USE_SPI
return sif_spi_epub_read_mix_sync(epub, addr, buf, len, NOT_DUMMYMODE);
#endif
} else {
#ifdef ESP_USE_SDIO
return sif_io_raw(epub, addr, buf, len, SIF_FROM_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR);
#endif
#ifdef ESP_USE_SPI
return sif_spi_epub_read_mix_nosync(epub, addr, buf, len, NOT_DUMMYMODE);
#endif
}
}
int esp_common_write_with_addr(struct esp_pub *epub, u32 addr, u8 *buf, u32 len, int sync)
{
if (sync) {
#ifdef ESP_USE_SDIO
return sif_io_sync(epub, addr, buf, len, SIF_TO_DEVICE | SIF_SYNC | SIF_BYTE_BASIS | SIF_INC_ADDR);
#endif
#ifdef ESP_USE_SPI
return sif_spi_epub_write_mix_sync(epub, addr, buf, len, NOT_DUMMYMODE);
#endif
} else {
#ifdef ESP_USE_SDIO
return sif_io_raw(epub, addr, buf, len, SIF_TO_DEVICE | SIF_BYTE_BASIS | SIF_INC_ADDR);
#endif
#ifdef ESP_USE_SPI
return sif_spi_epub_write_mix_nosync(epub, addr, buf, len, NOT_DUMMYMODE);
#endif
}
}
int esp_common_readbyte_with_addr(struct esp_pub *epub, u32 addr, u8 *buf, int sync)
{
if(sync){
#ifdef ESP_USE_SDIO
int res;
sif_lock_bus(epub);
*buf = sdio_io_readb(epub, addr, &res);
sif_unlock_bus(epub);
return res;
#endif
#ifdef ESP_USE_SPI
return sif_spi_epub_read_mix_sync(epub, addr, buf, 1, NOT_DUMMYMODE);
#endif
} else {
#ifdef ESP_USE_SDIO
int res;
*buf = sdio_io_readb(epub, addr, &res);
return res;
#endif
#ifdef ESP_USE_SPI
return sif_spi_epub_read_mix_nosync(epub, addr, buf, 1, NOT_DUMMYMODE);
#endif
}
}
int esp_common_writebyte_with_addr(struct esp_pub *epub, u32 addr, u8 buf, int sync)
{
if(sync){
#ifdef ESP_USE_SDIO
int res;
sif_lock_bus(epub);
sdio_io_writeb(epub, buf, addr, &res);
sif_unlock_bus(epub);
return res;
#endif
#ifdef ESP_USE_SPI
return sif_spi_epub_write_mix_sync(epub, addr, &buf, 1, NOT_DUMMYMODE);
#endif
} else {
#ifdef ESP_USE_SDIO
int res;
sdio_io_writeb(epub, buf, addr, &res);
return res;
#endif
#ifdef ESP_USE_SPI
return sif_spi_epub_write_mix_nosync(epub, addr, &buf, 1, NOT_DUMMYMODE);
#endif
}
}
int sif_read_reg_window(struct esp_pub *epub, unsigned int reg_addr, u8 *value)
{
u8 *p_tbuf = NULL;
int ret = 0;
int retry = 20;
reg_addr >>= 2;
if(reg_addr > 0x1f)
return -1;
p_tbuf = kzalloc(4, GFP_KERNEL);
if(p_tbuf == NULL)
return -ENOMEM;
p_tbuf[0] = 0x80 | (reg_addr & 0x1f);
ret = esp_common_write_with_addr(epub, SLC_HOST_WIN_CMD, p_tbuf, 1, ESP_SIF_NOSYNC);
if(ret == 0)
{
do{
if(retry < 20)
mdelay(10);
retry --;
ret = esp_common_read_with_addr(epub, SLC_HOST_STATE_W0, p_tbuf, 4, ESP_SIF_NOSYNC);
}while(retry >0 && ret != 0);
}
if(ret ==0)
memcpy(value,p_tbuf,4);
kfree(p_tbuf);
return ret;
}
int sif_write_reg_window(struct esp_pub *epub, unsigned int reg_addr,u8 *value)
{
u8 *p_tbuf = NULL;
int ret = 0;
reg_addr >>= 2;
if(reg_addr > 0x1f)
return -1;
p_tbuf = kzalloc(8, GFP_KERNEL);
if(p_tbuf == NULL)
return -ENOMEM;
memcpy(p_tbuf,value,4);
p_tbuf[4] = 0xc0 |(reg_addr & 0x1f);
ret = esp_common_write_with_addr(epub, SLC_HOST_CONF_W5, p_tbuf, 5, ESP_SIF_NOSYNC);
kfree(p_tbuf);
return ret;
}
int sif_ack_target_read_err(struct esp_pub *epub)
{
u32 value[1];
int ret;
ret = sif_read_reg_window(epub, SLC_RX_LINK, (u8 *)value);
if(ret)
return ret;
value[0] |= SLC_RXLINK_START;
ret = sif_write_reg_window(epub, SLC_RX_LINK, (u8 *)value);
return ret;
}
int sif_had_io_enable(struct esp_pub *epub)
{
u32 *p_tbuf = NULL;
int ret;
p_tbuf = kzalloc(sizeof(u32), GFP_KERNEL);
if(p_tbuf == NULL)
return -ENOMEM;
*p_tbuf = SLC_TXEOF_ENA | (0x4 << SLC_FIFO_MAP_ENA_S) | SLC_TX_DUMMY_MODE | SLC_HDA_MAP_128K | (0xFE << SLC_TX_PUSH_IDLE_NUM_S);
ret = sif_write_reg_window(epub, SLC_BRIDGE_CONF, (u8 *)p_tbuf);
if(ret)
goto _err;
*p_tbuf = 0x30;
ret = esp_common_write_with_addr((epub), SLC_HOST_CONF_W4 + 1, (u8 *)p_tbuf, 1, ESP_SIF_NOSYNC);
if(ret)
goto _err;
//set w3 0
*p_tbuf = 0x1;
ret = esp_common_write_with_addr((epub), SLC_HOST_CONF_W3, (u8 *)p_tbuf, 1, ESP_SIF_NOSYNC);
_err:
kfree(p_tbuf);
return ret;
}
typedef enum _SDIO_INTR_MODE {
SDIO_INTR_IB = 0,
SDIO_INTR_OOB_TOGGLE,
SDIO_INTR_OOB_HIGH_LEVEL,
SDIO_INTR_OOB_LOW_LEVEL,
} SDIO_INTR_MODE;
#define GEN_GPIO_SEL(_gpio_num, _sel_func, _intr_mode, _offset) (((_offset)<< 9 ) |((_intr_mode) << 7)|((_sel_func) << 4)|(_gpio_num))
//bit[3:0] = gpio num, 2
//bit[6:4] = gpio sel func, 0
//bit[8:7] = gpio intr mode, SDIO_INTR_OOB_TOGGLE
//bit[15:9] = register offset, 0x38
u16 gpio_sel_sets[17] = {
GEN_GPIO_SEL(0, 0, SDIO_INTR_OOB_TOGGLE, 0x34),//GPIO0
GEN_GPIO_SEL(1, 3, SDIO_INTR_OOB_TOGGLE, 0x18),//U0TXD
GEN_GPIO_SEL(2, 0, SDIO_INTR_OOB_TOGGLE, 0x38),//GPIO2
GEN_GPIO_SEL(3, 3, SDIO_INTR_OOB_TOGGLE, 0x14),//U0RXD
GEN_GPIO_SEL(4, 0, SDIO_INTR_OOB_TOGGLE, 0x3C),//GPIO4
GEN_GPIO_SEL(5, 0, SDIO_INTR_OOB_TOGGLE, 0x40),//GPIO5
GEN_GPIO_SEL(6, 3, SDIO_INTR_OOB_TOGGLE, 0x1C),//SD_CLK
GEN_GPIO_SEL(7, 3, SDIO_INTR_OOB_TOGGLE, 0x20),//SD_DATA0
GEN_GPIO_SEL(8, 3, SDIO_INTR_OOB_TOGGLE, 0x24),//SD_DATA1
GEN_GPIO_SEL(9, 3, SDIO_INTR_OOB_TOGGLE, 0x28),//SD_DATA2
GEN_GPIO_SEL(10, 3, SDIO_INTR_OOB_TOGGLE, 0x2C),//SD_DATA3
GEN_GPIO_SEL(11, 3, SDIO_INTR_OOB_TOGGLE, 0x30),//SD_CMD
GEN_GPIO_SEL(12, 3, SDIO_INTR_OOB_TOGGLE, 0x04),//MTDI
GEN_GPIO_SEL(13, 3, SDIO_INTR_OOB_TOGGLE, 0x08),//MTCK
GEN_GPIO_SEL(14, 3, SDIO_INTR_OOB_TOGGLE, 0x0C),//MTMS
GEN_GPIO_SEL(15, 3, SDIO_INTR_OOB_TOGGLE, 0x10),//MTDO
//pls do not change sel before, if you want to change intr mode,change the one blow
//GEN_GPIO_SEL(2, 0, SDIO_INTR_OOB_TOGGLE, 0x38)
GEN_GPIO_SEL(2, 0, SDIO_INTR_OOB_LOW_LEVEL, 0x38)
};
#if defined(USE_EXT_GPIO)
u16 gpio_forbidden = 0;
#endif
int sif_interrupt_target(struct esp_pub *epub, u8 index)
{
u8 low_byte = BIT(index);
return esp_common_writebyte_with_addr(epub, SLC_HOST_CONF_W4 + 2, low_byte, ESP_SIF_NOSYNC);
}
#ifdef USE_EXT_GPIO
int sif_config_gpio_mode(struct esp_pub *epub, u8 gpio_num, u8 gpio_mode)
{
u32 *p_tbuf = NULL;
int err;
if((BIT(gpio_num) & gpio_forbidden) || gpio_num > 15)
return -EINVAL;
p_tbuf = kzalloc(sizeof(u32), GFP_KERNEL);
if(p_tbuf == NULL)
return -ENOMEM;
*p_tbuf = (gpio_mode << 16) | gpio_sel_sets[gpio_num];
err = esp_common_write_with_addr(epub, SLC_HOST_CONF_W1, (u8*)p_tbuf, sizeof(u32), ESP_SIF_NOSYNC);
kfree(p_tbuf);
if (err)
return err;
return sif_interrupt_target(epub, 4);
}
int sif_set_gpio_output(struct esp_pub *epub, u16 mask, u16 value)
{
u32 *p_tbuf = NULL;
int err;
mask &= ~gpio_forbidden;
p_tbuf = kzalloc(sizeof(u32), GFP_KERNEL);
if(p_tbuf == NULL)
return -ENOMEM;
*p_tbuf = (mask << 16) | value;
err = esp_common_write_with_addr(epub, SLC_HOST_CONF_W2, (u8*)p_tbuf, sizeof(u32), ESP_SIF_NOSYNC);
kfree(p_tbuf);
if (err)
return err;
return sif_interrupt_target(epub, 5);
}
int sif_get_gpio_intr(struct esp_pub *epub, u16 intr_mask, u16 *value)
{
u32 *p_tbuf = NULL;
int err;
p_tbuf = kzalloc(sizeof(u32), GFP_KERNEL);
if(p_tbuf == NULL)
return -ENOMEM;
*p_tbuf = 0;
err = esp_common_read_with_addr(epub, SLC_HOST_CONF_W3, (u8*)p_tbuf, sizeof(u32), ESP_SIF_NOSYNC);
if (err){
kfree(p_tbuf);
return err;
}
*value = *p_tbuf & intr_mask;
kfree(p_tbuf);
if(*value == 0)
return 0;
return sif_interrupt_target(epub, 6);
}
int sif_get_gpio_input(struct esp_pub *epub, u16 *mask, u16 *value)
{
u32 *p_tbuf = NULL;
int err;
err = sif_interrupt_target(epub, 3);
if (err)
return err;
udelay(20);
p_tbuf = kzalloc(sizeof(u32), GFP_KERNEL);
if(p_tbuf == NULL)
return -ENOMEM;
*p_tbuf = 0;
err = esp_common_read_with_addr(epub, SLC_HOST_CONF_W3, (u8*)p_tbuf, sizeof(u32), ESP_SIF_NOSYNC);
if (err){
kfree(p_tbuf);
return err;
}
*mask = *p_tbuf >> 16;
*value = *p_tbuf & *mask;
kfree(p_tbuf);
return 0;
}
#endif
void check_target_id(struct esp_pub *epub)
{
u32 date;
int err = 0;
int i;
EPUB_CTRL_CHECK(epub, _err);
sif_lock_bus(epub);
for(i = 0; i < 4; i++) {
err = esp_common_readbyte_with_addr(epub, SLC_HOST_DATE + i, (u8 *)&date + i, ESP_SIF_NOSYNC);
err = esp_common_readbyte_with_addr(epub, SLC_HOST_ID + i, (u8 *)&EPUB_TO_CTRL(epub)->target_id + i, ESP_SIF_NOSYNC);
}
sif_unlock_bus(epub);
esp_dbg(ESP_DBG_LOG, "\n\n \t\t SLC data 0x%08x, ID 0x%08x\n\n", date, EPUB_TO_CTRL(epub)->target_id);
switch(EPUB_TO_CTRL(epub)->target_id) {
case 0x100:
EPUB_TO_CTRL(epub)->slc_window_end_addr = 0x20000;
break;
case 0x600:
EPUB_TO_CTRL(epub)->slc_window_end_addr = 0x20000 - 0x800;
do{
u16 gpio_sel;
u8 low_byte = 0;
u8 high_byte = 0;
u8 byte2 = 0;
u8 byte3 = 0;
#ifdef USE_OOB_INTR
gpio_sel = gpio_sel_sets[16];
low_byte = gpio_sel;
high_byte = gpio_sel >> 8;
#ifdef USE_EXT_GPIO
gpio_forbidden |= BIT(gpio_sel & 0xf);
#endif /* USE_EXT_GPIO */
#endif /* USE_OOB_INTR */
if(sif_get_bt_config() == 1 && sif_get_rst_config() != 1){
u8 gpio_num = sif_get_wakeup_gpio_config();
gpio_sel = gpio_sel_sets[gpio_num];
byte2 = gpio_sel;
byte3 = gpio_sel >> 8;
#ifdef USE_EXT_GPIO
gpio_forbidden |= BIT(gpio_num);
#endif
}
sif_lock_bus(epub);
err = esp_common_writebyte_with_addr(epub, SLC_HOST_CONF_W1, low_byte, ESP_SIF_NOSYNC);
err = esp_common_writebyte_with_addr(epub, SLC_HOST_CONF_W1 + 1, high_byte, ESP_SIF_NOSYNC);
err = esp_common_writebyte_with_addr(epub, SLC_HOST_CONF_W1 + 2, byte2, ESP_SIF_NOSYNC);
err = esp_common_writebyte_with_addr(epub, SLC_HOST_CONF_W1 + 3, byte3, ESP_SIF_NOSYNC);
sif_unlock_bus(epub);
}while(0);
break;
default:
EPUB_TO_CTRL(epub)->slc_window_end_addr = 0x20000;
break;
}
_err:
return;
}
u32 sif_get_blksz(struct esp_pub *epub)
{
EPUB_CTRL_CHECK(epub, _err);
return EPUB_TO_CTRL(epub)->slc_blk_sz;
_err:
return 512;
}
u32 sif_get_target_id(struct esp_pub *epub)
{
EPUB_CTRL_CHECK(epub, _err);
return EPUB_TO_CTRL(epub)->target_id;
_err:
return 0x600;
}
#ifdef ESP_USE_SDIO
void sif_dsr(struct sdio_func *func)
{
struct esp_sdio_ctrl *sctrl = sdio_get_drvdata(func);
#else
void sif_dsr(struct spi_device *spi)
{
struct esp_spi_ctrl *sctrl = spi_get_drvdata(spi);
u32 buf[1];
#endif
static int dsr_cnt = 0, real_intr_cnt = 0, bogus_intr_cnt = 0;
struct slc_host_regs *regs = &(sctrl->slc_regs);
esp_dbg(ESP_DBG_TRACE, " %s enter %d \n", __func__, dsr_cnt++);
#ifdef ESP_USE_SPI
if(sctrl->epub->wait_reset == 1)
{
mdelay(50);
return;
}
if(sctrl->epub->enable_int == 1)
{
sif_read_reg_window(sctrl->epub, SLC_INT_ENA, (u8 *)buf);
buf[0] &= ~(SLC_RX_EOF_INT_ENA);
buf[0] |= SLC_FRHOST_BIT2_INT_ENA;
sif_write_reg_window(sctrl->epub, SLC_INT_ENA, (u8 *)buf);
sctrl->epub->enable_int = 0;
}
#endif
atomic_set(&sctrl->irq_handling, 1);
#ifdef ESP_USE_SDIO
sdio_release_host(sctrl->func);
#endif
sif_lock_bus(sctrl->epub);
do {
int ret =0;
memset(regs, 0x0, sizeof(struct slc_host_regs));
ret = esp_common_read_with_addr(sctrl->epub, REG_SLC_HOST_BASE + 8, (u8 *)regs, sizeof(struct slc_host_regs), ESP_SIF_NOSYNC);
if ( (regs->intr_raw & SLC_HOST_RX_ST) && (ret == 0) ) {
esp_dbg(ESP_DBG_TRACE, "%s eal intr cnt: %d", __func__, ++real_intr_cnt);
esp_dsr(sctrl->epub);
} else {
#ifdef ESP_ACK_INTERRUPT
sif_platform_ack_interrupt(sctrl->epub);
#endif //ESP_ACK_INTERRUPT
sif_unlock_bus(sctrl->epub);
esp_dbg(ESP_DBG_TRACE, "%s bogus_intr_cnt %d\n", __func__, ++bogus_intr_cnt);
}
#ifdef SIF_DEBUG_DSR_DUMP_REG
dump_slc_regs(regs);
#endif /* SIF_DEBUG_DUMP_DSR */
} while (0);
#ifdef ESP_USE_SDIO
sdio_claim_host(func);
#endif
atomic_set(&sctrl->irq_handling, 0);
}
struct slc_host_regs * sif_get_regs(struct esp_pub *epub)
{
EPUB_CTRL_CHECK(epub, _err);
return &EPUB_TO_CTRL(epub)->slc_regs;
_err:
return NULL;
}
void sif_disable_target_interrupt(struct esp_pub *epub)
{
EPUB_FUNC_CHECK(epub, _exit);
sif_lock_bus(epub);
#ifdef HOST_RESET_BUG
mdelay(10);
#endif
memset(EPUB_TO_CTRL(epub)->dma_buffer, 0x00, sizeof(u32));
esp_common_write_with_addr(epub, SLC_HOST_INT_ENA, EPUB_TO_CTRL(epub)->dma_buffer, sizeof(u32), ESP_SIF_NOSYNC);
#ifdef HOST_RESET_BUG
mdelay(10);
#endif
sif_unlock_bus(epub);
mdelay(1);
sif_lock_bus(epub);
sif_interrupt_target(epub, 7);
sif_unlock_bus(epub);
_exit:
return;
}
#ifdef SIF_DEBUG_DSR_DUMP_REG
static void dump_slc_regs(struct slc_host_regs *regs)
{
esp_dbg(ESP_DBG_TRACE, "\n\n ------- %s --------------\n", __func__);
esp_dbg(ESP_DBG_TRACE, " \
intr_raw 0x%08X \t \n \
state_w0 0x%08X \t state_w1 0x%08X \n \
config_w0 0x%08X \t config_w1 0x%08X \n \
intr_status 0x%08X \t config_w2 0x%08X \n \
config_w3 0x%08X \t config_w4 0x%08X \n \
token_wdata 0x%08X \t intr_clear 0x%08X \n \
intr_enable 0x%08X \n\n", regs->intr_raw, \
regs->state_w0, regs->state_w1, regs->config_w0, regs->config_w1, \
regs->intr_status, \
regs->config_w2, regs->config_w3, regs->config_w4, regs->token_wdata, \
regs->intr_clear, regs->intr_enable);
}
#endif /* SIF_DEBUG_DSR_DUMP_REG */
static int bt_config = 0;
void sif_record_bt_config(int value)
{
bt_config = value;
}
int sif_get_bt_config(void)
{
return bt_config;
}
static int rst_config = 0;
void sif_record_rst_config(int value)
{
rst_config = value;
}
int sif_get_rst_config(void)
{
return rst_config;
}
static int ate_test = 0;
void sif_record_ate_config(int value)
{
ate_test =value;
}
int sif_get_ate_config(void)
{
return ate_test;
}
static int retry_reset = 0;
void sif_record_retry_config(void)
{
retry_reset = 1;
}
int sif_get_retry_config(void)
{
return retry_reset;
}
static int wakeup_gpio = 12;
void sif_record_wakeup_gpio_config(int value)
{
wakeup_gpio = value;
}
int sif_get_wakeup_gpio_config(void)
{
return wakeup_gpio;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/raisin_wheat/esp8089_sdio_driver.git
git@gitee.com:raisin_wheat/esp8089_sdio_driver.git
raisin_wheat
esp8089_sdio_driver
esp8089_sdio_driver
al177

搜索帮助