linux下的sdcard驱动学习

调一款加密ic ET300时,发现通信不上,报错-110,就是超时出错,检查了gpio和sdcard配置,也检查了sd供电,发现sdio的供电域是1.8v,而根据协议初始化时默认是3.3v,然后切换到1.8v,通过飞线,使用一个ldo来供电。修改后,还是通信异常。

加打印调试,在mmc_send_cid函数报错了,就是读不到卡的cid信息。默认读不到cid,代码就退出了。 检查了再检查,实在找不出问题,于是修改代码,强制往下跑,看log,居然读到了卡的信息。

也就是只有CMD2命令跑不过,其他命令都跑过了。

发送CMD2命令前会先切换到1.8v的电压,对应平台的sdio驱动

 也就是sdio host的名字是sdio_sd才会复位下平台的sdio host,而dts配置名字不是sdio_sd,导致没有复位平台的host,修改名字后,代码能正常跑过。

调是调完了,顺便把相关的代码逻辑整理下。

从mmc_rescan这个函数讲起,相关内容已在Linux下的eMMC_Android开发-优快云博客描述过。

//以不同频率去扫描卡,但实际上某些平台定义的最小频率是400k(只会以400k去扫)
void mmc_rescan(struct work_struct *work)
{
    ...
    for (i = 0; i < ARRAY_SIZE(freqs); i++) {
        if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
            break;
        if (freqs[i] <= host->f_min)
            break;
    }
    ...
}
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
    mmc_power_up(host, host->ocr_avail);
    if (!(host->caps2 & MMC_CAP2_NO_SDIO))
        sdio_reset(host);

    mmc_go_idle(host);
    mmc_attach_sd(host);
    mmc_power_off(host);
    return -EIO;
}

int mmc_attach_sd(struct mmc_host *host)
{
    ...
    err = mmc_send_app_op_cond(host, 0, &ocr);
    mmc_attach_bus(host, &mmc_sd_ops);
    if (host->ocr_avail_sd)
        host->ocr_avail = host->ocr_avail_sd;

    rocr = mmc_select_voltage(host, ocr);
    err = mmc_sd_init_card(host, rocr, NULL);
    mmc_release_host(host);
    err = mmc_add_card(host->card);
    mmc_claim_host(host);
    ...
}


比较关键了几个函数mmc_send_app_op_cond,mmc_sd_init_card仔细看的话,实际上是sd协议的代码实现。如果扫描到了sd卡,会在/sys/bus/mmc/devices

生成相应的设备节点。

说到sd协议,比较权威的资料就是官网文档了,下载地址Simplified Specifications | SD Association,下这一篇(Physical Layer Simplified Specification)速度慢点,还是能下载的(自己也上传了一份Part1_Physical_Layer_Simplified_Specification_Ver8.00.pdf-Android文档类资源-优快云下载)。

比较关键的一张图,然后按照代码慢慢看吧。

补上sdcard热插拔部分

dts配置检测脚,如

&sdio0 {
         cd-gpios = <&eic_sync 19 GPIO_ACTIVE_LOW>;
};
int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,unsigned int idx, bool override_active_level,unsigned int debounce, bool *gpio_invert)
{
	desc = devm_gpiod_get_index(host->parent, con_id, idx, GPIOD_IN);
	ctx->cd_gpio = desc;
}

void mmc_gpiod_request_cd_irq(struct mmc_host *host)
{
	irq = gpiod_to_irq(ctx->cd_gpio);
	ret = devm_request_threaded_irq(host->parent, irq,NULL, mmc_gpio_cd_irqt,IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,ctx->cd_label, host);
}

int mmc_of_parse(struct mmc_host *host){
{
	mmc_gpiod_request_cd(host, "cd", 0, true,0, &cd_gpio_invert);//获取热插拔的gpio
}
int mmc_add_host(struct mmc_host *host)
{
	mmc_start_host-->mmc_gpiod_request_cd_irq/申请中断
}
static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
{
	/* Schedule a card detection after a debounce timeout */
	struct mmc_host *host = dev_id;

	host->trigger_card_event = true;
	mmc_detect_change(host, msecs_to_jiffies(200));-->mmc_schedule_delayed_work(&host->detect, delay);

	return IRQ_HANDLED;
}


INIT_DELAYED_WORK(&host->detect, mmc_rescan);//进行重新扫描

 

<think>好的,我现在需要帮助用户解决SDIO功能启用失败的问题,错误码-110。首先,我需要理解这个错误码的具体含义。根据Linux内核的错误码,-110通常对应ETIMEDOUT,也就是操作超时。这可能意味着在启用SDIO功能时,设备没有在预期的时间内响应,导致超时错误。 接下来,我应该考虑可能的原因。首先,硬件连接问题可能导致通信失败,比如接触不良或线路损坏。其次,驱动配置是否正确也很重要,包括电源管理设置、时钟频率是否匹配,以及中断配置是否正确。另外,设备固件可能存在问题,需要更新或重新加载。还有,SDIO总线本身的配置,如总线宽度或电压,是否与设备兼容。 然后,我需要参考用户提供的引用内容。引用[1]提到了加载bdwlan30.bin的日志,这可能与无线模块的固件有关,提示检查固件是否正确加载。引用[2]提到了设置EXTRA_COMPONENT_DIRS路径,可能涉及驱动或组件的位置问题,需要确认驱动是否正确安装,路径是否配置妥当。 解决方案方面,我应该分步骤建议用户检查硬件连接,确认SDIO接口接触良好;检查驱动配置,特别是电源管理和时钟设置;更新或重新加载设备固件;验证SDIO总线参数是否符合设备要求;查看系统日志获取更多错误信息,比如使用dmesg命令;最后,如果问题依旧,可能需要联系硬件供应商寻求支持。 最后,我需要生成相关问题,帮助用户进一步排查,比如询问硬件兼容性、驱动版本、系统日志中的其他错误等。确保回答结构清晰,引用相关提示,并覆盖可能的原因和解决方法。</think>### SDIO功能启用失败错误码-110的解决方案 错误码`-110`在Linux系统中通常对应`ETIMEDOUT`,表示操作超时。在SDIO功能启用失败时,可能涉及硬件、驱动或配置问题。以下是分步解决方案: --- #### 1. **检查硬件连接** - **接触不良**:SDIO接口的物理接触不良可能导致通信失败。重新插拔设备或检查接口是否氧化/损坏[^1]。 - **电源供应**:确保设备供电稳定,电压符合规格(如3.3V或1.8V)。 - **信号完整性**:使用示波器检查时钟(CLK)、数据线(DAT0-DAT3)和命令线(CMD)的波形是否正常。 --- #### 2. **验证驱动与配置** - **驱动加载状态**:通过`lsmod`确认SDIO驱动(如`sdio_uart`或`ath6kl_sdio`)已正确加载。 - **时钟频率设置**:SDIO设备可能对时钟频率敏感,尝试降低时钟速度(如修改驱动中的`clock`参数)。 - **电源管理配置**:在设备树(Device Tree)或驱动代码中关闭电源管理(如设置`keep_power = 1`)。 - **中断配置**:检查中断请求(IRQ)是否冲突,确认驱动正确注册中断处理函数。 --- #### 3. **固件与固件路径** - **固件缺失/错误**:错误日志如`check_wifi_bdwlan_filename:HWID:0001`提示固件加载问题[^1]: - 确认固件文件(如`bdwlan30.bin`)存在于`/lib/firmware`目录。 - 检查固件版本是否与硬件匹配(如HWID字段)。 - **驱动路径配置**:若涉及自定义组件(如ESP-IoT-Solution),确保路径设置正确: ```bash set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/esp-iot-solution/components/usb/tinyusb) [^2] ``` --- #### 4. **调试与日志分析** - **内核日志**:通过`dmesg`查看详细错误信息,搜索`sdio_enable_func`相关日志。 - **协议分析**:使用逻辑分析仪或`sdio-utils`工具捕获SDIO命令序列,验证设备响应是否符合协议。 --- #### 5. **兼容性与替代方案** - **硬件兼容性**:确认主机控制器(如ESP32的SDIO接口)支持设备要求的协议版本(如SDIO 2.0)。 - **降级操作**:尝试以更低速模式(如SPI)通信,排除SDIO协议栈问题。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值