在第 67.1 章节学习 i2c 的时候,我们是在应用层操作设备节点对 i2c 设备进行读写的,那么如果我们在
驱动里面对 i2c 设备进行读写要怎么办呢?本章节我们将来学习。
我们复制第 67.3 章节的代码,在此基础上进行修改。我们在应用里面对 i2c 进行读写,最重要的是对
我们数据包的封包的操作,封装了一个 i2c_rdwr_ioctl_data 数据包,才对 i2c 进行读写,同样在驱动里面,
我们也可以使用这种方法。
本章内容对应视频讲解链接(在线观看):
驱动程序实现 I2C 通信 → https://www.bilibili.com/video/BV1Vy4y1B7ta?p=47
我们对某个可读可写的寄存器进行读写操作,我们打开触摸芯片 ft5x06 的数据手册,打开 2.1 章节,如
下图所示:
完整的代码如下所示:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
static struct i2c_client *ft5x06_client;
static void ft5x06_write_reg(u8 reg_addr, u8 data, u8 len);
static int ft5x06_read_reg(u8 reg_addr);
//读寄存器函数
static int ft5x06_read_reg(u8 reg_addr)
{
u8 data;
struct i2c_msg msgs[] = {
[0] = {
.addr = ft5x06_client->addr,
.flags = 0,
.len = sizeof(reg_addr),
.buf = ®_addr,
},
[1] = {
.addr = ft5x06_client->addr,
.flags = 1,
.len = sizeof(data),
.buf = &data,
},
};
i2c_transfer(ft5x06_client->adapter, msgs, 2);
return data;
}
//写寄存器函数
static void ft5x06_write_reg(u8 reg_addr, u8 data, u8 len)
{
u8 buff[256];
struct i2c_msg msgs[] = {
[0] = {
.addr = ft5x06_client->addr,
.flags = 0,
.len = len + 1,
.buf = buff,
},
};
buff[0] = reg_addr;
memcpy(&buff[1], &data, len);
i2c_transfer(ft5x06_client->adapter, msgs, 1);
}
//与设备树的 compatible 匹配
static const struct of_device_id ft5x06_id[] = {
{.compatible = "edt,edt-ft5306", 0},
{.compatible = "edt,edt-ft5x06", 0},
{.compatible = "edt,edt-ft5406", 0},
{}};
// 无设备树的时候匹配 ID 表
static const struct i2c_device_id ft5x06_id_ts[] = {
{"xxxxx", 0},
{}};
/* i2c 驱动的 remove 函数 */
int ft5x06_remove(struct i2c_client *i2c_client)
{
return 0;
}
/* i2c 驱动的 probe 函数 */
int ft5x06_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id)
{
int ret;
printk("This is ft5x06_probe\n");
//因为我们要在别的函数里面使用 client,所以我们要把他复制出来
ft5x06_client = i2c_client;
//往地址为 0x80 的寄存器里面写入数据 0x4b
ft5x06_write_reg(0x80, 0x4b, 1);
//读出 0x80 寄存器的值
ret = ft5x06_read_reg(0x80);
//打印 0x80 寄存器的值
printk("ret is %#x\n", ret);
return 0;
}
//定义一个 i2c_driver 的结构体
static struct i2c_driver ft5x06_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "ft5x06_test",
// 采用设备树的时候驱动使用的匹配表
.of_match_table = ft5x06_id,
},
.probe = ft5x06_probe,
.remove = ft5x06_remove,
.id_table = ft5x06_id_ts};
/* 驱动入口函数 */
static int ft5x06_driver_init(void)
{
int ret;
//注册 i2c_driver
ret = i2c_add_driver(&ft5x06_driver);
if (ret < 0)
{
printk(" i2c_add_driver is error \n");
return ret;
}
printk("This is ft5x06_driver_init\n");
return 0;
}
/* 驱动出口函数 */
static void ft5x06_driver_exit(void)
{
i2c_del_driver(&ft5x06_driver);
printk("This is ft5x06_driver_exit\n");
}
module_init(ft5x06_driver_init);
module_exit(ft5x06_driver_exit);
MODULE_LICENSE("GPL");
我们参考第三十九章 Linux 内核模块将刚刚编写的驱动代码编译为驱动模块,编译完如下图所示:
我们进入共享目录并且加载驱动模块,共享目录的搭建参考第三十七章 37.2.3 搭建 nfs 共享目录,
如下图所示:
如上图所示,我们可以看到读写函数是没问题的,可以对寄存器进行正常的读写操作。