RK3566(泰山派):3.1寸屏幕D310T9362V1SPEC触摸驱动(竖屏)

RK3566(泰山派):3.1寸屏幕D310T9362V1SPEC触摸驱动(竖屏)


文章目录

  • RK3566(泰山派):3.1寸屏幕D310T9362V1SPEC触摸驱动(竖屏)
  • 电路
  • 配置i2c1设备树
  • 创建驱动
  • 编写Makefile
  • my_touch.c驱动
    • I2C驱动框架
  • 驱动中的结构体
    • probe
      • 竖屏probe函数
      • 横屏probe函数
    • 中断
    • 中断线程服务函数
      • 竖屏中断线程服务函数
      • 横屏中断线程服务函数
    • TD_STATUS
    • TOUCHn_X寄存器
    • TOUCHn_Y寄存器
    • 上报数据
  • 触摸驱动完整代码
  • 编译生效
  • 效果


电路

在这里插入图片描述

配置i2c1设备树

从原理图中可知GP7101和触摸共同挂在道I2C下,所以引用&i2c1并添加一个我们自己定义的myts@38触摸节点。

&i2c1 {status = "okay";             // 表示这个i2c1设备是可用的clock-frequency = <400000>;  // 设置i2c1的时钟频率为400kHzmyts@38 {                    // 定义一个i2c设备,设备地址为0x38,设备名称为mytscompatible = "my,touch"; // 表示这个设备是触摸屏设备,驱动名称为my,touchreg = <0x38>;            // i2c设备地址tp-size = <89>;          // 触摸屏的大小max-x = <480>;           // 触摸屏支持的最大X坐标值max-y = <800>;           // 触摸屏支持的最大Y坐标值touch-gpio = <&gpio1 RK_PA0 IRQ_TYPE_LEVEL_LOW>; // 触摸屏的触摸中断引脚,连接到gpio1的第0个引脚,触发方式为低电平触发reset-gpio = <&gpio1 RK_PA1 GPIO_ACTIVE_HIGH>;   // 触摸屏的复位引脚,连接到gpio1的第1个引脚,有效电平为高电平};/****省略****/
};

在这里插入图片描述

创建驱动

一般触摸都放在
/kernel/drivers/input/touchscreen目录下,所以我们在此路径下创建一个my_touch目录用来存放Makefile和my_touch.c文件。

/home/paranoid/tspi/android/kernel/drivers/input/touchscreen
cd kernel/drivers/input/touchscreen
mkdir my_touch
cd my_touch/
touch Makefile
touch my_touch.c

在这里插入图片描述

编写Makefile

touchscreen/Makefile中把my_touch.c编译到内核中,当然也可以选择obj-m编译成模块。

obj-y   += my_touch.o

在这里插入图片描述

要想
my_touch下的Makefile生效还需要在上一层目录的Makefile中添加my_touch目录,所以我们需要在touchscreen目录下Makefile中加入:注释掉官方SDK的触摸驱动

在这里插入图片描述
添加自己写的驱动
在这里插入图片描述

my_touch.c驱动

I2C驱动框架

一个框架结构。

static int my_touch_ts_probe(struct i2c_client *client,const struct i2c_device_id *id)
{return 0;
}static int my_touch_ts_remove(struct i2c_client *client)
{MY_DEBUG("locat");return 0;
}static const struct of_device_id my_touch_of_match[] = {{ .compatible = "my,touch", },{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, my_touch_of_match);static struct i2c_driver my_touch_ts_driver = {.probe      = my_touch_ts_probe,.remove     = my_touch_ts_remove,.driver = {.name     = "my-touch",.of_match_table = of_match_ptr(my_touch_of_match),},
};static int __init my_ts_init(void)
{MY_DEBUG("locat");return i2c_add_driver(&my_touch_ts_driver);
}static void __exit my_ts_exit(void)
{MY_DEBUG("locat");i2c_del_driver(&my_touch_ts_driver);
}module_init(my_ts_init);
module_exit(my_ts_exit);MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("My touch driver");
MODULE_AUTHOR("KuLiT");

驱动中的结构体

因为驱动过程中会有很多参数,我们不可能创建全局变量去保存他们,在linux驱动中一般都是通过创建一个结构体来保存驱动相关的参数,所以这里创建一个my_touch_dev结构体。

// 定义一个表示触摸设备的结构体
struct my_touch_dev {struct i2c_client *client; // 指向与触摸设备通信的 I2C 客户端结构体的指针struct input_dev *input_dev; // 指向与输入设备关联的 input_dev 结构体的指针,用于处理输入事件int rst_pin; // 触摸设备的复位引脚编号int irq_pin; // 触摸设备的中断引脚编号u32 abs_x_max; // 触摸设备在 X 轴上的最大绝对值u32 abs_y_max; // 触摸设备在 Y 轴上的最大绝对值int irq; // 触摸设备的中断号
};

probe

当驱动中of_match_table = of_match_ptr(my_touch_of_match)和设备树匹配成功以后会执行探针函数,探针函数中我们会去初始化驱动。

竖屏probe函数

static int my_touch_ts_probe(struct i2c_client *client,const struct i2c_device_id *id)
{int ret; // 定义一个返回值变量struct my_touch_dev *ts; // 定义一个结构体指针,用来指向my_touch_dev结构体struct device_node *np = client->dev.of_node; // 获取设备节点// 打印调试信息MY_DEBUG("locat"); // 调用MY_DEBUG函数打印调试信息,此处打印"locat"ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); // 使用devm_kzalloc分配内存,减少内存申请操作if (ts == NULL){ // 检查内存分配是否成功dev_err(&client->dev, "Alloc GFP_KERNEL memory failed."); // 内存分配失败,打印错误信息return -ENOMEM; // 返回内存申请错误的码}ts->client = client; // 触摸屏设备的客户端指针指向i2c_client结构体i2c_set_clientdata(client, ts); // 将my_touch_dev结构体的指针设置为i2c客户端的数据// 从设备树中读取触摸屏的最大X和Y值if (of_property_read_u32(np, "max-x", &ts->abs_x_max)) {dev_err(&client->dev, "no max-x defined\n"); // 如果读取最大X值失败,打印错误信息return -EINVAL; // 返回参数无效的错误码}MY_DEBUG("abs_x_max:%d",ts->abs_x_max); // 打印X值if (of_property_read_u32(np, "max-y", &ts->abs_y_max)) {dev_err(&client->dev, "no max-y defined\n"); // 如果读取最大Y值失败,打印错误信息return -EINVAL; // 返回参数无效的错误码}MY_DEBUG("abs_x_max:%d",ts->abs_y_max); // 打印Y值// 获取并请求复位GPIO管脚ts->rst_pin = of_get_named_gpio(np, "reset-gpio", 0); // 从设备树中获取复位管脚ret = devm_gpio_request(&client->dev,ts->rst_pin,"my touch touch gpio"); // 请求使用复位管脚if (ret < 0){ // 如果请求失败dev_err(&client->dev, "gpio request failed."); // 打印错误信息return -ENOMEM;                                 // 返回内存申请错误的码}ts->irq_pin = of_get_named_gpio(np, "touch-gpio", 0); // 从设备树中获取中断管脚ret = devm_gpio_request_one(&client->dev, ts->irq_pin, // 请求使用中断管脚GPIOF_IN, "my touch touch gpio");if (ret < 0)return ret; // 如果请求失败,直接返回错误码// 复位触摸屏设备gpio_direction_output(ts->rst_pin,0); // 设置复位管脚输出低电平msleep(20); // 等待20毫秒gpio_direction_output(ts->irq_pin,0); // 设置中断管脚输出低电平msleep(2); // 等待2毫秒gpio_direction_output(ts->rst_pin,1); // 设置复位管脚输出高电平msleep(6); // 等待6毫秒gpio_direction_output(ts->irq_pin, 0); // 设置中断管脚输出低电平msleep(50); // 等待50毫秒// 申请中断服务ts->irq = gpio_to_irq(ts->irq_pin); // 将GPIO管脚转换为中断号if(ts->irq){ // 检查中断号是否有效ret = devm_request_threaded_irq(&(client->dev), ts->irq, // 请求线程化中断NULL, my_touch_irq_handler,                      // 中断服务函数IRQF_TRIGGER_FALLING | IRQF_ONESHOT,             // 中断触发方式为下降沿触发,且只触发一次client->name, ts);if (ret != 0) {MY_DEBUG("Cannot allocate ts INT!ERRNO:%d\n", ret); // 如果中断请求失败,打印错误信息return ret; // 返回错误码}}// 使用devm_input_allocate_device分配输入设备对象ts->input_dev = devm_input_allocate_device(&client->dev); if (!ts->input_dev) { // 检查输入设备对象是否分配成功dev_err(&client->dev, "Failed to allocate input device.\n"); // 打印错误信息return -ENOMEM; // 返回内存申请错误的码}// 设置输入设备的名称ts->input_dev->name = "my touch screen"; // 设置输入设备的总线类型为I2Cts->input_dev->id.bustype = BUS_I2C; // 设置X轴的最大值为480input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, 480, 0, 0); // 设置Y轴的最大值为800input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, 800, 0, 0); // 初始化5个多点触摸槽位,直接模式ret = input_mt_init_slots(ts->input_dev, 5, INPUT_MT_DIRECT); if (ret) {dev_err(&client->dev, "Input mt init error\n"); // 打印错误信息return ret; // 返回错误码}// 注册输入设备ret = input_register_device(ts->input_dev); // 注册输入设备if (ret)return ret; // 返回错误码// 读取版本号gt9271_read_version(client); return 0; // 如果一切顺利,返回0
}

横屏probe函数

static int my_touch_ts_probe(struct i2c_client *client,const struct i2c_device_id *id)
{int ret;struct my_touch_dev *ts;struct device_node *np = client->dev.of_node;u8 addr[1] = {0x00};u8 point_data[1]={00};//1个状态位置+5个触摸点,一个点是6个数据组成// 打印调试信息MY_DEBUG("locat");// ts = kzalloc(sizeof(*ts), GFP_KERNEL);ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);if (ts == NULL){dev_err(&client->dev, "Alloc GFP_KERNEL memory failed.");return -ENOMEM;}ts->client = client;i2c_set_clientdata(client, ts);if (of_property_read_u32(np, "max-x", &ts->abs_x_max)) {dev_err(&client->dev, "no max-x defined\n");return -EINVAL;}MY_DEBUG("abs_x_max:%d",ts->abs_x_max);if (of_property_read_u32(np, "max-y", &ts->abs_y_max)) {dev_err(&client->dev, "no max-y defined\n");return -EINVAL;}MY_DEBUG("abs_x_max:%d",ts->abs_y_max);//找复位gpiots->rst_pin = of_get_named_gpio(np, "reset-gpio", 0);//申请复位gpioret = devm_gpio_request(&client->dev,ts->rst_pin,"my touch touch gpio");if (ret < 0){dev_err(&client->dev, "gpio request failed.");return -ENOMEM;}//找中断引进ts->irq_pin = of_get_named_gpio(np, "touch-gpio", 0);/* 申请使用管脚 */ret = devm_gpio_request_one(&client->dev, ts->irq_pin,GPIOF_IN, "my touch touch gpio");if (ret < 0)return ret;/*reset 复位屏幕,如果屏幕没有成功被复位触摸是无法产生中断的*/gpio_direction_output(ts->rst_pin,0);msleep(20); gpio_direction_output(ts->irq_pin,0);msleep(2); gpio_direction_output(ts->rst_pin,1);msleep(6); gpio_direction_output(ts->irq_pin, 0);gpio_direction_output(ts->irq_pin, 0);msleep(50);//申请中断ts->irq = gpio_to_irq(ts->irq_pin); if(ts->irq){ret = devm_request_threaded_irq(&(client->dev), ts->irq, NULL, my_touch_irq_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT , client->name, ts);if (ret != 0) {MY_DEBUG("Cannot allocate ts INT!ERRNO:%d\n", ret);return ret;}}// 分配输入设备对象ts->input_dev = devm_input_allocate_device(&client->dev);if (!ts->input_dev) {dev_err(&client->dev, "Failed to allocate input device.\n");return -ENOMEM;}// 设置输入设备的名称和总线类型ts->input_dev->name = "my touch screen";ts->input_dev->id.bustype = BUS_I2C;/*设置触摸 x 和 y 的最大值*/// 设置输入设备的绝对位置参数,假如你的触摸出现范围很小的情况就是这值不对input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, 480, 0, 0);input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, 800, 0, 0);// 初始化多点触摸设备的槽位ret = input_mt_init_slots(ts->input_dev, 5, INPUT_MT_DIRECT);if (ret) {dev_err(&client->dev, "Input mt init error\n");return ret;}// 注册输入设备ret = input_register_device(ts->input_dev);if (ret)return ret;my_touch_i2c_write(ts->client, addr,sizeof(addr), point_data, sizeof(point_data));gt9271_read_version(client);return 0;
}

中断

读取触摸数据有很多方法比如轮询但是这样效率太低了,所以我们这里通过中断方式实现触摸数据读取,当屏幕被触控时,屏幕会通过irq引脚输出中断信号。

devm_request_threaded_irq(&(client->dev), ts->irq,   // 请求线程化中断NULL, my_touch_irq_handler,          // 中断服务函数IRQF_TRIGGER_FALLING | IRQF_ONESHOT, // 中断触发方式为下降沿触发,且只触发一次client->name, ts);

中断线程服务函数

上面中断以后当屏幕被触摸会触发中断线程服务函数my_touch_irq_handler,在这个函数里面我们通过i2c去读取屏幕相关的参数。

竖屏中断线程服务函数

static irqreturn_t my_touch_irq_handler(int irq, void *dev_id)
{s32 ret = -1;                        // 定义一个返回值,初始化为-1struct my_touch_dev *ts = dev_id;    // 获取指向设备数据的指针u8 addr[1] = {0x02};                 // 定义一个寄存器地址数组对应数据手册TD_STATUS u8 point_data[1+6*5]={0};            // 定义一个点数据数组,预留足够空间 for 5 touch pointsu8 touch_num = 0;                    // 定义一个变量来存储触摸点的数量u8 *touch_data;                       // 定义一个指针用于指向点数据int i = 0;                           // 定义一个循环变量int event_flag, touch_id, input_x, input_y; // 定义一些用于存储事件信息的变量MY_DEBUG("irq");                    // 打印中断信息ret = my_touch_i2c_read(ts->client, addr, sizeof(addr), point_data, sizeof(point_data)); // 尝试读取触摸屏设备的数据if (ret < 0){                        // 如果读取失败MY_DEBUG("I2C write end_cmd error!"); // 打印错误信息}touch_num = point_data[0]&0x0f;     // 获取触摸点的数量MY_DEBUG("touch_num:%d",touch_num); // 打印触摸点数量// 遍历触摸点数据for(i=0; i<5; i++){// 获取触摸点数据touch_data = &point_data[1+6*i];/*解析触摸点的事件标志位00b: 按下01b: 抬起10b: 接触11b: 保留*/event_flag = touch_data[0] >> 6;if(event_flag == 0x03)continue; // 如果事件标志位不是按下或抬起,则跳过此循环touch_id = touch_data[2] >> 4;    // 获取触摸点IDMY_DEBUG("i:%d touch_id:%d event_flag:%d",i,touch_id,event_flag); // 打印调试信息input_x  = ((touch_data[0]&0x0f)<<8) | touch_data[1]; // 计算X坐标input_y  = ((touch_data[2]&0x0f)<<8) | touch_data[3]; // 计算Y坐标// MY_SWAP(input_x,input_y); // 如果需要交换X和Y坐标,可以取消注释此行MY_DEBUG("i:%d,x:%d,y:%d",i,input_x,input_y); // 打印调试信息// 设置输入设备的触摸槽位input_mt_slot(ts->input_dev, touch_id);if(event_flag == 0){ // 如果是按下// 上报按下事件和坐标input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); // 设置为按下状态input_report_abs(ts->input_dev, ABS_MT_POSITION_X, 480-input_x); // 报告X坐标input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y); // 报告Y坐标}else if (event_flag == 2){ // 如果是长按// 直接上报数据input_report_abs(ts->input_dev, ABS_MT_POSITION_X, 480-input_x); // 报告X坐标input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y); // 报告Y坐标else if(event_flag == 1){ // 如果是触摸抬起// 上报事件input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false); // 设置为抬起状态}}// 报告输入设备的指针仿真信息input_mt_report_pointer_emulation(ts->input_dev, true);// 同步输入事件input_sync(ts->input_dev);// 返回IRQ_HANDLED,表示中断已经被处理return IRQ_HANDLED;
}

横屏中断线程服务函数

/*
1.中断来了,进入这里面,既然来中断证明屏幕被触摸了。
2.读取屏幕里面的触摸数据,每个屏幕不一样但是方法是一样怎么读my_touch_i2c_read读哪里
3.解析数据
4.上报数据*/
static irqreturn_t my_touch_irq_handler(int irq, void *dev_id)
{s32 ret = -1;struct my_touch_dev *ts = dev_id;u8 addr[1] = {0x02};u8 point_data[1+6*5]={0};//1个状态位置+5个触摸点,一个点是6个数据组成u8 touch_num = 0;u8 *touch_data;int i = 0;int event_flag, touch_id, input_x, input_y;MY_DEBUG("irq");ret = my_touch_i2c_read(ts->client, addr,sizeof(addr), point_data, sizeof(point_data));if (ret < 0){MY_DEBUG("I2C write end_cmd error!");}touch_num = point_data[0]&0x0f;MY_DEBUG("touch_num:%d",touch_num);//获取for(i=0; i<5; i++){//获取点touch_data = &point_data[1+6*i];/*00b: Put Down 01b: Put Up 10b: Contact 11b: Reserved*///TOUCHn_XH[7:6]event_flag = touch_data[0] >> 6;MY_DEBUG("event_flag:%d",event_flag);if(event_flag == 0x03)continue; touch_id = touch_data[2] >> 4;MY_DEBUG("i:%d touch_id:%d event_flag:%d",i,touch_id,event_flag);input_x  = ((touch_data[0]&0x0f)<<8) | touch_data[1];input_y  = ((touch_data[2]&0x0f)<<8) | touch_data[3];// MY_SWAP(input_x,input_y);MY_DEBUG("i:%d,x:%d,y:%d",i,input_x,input_y);// 设定输入设备的触摸槽位input_mt_slot(ts->input_dev, touch_id);if(event_flag == 0){// 如果是按下上报按下和坐标input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);input_report_abs(ts->input_dev, ABS_MT_POSITION_X, 480-input_x);input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);}else if (event_flag == 2){// 如果是长按直接上报数据input_report_abs(ts->input_dev, ABS_MT_POSITION_X, 480-input_x);input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);}else if(event_flag == 1){// 触摸抬起,上报事件input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false);}}// 报告输入设备的指针仿真信息input_mt_report_pointer_emulation(ts->input_dev, true);// 同步输入事件input_sync(ts->input_dev);return IRQ_HANDLED;
}

TD_STATUS

读取数据从TD_STATUS开始,一个触摸点包含6个数据分别是TOUCH1_XH、TOUCH1_XL、TOUCH1_YH、TOUCH1_YL、TOUCH1_WEIGHT,共计支持5点触控,所以连续读取的长度为1(TD_STATUS)+6(数据)*5。

ret = my_touch_i2c_read(ts->client, addr, sizeof(addr), point_data, sizeof(point_data)); 

在这里插入图片描述

TD_STATUS寄存器中的[3:0]位存储的是触摸点数据,所以我们通过下面语句读取到当前有多少点被按下。

touch_num = point_data[0]&0x0f;     // 获取触摸点的数量

TOUCHn_X寄存器

TOUCHn_XH寄存器的[7:6]位是事件标志位数,所以我们通过touch_data右移6位来获取[7:6]位值。通过判定这个标志位我们可以知道当前触摸状态。

值类型:

  • 触摸:00b
  • 抬起:01b
  • 长按:10b
  • 保留:11b
event_flag = touch_data[0] >> 6;

TOUCHn_XH寄存器的[3:0]位是x坐标的高[11:8]位数,要想获取完整的x坐标值需要把TOUCHn_XH的[3:0]位和TOUCHn_XL的[7:0]位进行组合。

input_x  = ((touch_data[0]&0x0f)<<8) | touch_data[1];

在这里插入图片描述

TOUCHn_Y寄存器

TOUCHn_YH寄存器的[7:4]位是触摸ID,通过右移4位获取到触摸id。

touch_id = touch_data[2] >> 4;    // 获取触摸点ID

TOUCHn_YH寄存器的[3:0]位是y坐标的高[11:8]位数,要想获取完整的x坐标值需要把TOUCHn_YH的[3:0]位和TOUCHn_YL的[7:0]位进行组合。

input_y  = ((touch_data[2]&0x0f)<<8) | touch_data[3]; // 计算Y坐标

在这里插入图片描述

上报数据

数据到以后调用input接口函数进行数据上报,详细的函数使用方法大家看代码里面的注释。

触摸驱动完整代码

#include "linux/stddef.h"
#include <linux/kernel.h>
#include <linux/hrtimer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/input/mt.h>
#include <linux/random.h>#define MY_SWAP(x, y)                 do{\typeof(x) z = x;\x = y;\y = z;\}while (0)#if 1
#define MY_DEBUG(fmt,arg...)  printk("MY_TOUCH:%s %d "fmt"",__FUNCTION__,__LINE__,##arg);
#else
#define MY_DEBUG(fmt,arg...)
#endifstruct my_touch_dev {struct i2c_client *client;struct input_dev *input_dev;int rst_pin;int irq_pin;u32 abs_x_max;u32 abs_y_max;int irq;
};s32 my_touch_i2c_read(struct i2c_client *client,u8 *addr,u8 addr_len, u8 *buf, s32 len)
{struct i2c_msg msgs[2];s32 ret=-1;msgs[0].flags = !I2C_M_RD;msgs[0].addr  = client->addr;msgs[0].len   = addr_len;msgs[0].buf   = &addr[0];msgs[1].flags = I2C_M_RD;msgs[1].addr  = client->addr;msgs[1].len   = len;msgs[1].buf   = &buf[0];ret = i2c_transfer(client->adapter, msgs, 2);if(ret == 2)return 0;if(addr_len == 2){MY_DEBUG("I2C Read: 0x%04X, %d bytes failed, errcode: %d! Process reset.", (((u16)(addr[0] << 8)) | addr[1]), len, ret);}else {MY_DEBUG("I2C Read: 0x%02X, %d bytes failed, errcode: %d! Process reset.", addr[0], len, ret);}return -1;
}s32 my_touch_i2c_write(struct i2c_client *client, u8 *addr, u8 addr_len, u8 *buf,s32 len)
{struct i2c_msg msg;s32 ret = -1;u8 *temp_buf;msg.flags = !I2C_M_RD;msg.addr  = client->addr;msg.len   = len+addr_len;temp_buf= kzalloc(msg.len, GFP_KERNEL);if (!temp_buf){goto error;}// 装填地址memcpy(temp_buf, addr, addr_len);// 装填数据memcpy(temp_buf + addr_len, buf, len);msg.buf = temp_buf;ret = i2c_transfer(client->adapter, &msg, 1);if (ret == 1) {kfree(temp_buf);return 0;}error:if(addr_len == 2){MY_DEBUG("I2C Read: 0x%04X, %d bytes failed, errcode: %d! Process reset.", (((u16)(addr[0] << 8)) | addr[1]), len, ret);}else {MY_DEBUG("I2C Read: 0x%02X, %d bytes failed, errcode: %d! Process reset.", addr[0], len, ret);}if (temp_buf)kfree(temp_buf);return -1;
}/*
1.中断来了,进入这里面,既然来中断证明屏幕被触摸了。
2.读取屏幕里面的触摸数据,每个屏幕不一样但是方法是一样怎么读my_touch_i2c_read读哪里
3.解析数据
4.上报数据*/
static irqreturn_t my_touch_irq_handler(int irq, void *dev_id)
{s32 ret = -1;struct my_touch_dev *ts = dev_id;u8 addr[1] = {0x02};u8 point_data[1+6*5]={0};//1个状态位置+5个触摸点,一个点是6个数据组成u8 touch_num = 0;u8 *touch_data;int i = 0;int event_flag, touch_id, input_x, input_y;MY_DEBUG("irq");ret = my_touch_i2c_read(ts->client, addr,sizeof(addr), point_data, sizeof(point_data));if (ret < 0){MY_DEBUG("I2C write end_cmd error!");}touch_num = point_data[0]&0x0f;MY_DEBUG("touch_num:%d",touch_num);//获取for(i=0; i<5; i++){//获取点touch_data = &point_data[1+6*i];/*00b: Put Down 01b: Put Up 10b: Contact 11b: Reserved*///TOUCHn_XH[7:6]event_flag = touch_data[0] >> 6;MY_DEBUG("event_flag:%d",event_flag);if(event_flag == 0x03)continue; touch_id = touch_data[2] >> 4;MY_DEBUG("i:%d touch_id:%d event_flag:%d",i,touch_id,event_flag);input_x  = ((touch_data[0]&0x0f)<<8) | touch_data[1];input_y  = ((touch_data[2]&0x0f)<<8) | touch_data[3];// MY_SWAP(input_x,input_y);MY_DEBUG("i:%d,x:%d,y:%d",i,input_x,input_y);// 设定输入设备的触摸槽位input_mt_slot(ts->input_dev, touch_id);if(event_flag == 0){// 如果是按下上报按下和坐标input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);input_report_abs(ts->input_dev, ABS_MT_POSITION_X, 480-input_x);input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);}else if (event_flag == 2){// 如果是长按直接上报数据input_report_abs(ts->input_dev, ABS_MT_POSITION_X, 480-input_x);input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);}else if(event_flag == 1){// 触摸抬起,上报事件input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false);}}// 报告输入设备的指针仿真信息input_mt_report_pointer_emulation(ts->input_dev, true);// 同步输入事件input_sync(ts->input_dev);return IRQ_HANDLED;
}s32 gt9271_read_version(struct i2c_client *client)
{s32 ret = -1;u8 addr[1] = {0xA1};u8 buf[3] = {0};ret = my_touch_i2c_read(client, addr,sizeof(addr), buf, sizeof(buf));if (ret < 0){MY_DEBUG("GTP read version failed");return ret;}if (buf[5] == 0x00){MY_DEBUG("IC Version: %0x %0x_%02x", buf[0], buf[1], buf[2]);}else{MY_DEBUG("IC Version: %0x %0x_%02x", buf[0], buf[1], buf[2]);}return ret;
}static int my_touch_ts_probe(struct i2c_client *client,const struct i2c_device_id *id)
{int ret;struct my_touch_dev *ts;struct device_node *np = client->dev.of_node;u8 addr[1] = {0x00};u8 point_data[1]={00};//1个状态位置+5个触摸点,一个点是6个数据组成// 打印调试信息MY_DEBUG("locat");// ts = kzalloc(sizeof(*ts), GFP_KERNEL);ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);if (ts == NULL){dev_err(&client->dev, "Alloc GFP_KERNEL memory failed.");return -ENOMEM;}ts->client = client;i2c_set_clientdata(client, ts);if (of_property_read_u32(np, "max-x", &ts->abs_x_max)) {dev_err(&client->dev, "no max-x defined\n");return -EINVAL;}MY_DEBUG("abs_x_max:%d",ts->abs_x_max);if (of_property_read_u32(np, "max-y", &ts->abs_y_max)) {dev_err(&client->dev, "no max-y defined\n");return -EINVAL;}MY_DEBUG("abs_x_max:%d",ts->abs_y_max);//找复位gpiots->rst_pin = of_get_named_gpio(np, "reset-gpio", 0);//申请复位gpioret = devm_gpio_request(&client->dev,ts->rst_pin,"my touch touch gpio");if (ret < 0){dev_err(&client->dev, "gpio request failed.");return -ENOMEM;}//找中断引进ts->irq_pin = of_get_named_gpio(np, "touch-gpio", 0);/* 申请使用管脚 */ret = devm_gpio_request_one(&client->dev, ts->irq_pin,GPIOF_IN, "my touch touch gpio");if (ret < 0)return ret;/*reset 复位屏幕,如果屏幕没有成功被复位触摸是无法产生中断的*/gpio_direction_output(ts->rst_pin,0);msleep(20); gpio_direction_output(ts->irq_pin,0);msleep(2); gpio_direction_output(ts->rst_pin,1);msleep(6); gpio_direction_output(ts->irq_pin, 0);gpio_direction_output(ts->irq_pin, 0);msleep(50);//申请中断ts->irq = gpio_to_irq(ts->irq_pin); if(ts->irq){ret = devm_request_threaded_irq(&(client->dev), ts->irq, NULL, my_touch_irq_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT , client->name, ts);if (ret != 0) {MY_DEBUG("Cannot allocate ts INT!ERRNO:%d\n", ret);return ret;}}// 分配输入设备对象ts->input_dev = devm_input_allocate_device(&client->dev);if (!ts->input_dev) {dev_err(&client->dev, "Failed to allocate input device.\n");return -ENOMEM;}// 设置输入设备的名称和总线类型ts->input_dev->name = "my touch screen";ts->input_dev->id.bustype = BUS_I2C;/*设置触摸 x 和 y 的最大值*/// 设置输入设备的绝对位置参数,假如你的触摸出现范围很小的情况就是这值不对input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, 480, 0, 0);input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, 800, 0, 0);// 初始化多点触摸设备的槽位ret = input_mt_init_slots(ts->input_dev, 5, INPUT_MT_DIRECT);if (ret) {dev_err(&client->dev, "Input mt init error\n");return ret;}// 注册输入设备ret = input_register_device(ts->input_dev);if (ret)return ret;my_touch_i2c_write(ts->client, addr,sizeof(addr), point_data, sizeof(point_data));gt9271_read_version(client);return 0;
}static int my_touch_ts_remove(struct i2c_client *client)
{struct my_touch_dev *ts = i2c_get_clientdata(client);MY_DEBUG("locat");input_unregister_device(ts->input_dev);return 0;
}static const struct of_device_id my_touch_of_match[] = {{ .compatible = "my,touch", },{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, my_touch_of_match);static struct i2c_driver my_touch_ts_driver = {.probe      = my_touch_ts_probe,.remove     = my_touch_ts_remove,.driver = {.name     = "my-touch",.of_match_table = of_match_ptr(my_touch_of_match),},
};static int __init my_ts_init(void)
{MY_DEBUG("locat");return i2c_add_driver(&my_touch_ts_driver);
}static void __exit my_ts_exit(void)
{MY_DEBUG("locat");i2c_del_driver(&my_touch_ts_driver);
}module_init(my_ts_init);
module_exit(my_ts_exit);MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("My touch driver");
MODULE_AUTHOR("KuLiT");

编译生效

cd u-boot && ./make.sh rk3566 && cd ../kernel && make distclean && make ARCH=arm64 tspi_defconfig rk356x_evb.config android-11.config && make ARCH=arm64 tspi-rk3566-user-v10.img -j16 && cd .. && source build/envsetup.sh && lunch rk3566_tspi-userdebug && make installclean -j16 && make -j16 && ./mkimage.sh

在这里插入图片描述

./build.sh -u

在这里插入图片描述

效果

触摸打印信息,表示生效

在这里插入图片描述

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

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

相关文章

(深度估计学习)Win11复现DepthFM

目录 1. 系统配置2. 拉取代码&#xff0c;配置环境3.开始深度预测4.运行结果 论文链接&#xff1a;https://depthfm.github.io/ 讲解链接&#xff1a;https://www.php.cn/faq/734404.html 1. 系统配置 本人系统&#xff1a;Win11 CUDA12.2 python3.11.5 这里附上几个CUDA安装链…

文字转成活码的3步操作,手机扫码即可查看文本信息

现在经常会通过二维码的方式来传递通知的文字信息&#xff0c;只需要分享文字生成二维码的图片到微信群或者印刷出来&#xff0c;其他人就可以通过扫码来查看文字内容&#xff0c;有利于其他人更快速的获取信息。 目前文本静态码无法通过微信来扫码展示&#xff0c;那么想要解…

力扣例题(循环队列)

链接 . - 力扣&#xff08;LeetCode&#xff09; 描述 思路 我们使用数组来创建循环队列 数组的大小我们就额外对开辟一块空间 MyCircularQueue(k) 开辟一个结构体&#xff0c;存放队列的相关数据 分别为size,数组指针_a,起始位置head,结束位置tail 注意&#xff1a;我们…

(四)Spring教程——控制反转或依赖注入与Java的反射技术

IoC的底层实现技术是反射技术&#xff0c;目前Java、C#、PHP 等语言均支持反射技术。 在运行状态中&#xff0c;对于任意一个类&#xff0c;都能够获取到这个类的所有属性和方法&#xff1b;对任意一个对象&#xff0c;都能够调用它的任意方法和属性&#xff08;包括私有的方法…

手撸XXL-JOB(四)——远程调用定时任务

Java Socket网络编程 网络编程是Java编程中的重要组成部分&#xff0c;包括服务端和客户端两部分内容。Socket是Java网络编程的基本组件之一&#xff0c;用于在应用程序之间提供双向通信&#xff0c;Socket提供了一种标准的接口&#xff0c;允许应用程序通过网络发送和接收数据…

项目实施方案:多点异地机动车典型系统试验状态可视监控系统

目录 一、需求分析 1.1项目背景 1.2项目概述 二、系统优势 2.1兼容性能力强 2.2接入协议多样 2.3并发能力强 2.3.1 单平台参数 2.3.2 多平台性能参数 2.4 系统稳定性 三、建设目标 3.1安全性 3.2可扩展性 3.3易用性 3.4兼容性 3.5 响应能力 四、系统整体解决方…

Nodejs笔记2

模块化 模块化初体验 模块暴露数据 导入模块 fs 写绝对路径 require写相对路径不会受到影响 ./../不能省略 js 和json文件后缀可以省略 如果存在 命名相同的js和json文件&#xff0c;优先导入js文件 导入文件夹时的情况 require导入模块的基本流程 commonJS模块…

上位机图像处理和嵌入式模块部署(树莓派4b和电源供给)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面&#xff0c;我们说过pc电脑和嵌入式设备&#xff0c;两者都可以实现相同的软件功能。但是和pc相比较&#xff0c;嵌入式设备不仅价格更便宜&a…

24深圳杯C题18页高质量论文+可执行代码+图表

比赛题目的完整版思路可执行代码数据参考论文都会在第一时间更新上传的&#xff0c;大家可以参考我往期的资料&#xff0c;所有的资料数据以及到最后更新的参考论文都是一次付费后续免费的。注意&#xff1a;&#xff08;建议先下单占坑&#xff0c;因为随着后续我们更新资料数…

129.哈希表:有效的字母异位词(力扣)

242. 有效的字母异位词 - 力扣&#xff08;LeetCode&#xff09; 题目描述 代码解决以及思路 这个方法的时间复杂度为O(N)&#xff0c;其中N是字符串的长度&#xff0c;空间复杂度为O(1)&#xff08;因为辅助数组的大小是固定的26&#xff09;。 class Solution { public:bo…

智能终端RK3568主板在智慧公交条形屏项目的应用,支持鸿蒙,支持全国产化

基于AIoT-3568A的智慧公交条形屏&#xff0c;可支持公交线路动态展示&#xff0c;语音到站提醒&#xff0c;减少过乘、漏乘的情况&#xff0c;有效提高了公交服务效率和质量&#xff0c;为乘客提供了更舒适、更安全和更方便的出行体验&#xff0c;为城市的发展增添了新的活力。…

在idea中使用vue

一、安装node.js 1、在node.js官网&#xff08;下载 | Node.js 中文网&#xff09;上下载适合自己电脑版本的node.js压缩包 2、下载完成后进行解压并安装&#xff0c;一定要记住自己的安装路径 一直点击next即可&#xff0c;这部选第一个 3、安装成功后&#xff0c;按住winR输入…