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