Linux I2C驱动架构学习
博客说明
撰写日期 | 2019.11.20 |
---|---|
完稿日期 | 2019.11.21 |
最近维护 | 暂无 |
本文作者 | multimicro |
联系方式 | multimicro@qq.com |
资料链接 | 本文无附件资料 |
GitHub | https://github.com/wifialan/drivers |
原文链接 | https://blog.youkuaiyun.com/multimicro/article/details/103164746 |
开发环境
环境说明 | 详细信息 | 备注信息 |
---|---|---|
操作系统 | Ubunut 18.04 | |
开发板 | JZ2440-V3 | |
u-boot | uboot-2012.04.01 | |
busybox | busybox-1.22.1 | |
u-boot和busybox编译器 | arm-linux-gcc (4.4.3) | |
Linux内核 | linux-4.19-rc3 | |
Linux内核编译器 | arm-linux-gnueabi-gcc (4.9.4) |
1. Linux I2C 体系结构
i2c的编程应用流程请参考我的上一篇文章Linux 设备树学习——基于i2c总线分析,这篇文章我是基于i2c总线而写的,里面包含注册和匹配方式的介绍,和相应的模板。
参考宋宝华 《Linux设备驱动开发详解》 第15章内容。
Linux的I2C体系结构分为3个组成部分:
- I2C核心
- I2C总线驱动(适配器驱动)
- I2C设备驱动
1.1 Linux I2C核心
借鉴 宋宝华 《Linux设备驱动开发详解》 第15章第2节内容。
I2C核心(drivers/i2c/i2c-core-base.c)中提供了一组不依赖于硬件平台的接口函数,这个文件一般不需要被工程师修改,但是理解其中的主要函数非常关键,因为I2C总线驱动和设备驱动之间以I2C核心作为纽带。I2C核心中的主要函数如下。
1.1.1 增加 / 删除 i2c_adapter
int i2c_add_adapter(struct i2c_adapter *adap);
void i2c_del_adapter(struct i2c_adapter *adap);
在有设备树版本中,内部都封装了从设备树中获取i2c
设备并注册为i2c client
的方法,如下:
/i2c节点一般表示i2c控制器, 它会被转换为platform_device, 在内核中有对应的platform_driver;
platform_driver的probe函数中会调用i2c_add_numbered_adapter:
i2c_add_numbered_adapter// drivers/i2c/i2c-core-base.c
__i2c_add_numbered_adapter
i2c_register_adapter
of_i2c_register_devices(adap); // drivers/i2c/i2c-core-of.c
for_each_available_child_of_node(bus, node) {
client = of_i2c_register_device(adap, node);
client = i2c_new_device(adap, &info); // 设备树中的i2c子节点被转换为i2c_client
}
上述第一个函数i2c_add_numbered_adapter
内容如下,通过Source Insight软件,可以一步一步定位分析,可以很好的帮助理解设备树汇总的i2c子设备节点是如何转换为i2c client
的。
int i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
if (adap->nr == -1) /* -1 means dynamically assign bus id */
return i2c_add_adapter(adap);
return __i2c_add_numbered_adapter(adap);
}
1.1.2 增加 / 删除 i2c_driver
int i2c_register_driver(struct module *owner, struct i2c_driver *driver);
void i2c_del_driver(struct i2c_driver *driver