针对Linux,RK3568平台下,I2C驱动的一点小小的领悟

总结:

I2C驱动子系统的实现是如下说明:以下说明仅针对硬件I2C;若所需为软件I2C的设备、驱动都需要我们自己编写

I2C驱动由:

i2c_client(i2c设备)、i2c_driver(i2c驱动)

i2c core:i2c核心层

i2c_adapter(i2c控制器/i2c适配器)、i2c_algorithm(i2c算法/i2c通信协议/i2c通信时序构成)

其中:i2c_client(i2c设备)、i2c_driver(i2c驱动),由我们驱动工程师做

i2c core:为硬件无关代码,主要作用是将i2c_client(i2c设备)、i2c_driver(i2c驱动)等的操作转换为i2c_adapter所需要的:简单理解为中间件/翻译等

i2c_adapter(i2c控制器/i2c适配器)、i2c_algorithm(i2c算法/i2c通信协议/i2c通信时序构成):由原厂工程师编写,也就是SOC的工程师:瑞芯微、海思等

其中I2C是具有自己的总线的,i2c_client、i2c_driver注册在I2C总线上

总线结构体如下:

c 复制代码
struct bus_type i2c_bus_type = {
	.name		= "i2c",
	.match		= i2c_device_match,
	.probe		= i2c_device_probe,
	.remove		= i2c_device_remove,
	.shutdown	= i2c_device_shutdown,
};

但反直觉的是,i2c_adapter并不是直接通过i2c总线去匹配注册的,而是转了一道,通过platform里面的probe去进行的注册

c 复制代码
static struct platform_driver rk3x_i2c_driver = {
	.probe   = rk3x_i2c_probe,
	.remove  = rk3x_i2c_remove,
	.driver  = {
		.name  = "rk3x-i2c",
		.of_match_table = rk3x_i2c_match,
		.pm = &rk3x_i2c_pm_ops,
	},
};

#ifdef CONFIG_ROCKCHIP_THUNDER_BOOT
static int __init rk3x_i2c_driver_init(void)
{
	return platform_driver_register(&rk3x_i2c_driver);
}
subsys_initcall_sync(rk3x_i2c_driver_init);

static void __exit rk3x_i2c_driver_exit(void)
{
	platform_driver_unregister(&rk3x_i2c_driver);
}
module_exit(rk3x_i2c_driver_exit);
#else
module_platform_driver(rk3x_i2c_driver);
#endif

不过也不难以理解,设备树中指定了硬件i2c的设备,然后编写驱动,通过platform_driver去匹配注册,然后再在对应的Probe内进行i2c_adapter、i2c_client的注册

i2c_adapter的注册在i2c_add_adapter申请空间,剩下的位置填充,最后赋给旗下的i2c_client

i2c_client的注册:i2c_add_adapter->i2c_register_adapter->of_i2c_register_devices->...->i2c_new_device

也就是说i2c_client的注册是随着i2c_adapter的注册一同完成的,不过也不难以理解,i2c_adapter是用来控制i2c设备的

误区:误以为i2c-core-base.c文件中的dummy:

c 复制代码
static struct i2c_driver dummy_driver = {
	.driver.name	= "dummy",
	.probe		= dummy_probe,
	.remove		= dummy_remove,
	.id_table	= dummy_id,
};

是注册的i2c驱动,实际上并不是,这个只是针对同一设备具有多地址时的一个优化,具体作用还没理解清楚。

误区2:i2c-dev.c文件中的const struct file_operations i2cdev_fops以为是注册了实际的设备

实际并不是,稍微追一下就可以发现是直接调用了i2c_adapter,可以很简单的理解为,通过这个玩意可以跳过编写i2c的驱动,在启动了对于管脚的i2c_adapter后,就可以在应用层编写应用,进行一定的处理,不需要在内核里面增加新的i2c_client、i2c_driver。

总结,对于非soc驱动工程师来说,针对硬件I2C,只需要关注i2c_client、i2c_driver的编写即可,甚至i2c_client直接使用设备树,而去编写i2c_driver就行。

核心思想依然是:总线、驱动、设备模型;
i2c_bus_type(总线)、i2c_driver(驱动)、i2c_client(设备)
platform_bus_type(总线)、platform_driver rk3x_i2c_driver(驱动)、rk3x_i2c_match/设备树中指定的i2c节点(设备)

相关推荐
Forever Nore18 小时前
LeetCode 14 最长公共前缀 - 纵向扫描
linux·服务器·leetcode
拂拉氏18 小时前
【知识讲解】 Linux权限相关知识讲解
linux·权限
桑榆4161 天前
双系统(Windows + Ubuntu)安装流程
linux·windows·ubuntu
ltl1 天前
实时 OS 巡礼:VxWorks、QNX、Zephyr 与 PREEMPT_RT
linux
我是谁??1 天前
Ubuntu22.04更换清华源
linux·运维·服务器
Shell运维手记1 天前
Linux 常用基础命令学习笔记
linux·运维·笔记·学习·算法·github
测试运维日常笔记1 天前
Linux系统安装配置TigerVNC服务器完整指南
linux·运维·服务器
雾时之林1 天前
Linux----cron定时服务
linux·运维·服务器
wengqidaifeng1 天前
1.从“会敲命令”到理解 Linux:15 个基础指令、文件树与命令执行的本质
linux·运维·服务器·ubuntu
奔跑的架构师2 天前
[A-49]ARMv9/v8-PSCI接口规范与工作流程简介
android·linux·arm开发·arm