I2C驱动框架
Posted 天地有大美而不言
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了I2C驱动框架相关的知识,希望对你有一定的参考价值。
参考:I2C子系统之I2C bus初始化——I2C_init()
在linux内核启动的时候最先执行的和I2C子系统相关的函数应该是driver/i2c/i2c-core.c文件中的i2c_init()函数。
1 static int __init i2c_init(void) 2 { 5 retval = bus_register(&i2c_bus_type); 9 i2c_adapter_compat_class = class_compat_register("i2c-adapter"); 15 retval = i2c_add_driver(&dummy_driver); 18 return 0; 27 }
1.bus_register(&i2c_bus_type)注册i2c总线
struct bus_type i2c_bus_type = { .name = "i2c", .match = i2c_device_match, .probe = i2c_device_probe, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown, .pm = &i2c_device_pm_ops, };
该函数执行完会在/sys/bus目录下创建i2c子目录,并在i2c子目录下创建devices和drivers两个目录,以后注册到i2c总线上的设备和驱动会分别放在这两个目录。
2.class_compat_register("i2c-adapter")在/sys/class/目录下创建i2c-adapter子类目录
3.i2c_add_driver(&dummy_driver)在i2c-bus上注册驱动,该函数执行成功后会在/sys/bus/i2c/drivers目录下创建.driver.name = "dummy"为名字的目录。
static struct i2c_driver dummy_driver = { .driver.name = "dummy", .probe = dummy_probe, .remove = dummy_remove, .id_table = dummy_id, };
分析该该函数前先看一下i2c_bus_type总线-设备-驱动模型。
struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)和
int i2c_add_adapter(struct i2c_adapter *adapter)向i2c_bus_type注册i2c_client和i2c_adapter。两种不同的设备以dev->type来区分,
struct device_type i2c_adapter_type = { .groups = i2c_adapter_attr_groups, .release = i2c_adapter_dev_release, }; static struct device_type i2c_client_type = { .groups = i2c_dev_attr_groups, .uevent = i2c_device_uevent, .release = i2c_client_dev_release, };
static inline int i2c_add_driver(struct i2c_driver *driver)则向i2c_bus_type注册i2c_driver。
i2c_add_driver(&dummy_driver); --> i2c_register_driver(THIS_MODULE, driver); -->&dummy_driver->driver.bus = &i2c_bus_type; -->res = driver_register(&(&dummy_driver)->driver);//将驱动注册到i2c_bust_type -->i2c_for_each_dev(&dummy_driver, __process_new_driver); //遍历i2c_bus_type总线上的设备 -->bus_for_each_dev(&i2c_bus_type, NULL, &dummy_driver, __process_new_driver); //以找到的设备和dummy_driver为参数调用__process_new_driver函数 -->__process_new_driver(dev, &dummy_driver);
由于i2c_add_driver(&dummy_driver)执行时,i2c_bus_type总线上还没有注册设备,所以不会执行__process_new_driver函数。
但下面还是分析一下__process_new_driver函数的执行过程,该函数最终调用i2c_detect函数检测设备是否存在。
__process_new_driver(dev,&dummy_driver) -->if (dev->type != &i2c_adapter_type) return 0;//判断是i2c_adapter_type类型的设备才继续执行 --> i2c_do_add_adapter(&dummy_driver, to_i2c_adapter(dev)); -->i2c_detect(adap, &dummy_driver);// Detect supported devices on that bus, and instantiate them
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) -->int adap_id = i2c_adapter_id(adapter);//获取adapter的序列号,即处理器的第几个I2C控制器 -->const unsigned short *address_list = driver->address_list; //获取I2C从设备的地址数组 -->if (!(adapter->class & driver->class)) return 0; //类型匹配后才继续执行 -->struct i2c_client *temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);//分配i2c_client结构体 -->temp_client->adapter = adapter; -->for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) //遍历address_list里的i2c地址 -->temp_client->addr = address_list[i];//设置从地址到i2c_client结构体 -->i2c_detect_address(temp_client, driver);//检测该从地址对应的设备是否存在
static int i2c_detect_address(struct i2c_client *temp_client,struct i2c_driver *driver) -->int addr = temp_client->addr; -->i2c_check_addr_validity(addr);//检测地址有效性 -->i2c_check_addr_busy(adapter, addr);//检测设备是否正在使用,同一条物理I2Cbus上不能有两个相同address的器件 -->i2c_default_probe(adapter, addr);//检测i2c物理总线上是否有设备应答 -->struct i2c_board_info info.addr=temp_client->addr -->driver->detect(temp_client, &info);//调用i2c_driver的detect函数检测设备,并经info.type赋值 -->struct i2c_client *client = i2c_new_device(adapter, &info);//在i2b_bus_type总线上创建i2c_client设备 -->list_add_tail(&client->detected, &driver->clients);//创建设备成功则将该i2c_client挂到i2c_driver的链表上
以上是关于I2C驱动框架的主要内容,如果未能解决你的问题,请参考以下文章
Linux——Linux驱动之玩转I2C(下)I2C driver驱动程序框架实现总结(i2c_driver结构体框架实现步骤驱动中读写I2C设备实测)
Linux——Linux驱动之玩转I2C(下)I2C driver驱动程序框架实现总结(i2c_driver结构体框架实现步骤驱动中读写I2C设备实测)