RK3568平台(触摸篇)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 引脚,电平为低电平有效。

interrupt-parent = ;: 指定中断的父节点为 GPIO3。

interrupts-gpio = ;: 定义了设备的中断引脚,连 接到 GPIO3 的 RK_PA5 引脚,电平为低电平触发。

interrupts = ;: 进一步描述了中断的触发方式,为电 平低电平触发。

pinctrl-names = "default"; pinctrl-0 = ;: 指定了设备使用的默认针脚配 置。

这里指定的 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>;};};
};

二.FT5X06 驱动

#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>
#include <linux/input.h>
#include <linux/workqueue.h>// 声明工作队列要用到的函数
void ft5x06_func(struct work_struct *work);// 声明一个工作结构体
static DECLARE_WORK(ft5x06_work, ft5x06_func);// 定义 ft5x06 设备的 GPIO 描述符
// 用于保存 reset 和 interrupt 引脚的 GPIO 描述符
struct gpio_desc *reset_gpio, *irq_gpio;// 保存 ft5x06 设备的 i2c 客户端对象指针
struct i2c_client *ft5x06_client;// 保存 ft5x06 输入设备的dev指针
struct input_dev *ft5x06_input_dev;// 读取 ft5x06 设备寄存器的函数
int ft5x06_read_reg(u8 reg_addr)
{u8 data;// 定义两个 i2c_msg 结构体,分别表示写操作和读操作struct i2c_msg msgs[2] = {[0] = {.addr = ft5x06_client->addr, // 设备地址.flags = 0,        // 写操作.len = sizeof(reg_addr),.buf = &reg_addr,  // 写入要读取的寄存器地址},[1] = {.addr = ft5x06_client->addr,.flags = I2C_M_RD, // 读操作.len = sizeof(data),.buf = &data,      // 读取到的数据存储位置},};// 使用 i2c_transfer 函数进行 i2c 总线读取操作// 如果读取失败,返回 -EIO 错误码if (i2c_transfer(ft5x06_client->adapter, msgs, ARRAY_SIZE(msgs)) != ARRAY_SIZE(msgs)){return -EIO;}return data; // 返回读取到的寄存器值
}// 向 ft5x06 设备写入寄存器的函数
void ft5x06_write_reg(u8 reg_addr, u8 *data, u16 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 函数进行 i2c 总线写入操作// 如果写入失败,直接返回if (i2c_transfer(ft5x06_client->adapter, msgs, ARRAY_SIZE(msgs)) != ARRAY_SIZE(msgs)) {return;}
}// 工作函数
void ft5x06_func(struct work_struct *work)
{int TOUCH1_XH, TOUCH1_XL, x;int TOUCH1_YH, TOUCH1_YL, y;int TD_STATUS;// 从寄存器中读取触摸坐标数据TOUCH1_XH = ft5x06_read_reg(0x03);TOUCH1_XL = ft5x06_read_reg(0x04);x = ((TOUCH1_XH << 8) | TOUCH1_XL) & 0xfff;TOUCH1_YH = ft5x06_read_reg(0x05);TOUCH1_YL = ft5x06_read_reg(0x06);y = ((TOUCH1_YH << 8) | TOUCH1_YL) & 0xfff;// 读取触摸状态寄存器TD_STATUS = ft5x06_read_reg(0x02);TD_STATUS = TD_STATUS & 0xf;// 根据触摸状态更新输入设备if (TD_STATUS == 0) {// 触摸释放input_report_key(ft5x06_input_dev, BTN_TOUCH, 0);input_sync(ft5x06_input_dev);} else {// 触摸按下input_report_key(ft5x06_input_dev, BTN_TOUCH, 1);input_report_abs(ft5x06_input_dev, ABS_X, x);input_report_abs(ft5x06_input_dev, ABS_Y, y);input_sync(ft5x06_input_dev);}
}// ft5x06 中断处理函数
irqreturn_t ft5x06_handler(int irq, void *args)
{// 将 ft5x06_work 工作结构体提交到工作队列中schedule_work(&ft5x06_work);// 表示中断已经被处理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");ft5x06_client = client; // 保存 i2c 客户端对象指针// 获取 reset GPIO 描述符// gpiod_get_optional 函数尝试获取设备树中名为 "reset" 的 GPIO 描述符,// 如果获取失败则返回 NULLreset_gpio = gpiod_get_optional(&client->dev, "reset", 0);if (!reset_gpio) {printk("gpiod_get_optional reset gpio is error\n");return -1;}// 获取 irq GPIO 描述符// gpiod_get_optional 函数尝试获取设备树中名为 "interrupts" 的 GPIO 描述符,// 如果获取失败则返回 NULLirq_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 后拉高// 这是一个复位操作,用于初始化 ft5x06 设备gpiod_direction_output(reset_gpio, 0);msleep(5);gpiod_direction_output(reset_gpio, 1);// 请求中断,设置为下降沿触发,单次触发// 当 ft5x06 设备产生中断时,会调用 ft5x06_handler 函数处理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;}// 分配一个 input 设备ft5x06_input_dev = input_allocate_device();if (ft5x06_input_dev == NULL) {printk("input allocate device is error\n");return -2;}// 设置 input 设备的名称ft5x06_input_dev->name = "ft5x06_dev";// 设置 input 设备支持的事件类型和事件set_bit(EV_KEY, ft5x06_input_dev->evbit);set_bit(BTN_TOUCH, ft5x06_input_dev->keybit);set_bit(EV_ABS, ft5x06_input_dev->evbit);set_bit(ABS_X, ft5x06_input_dev->absbit);set_bit(ABS_Y, ft5x06_input_dev->absbit);// 设置 input 设备的绝对坐标范围input_set_abs_params(ft5x06_input_dev, ABS_X, 0, 800, 0, 0);input_set_abs_params(ft5x06_input_dev, ABS_Y, 0, 1280, 0, 0);// 注册 input 设备ret = input_register_device(ft5x06_input_dev);if (ret < 0) {printk("input register device is error\n");goto error_0;}return 0;error_0:input_free_device(ft5x06_input_dev);free_irq(client->irq, NULL);gpiod_put(reset_gpio);gpiod_put(irq_gpio);return ret;
}// ft5x06 设备的移除函数
// 参数 client 是 i2c 客户端对象指针
int ft5x06_remove(struct i2c_client *client)
{// 释放中断free_irq(client->irq, NULL);// 释放 GPIO 资源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 ft5x06_driver_exit(void)
{/* 释放中断 */free_irq(ft5x06_client->irq, NULL);/* 注销输入设备 */input_unregister_device(ft5x06_input_dev);/* 释放 GPIO */gpiod_put(reset_gpio);gpiod_put(irq_gpio);/* 删除 I2C 驱动 */i2c_del_driver(&ft5x06_driver);
}module_init(ft5x06_driver_init);
module_exit(ft5x06_driver_exit);
MODULE_LICENSE("GPL");

三.报点分析

点击屏幕的左上角:然后hexdump /dev/input/event4

首先对得到的数据进行分组,分组之后的数据如下所示:

c282 6666 0000 0000 36d3 000c 0000 0000 0001 014a 0001 0000
c282 6666 0000 0000 36d3 000c 0000 0000 0003 0000 0001 0000
c282 6666 0000 0000 36d3 000c 0000 0000 0003 0001 0005 0000
c282 6666 0000 0000 36d3 000c 0000 0000 0000 0000 0000 0000
c282 6666 0000 0000 ca15 000d 0000 0000 0001 014a 0000 0000
c282 6666 0000 0000 ca15 000d 0000 0000 0000 0000 0000 0000

这 6 组数据具体代表的含义如下所示:

四.触摸测试程序

#include <fcntl.h>
#include <linux/input.h>
#include <unistd.h>
#include <stdio.h>int main(int argc, char *argv[]) {int fd;struct input_event event;// 打开输入设备事件流fd = open("/dev/input/event4", O_RDONLY);if (fd < 0) {perror("open");return -1;}while (1) {// 读取一个事件if (read(fd, &event, sizeof(event)) != sizeof(event)) {perror("read");close(fd);return -1;}// 判断事件类型是否为绝对坐标事件if (event.type == EV_ABS) {// 判断事件编码是否为X轴坐标if (event.code == ABS_X) {printf("x = %d\n", event.value);}// 判断事件编码是否为Y轴坐标else if (event.code == ABS_Y) {printf("y = %d\n", event.value);}}}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/394764.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据-70 Kafka 高级特性 物理存储 日志存储 日志清理: 日志删除与日志压缩

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

K8S资源之NameSpace

作用 隔离资源(默认不隔离网络) 查看所有的NS kubectl get ns创建NS kubectl create ns hello删除NS kubectl delete ns hello

VUE基础快速入门

VUE 和 VUE-Cli VUE 是一种流行的渐进式JavaScript框架&#xff0c;用于构建Web用户界面它具有易学、轻量级、灵活性强、高效率等特点&#xff0c;并且可以与其他库和项目集成是目前最流行的前端框架之一VUE-Cli 称为“VUE脚手架”,它是由VUE官方提供的客户端&#xff0c;专门为…

简单Qt贪吃蛇项目

目录 先看效果 项目介绍 界面一&#xff1a;游戏大厅界面 界面二&#xff1a;关卡选择界面​编辑 界面三&#xff1a;游戏界面 游戏大厅页面 游戏关卡选择页面 游戏房间页面 封装贪吃蛇数据结构 初始化游戏房间界面 设置窗口大小、标题、图标等 蛇的移动 初始化贪…

RocketMQ Dashboard安装

RocketMQ Dashboard 是一个基于 Web 的管理工具&#xff0c;用于监控和管理 RocketMQ 集群。它提供了一个用户友好的界面&#xff0c;使管理员能够轻松地查看和操作 RocketMQ 系统中的各种组件和状态。 主要功能包括&#xff1a; 集群管理: 监控和管理 NameServer 和 Broker …

大数据-65 Kafka 高级特性 分区 Broker自动再平衡 ISR 副本 宕机恢复再重平衡 实测

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

【vulnhub】W34kn3ss 1靶机

安装靶机 下载地址&#xff1a;https://www.vulnhub.com/entry/w34kn3ss-1,270/# 信息收集 靶机扫描 nmap 192.168.93.0/24 打开端口为22、80、443 网址访问 目录扫描 dirsearch -u http://192.168.93.162 在网址后面拼接扫到的目录&#xff0c;在/test目录下发现信息 提…

微型导轨:光学仪器精准定位的支撑者

微型导轨是指宽度在25mm以下的导轨系统&#xff0c;通常由导轨和滑块组成&#xff0c;具有体积小、重量轻、精度高、噪音低、寿命长等特点。主要用于支撑和定位光学元件&#xff0c;如镜子、透镜、滤光片等。微型导轨通过提供高精度的运动控制&#xff0c;‌有利于提高设备的性…

【Tessent IJATG Users Manual】【Ch5】IJTAG Network Insertion

The IJTAG Network Insertion FlowIJTAG Network Insertion ExampleModification of the IJTAG Network Insertion Flow How to Edit or Modify a DftSpecificationEdit or Modify MethodDftSpecification Examples IJTAG Network Insertion 可以将已有的 instrument 连接起来&…

Docker学习(6):Docker Compose部署案例

一、docker-compose部署mysql 1、准备镜像 2、编写my.cnf配置文件 # 服务端参数配置 [mysqld] usermysql # MySQL启动用户 default-storage-engineINNODB # 创建新表时将使用的默认存储引擎 character-set-serverutf8mb4 # 设置mysql服务端默认字符集…

离线+树状数组,ABC253 F - Operations on a Matrix

一、题目 1、题目描述 2、输入输出 2.1输入 2.2输出 3、原题链接 F - Operations on a Matrix 二、解题报告 1、思路分析 我们通过差分树状数组&#xff0c;可以轻松解决操作1 操作3我们也可以通过树状数组来获取对应列的值 关键是操作2会对操作3造成影响 所以我们先对…

【Linux】yum软件包管理器(使用、生态、yum源切换)

目录 1.yum-软件包管理器&#x1f638;1.1yum使用方法1.2什么是yum&#xff1f;&#x1f638;1.3yum的周边生态1.4yum源切换1.4.1 查看系统本身yum源1.4.2 软件源1.4.3yum源配置 1.yum-软件包管理器 以下操作需要联网的情况下进行 &#x1f638;1.1yum使用方法 安装软件时由于需…

【学习笔记】Day 7

一、进度概述 1、DL-FWI基础入门培训笔记 2、inversionnet_train 试运行——未成功 二、详情 1、InversionNet: 深度学习实现的反演 InversionNet构建了一个具有编码器-解码器结构的卷积神经网络&#xff0c;以模拟地震数据与地下速度结构的对应关系。 &#xff08;一…

03 库的操作

目录 创建查看修改删除备份和恢复查看连接情况 1. 创建 语法 CRATE DATABASE [IF NOT EXISTS] db_name [create_specification [, create_specification] …] create_specification:  CHARACTER SET charset_name  CPLLATE collation_name 说明&#xff1a; 大写的标识关键…

基于YOLOv8的小麦种子品质检测系统

基于YOLOv8的小麦种子品质检测系统 (价格85) 包含 [bad seed, healthy seed, impurity] 3个类 通过PYQT构建UI界面&#xff0c;包含图片检测&#xff0c;视频检测&#xff0c;摄像头实时检测。 &#xff08;该系统可以根据数据训练出的yolov8的权重文件&#xff0c;运用在…

【多线程-从零开始-捌】代码案例2—阻塞队列

什么是阻塞队列 阻塞队里是在普通的队列&#xff08;先进先出队列&#xff09;基础上&#xff0c;做出了扩充 线程安全 标准库中原有的队列 Queue 和其子类&#xff0c;默认都是线程不安全的 具有阻塞特性 如果队列为空&#xff0c;进行出队列操作&#xff0c;此时就会出现阻…

vue2知识点4(组件 全局组件 局部组件 父子组件的生命周期钩子函数 父子组件之间的数据传递 局部路由)

目录 一、组件 1. 介绍 2. 全局组件 使用全局组件 实例和组件之间的数据不互通 组件复用 data函数式和data对象的区别: 注意 3. 局部组件 全局组件和局部组件的区别: 注册多个子组件&#xff08;局部组件&#xff09; 4. 父子组件的生命周期钩子函数 加载渲染过程…

RIP路由协议之网络工程师软考中级

几种常见的路由协议 路由协议名称路由协议分类&#xff08;工作原理&#xff09;协议分类&#xff08;工作区域&#xff09;路由算法RIP距离矢量IGPBellman-FordOSPF-ISIS链路状态IGPDijkstraBGP路径向量EGP/ IGP称为内部网关协议&#xff08;I人&#xff0c;内向&#xff09…

python判断和循环语句

python判断语句 1、单个条件判断 if 条件:满足条件要做的事情1满足条件要做的事情2 else:不满足条件要做的事情3不满足条件要做的事情2 2、多个条件判断&#xff08;满足条件1就不会判断条件2&#xff09; else可以省略不写 if 条件1:满足条件1要做的事情a满足条件1要做的事…