当遇到一些质量不是很好的sdcard,可能多次suspend & resume的操作后,某一次resume可能会失败,看到的现象就是当手机唤醒后会看到sdcard移除或者重新插入sdcard的提示,一般处理方式都是先加强下SD的pin脚驱动能力,如下
msdc1_pins_default: msdc1@default {
pins_cmd {
drive-strength = /bits/ 8 <3>;
};
pins_dat {
drive-strength = /bits/ 8 <3>;
};
pins_clk {
drive-strength = /bits/ 8 <4>;
};
};
现在主要介绍的是另外一个解决思路,在resume失败后,重新再给卡power off -> power on-> reinit
/kernel-3.10/drivers/mmc/core/core.c 添加函数mmc_power_cycle_special()
void mmc_power_cycle(struct mmc_host *host)
{
mmc_power_off(host);
/* Wait at least 1 ms according to SD spec */
mmc_delay(1);
mmc_power_up(host);
}
void mmc_power_cycle_special(struct mmc_host *host)
{
mmc_power_off(host);
/* Wait at least 1 ms according to SD spec */
mmc_delay(20);
mmc_power_up(host);
mmc_delay(20);
}
/kernel-3.10/drivers/mmc/core/sd.c mmc_sd_resume 函数err时调用mmc_power_cycle_special重新初始化
extern void mmc_power_cycle_special(struct mmc_host *host);
static int mmc_sd_resume(struct mmc_host *host)
{
int err;
#ifdef CONFIG_MMC_PARANOID_SD_INIT
int retries;
#endif
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
#ifdef 1
retries = 3;//modify by blogger
while (retries) {
err = mmc_sd_init_card(host, host->ocr, host->card);
if (err) {
printk(KERN_ERR "%s: Re-init card rc = %d (retries = %d)\n",
mmc_hostname(host), err, retries);
mdelay(5);
retries--;
mmc_power_cycle_special(host);//add by blogger
continue;
}
break;
}
#else
err = mmc_sd_init_card(host, host->ocr, host->card);
#endif
mmc_release_host(host);
return err;
}
现在kernel-4.4 MTK平台有个专门针对此类的问题的宏控处理,CONFIG_MMC_PARANOID_SD_INIT, 请搜索该关键字宏控,参考代码如下,
static int _mmc_sd_resume(struct mmc_host *host)
{
int err = 0;
#ifdef CONFIG_MMC_PARANOID_SD_INIT
int retries;
#endif
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
if (!mmc_card_suspended(host->card))
goto out;
mmc_power_up(host, host->card->ocr);
#ifdef CONFIG_MMC_PARANOID_SD_INIT
retries = 5;
while (retries) {
err = mmc_sd_init_card(host, host->card->ocr, host->card);
if (err) {
printk(KERN_ERR "%s: Re-init card rc = %d (retries = %d)\n",
mmc_hostname(host), err, retries);
mdelay(5);
retries--;
continue;
}
break;
}
#else
err = mmc_sd_init_card(host, host->card->ocr, host->card);
#endif
mmc_card_clr_suspended(host->card);
out:
mmc_release_host(host);
return err;
}
static void mmc_sd_detect(struct mmc_host *host)
{
int err = 0;
#ifdef CONFIG_MMC_PARANOID_SD_INIT
int retries = 5;
#endif
BUG_ON(!host);
BUG_ON(!host->card);
mmc_get_card(host->card);
/*
* Just check if our card has been removed.
*/
#ifdef CONFIG_MMC_PARANOID_SD_INIT
while(retries) {
err = mmc_send_status(host->card, NULL);
if (err) {
retries--;
udelay(5);
continue;
}
break;
}
if (!retries) {
printk(KERN_ERR "%s(%s): Unable to re-detect card (%d)\n",
__func__, mmc_hostname(host), err);
}
#else
err = _mmc_detect_card_removed(host);
#endif
mmc_put_card(host->card);
if (err) {
mmc_sd_remove(host);
mmc_claim_host(host);
mmc_detach_bus(host);
mmc_power_off(host);
mmc_release_host(host);
}
}