背景
在使用emmc设备过程中,由于需要用到休眠唤醒功能,对emmc频繁的开关电和挂载卸载,为了降低休眠功耗延长电池通电时间。
DTS
由于没有使用到sdhc2_cd_pin,所以需要使用polling轮询的方式来检测上电后加载设备:
sdhc_2: sdhci@07864900 {
compatible = "qcom,sdhci-msm";
reg = <0x07864900 0x200>, <0x07864000 0x800>;
reg-names = "hc_mem", "core_mem";
interrupts = <0 125 0>, <0 221 0>;
interrupt-names = "hc_irq", "pwr_irq";
qcom,bus-width = <4>;
qcom,devfreq,freq-table = <50000000 200000000>;
qcom,msm-bus,name = "sdhc2";
qcom,msm-bus,num-cases = <8>;
qcom,msm-bus,num-paths = <1>;
qcom,msm-bus,vectors-KBps = <81 512 0 0>, /* No vote */
<81 512 1600 3200>, /* 400 KB/s*/
<81 512 80000 160000>, /* 20 MB/s */
<81 512 100000 200000>, /* 25 MB/s */
<81 512 200000 400000>, /* 50 MB/s */
<81 512 400000 800000>, /* 100 MB/s */
<81 512 800000 800000>, /* 200 MB/s */
<81 512 2048000 4096000>; /* Max. bandwidth */
qcom,bus-bw-vectors-bps = <0 400000 20000000 25000000 50000000
100000000 200000000 4294967295>;
clocks = <&clock_gcc clk_gcc_sdcc2_ahb_clk>,
<&clock_gcc clk_gcc_sdcc2_apps_clk>;
clock-names = "iface_clk", "core_clk";
qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>;
qcom,pm-qos-irq-type = "affine_irq";
qcom,pm-qos-irq-latency = <2 250>;
status = "disabled";
};
&sdhc_2 {
/*vdd-supply = <&sdcard_ext_vreg>;*/
qcom,vdd-voltage-level = <2850000 2850000>;
qcom,vdd-current-level = <15000 400000>;
vdd-io-supply = <&mdm9607_l13>;
qcom,vdd-io-always-on;
qcom,vdd-io-voltage-level = <1800000 2850000>;
qcom,vdd-io-current-level = <200 50000>;
#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 &tlmm_pinmux 26 0>;
interrupt-names = "hc_irq", "pwr_irq", "status_irq";
/*cd-gpios = <&tlmm_pinmux 26 0x1>;*/
/*qcom,nonhotplug;*/
pinctrl-names = "active", "sleep";
pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>;
pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>;
status = "ok";
};
代码
查看对应的sdhci-msm驱动代码读取dts中的配置:
drivers/mmc/host/sdhci-msm.c
sdhci_msm_populate_pdata
if (of_get_property(np, "qcom,nonremovable", NULL))
pdata->nonremovable = true;
if (of_get_property(np, "qcom,nonhotplug", NULL))
pdata->nonhotplug = true;
sdhci_msm_probe
if (msm_host->pdata->nonremovable)
msm_host->mmc->caps |= MMC_CAP_NONREMOVABLE;
if (msm_host->pdata->nonhotplug)
msm_host->mmc->caps2 |= MMC_CAP2_NONHOTPLUG;
drivers/mmc/host/sdhci.c
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;
根据上面的代码看出,如果需要开启MMC_CAP_NEEDS_POLL则需要把nonhotplug和nonremovable在dts中关闭掉,所以已经在dts中注释了/*qcom,nonhotplug;*/,这样默认就开启了emmc 的polling功能。
polling功能控制文件在:/sys/devices/7864900.sdhci/polling,1为开启,0为关闭,默认开
休眠唤醒
休眠时会关闭polling并卸载emmc并关电,唤醒时开电然后开启polling并挂载emmc。
由于polling轮询时间需要1秒,所以emmc上电后驱动加载完成时需要1秒多时间完成设备节点的创建,开启polling后马上去挂载emmc会导致失败,这时需要在挂载emmc脚本里面设置等待超时时间5秒。
开关polling和挂载emmc的顺序搞反了会导致大概率的出现挂载失败问题,需注意。