瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。
【公众号】迅为电子
【粉丝群】258811263(加群获取驱动文档+例程)
【视频观看】嵌入式学习之Linux驱动(第十五篇 I2C_全新升级)_基于RK3568
【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板
第173章 完善FT5X06设备节点和驱动
在上一章中我们编写了I2C 的Platform device代码,这种方式后面已经被设备树所取代,这里讲解只是为了更好的理解I2C子系统框架,而从本章节开始将会回到FT5X06设备树和I2C驱动程序的完善,在本章将先对FT5X06输入子系统相关的部分进行完善。
173.1 完善FT5X06设备节点
本实验修改完成的设备树对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动程序\104_ft5x06_03\01_修改完成的设备树。
在第170章中已经编写了FT5X06设备树框架,具体如下所示:
&i2c1 {
status = "okay";
myft5x06: my-ft5x06@38 {
compatible = "my-ft5x06";
reg = <0x38>;
};
};
而FT5X06触摸芯片除了I2C部分,还有另外两个GPIO分别为中断引脚和复位引脚,每个引脚对应的功能匹配表格如下所示:
在开发板上电的时候,FT5X06芯片复位之后才能正常使用,而当屏幕按下之后,需要产生一个中断信号,在驱动中通过中断服务函数来读取触摸芯片的寄存器,从而上报一系列的数据,填充完成的设备树内容如下所示:
&i2c1 {
status = "okay";
myft5x06: my-ft5x06@38 {
compatible = "my-ft5x06";
reg = <0x38>;
reset-gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_LOW>;
interrupt-parent = <&gpio3>;
interrupts-gpio = <&gpio3 RK_PA5 GPIO_ACTIVE_LOW>;
interrupts = <RK_PA5 IRQ_TYPE_LEVEL_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&myft5x06_pins>;
};
};
reset-gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_LOW>;: 定义了设备的复位引脚,连接到 GPIO0 的 RK_PB6 引脚,电平为低电平有效。
interrupt-parent = <&gpio3>;: 指定中断的父节点为 GPIO3。
interrupts-gpio = <&gpio3 RK_PA5 GPIO_ACTIVE_LOW>;: 定义了设备的中断引脚,连接到 GPIO3 的 RK_PA5 引脚,电平为低电平触发。
interrupts = <RK_PA5 IRQ_TYPE_LEVEL_LOW>;: 进一步描述了中断的触发方式,为电平低电平触发。
pinctrl-names = "default"; pinctrl-0 = <&myft5x06_pins>;: 指定了设备使用的默认针脚配置。
这里指定的pinctrl节点名为myft5x06_pins,所以还需要对pinctrl节点进行追加,追加内容如下所示:
&pinctrl {
myft5x06 {
myft5x06_pins: myft5x06-pins {
rockchip,pins =
<0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>,
<0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};
保存退出之后,重新编译内核源码,得到boot.img镜像,然后烧写到开发板。
173.2 完善FT5X06驱动
本实验修改完成的驱动对应的网盘路径为:iTOP-RK3568开发板【底板V1.7版本】\03_【iTOP-RK3568开发板】指南教程\02_Linux驱动配套资料\04_Linux驱动程序\104_ft5x06_03\03_module。
在171章已经编写了最简单的I2C驱动框架程序,而在上个小节填充了设备树的中断和复位引脚之后,同样需要完善FT5X06驱动对应的部分,申请两个GPIO,要求在加载驱动之后reset引脚进行复位,编写中断引脚的中断服务函数,当按下MIPI屏幕之后就会产生中断,并在中断服务函数中添加打印信息。
编写完成的驱动程序如下所示:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
// 定义 ft5x06 设备的 GPIO 描述符
struct gpio_desc *reset_gpio, *irq_gpio;
// ft5x06 中断处理函数
irqreturn_t ft5x06_handler(int irq, void *args)
{
printk("This is ft5x06 handler\n");
// 返回中断已处理标志
return IRQ_RETVAL(IRQ_HANDLED);
}
// ft5x06 设备的探测函数
int ft5x06_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int ret;
printk("This is ft5x06 probe\n");
// 获取 reset GPIO 描述符
reset_gpio = gpiod_get_optional(&client->dev, "reset", 0);
if (!reset_gpio) {
printk("gpiod_get_optional reset gpio is error\n");
return -1;
}
// 获取 irq GPIO 描述符
irq_gpio = gpiod_get_optional(&client->dev, "interrupts", 0);
if (!irq_gpio) {
printk("gpiod_get_optional irq gpio is error\n");
return -1;
}
// 设置 reset GPIO 为输出,并拉低 5ms 后拉高
gpiod_direction_output(reset_gpio, 0);
msleep(5);
gpiod_direction_output(reset_gpio, 1);
// 请求中断,设置为下降沿触发,单次触发
ret = request_irq(client->irq, ft5x06_handler,
IRQ_TYPE_EDGE_FALLING | IRQF_ONESHOT, "ft5x06 irq", NULL);
if (ret < 0) {
printk("request irq is error\n");
return -2;
}
return 0;
}
// ft5x06 设备的移除函数
int ft5x06_remove(struct i2c_client *client)
{
free_irq(client->irq, NULL);
gpiod_put(reset_gpio);
gpiod_put(irq_gpio);
return 0;
}
// 定义 i2c_device_id 结构体数组,用于标识 ft5x06 设备
static const struct i2c_device_id ft5x06_id[] = {
{ "my-ft5x06", 0 },
{ }
};
// 定义 i2c_driver 结构体,描述 ft5x06 设备驱动
static struct i2c_driver ft5x06_driver = {
.driver = {
.name = "my-ft5x06",
.owner = THIS_MODULE,
},
.probe = ft5x06_probe,
.remove = ft5x06_remove,
.id_table = ft5x06_id,
};
// 驱动初始化函数
static int __init ft5x06_driver_init(void)
{
int ret;
// 注册 I2C 设备驱动
ret = i2c_add_driver(&ft5x06_driver);
if (ret < 0) {
printk("i2c_add_driver is error\n");
return ret;
}
return 0;
}
// 驱动退出函数
static void __exit ft5x06_driver_exit(void)
{
// 注销 I2C 设备驱动
i2c_del_driver(&ft5x06_driver);
}
module_init(ft5x06_driver_init);
module_exit(ft5x06_driver_exit);
MODULE_LICENSE("GPL");
173.3 运行测试
173.3.1 编译驱动程序
首先在上一小节中的ft5x06_driver.c代码同一目录下创建 Makefile 文件,Makefile 文件内容如下所示:
export ARCH=arm64#设置平台架构
export CROSS_COMPILE=aarch64-linux-gnu-#交叉编译器前缀
obj-m += ft5x06_driver.o #此处要和你的驱动源文件同名
KDIR :=/home/topeet/Linux/linux_sdk/kernel #这里是你的内核目录
PWD ?= $(shell pwd)
all:
make -C $(KDIR) M=$(PWD) modules #make操作
clean:
make -C $(KDIR) M=$(PWD) clean #make clean操作
对于Makefile的内容注释已在上图添加,保存退出之后,来到存放platform_driver.c和Makefile文件目录下,如下图所示:
然后使用命令“make”进行驱动的编译,编译完成如下图所示:
编译完生成ft5x06_driver.ko目标文件,如下图所示:
173.3.2 运行测试
在进行实验之前,首先要确保开发板烧写的是我们在173.1小节中编译出来的boot.img。开发板启动之后进入系统之后如下图所示:
然后将上一个小节编译完成的ko文件拷贝到开发板上,拷贝完成如下图所示:
然后使用以下命令加载驱动,加载完成如下图所示:
insmod ft5x06_driver.ko
然后点击MIPI屏幕,可以看到中断服务函数中的打印信息“This is ft5x06 handler”具体如下所示:
然后使用以下命令进行驱动模块的卸载,如下图所示:
rmmod ft5x06_driver.ko
由于没有在remove卸载函数中添加打印相关内容,所以使用rmmod命令卸载驱动之后,没有任何打印,至此,初步完善 I2C驱动实验就完成了。