|
二、sd card插入状态的获取
通过第一节中,我们知道了mmc_rescan是通过调用mmc_host->mmc_host_ops->get_cd来获取当前card的插入状态的。
那么这个方法是怎么实现的呢?如何获取card当前的插入状态呢?以下来说明一下这两个问题。
1、获取sd card当前的插入状态
一般来说有两种方式来获取到sd card当前的插入状态
(1)GPIO获取的方法
可以通过sd card的card detect引脚来判断当前是否有sd card插入
(2)host寄存器获取的方法
某些host在硬件上有识别sd card是否插入的能力。这种情况下,可以通过读取host的寄存器来获取到当前是否有sd card插入。
1(1)、通过GPIO获取当前sd card的插入状态
DECECT引脚
这里先
以TF card为例,参考blog.csdn.net/xqhrs232/article/details/43339171。
首先以一个原理图来看一下TF card卡座的连接
(其中SD_CARD_DET_N是有外部上拉的)。
以卡座的DET_SWITCH引脚作为card检测脚。
其card和卡座引脚定义如下:
可以观察到,虽然TF CARD(micro)只有8个引脚,但是卡座另外定义了一个CD引脚(DET_SWITCH)。
我的猜想是,对于某些tf card卡座来说,当tf card插入时,会把CD引脚(DET_SWITCH)直接定义到连接到groud上去。
所以,这里可以梳理出,
●当card没有插入的情况下,由于外部上拉的关系,cpu连接到DET_SWITCH的gpio为高电平。
●当card插入时,tf card卡座会把DET_SWITCH拉低,相应的,cpu连接到DET_SWITCH的gpio为低电平。
当然,上述只是一种情况,具体cd gpio的电平情况取决于使用的卡座的实现。
●注册card插入状态检测GPIO软件介绍
mmc core提供了mmc_gpio_request_cd来为host定义自己的cd-detect引脚,也就是对应上面连接到卡座上的CD引脚的GPIO。
mmc_gpio_request_cd实现如下(虽然也会注册GPIO中断,但是这里先不关心):
int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
{
struct mmc_gpio *ctx; // struct mmc_gpio用来表示连接卡槽的一些GPIO的状态
int ret;
ret = mmc_gpio_alloc(host); // 调用mmc_gpio_alloc来为host分配一个struct mmc_gpio
ctx = host->slot.handler_priv; // 获取struct mmc_gpio
ret = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN, ctx->cd_label); // 申请这个GPIO
ctx->cd_gpio = gpio; // 将设置到ctx->cd_gpio中
}
所以后续就可以通过读取 mmc_host->slot.handler_priv->cd_gpio的电平状态来判断当前card的插入状态
通过GPIO获取当前sd card的插入状态
在上述通过mmc_gpio_request_cd注册完成cd gpio之后,就可以通过mmc_gpio_get_cd来获取card的插入状态。
当其返回1时,表示当前有card插入,当其返回0是,表示当前没有card插入。
其实现如下
int mmc_gpio_get_cd(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv; // 提取出host对应的struct mmc_gpio
if (!ctx || !gpio_is_valid(ctx->cd_gpio)) // 如果没有注册cd gpio的情况下,直接返回了
return -ENOSYS;
return !gpio_get_value_cansleep(ctx->cd_gpio) ^ !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
// 因为mmc_gpio_get_cd返回1表示有card插入,返回0是表示没有card插入
// MMC_CAP2_CD_ACTIVE_HIGH属性被设置的话,表示当有card插入时为cd gpio为高电平(主要取决于卡座)
// 假设这里MMC_CAP2_CD_ACTIVE_HIGH没有被设置,也就是有card插入时cd gpio为低电平
// 当cd gpio检测到低电平的时候,相当于是!0 ^ 0=1,因此会返回1,有card插入
// 当cd gpio检测到高电平的时候,相当于是!1 ^ 0=0,因此会返回0,没有card插入
}
1(2)、通过host寄存器获取当前card插入状态
前提是某些host在硬件上有识别sd card是否插入的能力。这种情况下,可以通过读取host的寄存器来获取到当前是否有sd card插入。
●寄存器介绍
以sdhci类host为例,根据《SDHC_Ver3.00_Final_110225》 “2.2.9 Present State Register(Offset 024h)”
可以通过Present State Register(偏移地址为0x24)的bit16来判断card的插入状态。
**注意:有可能存在实际使用sdhci的host不符合上述标准的情况,对于这类host,会定义sdhci_host中的quirks的SDHCI_QUIRK_BROKEN_CARD_DETECTION。
SDHCI_QUIRK_BROKEN_CARD_DETECTION说明该sdhci host并没有通过Present State Register(偏移地址为0x24)的bit16来提供一个可靠的card插入状态判断方式。**
●软件介绍
以sdhci类host为例
static int sdhci_do_get_cd(struct sdhci_host *host)
{
if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
return 1;
/* Host native card detect */
return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
}
2、mmc_host_ops->get_cd方法的实现
通过上述我们已经知道了两种获取当前card插入状态的方法。
接下来就是利用上述的两种方法来实现mmc_host_ops->get_cd。
对于这个方法来说,返回1表示当前有card插入,返回0表示当前没有card插入。
对于sdhci类host来说,这个方法对应实现为sdhci_do_get_cd,实现方法如下:
static int sdhci_get_cd(struct mmc_host *mmc)
{
struct sdhci_host *host = mmc_priv(mmc);
int ret;
sdhci_runtime_pm_get(host);
ret = sdhci_do_get_cd(host); // 进一步调用sdhci_do_get_cd
sdhci_runtime_pm_put(host);
return ret;
}
static int sdhci_do_get_cd(struct sdhci_host *host)
{
int gpio_cd = mmc_gpio_get_cd(host->mmc);
// 通过调用mmc_gpio_get_cd,通过cd gpio获取当前的card插入状态,对应上述“通过GPIO获取当前sd card的插入状态”
/* If polling/nonremovable, assume that the card is always present. */
if (host->mmc->caps & MMC_CAP_NONREMOVABLE) // 对于不可移除的设备,总是返回1
return 1;
if (!IS_ERR_VALUE(gpio_cd))
return !!gpio_cd; // mmc_gpio_get_cd返回值有效的话,返回插入状态
// 因为host并不一定有通过mmc_gpio_request_cd注册cd gpio,也就是没有实现“通过GPIO获取当前sd card的插入状态”
// 这种情况下就尝试通过用sdhci的寄存器来获取
// 当SDHCI_QUIRK_BROKEN_CARD_DETECTION被设置的时候,说明该host并没有提供检测card插入状态检测的能力,
// 直接返回1,假设插入,由后续协议的工作来尝试初始化
if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
return 1;
// 读取sdhci的SDHCI_PRESENT_STATE的bit SDHCI_CARD_PRESENT来获取card的插入状态。
/* Host native card detect */
return !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT);
}
|
|