bring up阶段SD始终不能检卡,我觉得软件配置应该没问题,硬件是外包的,硬件答复这套设计其他厂商也在用没问题。SD一个卡槽,SIM一个卡槽,高通平台,Linux内核版本3.18。

先看下内核文档关于检卡的描述:

Card detection:
If no property below is supplied, host native card detect is used.
Only one of the properties in this section should be supplied:

  • broken-cd: There is no card detection available; polling must be used.
  • cd-gpios: Specify GPIOs for card detection, see gpio binding
  • non-removable: non-removable slot (like eMMC); assume always present.

再看下dts配置:

&sdhc_2 {
#address-cells = <0>;
interrupt-parent = <&sdhc_2>;
interrupts = <0 1 2>;
#interrupt-cells = <1>;
interrupt-map-mask = <0xffffffff>;
interrupt-map = <0 &intc 0 125 0
1 &intc 0 221 0
2 &msm_gpio 38 0>;
interrupt-names = "hc_irq", "pwr_irq", "status_irq";
cd-gpios = <&msm_gpio 38 0x1>; //0x1 - 表示插卡低有效

这里用的就是gpio中断检卡方式不能工作,解析cd-gpios在sdhci_msm_populate_pdata

enum of_gpio_flags flags = OF_GPIO_ACTIVE_LOW; //is 1

...

pdata->status_gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &flags);
if (gpio_is_valid(pdata->status_gpio) & !(flags & OF_GPIO_ACTIVE_LOW))
pdata->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;

把cd-gpios去掉就是用host native方式插拔检测正常,这种是轮训方式,sdhci_add_host里有:

/*   
* Enable polling on when card detection is broken and no card detect
* gpio is present.
*/
if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
!(mmc->caps & MMC_CAP_NONREMOVABLE) &&
(mmc_gpio_get_cd(host->mmc) < 0) &&
!(mmc->caps2 & MMC_CAP2_NONHOTPLUG))
mmc->caps |= MMC_CAP_NEEDS_POLL;

为什么用gpio中断方式不能检测呢,来看下:

中断注册在mmc_gpiod_request_cd_irq

void mmc_gpiod_request_cd_irq(struct mmc_host *host)
{
struct mmc_gpio *ctx = host->slot.handler_priv;
int ret, irq;

if (host->slot.cd_irq >= 0 || !ctx || !ctx->cd_gpio)
return;

irq = gpiod_to_irq(ctx->cd_gpio);

/*
* Even if gpiod_to_irq() returns a valid IRQ number, the platform might
* still prefer to poll, e.g., because that IRQ number is already used
* by another unit and cannot be shared.
*/
if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL)
irq = -EINVAL;

if (irq >= 0) {
ret = devm_request_threaded_irq(&host->class_dev, irq,
NULL, mmc_gpio_cd_irqt,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
ctx->cd_label, host);
if (ret < 0)
irq = ret;
}

host->slot.cd_irq = irq;

if (irq < 0)
host->caps |= MMC_CAP_NEEDS_POLL;
}

中断处理是mmc_gpio_cd_irqt

static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
{
/* Schedule a card detection after a debounce timeout */
struct mmc_host *host = dev_id;

host->trigger_card_event = true;
mmc_detect_change(host, msecs_to_jiffies(200));

return IRQ_HANDLED;
}

mmc_detect_change会callmmc_schedule_delayed_work(&host->detect, delay);,也就是会走mmc_rescan,因为前面有挂INIT_DELAYED_WORK(&host->detect, mmc_rescan);

sdhci_request里检卡:

/*   
* Firstly check card presence from cd-gpio. The return could
* be one of the following possibilities:
* negative: cd-gpio is not available
* zero: cd-gpio is used, and card is removed
* one: cd-gpio is used, and card is present
*/
present = mmc_gpio_get_cd(host->mmc);
if (present < 0) {
/* If polling, assume that the card is always present. */
if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)
present = 1;
else
present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
SDHCI_CARD_PRESENT;
}

注释写的很清楚,先看cd-gpio情况。

mmc_gpio_get_cd加入中断处理mmc_gpio_cd_irqt中查看发现插卡时有太多的中断打印,拔出停止。

中断频繁可以看到142一直在增:

msmxxx:/ # cat /proc/interrupts  | grep msmgpio
117: 11 1 1 2 msmgpio 13 msg2xxx
125: 0 0 0 0 msmgpio 21 cs35l41
142: 10651 1639 499 0 msmgpio 38 7864900.sdhci cd

GPIO配置确认:

msmxxx:/ # cat /sys/kernel/debug/gpio | grep 38
gpio38 : in 0 2mA no pull

当修改为高有效后插入中断一个,拔出中断多出几个,但是仍然不能检卡,插卡mmc_gpio_get_cd返回0,拔卡返回1。之前其他项目配置高有效时,插卡get_cd返回的都是1,拔卡返回的是0,所以应该是硬件问题,push硬件修改后果然正常了。

这类情况以前在Z就遇到过,so有时不想调dd:]