最近在研究wifi模组, 是sdio接口的, 而手头刚好有一块mini2440,了解了一下sdio加载的过程, 发现和sd卡加载的过程是类似的。
这里用mini2440的内核源码, 来剖析一下sd卡的加载过程:
首先, mini2440内核加载的时候, 就会指定一部分设备初始化列表:
//---------------------------- arch/arm/mach-s3c2440/mach-mini2440.c ----------------------------//
/* devices we initialise */
static struct platform_device *mini2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_rtc,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&mini2440_device_eth,
&s3c24xx_uda134x,
&s3c_device_nand,
&s3c_device_sdi, // sd设备
&s3c_device_usbgadget,
};
/* MMC/SD */
static struct s3c24xx_mci_pdata mini2440_mmc_cfg = {
.gpio_detect = S3C2410_GPG(8), // 插入检测引脚
.gpio_wprotect = S3C2410_GPH(8), // 写保护引脚
.set_power = NULL,
.ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34, // 有效电压范围是3.2~3.3V, 3.3~3.4V
};
static void __init mini2440_machine_init(void)
{
s3c_device_sdi.dev.platform_data = &mini2440_mmc_cfg;
platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
}
来看看s3c_device_sdi的定义:
//---------------------------- arch/arm/plat-s3c24xx/devs.c ----------------------------//
/* SDI */
static struct resource s3c_sdi_resource[] = {
[0] = {
.start = S3C24XX_PA_SDI,
.end = S3C24XX_PA_SDI + S3C24XX_SZ_SDI - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_SDI,
.end = IRQ_SDI,
.flags = IORESOURCE_IRQ,
}
};
struct platform_device s3c_device_sdi = {
.name = "s3c2410-sdi",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_sdi_resource),
.resource = s3c_sdi_resource,
};
有些人会奇怪, 我们这里不是在讲解2440吗, 为什么这里是s3c2410-sdi, 别急, 往下看:
//---------------------------- arch/arm/mach-s3c2440/mach-mini2440.c ----------------------------//
static void __init mini2440_machine_init(void)
{
s3c_device_sdi.dev.platform_data = &mini2440_mmc_cfg;
platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
}
//---------------------------- arch/arm/plat-s3c24xx/s3c244x.c ----------------------------//
void __init s3c244x_map_io(void)
{
iotable_init(s3c244x_iodesc, ARRAY_SIZE(s3c244x_iodesc));
/* rename any peripherals used differing from the s3c2410 */
s3c_device_sdi.name = "s3c2440-sdi"; // 重命名为s3c2440-sdi
s3c_device_i2c0.name = "s3c2440-i2c";
s3c_device_nand.name = "s3c2440-nand";
s3c_device_usbgadget.name = "s3c2440-usbgadget";
}
理解了吧?
接下来讲sd驱动的加载:
//---------------------------- drivers/mmc/host/s3cmci.c ----------------------------//
static struct platform_device_id s3cmci_driver_ids[] = {
{
.name = "s3c2410-sdi",
.driver_data = 0,
}, {
.name = "s3c2412-sdi",
.driver_data = 1,
}, {
.name = "s3c2440-sdi",
.driver_data = 1, // 下面会用到!!!
},
{ }
};
static struct platform_driver s3cmci_driver = {
.driver = {
.name = "s3c-sdi",
.owner = THIS_MODULE,
.pm = s3cmci_pm_ops,
},
.id_table = s3cmci_driver_ids,
.probe = s3cmci_probe,
.remove = __devexit_p(s3cmci_remove),
.shutdown = s3cmci_shutdown,
};
static int __init s3cmci_init(void)
{
return platform_driver_register(&s3cmci_driver);
}
module_init(s3cmci_init);
驱动和设备匹配上的话,就会调用驱动的probe函数:
static int __devinit s3cmci_probe(struct platform_device *pdev)
{
struct s3cmci_host *host;
struct mmc_host *mmc;
is2440 = platform_get_device_id(pdev)->driver_data; // 是否是2440, 这里就用到上面提到的driver_data,
mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev); // 分配mmc_host结构体
for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) { // SDCLK SDCMD DATA0~DATA3
ret = gpio_request(i, dev_name(&pdev->dev)); // 申请gpio资源
if (ret) {
dev_err(&pdev->dev, "failed to get gpio %dn", i);
for (i--; i >= S3C2410_GPE(5); i--)
gpio_free(i);
goto probe_free_host;
}
}
host = mmc_priv(mmc); // 获取private域
host->mmc = mmc;
host->pdev = pdev;
host->is2440 = is2440;
host->pdata = pdev->dev.platform_data; // 即上面提到的mini2440_mmc_cfg
if (!host->pdata) {
pdev->dev.platform_data = &s3cmci_def_pdata;
host->pdata = &s3cmci_def_pdata;
}
if (is2440) {
host->sdiimsk = S3C2440_SDIIMSK;
host->sdidata = S3C2440_SDIDATA;
host->clk_div = 1;
} else {
host->sdiimsk = S3C2410_SDIIMSK;
host->sdidata = S3C2410_SDIDATA;
host->clk_div = 2;
}
// 申请内存
host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); // 这里会读取IORESOURCE_MEM域
host->mem = request_mem_region(host->mem->start,
resource_size(host->mem), pdev->name);
host->base = ioremap(host->mem->start, resource_size(host->mem));
host->irq = platform_get_irq(pdev, 0); // 这里会读取IORESOURCE_IRQ域, 返回start地址
if (host->irq == 0) {
dev_err(&pdev->dev, "failed to get interrupt resouce.n");
ret = -EINVAL;
goto probe_iounmap;
}
// 申请中断,该中断为读写SD卡数据时所产生的中断
if (request_irq(host->irq, s3cmci_irq, 0, DRIVER_NAME, host)) {
dev_err(&pdev->dev, "failed to request mci interrupt.n");
ret = -ENOENT;
goto probe_iounmap;
}
// 禁止上面所申请的中断
disable_irq(host->irq);
host->irq_state = false;
if (!host->pdata->no_detect) { // 如果SD控制器具有检测SD卡插拔状态的功能
ret = gpio_request(host->pdata->gpio_detect, "s3cmci detect"); // 申请插入检测io
host->irq_cd = s3c2410_gpio_getirq(host->pdata->gpio_detect);
if (host->irq_cd >= 0) {
if (request_irq(host->irq_cd, s3cmci_irq_cd, // 注册插入检测中断处理函数, 申请中断,当有SD卡插入或拔出时,则进入该中断
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING,
DRIVER_NAME, host)) {
dev_err(&pdev->dev,
"can't get card detect irq.n");
ret = -
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』