一、概述
在设备驱动模型中,需要关心总线、设备和驱动这3个实体,
总线将设备和驱动绑定。
在系统每注册一个设备的时候,会寻找与之匹配的驱动;
同样,系统每注册一个驱动的时候,会寻找匹配的设备,而匹配由总线完成。
注册设备与驱动不分先后顺序。
对于没有总线得设备,需要一种虚拟的总线,称为platform总线,相应的设备称为platform_device,而驱动成为platform_driver。android把内部i2c、LCD等归纳到platform_device,便于统一管理。
二、驱动学习流程
以i2c为例 ,一般而言所说得驱动包含两部分
1、bus_driver用于将设备挂载在i2总线上,代码在i2c\bus\i2c_qup.c中,使用得总线由主芯片支持决定。
2、设备本身而言的驱动。代码在driver\misc\eeprom\microp_nutorn.c中。由外设或者从设备的芯片支持决定。
针对驱动得开发过程,针对性得学习时大致有以下流程
1、定义 、注册platform_device 包含它的子类实例
2、定义、注册 platform_driver 包含它的子类实例
注意点:device是一个类的概念,这一类得device共用一条总线。每个子类是挂载在这条总线下得不同得从设备。
同样的,driver包含总线得driver以及针对每个从设备不同的driver
2.1定义注册platform_device
1、定义platform_device 资源信息
代码在 kernel/arch/arm/mach-msm/device-8064.c
定义系统需求得resource
它描述了一个I2C总线设备的资源,设备驱动会根据flags获取相应的资源信息
A当为 IORESOURCE_MEM 表示描述的是内存类型的资源信息,此时 start end 表示起始内存得地址,同类设备可占据两个内存区域,这个一般是固定设计好得值。移植过程中尽量不变。
B当为IORESOURCE_IRQ表示描述了这个 I2C 设备的中断资源,此时 start end表示设备只用得中断号起始值。
C当为IORESOURCE_IO 表示 描述的是GPIO资源信息。此时 start end 表示 设备只用得GPIO值。可在GPIO table中对比。
static struct resource resources_qup_i2c_gsbi3[] = {
{
.name = "gsbi_qup_i2c_addr",
.start = MSM_GSBI2_PHYS,
.end = MSM_GSBI2_PHYS + 4 - 1,
.flags = IORESOURCE_MEM,
},
{
.name = "i2c_clk",
.start = 25,
.end = 25,
.flags = IORESOURCE_IO,
},
};
有resource 信息,就可以定义 platform_device
struct platform_device apq8064_device_qup_i2c_gsbi3= {
.name = "qup_i2c", //与driver注册是名称匹配
.id = MSM_GSBI3_QUP_I2C_BUS_ID,
.num_resources = ARRAY_SIZE(gsbi3_qup_i2c_resources),
.resource = gsbi3_qup_i2c_resources,
};
前面前定义好了 platform_device 结构体后 在板级支持文件 board-xxx.c文件中进行注册 代码在:
kernel/arch/arm/mach-msm/boad-8064.c
static struct platform_device *common_not_mpq_devices[] __initdata =
{
&apq8064_device_qup_i2c_gsbi3,
};
//在初始化时会向系统中添加该类设备
static void __init apq8064_common_init(void)
{
platform_add_devices(common_not_mpq_devices );
}
static struct i2c_board_info __initdata enterprise_nuvoton_microp[] = {
I2C_BOARD_INFO("microp", 0x15), //microp名称要与具体driver中相同,
.irq=MSM_GPIO_TO_INT(7),
.platform_data = &nuvoton_microp_pdata,
};
4、注册
最终在 初始化函数中被加载到board中得of_node中去。
static void __init register_i2c_devices(void)
{
i2c_register_board_info();
}
1、总线驱动程序
需要实现结构体platform_driver中得接口
I2C总线我们使用得高通平台,所以是QUP,代码在
i2c/bus/i2c_qup.c
static struct platform_driver qup_i2c_driver = {
.probe = qup_i2c_probe,
.remove = __devexit_p(qup_i2c_remove),
.driver = {
.name = "qup_i2c", // 与platform_device 中name要一样
.owner = THIS_MODULE,
.pm = &i2c_qup_dev_pm_ops,
//.of_match_table = i2c_qup_dt_match,
},
};
static struct of_device_id i2c_qup_dt_match[] = {
{
.compatible = "qcom,i2c-qup",
},
{}
};
//其中 "qcom,i2c-qup" 与DTS中总线得属性得要一样
在初始时中初始化函数qup_i2c_init_driver被调用,
static int __init qup_i2c_init_driver(void)
{
return platform_driver_register(&qup_i2c_driver);
}
第1步把bus驱动做好来,现在是设备驱动,针对每个client从设备得驱动,代码:
driver/misc/eeprom/microp_nuvoton.c
添加具体驱动信息。
static struct i2c_driver microp_nuvoton_driver = {
.driver = {
.name = TEGRA_MICROP_NAME,
.owner = THIS_MODULE,
},
.probe = microP_probe,
.remove = microP_remove,
.suspend= microp_suspend,
.resume= microp_resume,
.id_table = microP_id,
};
static int __init microP_init(void)
{
return i2c_add_driver(µp_nuvoton_driver);
}
三、注意事项
个人认为在参考移植得代码时除去probe中得相关初始化操作外着重主要以下几点
1、resume、suspend函数:对电源管理影响较大
2、定时器或者延时work等:确定延时运行得work,定时运行得work
3、中断处理函数:确认定义的中断触发条件,输入类驱动重点。
4、数据接受和发送得接口函数:大数据收发类驱动得重点。一般有指令模式和数据模式
5、其他一些类似使能、关闭某些功能得标志位得操作函数:影响自身或着其他驱动上层