s5pv210-Linux驱动之SD卡插拨识别

一、开发环境

硬件平台:我用的是TQ210核心板,板载S5PV210芯片
软件平台:开发板移植的是Linux3.10.46内核,UBOOT移植的是2014.12版本

二、资源简介

内核自带S5PV210芯片的SD卡驱动,drivers/mmc/host/sdhci-s3c.c

三、驱动分析

1、插入SD卡识别

在前一篇对主机控制器驱动分析中,sdhci-s3c.c的probe函数中调用sdhci_add_host函数,在此函数里会注册一个中断,如下:

int sdhci_add_host(struct sdhci_host *host)
{
... ... ... ...
    tasklet_init(&host->card_tasklet,  
        sdhci_tasklet_card, (unsigned long)host);  
    tasklet_init(&host->finish_tasklet,  
        sdhci_tasklet_finish, (unsigned long)host);  
... ... ...  
    ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,  
        mmc_hostname(mmc), host); 
... ... ... ...
}
中断服务程序定义如下:

static irqreturn_t sdhci_irq(int irq, void *dev_id)  
{  
... ... ... ...  
    intmask = sdhci_readl(host, SDHCI_INT_STATUS);  
... ... ... ...  
        sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT :  
                        SDHCI_INT_CARD_REMOVE);  
        sdhci_unmask_irqs(host, present ? SDHCI_INT_CARD_REMOVE :  
                          SDHCI_INT_CARD_INSERT);  
  
        sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |  
                 SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);  
        intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);  
        tasklet_schedule(&host->card_tasklet);  
    }  
... ... ... ...  
}
程序首先读取寄存器NORINTSTSn的值,该寄存器中有两个bit分别来表示卡的插入与拔出过程(注意,必须是动态变化过程,才会让相应的两个bit置1),那么接下来的if语句就是从该寄存器的那两个bit来判断是否有卡的插入或拔出,并同时清除这两个bit,准备下一次的检测,紧接着就调用中断的下半部分函数 sdhci_tasklet_card,函数定义如下:

static void sdhci_tasklet_card(unsigned long param)
{
	struct sdhci_host *host = (struct sdhci_host*)param;

	sdhci_card_event(host->mmc);

	mmc_detect_change(host->mmc, msecs_to_jiffies(200));
}
这个函数判断,如果此时有卡的话就通过mmc_detect_chang函数调用mmc_schedule_delayed_work(&host->detect, delay),最终调用mmc_rescan函数。定义如下:

static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };

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;
	}
... ... ...
}
这个函数我们重点关注上述两个地方,其实真正的扫描动作发生在函数mmc_rescan_try_freq函数里面,该函数的第二个参数表示以什么样的频率去进行扫描,那么可选的频率值在那个数组freqs里面,一般当用某个频率值扫描成功后,就直接退出了,否则,会以下一个更低的频率值来扫描。mmc_rescan_try_freq定义如下:

static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
... ... ...
	if (!mmc_attach_sdio(host))
		return 0;
	if (!mmc_attach_sd(host))
		return 0;
	if (!mmc_attach_mmc(host))
		return 0;
... ... ...
}
可以看到, 其识别的顺序为SDIO  SD MMC

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值