//参考给一些前辈们的文章
1、sdio接口层解析
SDIO总线
SDIO总线和USB总线类似,SDIO也有两端,其中一端是HOST端,另一端是device端。所有的通信都是由HOST端发送命令开始的,Device端只要能解析命令,就可以相互通信。
CLK信号:HOST给DEVICE的时钟信号.每个时钟周期传输一个命令或数据位。
CMD信号:双向的信号,用于传送命令和反应。
DAT0-DAT3 信号:四条用于传送的数据线。
VDD信号:电源信号。
VSS1,VSS2:电源地信号。
nCD 用于检测卡是否插入。
fs2410 mmc/sd的电路图
SDIO热插拔原理:
方法:设置一个定时器检查或插拔中断检测
硬件:GPG10(EINT18)用于SD卡检测
GPG10 为高电平 即没有插入SD卡(参见fs2410原理图/芯片手册)
GPG10为低电平 即插入了SD卡
SDIO命令
SDIO总线上都是HOST端发起请求,然后DEVICE端回应请求。其中请求和回应中会数据信息。sdio命令由6个字节组成。
1. Command:用于开始传输的命令,是由HOST端发往DEVICE端的。其中命令是通过CMD信号线传送的。
2. Response:回应是DEVICE返回的HOST的命令,作为Command的回应。也是通过CMD线传送的。
3. Data:数据是双向的传送的。可以设置为1线模式,也可以设置为4线模式。数据是通过DAT0-DAT3信号线传输的。
SDIO的每次操作都是由HOST在CMD线上发起一个CMD,对于有的CMD,DEVICE需要返回Response,有的则不需要。
对于读命令,首先HOST会向DEVICE发送命令,紧接着DEVICE会返回一个握手信号,此时,当HOST收到回应的握手信号后,会将数据放在4位的数据线上,在传送数据的同时会跟随着CRC校验码。当整个读传送完毕后,HOST会再次发送一个命令,通知DEVICE操作完毕,DEVICE同时会返回一个响应。
对于写命令,首先HOST会向DEVICE发送命令,紧接着DEVICE会返回一个握手信号,此时,当HOST收到回应的握手信号后,会将数据放在4位的数据线上,在传送数据的同时会跟随着CRC校验码。当整个写传送完毕后,HOST会再次发送一个命令,通知DEVICE操作完毕,DEVICE同时会返回一个响应。
sd命令格式
以IO_SEND_OP_COND命令为例包含以下部分:
S(开始位) 总为0
D(方向位) 1 从host到 device (0 从device到host)
命令索引: 通过值000101B来
填充位 0
IO_OCR 运转条件寄存器所支持的VDD的最小值和最大值
CRC7 7位CRC校验数据
E(结束位) 总为1
MMC命令总共有40多个,分为class0 ~class7共8类,class0的所有卡必须支持。驱动程序通过发送cmd1、cmd41来区分sd卡和mmc卡,如果发送cmd1返回成功,则为mmc卡,否则发送cmd41返回成功,则为sd卡。
cmd0 初始化mmc卡
Sdio接口驱动
首先我们来探讨几个重要的数据结构:该结果位于core核心层,主要用于核心层与主机驱动层的数据交换处理。/include/linux/mmc/host.h
struct mmc_host 用来描述卡控制器
struct mmc_card 用来描述卡
struct mmc_driver 用来描述 mmc 卡驱动
struct sdio_func 用来描述功能设备
struct mmc_host_ops 用来描述卡控制器操作接口函数功能,用于从主机控制器层向 core 层注册操作函数,从而将core 层与具体的主机控制器隔离。也就是说 core 要操作主机控制器,就用这个 ops 当中给的函数指针操作,不能直接调用具体主控制器的函数。
/drivers/mmc/host/s3cmci.c
static struct platform_driver s3cmci_driver = {
.driver = {
.name = "s3c-sdi", //名称和平台设备定义中的对应
.owner = THIS_MODULE,
.pm = s3cmci_pm_ops,
},
.id_table = s3cmci_driver_ids,
.probe = s3cmci_probe, //平台设备探测接口函数
.remove = __devexit_p(s3cmci_remove),
.shutdown = s3cmci_shutdown,
};
s3cmci_probe(struct platform_device *pdev);
mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev); //分配mmc_host结构体
---->INIT_DELAYED_WORK(&host->detect, mmc_rescan); //初始化工作队列
/*注册中断处理函数s3cmci_irq,来处理数据收发过程引起的各种中断*/
request_irq(host->irq, s3cmci_irq, 0, DRIVER_NAME, host) //注册中断处理函数s3cmci_irq
/*注册中断处理s3cmci_irq_cd函数,来处理热拨插引起的中断,中断触发的形式为上升沿、下降沿触发*/
request_irq(host->irq_cd, s3cmci_irq_cd,IRQF_TRIGGER_RISING |IRQF_TRIGGER_FALLING,
DRIVER_NAME, host)
mmc_add_host(mmc); //initialise host hardware 初始化host控制器
----> device_add(&host->class_dev); //添加设备到mmc_bus_type总线上的设备链表中
----> mmc_start_host(host); //启动mmc host
/*MMC drivers should call this when they detect a card has been inserted or removed.检测sd卡是否插上或移除*/
---->mmc_detect_change(host, 0);
/*Schedule delayed work in the MMC work queue.调度延时工作队列*/
mmc_schedule_delayed_work(&host->detect, delay);
搜索host->detected得到以下信息:
/drivers/mmc/core/host.c
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
mmc_rescan(struct work_struct *work)
---->mmc_bus_put(host);//card 从bus上移除时,释放它占有的总线空间
/*判断当前mmc host控制器是否被占用,当前mmc控制器如果被占用,那么 host->claimed = 1;否则为0
*如果为1,那么会在while(1)循环中调用schedule切换出自己,当占用mmc控制器的操作完成之后,执行 *mmc_release_host()的时候,会激活登记到等待队列&host->wq中的其他程序获得mmc主控制器的使用权
*/
mmc_claim_host(host);
mmc_rescan_try_freq(host, max(freqs[i], host->f_min);
/**/
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
…………………………………………..