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,
};

posted @ 2013-05-22 13:44  天地不仁  阅读(4083)  评论(0编辑  收藏  举报