sdio 框架分析<1>


SDIO的master board info:
---------------------------------------------------------------------------------------------------------
#define SD0_DETECT_GPIO        101
//驅動器所占資源【host寄存器所占用的AP地址,及大小,探測GPIO/中斷等】
static struct resource sprd_sdio_resource[][3] = {
       SDIO_RESOURCE_BUILDER(SPRD_SDIO0_BASE, SPRD_SDIO0_SIZE, SD0_DETECT_GPIO, IRQ_SDIO0_INT),/*sdio0*/
 };

//相關Pin配置,初始化SDIO的PIN狀態
static unsigned long sdio_func_cfg[] __initdata = {
        MFP_CFG_X(SD0_CLK, AF0, DS3, F_PULL_NONE, S_PULL_NONE, IO_Z),
        MFP_CFG_X(SD_CMD, AF0, DS1, F_PULL_UP,  S_PULL_NONE, IO_Z),
        MFP_CFG_X(SD_D0, AF0, DS1, F_PULL_UP, S_PULL_NONE, IO_Z),
        MFP_CFG_X(SD_D1, AF0, DS1, F_PULL_UP, S_PULL_NONE, IO_Z),
        MFP_CFG_X(SD_D2, AF0, DS1, F_PULL_UP, S_PULL_NONE, IO_Z),
        MFP_CFG_X(SD_D3, AF0, DS1, F_PULL_UP, S_PULL_NONE, IO_Z),
};
static unsigned long sdcard_detect_gpio_cfg = MFP_CFG_X(RFCTL11, AF3, DS1, F_PULL_UP,S_PULL_NONE, IO_Z);
static void sprd_config_sdio_pins(void)
{
        sprd_mfp_config(sdio_func_cfg, ARRAY_SIZE(sdio_func_cfg));
        sprd_mfp_config(&sdcard_detect_gpio_cfg, 1);
}
//platform device聲明
#define SDIO_DEV_BUILDER(bus_id, res)          \
       {       \
               .name           = "sprd-sdhci", \
               .id     = (bus_id),     \
               .num_resources  = ARRAY_SIZE(res),      \
               .resource       = (res),        \
       }

struct platform_device sprd_sdio_device[] = {
       SDIO_DEV_BUILDER(0, sprd_sdio_resource[0]),
 };

//啟用AHB,注冊platfrom device到系統中
void __init sprd_add_sdio0_device(void)
{
        int err;
        /* Enable SDIO0 Module */
        __raw_bits_or(BIT_4, AHB_CTL0);
        /* reset sdio0 module*/
        __raw_bits_or(BIT_12, AHB_SOFT_RST);
        __raw_bits_and(~BIT_12, AHB_SOFT_RST);
        platform_device_register(&sprd_sdio_device[0]);
}

SDIO master platform drvier:
-------------------------------------------------------------------------------------------------------------
static struct platform_driver sdhci_sprd_driver = {
    .probe        = sdhci_sprd_probe,
    .remove        = __devexit_p(sdhci_sprd_remove),
    .suspend    = sdhci_sprd_suspend,
    .resume            = sdhci_sprd_resume,
    .driver        = {
        .owner    = THIS_MODULE,
        .name    = "sprd-sdhci",
    },
};
注冊驅動到系統:
static int __init sdhci_sprd_init(void)
{
    return platform_driver_register(&sdhci_sprd_driver);
}
匹配過程如SPI,不再詳細敘述。
sdhci_sprd_driver的probe函數中具體做的事情如SPI:
邏輯與SPI基本相同,只是master由spi_master換成了sdhci_host【sdhci_alloc_host】,
最后通過sdhci_add_host(host),添加到MMC系統中,此時dev與host已經完成了掛接的操作
在此其中將sdhci_host轉換成mmc結構,並添加到系統中:mmc_add_host(mmc);

這里我們着重分析加入MMC子系統的詳細過程:sdhci_add_host(struct sdhci_host *host)
此函數的主要功能為,轉換sdhci_host結構體到mmc_host內核標准結構體,並掛接上相關標准函數,加入MMC子系統中

1. 設置MMC操作接口:mmc->ops = &sdhci_ops; 【后面需要詳解】  
2. 添加兩個tasklet並啟動計時器:
tasklet_init(&host->card_tasklet, sdhci_tasklet_card, (unsigned long)host);【用於MMC插槽上的狀態變化】
tasklet_init(&host->finish_tasklet, sdhci_tasklet_finish, (unsigned long)host);【用於命令傳輸完成后的處理】
setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);【用於等待硬件中斷】
3. 中斷映射:
ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED, mmc_hostname(mmc), host);【中斷處理】
4. 初始化MMC設備,包括復位控制器:
sdhci_init(host, 0);
5. 加入MMC子系統:
mmc_add_host(mmc);
6. 使能設備探測功能:
sdhci_enable_card_detection(host);

在步驟5中最重要的操作是:
void mmc_start_host(struct mmc_host *host)
{
    host->f_init = max(freqs[0], host->f_min);        //獲取初始頻率
    host->rescan_disable = 0;                        //使能探測
    mmc_power_up(host);                                //上電
    mmc_detect_change(host, 0);                        //延遲0,直接調用host->detect進行設備探測
}
這個detect域在分配sdhc_host中的mmc_host時被初始化,INIT_DELAYED_WORK(&host->detect, mmc_rescan);
這里相當於一上電后,立刻進行掃描操作.

掃描操作在下面會詳細描述,這里來簡述掃描完成后的設備匹配工作:
當掃描到對應的設備時,會分配對應的func,根據協議寄存器初始化相關數據域后,並掛在對應的sdio_bus_type總線上:
mmc_attach_sdio---->sdio_init_func----> sdio_alloc_func ----> func->dev.bus = &sdio_bus_type;
當sdio func驅動加載時,也直接掛在sdio總線上,並注冊到系統中【關鍵點】:
sdio_register_driver----> drv->drv.bus = &sdio_bus_type
這個時候總線優先調用match函數進行匹配, bus.probe與driver.probe選其一,在sdio bus的probe中,已經包含了driver.probe.

其它兩種設備:sd與mmc都對應與mmc_bus_type,
在注冊塊設備時調用:mmc_register_driver---->drv->drv.bus = &mmc_bus_type;
這樣也完成了對應的probe流程。
注:在sdio_bus中match做的是匹配vendor/device id,而在mmc_bus中的match做的是直接返回1,probe也是直接調用driver的probe,故后者的匹配工作
完全在mmc設備驅動這一端.
static int mmc_blk_probe(struct mmc_card *card)
{
    struct mmc_blk_data *md, *part_md;
    char cap_str[10];

    md = mmc_blk_alloc(card);

    string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2, cap_str, sizeof(cap_str));

    mmc_blk_alloc_parts(card, md);

    mmc_set_drvdata(card, md);
    mmc_fixup_device(card, blk_fixups);

    mmc_add_disk(md);

    list_for_each_entry(part_md, &md->part, part) {
        if (mmc_add_disk(part_md))
            goto out;
    }
    return 0;
}
為每一個mmc設備都獨立建一個管理結構提並置於card device的driver data中.


這里來總結下,mmc的幾個ops域:

sdhci_host->ops【sdhci_ops】:主要是相關的sdio主控制器的參數:由mmc驅動來實現
    void    (*set_clock)(struct sdhci_host *host, unsigned int clock);
    int        (*enable_dma)(struct sdhci_host *host);
    unsigned int    (*get_max_clock)(struct sdhci_host *host);
    unsigned int    (*get_min_clock)(struct sdhci_host *host);
    unsigned int    (*get_timeout_clock)(struct sdhci_host *host);
    int        (*platform_8bit_width)(struct sdhci_host *host, int width);
    void (*platform_send_init_74_clocks)(struct sdhci_host *host, u8 power_mode);
    unsigned int    (*get_ro)(struct sdhci_host *host);
    void    (*platform_reset_enter)(struct sdhci_host *host, u8 mask);
    void    (*platform_reset_exit)(struct sdhci_host *host, u8 mask);
    int    (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
    void    (*hw_reset)(struct sdhci_host *host);
    void    (*platform_suspend)(struct sdhci_host *host);
    void    (*platform_resume)(struct sdhci_host *host);
    void    (*platform_init)(struct sdhci_host *host);
提供者: mmc master驅動

mmc_host->ops 【mmc_host_ops】:這個域由mmc core來提供
    int (*enable)(struct mmc_host *host);
    int (*disable)(struct mmc_host *host);
    void    (*post_req)(struct mmc_host *host, struct mmc_request *req, int err);
    void    (*pre_req)(struct mmc_host *host, struct mmc_request *req,bool is_first_req);
    void    (*request)(struct mmc_host *host, struct mmc_request *req);
    void    (*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
    int    (*get_ro)(struct mmc_host *host);
    int    (*get_cd)(struct mmc_host *host);
    void    (*enable_sdio_irq)(struct mmc_host *host, int enable);
    void    (*init_card)(struct mmc_host *host, struct mmc_card *card);
    int    (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
    int    (*execute_tuning)(struct mmc_host *host, u32 opcode);
    void    (*enable_preset_value)(struct mmc_host *host, bool enable);
    int    (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
    void    (*hw_reset)(struct mmc_host *host);

提供者:
static const struct mmc_host_ops sdhci_ops = {
    .request    = sdhci_request,
    .set_ios    = sdhci_set_ios,
    .get_ro        = sdhci_get_ro,
    .hw_reset    = sdhci_hw_reset,
    .enable_sdio_irq = sdhci_enable_sdio_irq,
    .start_signal_voltage_switch    = sdhci_start_signal_voltage_switch,
    .execute_tuning            = sdhci_execute_tuning,
    .enable_preset_value        = sdhci_enable_preset_value,
};

mmc_host->bus_ops 【mmc_bus_ops】:
struct mmc_bus_ops {
    int (*awake)(struct mmc_host *);
    int (*sleep)(struct mmc_host *);
    void (*remove)(struct mmc_host *);
    void (*detect)(struct mmc_host *);
    int (*suspend)(struct mmc_host *);
    int (*resume)(struct mmc_host *);
    int (*power_save)(struct mmc_host *);
    int (*power_restore)(struct mmc_host *);
    int (*alive)(struct mmc_host *);
};
提供者:主要針對相關的設備
SDIO:
static const struct mmc_bus_ops mmc_sdio_ops = {
    .remove = mmc_sdio_remove,
    .detect = mmc_sdio_detect,
    .suspend = mmc_sdio_suspend,
    .resume = mmc_sdio_resume,
    .power_restore = mmc_sdio_power_restore,
    .alive = mmc_sdio_alive,
};
SD:
static const struct mmc_bus_ops mmc_sd_ops = {
    .remove = mmc_sd_remove,
    .detect = mmc_sd_detect,
    .suspend = NULL,
    .resume = NULL,
    .power_restore = mmc_sd_power_restore,
    .alive = mmc_sd_alive,
};
MMC:
static const struct mmc_bus_ops mmc_ops = {
    .awake = mmc_awake,
    .sleep = mmc_sleep,
    .remove = mmc_remove,
    .detect = mmc_detect,
    .suspend = NULL,
    .resume = NULL,
    .power_restore = mmc_power_restore,
    .alive = mmc_alive,
};


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM