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