Linux下I2C驱动框架: I2C驱动框架与I2C总线驱动(即I2C控制器)

发布于:2024-04-05 ⋅ 阅读:(79) ⋅ 点赞:(0)

一.  简介

现在,我们来学习一下如何在 Linux 下开发 I2C 接口器件 驱动,重点是学习 Linux 下的 I2C 驱动框架,按照指定的框架去编写 I2C 设备驱动。
本文来了解以下 Linux下 I2C 驱动框架,框架下的  i2C总线驱动(也就是I2C控制器驱动)。

二.  Linux下I2C驱动实验: I2C驱动框架与I2C总线驱动

1.  Linux I2C 驱动框架简介

回想一下我们在裸机篇中是怎么编写 AP3216C 驱动的,我们编写了四个文件: bsp_i2c.c
bsp_i2c.h bsp_ap3216c.c bsp_ap3216c.h 。其中前两个是 I.MX6U IIC 接口驱动,后两个文 件是 AP3216C 这个 I2C 设备驱动文件。相当于有两部分驱动:
(1)  I2C 主机驱动。
(2)  I2C 设备驱动。
对于 I2C 主机驱动,一旦编写完成就不需要再做修改,其他的 I2C 设备直接调用主机驱动提供的 API 函数完成读写操作即可。这个正好符合 Linux 的驱动分离与分层的思想,因此, Linux 内核也将 I2C 驱动分为两部分:
(1)  I2C 总线驱动, I2C 总线驱动就是 SOC I2C 控制器驱动,也叫做 I2C 适配器驱动。
(2)  I2C 设备驱动, I2C 设备驱动就是针对具体的 I2C 设备而编写的驱动。

2. I2C 总线驱动(I2C控制器驱动)

首先来看一下 I2C 总线,在讲 platform 的时候就说过, platform 是虚拟出来的一条总线,目的是为了实现总线、设备、驱动框架。
对于 I2C 而言,不需要虚拟出一条总线,直接使用 I2C 总线即可。 I2C 总线驱动重点是 I2C 适配器 ( 也就是 SOC I2C 接口控制器 ) 驱动。

(1)  I2C总线驱动的结构体

这里要用到两个重要的数据结构:i2c_adapter i2c_algorithmLinux 内核将 SOC I2C 适配器 ( 控制器 ) 抽象成 i2c_adapter i2c_adapter 结构体定义在 include/linux/i2c.h 文件中,结构体内容如下:
struct i2c_adapter {
	struct module *owner;
	unsigned int class;		  /* classes to allow probing for */
	const struct i2c_algorithm *algo; /* the algorithm to access the bus */
	void *algo_data;

	/* data fields that are valid for all devices	*/
	struct rt_mutex bus_lock;

	int timeout;			/* in jiffies */
	int retries;
	struct device dev;		/* the adapter device */

	int nr;
	char name[48];
	struct completion dev_released;

	struct mutex userspace_clients_lock;
	struct list_head userspace_clients;

	struct i2c_bus_recovery_info *bus_recovery_info;
	const struct i2c_adapter_quirks *quirks;
};

4 行, i2c_algorithm 类型的指针变量 algo ,对于一个 I2C 适配器,肯定要对外提供读 API 函数,设备驱动程序可以使用这些 API 函数来完成读写操作。 i2c_algorithm 就是 I2C 配器与 IIC 设备进行通信的方法。
i2c_algorithm 结构体定义在 include/linux/i2c.h 文件中,内容如下 ( 删除条件编译 )
 struct i2c_algorithm {
......
    int (*master_xfer)(struct i2c_adapter *adap,
    struct i2c_msg *msgs,
    int num);
    int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
    unsigned short flags, char read_write,
    u8 command, int size, union i2c_smbus_data *data);

 /* To determine what the adapter supports */
   u32 (*functionality) (struct i2c_adapter *);
......
};

3 行, master_xfer 就是 I2C 适配器的传输函数,可以通过此函数来完成与 IIC 设备之间的通信。
6 行, smbus_xfer 就是 SMBUS 总线的传输函数。
综上所述,I2C 总线驱动,或者说 I2C 适配器驱动的主要工作就是初始化 i2c_adapter 结构体变量,然后设置 i2c_algorithm 中的 master_xfer 函数。

(2)  I2C 总线驱动注册与注销

完成以后通过 i2c_add_numbered_adapter函数 或 i2c_add_adapter函, 这两个函数向系统注册设置好的 i2c_adapter ,这两个函数的原型如下:
int i2c_add_adapter(struct i2c_adapter *adapter)
int i2c_add_numbered_adapter(struct i2c_adapter *adap)

这两个函数的区别在于, i2c_add_adapter 函数使用动态的总线号,而 i2c_add_numbered_adapter 函数使用静态总线号。函数参数和返回值含义如下:

adapter adap :要添加到 Linux 内核中的 i2c_adapter ,也就是 I2C 适配器。
返回值: 0 ,成功;负值,失败。

如果要删除 I2C 适配器的话使用 i2c_del_adapter 函数即可,函数原型如下:
void i2c_del_adapter(struct i2c_adapter * adap)
函数参数和返回值含义如下:
adap :要删除的 I2C 适配器。
返回值: 无。

三.  总结

关于 I2C 的总线 ( 控制器或适配器 ) 驱动就讲解到这里,一般 SOC I2C 总线驱动都是由半导体厂商编写的,比如, I.MX6U I2C 适配器驱动 NXP 已经编写好了,这个不需要用户去编 写。
因此, I2C 总线驱动对我们这些 SOC 使用者来说是被屏蔽掉的,我们只要专注于 I2C 设备驱 动即可。除非你是在半导体公司上班,工作内容就是写 I2C 适配器驱动。


今日签到

点亮在社区的每一天
去签到