首页 > 编程知识 正文

sdio wifi驱动,sdio网卡驱动

时间:2023-05-04 23:38:58 阅读:260159 作者:3491

1、SDIO卡的扫描流程

接上文:

core.c (driversmmccore)static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq){ sdio_reset(host);-->a mmc_go_idle(host);-->b mmc_send_if_cond(host, host->ocr_avail);-->c if (!mmc_attach_sdio(host))-->d return 0; return -EIO;}

a, 复位卡,见第3小节

b,设置卡状态:idle,见第4小节

c,检测卡支持的工作电压,见第5小节

d,SDIO工作环境设置及card初始化,见第6小节

在SDIO中b、c步骤是不需要的,对于这两个操作,SDIO卡可以不作回应(忽略即可)。


2、SDIO新增命令

为了支持I/O特性,SDIO标准在SD的基础上增加了两条命令
 - IO_RW_DIRECT(CMD52)
 - IO_RW_EXTENDED(CMD53)

2.1 CMD52简介
 - 用来访问单个的寄存器(SD标准中,寄存器空间共128K)
 - 初始化寄存器或为IO功能检测相关状态值
 - 读/写1字节的数据,仅仅需要一个commond/response对(读写单个寄存器最快的方式)

2.2 CMD52命令




2.3 Response R5

注:SD模式下48 bits;SPI模式下16bits




2.4 Command是如何构建的

kernel中命令及Response由结构体mmc_command表示:

struct mmc_command {u32opcode; // Command的操作码u32arg; // Command携带的参数u32resp[4]; // Command发出后,如果需要应答,结果保存在resp数组中,最多可以保存128bits的应答unsigned intflags;// 保存该命令所期望的应答类型unsigned intretries; // 指明最多可重发的次数unsigned interror; // 如果最终还是出错,通过该字段返回错误的原因,例如ETIMEDOUT、EILSEQ、EINVAL、ENOMEDIUM等unsigned intcmd_timeout_ms;/* in milliseconds */boolsanitize_busy;struct mmc_data*data;/* data segment associated with cmd */struct mmc_request*mrq;/* associated request */};


所以发送Command前就需构建结构体mmc_command。以CMD52为例:

sdio_ops.c (driversmmccore)static int mmc_io_rw_direct_host(struct mmc_host *host, int write, unsigned fn,unsigned addr, u8 in, u8 *out){struct mmc_command cmd = {0};// 构建Command,#define SD_IO_RW_DIRECT 52 cmd.opcode = SD_IO_RW_DIRECT;cmd.arg = write ? 0x80000000 : 0x00000000;cmd.arg |= fn << 28;cmd.arg |= (write && out) ? 0x08000000 : 0x00000000;cmd.arg |= addr << 9;cmd.arg |= in;cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_AC;...return 0;}

arg是32bits无符号整形值,而SDIO命令是48bits,对应关系就是cmd[8:39],arg即是

[31] R/W flag[30:28] Function number[27] RAW flag[25:9] Register address[7:0] Data

2.5 Command是如何发送的

command发送:mmc_io_rw_direct_host->mmc_wait_for_cmd-->mmc_wait_for_req--->__mmc_start_req---->mmc_start_request----->__mmc_start_request------>host->ops->request(host, mrq)九曲十八弯后调用struct mmc_host_ops的requeststatic const struct mmc_host_ops dw_mci_ops = {.request= dw_mci_request,}sdio card的response:-->mmc_wait_for_req_done

3、SDIO卡的复位

SDIO Spec:

In order to reset an I/O only card or the I/O portion of a combo card, use CMD52 to writea 1 to the RES bit in the CCCR (bit 3 of register 6)

CCCR(Card Common Control Registers):


代码实现:

int sdio_reset(struct mmc_host *host){int ret;u8 abort;/* SDIO Simplified Specification V2.0, 4.4 Reset for SDIO */ret = mmc_io_rw_direct_host(host, 0, 0, SDIO_CCCR_ABORT, 0, &abort);-->aif (ret) -->babort = 0x08;elseabort |= 0x08;ret = mmc_io_rw_direct_host(host, 1, 0, SDIO_CCCR_ABORT, abort, NULL); -->creturn ret;}

a, 读取0x06地址寄存器内容

b, 读取正常(ret=0)只设置RES位,否则写寄存器内容为0x08

c, 写0x06地址寄存器

至此完成card的复位操作。

4、设置卡为IDLE状态

该操作由mmc_go_idle()完成:

int mmc_go_idle(struct mmc_host *host){if (!mmc_host_is_spi(host)) { -->ammc_set_chip_select(host, MMC_CS_HIGH);mmc_delay(1);}cmd.opcode = MMC_GO_IDLE_STATE; -->bcmd.arg = 0;cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;err = mmc_wait_for_cmd(host, &cmd, 0); -->cmmc_delay(1);if (!mmc_host_is_spi(host)) { -->dmmc_set_chip_select(host, MMC_CS_DONTCARE);mmc_delay(1);}host->use_spi_crc = 0;return err;}a, 在SD模式下,把片选pin拉高避免进入SPI模式。看下图就一目了然:

b, 构建CMD0,SDIO对此命令不做反应!

c, 发送CMD0

d, SD模式下不关心片选引脚状态(作为数据DAT3存在)


5、检测卡支持的工作电压

通过命令CMD8检测card支持的工作电压。

int mmc_send_if_cond(struct mmc_host *host, u32 ocr){struct mmc_command cmd = {0};int err;static const u8 test_pattern = 0xAA;u8 result_pattern;cmd.opcode = SD_SEND_IF_COND;cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; // cmd.arg = 0x1AAcmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR;err = mmc_wait_for_cmd(host, &cmd, 0);if (mmc_host_is_spi(host))result_pattern = cmd.resp[1] & 0xFF;elseresult_pattern = cmd.resp[0] & 0xFF;if (result_pattern != test_pattern)return -EIO;return 0;}参照CMD8命令的说明,mmc_send_if_cond就很好理解了:

cmd8:


voltage supplied:

When the card is in idle state, the host shall issue CMD8 before ACMD41. In the argument, 'voltage supplied' is set to the host supply voltage and 'check pattern' is set to any 8-bit pattern.


The card checks whether it can operate on the host's supply voltage
. The card that accepted the supplied voltage returnsR7 response.In the response , the card echoes back both the voltage range and check pattern set in the argument. If the carddoes not support the host supply voltage, it shall not return response andstays in Idle state.
It is recommeded to use '10101010b'(0xAA) for the 'check pattern'.


6、SDIO工作环境设置

6.1 查询card支持的操作电压

int mmc_send_io_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr){cmd.opcode = SD_IO_SEND_OP_COND; ----------->acmd.arg = ocr;cmd.flags = MMC_RSP_SPI_R4 | MMC_RSP_R4 | MMC_CMD_BCR;{err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);------>b/* if we're just probing, do a single pass */if (ocr == 0)break;/* otherwise wait until reset completes */if (mmc_host_is_spi(host)) {} else {if (cmd.resp[0] & MMC_CARD_BUSY)------>cbreak;}}if (rocr)*rocr = cmd.resp[mmc_host_is_spi(host) ? 1 : 0];return err;}a, 通过IO_SEND_OP_COND(CMD5)命令查询card的支持电压范围。



b, 发送命令。Response保存在R4中:


c, resp[31:0] = R4[39:8]。

bit C: 1:card ready。这里check card是否ready。


6.2 确定host、card都支持的最低电压

u32 mmc_select_voltage(struct mmc_host *host, u32 ocr){int bit;if (ocr & 0x7F) { --------------------->adev_warn(mmc_dev(host), "card claims to support voltages below defined rangen");ocr &= ~0x7F;}ocr &= host->ocr_avail;----->bif (!ocr) {dev_warn(mmc_dev(host), "no support for card's voltsn");return 0;}if (host->fdbbt2 & MMC_CAP2_FULL_PWR_CYCLE) {bit = ffs(ocr) - 1;ocr &= 3 << bit;mmc_power_cycle(host, ocr);} else { -------------------->cbit = fls(ocr) - 1;ocr &= 3 << bit;if (bit != host->ios.vdd) ---->ddev_warn(mmc_dev(host), "exceeding card's voltsn");}return ocr;}

a, CMD5的OCD为24 bits,其中bit[7:0]为Reserved,所以正常情况下其值为0。这里检测避免出现不支持的数据。

b, 参数ocr从card读取,ocr_avail是host支持的电压范围,所以这里用来确定card、host双方都支持的电压

c, fls(x):返回x中第一个非0bit的位置,返回值[1:32],ffs(1)=1,ffs(8)=4,特别的,fls(0) = 0。所以这里作用就是返回双方都支持的最低电压

d, bit = fls(ocr) - 1而host->ios.vdd = fls(ocr) - 1,所以两者应该相同,否则就是上面说的 "exceeding card's volts"。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。