今天重新看了一下Motorola的SD/MMC驱动源码,并结合以前的分析记录,做一个总结。
以E680为例,按照初始化的过程进行分析。
模块初始化函数
module_init(e680_mmc_init);
在函数e680_mmc_init里初始化定时器,定时器的function函数为e680_detect_handler,当卡插入或取出时调用该函数。
init_timer(&e680_detection);
e680_detection.function = e680_detect_handler;
e680_mmc_slot_init完成进一步初始化。
retval = mmc_register_slot_driver(&e680_dops, 1);
static struct mmc_slot_driver e680_dops = {
owner: THIS_MODULE,
name: "Motorola E680 MMC/SD",
ocr: 1 << 19, /* Mainstone voltage is 3.15V */
flags: MMC_SDFLAG_MMC_MODE | MMC_SDFLAG_SD_MODE | MMC_SDFLAG_SPI_MODE,
init: e680_mmc_slot_init,
cleanup: e680_mmc_slot_cleanup,
is_empty: e680_mmc_slot_is_empty,
is_wp: e680_mmc_slot_is_wp,
send_cmd: bvd_mmc_send_command,
set_clock: bvd_mmc_set_clock,
};
设置检测是否有卡的管脚的中断属性,并申请中断。
set_GPIO_IRQ_edge( GPIO_MMC_DETECT, GPIO_FALLING_EDGE | GPIO_RISING_EDGE);
/* Request card detect interrupt */
retval = request_irq(IRQ_GPIO(GPIO_MMC_DETECT), e680_detect_int,
SA_INTERRUPT | SA_SAMPLE_RANDOM,
"MMC/SD card detect", (void*)1);
中断处理函数e680_detect_int如下:
static void e680_detect_int(int irq, void *dev, struct pt_regs *regs)
{
DEBUG(2, "card detect IRQ\n");
mod_timer(&e680_detection, jiffies + HZ);
}
更新定时器,到达时间点(jiffies + HZ)时执行前面所说的e680_detect_handler。
检测卡是否存在。
e680_mmc_slot_is_empty(0);
通过e680_mmc_slot_up(0)调用bvd_mmc_slot_up()
在bvd_mmc_slot_up()完成时钟和GPIO的设置,移植的时候按自己的板子做对应的修改。
CKEN |= CKEN12_MMC;
DEBUG(3, " ...core MMC clock OK\n");
/* Configure MMCLK bus clock output signal
([2], 15.3, 24.4.2) */
set_GPIO_mode(GPIO_MMC_CLK | GPIO_ALT_FN_2_OUT);
DEBUG(3, " ...MMCLK signal OK\n");
/* Configure MMCMD command/response bidirectional signal
([2], 15.3, 24.4.2) */
set_GPIO_mode(GPIO_MMC_CMD | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);
DEBUG(3, " ...MMCMD signal OK\n");
/* Configure MMDAT[0123] data bidirectional signals
([2], 15.3, 24.4.2) */
set_GPIO_mode(GPIO_MMC_DATA0 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);
// for dat3 used to detect card insert and remove on A780,
// so we only use 1 bit transfer mode ---zq
#ifndef CONFIG_ARCH_EZX_A780
//from Barbados P3, we will use 4 bit mode --jll
set_GPIO_mode(GPIO_MMC_DATA1 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);
set_GPIO_mode(GPIO_MMC_DATA2 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);
set_GPIO_mode(GPIO_MMC_DATA3 | GPIO_ALT_FN_1_IN | GPIO_ALT_FN_1_OUT);
#endif
DEBUG(3, " ...MMDATx signals OK\n");
至此,跟底层相关的初始化完成。
驱动移植过程