<驱动开发>
一、i2c子系统框架
1.1 工作原理

1.2 分配i2c_driver对象
#include <linux/i2c.h>
struct i2c_driver {
int (*probe)(struct i2c_client *client, const struct i2c_device_id *id); //匹配成功执行probe函数
int (*remove)(struct i2c_client *client);//分离时执行remove函数
struct device_driver driver; //父类
const struct i2c_device_id *id_table; //idtable匹配
};
struct device_driver {
const char *name; //名字
const struct of_device_id *of_match_table; //设备树匹配
};
1.3 注册
i2c_add_driver(struct i2c_driver *driver);
1.4 注销
void i2c_del_driver(struct i2c_driver *driver);
1.5 一键注册宏
module_i2c_driver(i2c_driver结构体变量名字)
1.5 代码实例
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
int si7006_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
//设备驱动层和总线驱动层匹配成功执行函数
printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
return 0;
}
int si7006_remove(struct i2c_client *client)
{
//设备驱动层和总线驱动层分离执行函数
printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
return 0;
}
const struct of_device_id ofmatch[] = {
{.compatible = "hqyj,si7006"},
{},
};
//分配i2c_driver对象
struct i2c_driver si7006 = {
.probe = si7006_probe,
.remove = si7006_remove,
.driver = {
.name = "hahaha",
.of_match_table = ofmatch,
},
};
//一键注册i2c子系统宏
module_i2c_driver(si7006);
MODULE_LICENSE("GPL");
二、i2c子系统设备树编写
2.1 硬件电路图连接

2.2 分析内核设备树
linux@ubuntu:~/linux-5.10.61/arch/arm/boot/dts$ vi stm32mp151.dtsi
i2c1: i2c@40012000 { =========> 节点取别名 i2c1 = i2c@40012000
compatible = "st,stm32mp15-i2c"; =========> 厂商固定含义键
reg = <0x40012000 0x400>; =========> 寄存器地址,以及地址长度固定固定含义键
#address-cells = <1>;
#size-cells = <0>;
status = "disabled"; =========> 工作状态没有使能
};
2.3 分析内核帮助文档
1、参考帮助文档得到如下信息
linux@ubuntu:~/linux-5.10.61/Documentation/devicetree/bindings/i2c$ vi i2c-s3c2410.txt
si7006@40 {
compatible = "hqyj,si7006"; =========> 和设备驱动层匹配固定含义键
reg = <0x40>; =========> 从机地址
};
2、在内核中,查看在其他文件中如何引用i2c1节点
linux@ubuntu:~/linux-5.10.61$ grep "&i2c1" * -nR
linux@ubuntu:~/linux-5.10.61$ vi arch/arm/boot/dts/stm32mp15xx-dkx.dtsi +206
&i2c1 {
pinctrl-names = "default", "sleep"; =========> 设置引脚复用功能模式
pinctrl-0 = <&i2c1_pins_a>; =========> ?????????查看i2c1_pins_a这个节点作用?????????
pinctrl-1 = <&i2c1_sleep_pins_a>; =========> 休眠状态
//设置i2c控制器上升沿和下降沿时间
i2c-scl-rising-time-ns = <100>; // 上升沿时间
i2c-scl-falling-time-ns = <7>; // 下降沿时间
status = "okay"; //工作状态okay
//删除键值对信息
/delete-property/dmas;
/delete-property/dma-names;
};
3、 在内核中,查看在其他文件中引用i2c1_pins_a节点作用?
查找结果:arch/arm/boot/dts/stm32mp15-pinctrl.dtsi:436: i2c1_pins_a: i2c1-0 {
436 i2c1_pins_a: i2c1-0 {
437 pins {
438 pinmux = <STM32_PINMUX('D', 12, AF5)>, /* I2C1_SCL */
439 <STM32_PINMUX('F', 15, AF5)>; /* I2C1_SDA */
440 bias-disable;
441 drive-open-drain;
442 slew-rate = <0>;
443 };
444 };
========================================================================================================
453 i2c1_pins_b: i2c1-1 {
454 pins {
455 pinmux = <STM32_PINMUX('F', 14, AF5)>, /* I2C1_SCL */
456 <STM32_PINMUX('F', 15, AF5)>; /* I2C1_SDA */
457 bias-disable;
458 drive-open-drain;
459 slew-rate = <0>;
460 };
461 };
1.4 编写i2c设备树
1.添加设备树目录:linux@ubuntu:~/linux-5.10.61/arch/arm/boot/dts$ vi stm32mp157a-fsmp1a.dts
&i2c1 {
pinctrl-names = "default", "sleep";
pinctrl-0 = <&i2c1_pins_b>;
pinctrl-1 = <&i2c1_sleep_pins_b>;
//设置i2c控制器上升沿和下降沿时间
i2c-scl-rising-time-ns = <100>; // 上升沿时间
i2c-scl-falling-time-ns = <7>; // 下降沿时间
status = "okay"; //工作状态okay
//删除键值对信息
/delete-property/dmas;
/delete-property/dma-names;
si7006@40 {
compatible = "hqyj,si7006";
reg = <0x40>;
};
};
2、编译拷贝
linux@ubuntu:~/linux-5.10.61$ make dtbs
DTC arch/arm/boot/dts/stm32mp157a-fsmp1a.dtb
linux@ubuntu:~/linux-5.10.61$ cp arch/arm/boot/dts/stm32mp157a-fsmp1a.dtb ~/tftpboot/