一:sdio wifi接口 使用imx6,三个host,这里使用第三个
1 :clk:主要用于时钟信号,传输数据时,同步作用
2:cmd用于传输命令和应答,SDIO为主从模式,host主要发送命令,device端接收命令,应答或者处理命令;
3:SDIO_DAT_0-DAT_4主要用于数据传输
二:SDIO命令:
SDIO总线上都是HOST端发起请求,然后DEVICE端回应请求。SDIO命令由6个字节组成,如下图:
/* SDIO commands type argument response */
#define SD_IO_SEND_OP_COND 5 /* bcr [23:0] OCR R4 */
#define SD_IO_RW_DIRECT 52 /* ac [31:0] See below R5 */
#define SD_IO_RW_EXTENDED 53 /* adtc [31:0] See below R5 */
int mmc_attach_sdio(struct mmc_host *host)
{
.....
err = mmc_send_io_op_cond(host, 0, &ocr);
.....
}
通过mmc_send-io_cond函数代码,发送cmd5命令,返回值为ocr,也就是R4
ocr为long类型,长度为32位,R4为48位,所以去除R4前8bit后8bit
Numbei of I/O functions :记录sdio卡功能块,3bit,最多有7个func
Memory Present:如果是1代表是功能块加存储,0代表功能块
S18A: 1bit :用于设置电压1.8V
I/O OCR:支持的电压,下表
2.配置电压
host->ocr = mmc_select_voltage(host, ocr);
3.初始化卡
err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
card = mmc_alloc_card(host, NULL);
if ((ocr & R4_MEMORY_PRESENT) &&
mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid, NULL) == 0) {
card->type = MMC_TYPE_SD_COMBO;
}
} else {
card->type = MMC_TYPE_SDIO;
}
分配一个卡,根据OCR第27位设置卡类型
err = mmc_send_relative_addr(host, &card->rca);
err = mmc_select_card(card);
mmc_set_clock(host, card->cis.max_dtr);
sdio_enable_4bit_bus(card);
1、通过发送CMD3命令获取设备的从地址(relative addr),并且存放在变量card->rca中。笔者使用的WIFI模块的card->rca = 1
2、通过发送CMD7,选中相应从地址的卡
3. 通过调用函数mmc_set_clock设置卡工作的时钟频率
4. 通过发送CMD6命令,设置4位数据传输模式
二. SD_IO_RW_DIRECT CMD52
[31] R/W flag
[30:28] Function number
[27] RAW flag
[25:9] Register address
[7:0] Data
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};
int err;
BUG_ON(!host);
BUG_ON(fn > 7);
/* sanity check */
if (addr & ~0x1FFFF)
return -EINVAL;
cmd.opcode = SD_IO_RW_DIRECT;//cmd52
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;
err = mmc_wait_for_cmd(host, &cmd, 0);
return 0;
}
1:BUG_ON(fn > 7);
if (addr & ~0x1FFFF)
return -EINVAL;
对应cmd52配置,超出bit位数,出现bug
2:mmc_command
struct mmc_command {
u32 opcode;
u32 arg;
u32 resp[4];
unsigned int flags; /* expected response type */
unsigned int retries; /* max number of retries */
unsigned int error; /* command error */
unsigned int cmd_timeout_ms; /* in milliseconds */
struct mmc_data *data; /* data segment associated with cmd */
struct mmc_request *mrq; /* associated request */
};
成员arg 代表如下图:
3:mmc_command发送
int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries)
{
struct mmc_request mrq = {0};
WARN_ON(!host->claimed);
memset(cmd->resp, 0, sizeof(cmd->resp));
cmd->retries = retries;
mrq.cmd = cmd;
cmd->data = NULL;
mmc_wait_for_req(host, &mrq);
return cmd->error;
}
void mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
__mmc_start_req(host, mrq);
mmc_wait_for_req_done(host, mrq);
}
static void __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
{
init_completion(&mrq->completion);
mrq->done = mmc_wait_done;
mmc_start_request(host, mrq);
}
初始化mrq->completion,开始发送命令
static void mmc_wait_for_req_done(struct mmc_host *host,
struct mmc_request *mrq)
{
struct mmc_command *cmd;
while (1) {
wait_for_completion(&mrq->completion);
cmd = mrq->cmd;
if (!cmd->error || !cmd->retries)
break;
pr_debug("%s: req failed (CMD%u): %d, retrying...\n",
mmc_hostname(host), cmd->opcode, cmd->error);
cmd->retries--;
cmd->error = 0;
host->ops->request(host, mrq);
}
}
wait_for_completion(&mrq->completion);等待,mrq->completion
执行完以后,out 指向cmd52的返回值
*out = cmd.resp[0] & 0xFF;
对应上图的Response Flags
Response Flags 8 Bits of flag data indicating the status of the SDIO card. T