从Linux2.6起引入了一套新的驱动管理和注册模型,即平台设备platform_device和平台驱动platform_driver.
Linux中大部分的设备驱动,都可以使用这套机制,设备用platform_device表示,驱动用platform_driver表示。平台设备模型与传统的device和driver模型相比,一个十分明显的优势在于平台设备模型将设备本身的资源注册进内核,由内核统一管理。这样提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性。通过平台设备模型开发底层驱动的大致流程为下图:
平台设备是指处理器上集成的额外功能的附加设备,如Watch Dog,IIC,IIS,RTC,ADC等设备。这些额外功能设备是为了节约硬件成本、减少产品功耗、缩小产品形状而集成到处理器内部的。需要注意的是,平台设备并不是与字符设备、块设备和网络设备并列的概念,而是一种平行的概念,其从另一个角度对设备进行了概括。如果从内核开发者的角度来看,平台设备的引入,是为了更容易开发字符设备、块设备和网络设备驱动
当一个驱动注册[platform_driver_register()]的时候,他会遍历所有总线上的设备来寻找匹配,在启动的过程驱动的注册一般比较晚,或者在模块载入的时候 当一个驱动注册[platform_driver_probe()]的时候, 功能上和使用platform_driver_register()是一样的,唯一的区别是它不能被以后其他的device probe了,也就是说这个driver只能和一个device绑定。
高通的I2C控制器为QUP –> Use I2C Driver
Use CCI-> Platform Driver
节点名的命名规则一般是 [name]@[address],也可以只有name而没有@之后的内容,但是要确保name不能重名。如果加了@以及地址,那么name可以相同,只要address不同即可。
每一个设备节点都要有一个compatible属性 compatible的内容是用来匹配驱动的,组成方式为"[manufacturer], [model]",加入厂商名是为了避免重名。有的时候后边还会跟一个名字,如:
compatible = "acme,coyotes-revenge", "acmd-board";
设备的地址特性根据一下几个属性来控制:
- reg
- #address-cells
- #size-cells
reg意为region,区域。格式为:
reg = <address1 length1 [address2 length2] [address3 length3]>;
spi@10115000 { compatible = "arm,pl022"; reg = <0x10115000 0x1000 >; };
位于0x10115000的SPI设备申请地址空间,起始地址为0x10115000,长度为0x1000,即属于这个SPI设备的地址范围是0x10115000~0x10116000。
实际应用中,有另外一种情况,就是通过外部芯片片选激活模块。例如,挂载在外部总线上,需要通过片选线工作的一些模块:
i2c@1,0 { compatible = "acme,a1234-i2c-bus"; #address-cells = <1>; #size-cells = <0>; reg = <1 0 0x1000>; rtc@58 { compatible = "maxim,ds1338"; reg = <58>; }; };
external-bus使用两个cell来描述地址,一个是片选序号,另一个是片选序号上的偏移量。而地址空间长度依然用一个cell来描述。所以以上的子设备们都需要3个cell来描述地址空间属性——片选、偏移量、地址长度。在上个例子中,有一个例外,就是i2c控制器模块下的rtc模块。因为I2C设备只是被分配在一个地址上,不需要其他任何空间,所以只需要一个address的cell就可以描述完整,不需要size-cells。
以高通8974平台为例,在注册i2c总线时,会调用到qup_i2c_probe()接口,该接口用于申请总线资源和添加i2c适配器。在成功添加i2c适配器后,会调用of_i2c_register_devices()接口。此接口会解析i2c总线节点的子节点(挂载在该总线上的i2c设备节点),获取i2c设备的地址、中断号等硬件信息。然后调用request_module()加载设备对应的驱动文件,调用i2c_new_device(),生成i2c设备。此时设备和驱动都已加载,于是drvier里面的probe方法将被调用。后面流程就和之前一样了。
加载流程并不是按找从树根到树叶的方式递归注册,而是只注册根节点下的第一级子节点,第二级及之后的子节点暂不注册。Linux系统下的设备大多都是挂载在平台总线下的,因此在平台总线被注册后,会根据allnodes节点的树结构,去寻找该总线的子节点,所有的子节点将被作为设备注册到该总线上。
dtb-$(CONFIG_ARCH_MSM8994) += msm8994-v1-sim.dtb msm8994-rumi.dtb msm8994-v1-cdp.dtb msm8994-pmi8994-pm8004-v1-cdp.dtb msm8994-v1-mtp.dtb msm8994-pmi8994-pm8004-v1-mtp.dtb msm8994-v1-liquid.dtb msm8994-v1-fluid.dtb apq8094-v1-cdp.dtb apq8094-v1-mtp.dtb apq8094-v1-liquid.dtb apq8094-v1-fluid.dtb apq8094-v1-dragonboard.dtb msm8994-v2-sim.dtb msm8994-v2-cdp.dtb msm8994-pmi8994-pm8004-v2-cdp.dtb msm8994-v2-mtp.dtb msm8994-pmi8994-pm8004-v2-mtp.dtb msm8994-v2-liquid.dtb msm8994-v2-fluid.dtb apq8094-v2-cdp.dtb apq8094-v2-mtp.dtb apq8094-v2-liquid.dtb apq8094-v2-fluid.dtb apq8094-v2-dragonboard.dtb
reg : should contain i2c slave address of the device
qcom,slave-id : should contain i2c slave address, device id address and expected id read value
DTS设置的I2C slave地址是八位地址,其中高7位为I2C slave地址,最低位是写标记0.
比如器件的七位Slave地址为0x23,那么DTS中需要左移一位变成0x46
qcom,camera@90 compatible = "qcom,mt9m114"; reg = <0x90>; qcom,slave-id = <0x90 0x0 0x2481>;