emmc host调用mmc_rescan发现设备

来源:互联网 发布:python入门到精通 pdf 编辑:程序博客网 时间:2024/06/13 05:16
在调用mmc_start_host 来enable一个emmc host的时候
void mmc_start_host(struct mmc_host *host)
{
    host->f_init = max(freqs[0], host->f_min);
    host->rescan_disable = 0;
    host->ios.power_mode = MMC_POWER_UNDEFINED;

    mmc_claim_host(host);
    if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)
        mmc_power_off(host);
    else
        mmc_power_up(host, host->ocr_avail);
    mmc_release_host(host);

    mmc_gpiod_request_cd_irq(host);
    _mmc_detect_change(host, 0, false);
}
在mmc_start_host 通过_mmc_detect_change 来启动scan连接在这个host上的mmc device
static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
                bool cd_irq)
{
    /*
     * If the device is configured as wakeup, we prevent a new sleep for
     * 5 s to give provision for user space to consume the event.
     */
    if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL) &&
        device_can_wakeup(mmc_dev(host)))
        pm_wakeup_event(mmc_dev(host), 5000);

    host->detect_change = 1;
    mmc_schedule_delayed_work(&host->detect, delay);
}
置位host->detect_change,并调用mmc_schedule_delayed_work 来scan device
static int mmc_schedule_delayed_work(struct delayed_work *work,
                     unsigned long delay)
{
    return queue_delayed_work(system_freezable_wq, work, delay);
}
但是这个host->detect这个work对应的func 是通过下面的方式赋值
而在mmc_alloc_host 中的赋值如下:
    INIT_DELAYED_WORK(&host->detect, mmc_rescan);
这样当调用mmc_schedule_delayed_work的时候,会调用mmc_rescan
在mmc_rescan 中最要的如下:
    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;
    }

static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
可以看到每个host 最多scan四次,在当前freqs上找到device就退出
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
    host->f_init = freq;

#ifdef CONFIG_MMC_DEBUG
    pr_info("%s: %s: trying to init card at %u Hz\n",
        mmc_hostname(host), __func__, host->f_init);
#endif
    mmc_power_up(host, host->ocr_avail);

    /*
     * Some eMMCs (with VCCQ always on) may not be reset after power up, so
     * do a hardware reset if possible.
     */
    mmc_hw_reset_for_init(host);

    /*
     * sdio_reset sends CMD52 to reset card.  Since we do not know
     * if the card is being re-initialized, just send it.  CMD52
     * should be ignored by SD/eMMC cards.
     * Skip it if we already know that we do not support SDIO commands
     */
    if (!(host->caps2 & MMC_CAP2_NO_SDIO))
        sdio_reset(host);

    mmc_go_idle(host);

    if (!(host->caps2 & MMC_CAP2_NO_SD))
        mmc_send_if_cond(host, host->ocr_avail);

    /* Order's important: probe SDIO, then SD, then MMC */
    if (!(host->caps2 & MMC_CAP2_NO_SDIO))
        if (!mmc_attach_sdio(host))
            return 0;

    if (!(host->caps2 & MMC_CAP2_NO_SD))
        if (!mmc_attach_sd(host))
            return 0;

    if (!(host->caps2 & MMC_CAP2_NO_MMC))
        if (!mmc_attach_mmc(host))
            return 0;

    mmc_power_off(host);
    return -EIO;
}

可以从mmc_rescan_try_freq看到,emmc host上可以挂三种设备,这三种设别只能挂一个不能共存,且有一定的优先级
其中优先级为:mmc->sd->sdio
以mmc_attach_sdio->mmc_add_card为例开机会打印如下log
[   11.565233] mmc_host mmc2: Bus speed (slot 0) = 25000000Hz (slot req 2500000)
++ Setting up mdev                                                              
[   11.587289] mmc2: queuing unknown CIS tuple 0x91 (3 bytes)                   
[   11.599206] mmc2: new SDIO card at address 0001     

在mmc_rescan_try_freq 中是通过host->caps2 & MMC_CAP2_NO_SDIO 来判断是否有SDIO的,也就是如果在mmc_of_parse中没有添加这个flag就默认调用mmc_attach_sdio。而mmc_of_parse 是在parse host对应的dts,也就是说在dts中如果没有
    if (of_property_read_bool(np, "no-sdio"))
        host->caps2 |= MMC_CAP2_NO_SDIO;
就默认调用mmc_attach_sdio

int mmc_of_parse(struct mmc_host *host)
{
    
    if (of_property_read_bool(np, "disable-wp"))
        host->caps2 |= MMC_CAP2_NO_WRITE_PROTECT;

    /* See the comment on CD inversion above */
    if (ro_cap_invert ^ ro_gpio_invert)
        host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;

    if (of_property_read_bool(np, "cap-sd-highspeed"))
        host->caps |= MMC_CAP_SD_HIGHSPEED;
    if (of_property_read_bool(np, "cap-mmc-highspeed"))
        host->caps |= MMC_CAP_MMC_HIGHSPEED;
    if (of_property_read_bool(np, "sd-uhs-sdr12"))
        host->caps |= MMC_CAP_UHS_SDR12;
    if (of_property_read_bool(np, "sd-uhs-sdr25"))
        host->caps |= MMC_CAP_UHS_SDR25;
    if (of_property_read_bool(np, "sd-uhs-sdr50"))
        host->caps |= MMC_CAP_UHS_SDR50;
    if (of_property_read_bool(np, "sd-uhs-sdr104"))
        host->caps |= MMC_CAP_UHS_SDR104;
    if (of_property_read_bool(np, "sd-uhs-ddr50"))
        host->caps |= MMC_CAP_UHS_DDR50;
    if (of_property_read_bool(np, "cap-power-off-card"))
        host->caps |= MMC_CAP_POWER_OFF_CARD;
    if (of_property_read_bool(np, "cap-mmc-hw-reset"))
        host->caps |= MMC_CAP_HW_RESET;
    if (of_property_read_bool(np, "cap-sdio-irq"))
        host->caps |= MMC_CAP_SDIO_IRQ;
    if (of_property_read_bool(np, "full-pwr-cycle"))
        host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
    if (of_property_read_bool(np, "keep-power-in-suspend"))
        host->pm_caps |= MMC_PM_KEEP_POWER;
    
}
0 0
原创粉丝点击