没志青年
发布于 2025-06-14 / 11 阅读
0

14 Linux 总线驱动 - I2C & SPI

I2C 和 SPI 很相似,放在一起讲。

I2C 和 SPI 都是 SOC 上的外设,厂商已经实现好了主机控制器驱动,所以无论换什么芯片,驱动的写法都是一样的。

总线架构

I2C 功能架构:

SPI 功能架构:

原来的名称匹配、ID 匹配被淘汰了(需要手动创建 struct i2c_client 结构体对象),现在都用设备树匹配了,

内核启动时解析设备树,会自动将I2C设备节点转换为一个 struct i2c_client 结构对象,当有匹配的驱动注册时,会调用其 probe 函数。

设备树语法

I2C:

&i2c2 {
	clock_frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c2>;
	status = "okay";

	gt9147: gt9147@14 {
        compatible = "goodix,gt9147", "goodix,gt9xx";
        reg = <0x14>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_ts_int
                     &pinctrl_ts_reset>;
        interrupt-parent = <&gpio1>;
        interrupts = <9 0>;
        reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; 
        interrupt-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
        status="okay";
    };

};

设备节点写在 i2c 节点下,关键是设置设备的通信地址 reg = <0x14>,这个地址是 7 位地址,不包括读写位。

SPI:

使用方法

有两种使用方式:

  1. 应用层直接使用主机控制器驱动,即使用 /dev/i2c-N/dev/spidev总线号.片选编号 设备文件,这种情况适合外设比较简单的。

  2. 如果外设比较复杂,还是需要写个专门的驱动给应用层屏蔽一下复杂的操作,。

第一种方式:

这个的前提是配置中开启了:

ioctl(fd, I2C_SLAVE, long addr)
ioctl(fd, I2C_FUNCS, unsigned long * funcs)
ioctl(fd, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)

ioctl:

第二种方式:

i2c_add_driver
i2c_set_clientdata

设备相关函数:

1、注册和删除 I2C 设备驱动

i2c_add_driver
i2c_del_driver

示例:

static struct i2c_driver gt9147_driver = {
    .driver = {
        .name   = "gt9147",
        .owner  = THIS_MODULE,
        .of_match_table = of_match_ptr(gt9147_of_match),
    },
    .probe      = gt9147_probe,
    .remove     = gt9147_remove,
};

static int __init gt9147_init(void)
{
    return i2c_add_driver(&gt9147_driver);
}

static void __exit gt9147_exit(void)
{
    i2c_del_driver(&gt9147_driver);
}

module_init(gt9147_init);
module_exit(gt9147_exit);

static int __init gt9147_init(void)module_exit(gt9147_exit); 这一段代码都是固定的,有专门简化的宏:

module_i2c_driver(gt9147_driver);

2、设置/获取客户端数据

3、检查

(2)数据收发函数:

s32 i2c_smbus_write_byte_data(const struct i2c_client *client, 
                              u8 command, u8 value);

s32 i2c_smbus_read_byte_data(const struct i2c_client *client, 
                             u8 command);

s32 i2c_smbus_write_word_data(const struct i2c_client *client, 
                              u8 command, u16 value);

s32 i2c_smbus_read_word_data(const struct i2c_client *client, 
                             u8 command);

s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client, 
                                  u8 command, u8 length, u8 *values);

s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, 
                                   u8 command, u8 length, const u8 *values);

原始函数:

int i2c_master_send(const struct i2c_client *client, const char *buf, int count);

int i2c_master_recv(const struct i2c_client *client, char *buf, int count);