由于使用的linux内核版本为3.6.0 由于3.6版本的内核使用了dts,导致很难找到这方面的资料,对于一个初学者的我来说,花了很久才大概明白这里面驱动的实现方法,忘各位前辈指导;
i2C 设备驱动的工作调用过程:当调用i2c_add_driver函数向I2C总线(i2c-core.c文件中注册的”i2c”总线)增加一个i2c_driver时,会遍历总线中的所有i2c_client,调用总线注册的match函数I2C适配器上是否有与i2c_driver匹配的i2c_client,如果匹配会调用I2C注册的probe函数,然后再调用i2c_driver定义的probe来进行关联和初始化工作。
1.在/driver/i2c/buses/.. 有和平台相关的i2c代码文件,本次使用的平台为ATSAMA5D35,故我所关注的文件为I2c-at91.c。在介绍此文件之前,首先介绍一下我之前学习的i2c框架,设备——总线——驱动模型。这是我对驱动框架的理解,驱动可拆分为driverv——device两部分,dev(i2c-client)会将自己添加到bus的设备链表(注册设备),drv(i2c-drv)会将自己添加到bus的驱动链表(注册驱动),当有设备被添加到bus如果match(i2c-bus-type)成功,将会调用对应的驱动中的probe函数。在这中间构造i2c-client的方法又有4种,面对不同的场合用不同的方法(来自内核代码中i2c相关的docment):
方法一:通过构造i2c_board_info结构体;注册i2c-register_board_info -> list_add_tail ,当完成board_info 注册后,在下面将使用他:i2c_register_adapter >i2c_scan_static_board_info >i2c_new_device,由于在使用register_adapter之前需要注册好board_info,故此方法不适合动态加载
即insmod;
方法二:直接i2c_new_device (struct i2c_adapter *adapter,struct i2c_board_info *info) 认为设备肯定存在,和i2c_new_probe_device 首先枚举,如果设备存在则继续执行,否则失败返回
方法三:其他三种方法,适配器都是事先确定的,如果事先并不知道i2c适配器,则此种方法适用。在i2c_driver中使用了.class detect address_list .class 表示这一类适配器用detect函书查找addr_list里得的设备,如果找到,则调用i2c_new_device 如 .class = I2C_CLASS_HWMON
方法四:创建设备 echo ... ... > /sys/devices/platform/... 从代码知道 最后还是调用了i2c_new_device
a . i2c_add_driver 会将driver 加入到i2c_bus_type的drv链表,并从链表中取出能匹配的i2c_client 并使用probe函数。driver_register
b. 对于每一个适配器,调用process_new_driver ,对于每一个适配器,调用detect_address函数看确定address _list里面的设备是否存在,如果存在,再调用detect函数进一步确定,(detect函数就是进一步读写I2C确定是哪一款IC,并设置info->type),然后调用i2c_new_device
以上是对通用的i2c设备驱动的描述,那么在ATSAMA5D35 平台 linux 3.6.0上 pcf8563这一具体设备的实现介绍如下:
static const struct of_device_id pcf8563_of_match[] __devinitconst = {
{ .compatible = "nxp,pcf8563" },
{}
};由于在3.6版本的内核中使用了设备树,从.compatible可以看出此rtc设备使用的是设备树。
根据驱动的实现步骤:1.of_match_table = of_match_ptr(pcf8563_of_match) 如果成功,则调用相应的驱动中的probe函数,实现功能函数.probe = pcf8563_probe,
在probe函数中: 首选执行的函数 if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) 调用适配器。