基于RK3399的Linux驱动开发 -- I2C驱动框架

本文深入剖析基于RK3399的Linux系统中I2C驱动架构,涵盖核心接口、adapter和client驱动骨架,以及注册与匹配的时序流程。介绍了i2c-core.c实现的总线、i2c-rk3x.c实现的adapter和如rk808电源管理芯片的client驱动。核心接口用于总线初始化和设备读写,adapter接口涉及控制器驱动的算法回调,client接口则关注驱动注册。时序图展示了总线、adapter和client驱动的注册及匹配过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、概述

本文讲述如何从源代码分析i2c驱动架构,i2c的主体包含i2c总线、adapter设备和client设备。总线由i2c-core.c实现;adapter是具体的芯片i2c控制器,rk3399的adapter驱动由i2c-rk3x.c实现;client则是具体的i2c设备,如使用i2c通信的电源管理芯片rk808的驱动为rk808.c。

二、core

core主要实现一些与具体soc平台和具体i2c设备无关的接口,如adapter的注册、i2c设备注册、i2c总线初始化、和i2c设备读写功能等。读写通过底层回调接口实现。

1、core接口

i2c_init

这个接口主要向系统初始化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,
};
EXPORT_SYMBOL_GPL(i2c_bus_type);

static int __init i2c_init(void)
{
   
   
	int retval;

	/* 注册i2c总线 */
	retval = bus_register(&i2c_bus_type);
}

i2c_device_match

这个回调主要用于匹配i2c总线上的设备和驱动

static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
   
   
	/* 获取对应的i2c_client */
	struct i2c_client	*client = i2c_verify_client(dev);
	struct i2c_driver	*driver;
	
	/* 使用of_match_table尽心匹配, */
	if (of_driver_match_device(dev, drv))
		return 1;
	
	/* 获取i2c驱动实例 */
	driver = to_i2c_driver(drv);
	/* 使用dts具体i2c设备节点的compatible属性后半部和i2c_driver的id_table对应字段做对比,一样就返回真。
	如rk808的compatible为"rockchip,rk808",而rk808驱动的id_table包含"rk808" */
	if (driver->id_table)
		return i2c_match_id(driver->id_table, client) != NULL;		
}

i2c_device_probe

这个回调主要在驱动和设备匹配成功后,调用驱动的probe回调执行一些初始化操作

static int i2c_device_probe(struct device *dev)
{
   
   
	struct i2c_client	*client = i2c_verify_client(dev);
	struct i2c_driver	*driver;
	int status;

	if (!client->irq) {
   
   
		int irq = -ENOENT;
		
		if (dev->of_node) {
   
   
			irq = of_irq_get_byname(dev->of_node, "irq");
		}
		/* 获取中断源 */
		client->irq = irq;
	}
	
	/* 获取client的驱动, 并执行驱动的probe回调,比如rk808的rk808_probe函数 */
	driver = to_i2c_driver(dev->driver);
	status = driver->probe(client, i2c_match_id(driver->id_table, client));	
}

2、对接adapter的接口

i2c_adapter

这个结构描述一个i2c适配器,指的就是soc上的具体i2c控制器,控制器驱动需要实现i2c读写时需要用到的核心算法回调

struct i2c_adapter {
   
   
	const struct i2c_algorithm *algo; /* the algorithm to access the bus */
	void *algo_data;
	struct device dev;		/* the adapter device */
};

i2c_client

这个结构描述具体的i2c设备,它一般会包含地址和关联的适配器指针

struct i2c_client {
   
   
	unsigned short addr;		/* chip address - NOTE: 7bit	*/
					/* addresses are stored in the	*/
					/* _LOWER_ 7 bits		*/	
	char name[I2C_NAME_SIZE];
	struct i2c_adapter *adapter;	/* the adapter we sit on	*/
	struct device dev;		/* the device structure		*/
	int irq;			/* irq issued by device		*/				
};

i2c_add_adapter

这个接口实现如何向i2c总线添加一个适配器,并根据dts向总线添加一些列的i2c设备

int i2c_add_adapter(struct i2c_adapter *adapter)
{
   
   
	if (dev->of_node) {
   
   
		/* 根据dts的alias获取后面的索引数字,可以查看rk3399.dtsi的alias定义 */
		id = of_alias_get_id(dev->of_node, "i2c");
		if (id >= 0) {
   
   
			adapter->nr = id;
			return __i2c_add_numbered_adapter(adapter);
		}
	}
}

__i2c_add_numbered_adapter

static int __i2c_add_numbered_adapter(struct i2c_adapter *adap)
{
   
   
	return i2c_register_adapter(adap);
}

i2c_register_adapter

该函数首先注册adapter设备,并根据adapter的dts节点描述遍历adapter上挂载的i2c设备,并一一添加到i2c总线

static int i2c_register_adapter(struct i2c_adapter *adap)
{
   
   
	/* 设置设备名称 */
	dev_set_name(&
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值