hy46xx是HYCON科技一款触摸IC。
上电时序:

通信接口:

中断方式:

INT引脚产生下降沿的时候,触摸数据就绪,这样就可以在中断中读取两种实现驱动方式:
内核中MT协议相关文档:Documentation\input\multi-touch-protocol.rst
老旧版本的linux内核不支持MT协议,如2.x 版本 linux 内核的话可能找不到 MT 协议
MT协议数以input子系统的一部分。
凡是触摸屏驱动若是按照input子系统框架来实现触摸都要按照MT协议来
MT协议被分为两种:
hy46xx 便是一款支持多点触摸的的Touch IC,从手册上可得知,其最高可支持11点触摸
现今多数Touch IC都支持多点触摸,遇到的Touch IC基本都是使用I2C接口
内核定义的MT相关的事件: include\uapi\linux\input-event-codes.h
#define ABS_MT_SLOT 0x2f /* MT slot being modified */#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */#define ABS_MT_POSITION_X 0x35 /* Center X touch position */#define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */#define ABS_MT_TOOL_X 0x3c /* Center X tool position */#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */常用MT事件:
Type A Touch Device 上报触摸数据流程 :
1、 ABS_MT_POSITION_X x[0] ,上报触摸点0的x坐标 调用staticinlinevoidinput_report_abs(struct input_dev *dev, unsignedint code, int value)上报2 、ABS_MT_POSITION_Y y[0] ,上报触摸点0的y坐标3、 SYN_MT_REPORT , 上报该事件,用于隔离区分不同触摸点,因为Type A设备无法区分触摸点, 调用staticinlinevoidinput_mt_sync(struct input_dev *dev)来上报该事件4、 ABS_MT_POSITION_X x[1] ,上报触摸点1的x坐标5 、ABS_MT_POSITION_Y y[1] ,上报触摸点1的y坐标6、 SYN_MT_REPORT ...... 以此类推,上报所有触摸点坐标n、 SYN_REPORT , 最后结束,上报同步事件, 调用staticinlinevoidinput_sync(struct input_dev *dev)来上报staticinlinevoidinput_mt_sync(struct input_dev *dev){ input_event(dev, EV_SYN, SYN_MT_REPORT, 0);}staticinlinevoidinput_report_abs(struct input_dev *dev, unsignedint code, int value){ input_event(dev, EV_ABS, code, value);}staticinlinevoidinput_sync(struct input_dev *dev){ input_event(dev, EV_SYN, SYN_REPORT, 0);}内核中的一个参考例子:drivers\input\touchscreen\st1232.c
staticirqreturn_tst1232_ts_irq_handler(int irq, void *dev_id){structst1232_ts_data *ts = dev_id;structst1232_ts_finger *finger = ts->finger;structinput_dev *input_dev = ts->input_dev;int count = 0;int i, ret; ret = st1232_ts_read_data(ts);if (ret < 0)goto end;/* multi touch protocol */for (i = 0; i < MAX_FINGERS; i++) {if (!finger[i].is_valid)continue; input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t); input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x); input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].y); input_mt_sync(input_dev); count++; }/* SYN_MT_REPORT only if no contact */if (!count) { input_mt_sync(input_dev);if (ts->low_latency_req.dev) { dev_pm_qos_remove_request(&ts->low_latency_req); ts->low_latency_req.dev = NULL; } } elseif (!ts->low_latency_req.dev) {/* First contact, request 100 us latency. */ dev_pm_qos_add_ancestor_request(&ts->client->dev, &ts->low_latency_req, DEV_PM_QOS_RESUME_LATENCY, 100); }/* SYN_REPORT */ input_sync(input_dev);end:return IRQ_HANDLED;}linux内核是一个宝库,只要熟悉框架,对于一般驱动基本都可以参考内核已有的驱动去编写驱动。
Type B Touch Device 上报触摸数据流程 :
1、 ABS_MT_SLOT 0 ,上报 ABS_MT_SLOT 事件,就是触摸点0的ID,调用input_mt_slot上报2、 ABS_MT_TRACKING_ID 45,按照Type B类型设备要求每个slot必须 关联一个TRACKING_ID完成对触摸点的添加、替换或删除,调用input_mt_report_slot_state实现3、 ABS_MT_POSITION_X x[0],上报触摸点0的x坐标, input_report_abs4、 ABS_MT_POSITION_Y y[0],上报触摸点0的y坐标, input_report_abs5、 ABS_MT_SLOT 1 ,上报触摸点1的ABS_MT_SLOT 事件6、 ABS_MT_TRACKING_ID 467、 ABS_MT_POSITION_X x[1] 8、 ABS_MT_POSITION_Y y[1] ..... // 以此类推上报所有触摸点x、 SYN_REPORT,调用input_sync上报staticinlinevoidinput_mt_slot(struct input_dev *dev, int slot){ input_event(dev, EV_ABS, ABS_MT_SLOT, slot);}staticinlinevoidinput_report_abs(struct input_dev *dev, unsignedint code, int value){ input_event(dev, EV_ABS, code, value);}Type B Touch Device 触摸数据移除流程 :
1、 ABS_MT_TRACKING_ID -1 ,调用input_mt_report_slot_state实现不需要手动设置值为-1, 将改函数名为active参数设置为false即可2、 SYN_REPORT boolinput_mt_report_slot_state(struct input_dev *dev,unsignedint tool_type, bool active){structinput_mt *mt = dev->mt;structinput_mt_slot *slot;int id;if (!mt)returnfalse; slot = &mt->slots[mt->slot]; slot->frame = mt->frame;if (!active) { input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);returnfalse; } id = input_mt_get_value(slot, ABS_MT_TRACKING_ID);if (id < 0) id = input_mt_new_trkid(mt); input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id); input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);returntrue;}从input_mt_report_slot_state函数实现中可以看到,当active设置为false时,会调用input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1)上报ABS_MT_TRACKING_ID,值为-1iomuxc节点增加复位引脚的pinctrl节点:pinctrl_tsc_reset
&iomuxc { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_hog_1>; ...... pinctrl_tsc_reset: tscresetgrp { fsl,pins = </* used for tsc reset */ MX6UL_PAD_LCD_RESET__GPIO3_IO04 0x05 >; }; ......}在IO复用节点 —— iomuxc节点中增加即可,位置放在那里都没关系
iomuxc_snvs节点增加中断引脚的pinctrl节点:pinctrl_tsc_irq
&iomuxc_snvs { pinctrl-names = "default_snvs"; ...... pinctrl_tsc_irq: tsc_irq { fsl,pins = < MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x4001b8b0 >; };};最重要是在根节点下增加hy46xx触摸IC的节点:
hy46xx@0x38 { compatible = "hy46xx,ts"; /* 设备树和驱动匹配属性 */ pinctrl-0 = <&pinctrl_tsc_reset>; pinctrl-1 = <&pinctrl_tsc_irq>; reg = <0x38>; /* i2c设备地址 */ status = "okay";/*gpio*/ reset-gpios = <&gpio3 4 GPIO_ACTIVE_LOW>; irq-gpios = <&gpio5 9 GPIO_ACTIVE_HIGH>;/*interrupt*/ interrupt-parent = <&gpio5>; interrupts = <9 IRQ_TYPE_EDGE_FALLING>; irq-flags = <2>; /* 1:rising 2: falling */};设备树编译:
ares@ubuntu:~/work/ebf_linux_kernel-ebf_4.19.35_imx6ul$ cat make_dtb.sh#!/bin/shmake ARCH=arm -j4 CROSS_COMPILE=arm-linux-gnueabihf- dtbs将设备树拷贝系统内核目录:
debian@npi:~/nfs_root/driver$ cat cp_dtb_to_linux.sh#!/bin/shsudo cp imx6ull-mmc-npi.dtb /usr/lib/linux-image-4.19.35-carp-imx6/重启系统设备树生效:
sudo reboot查看设备树是否生效 :
debian@npi:~$ ls /sys/bus/i2c/devices/0-001e 0-00380-005d 0-00681-001a 1-0039 i2c-0 i2c-1可以看到出现了I2C设备地址为0x38的设备。
头文件:
#include<linux/init.h>#include<linux/module.h>#include<linux/fs.h>#include<linux/cdev.h>#include<linux/uaccess.h>#include<linux/types.h>#include<linux/kernel.h>#include<linux/delay.h>#include<linux/ide.h>#include<linux/errno.h>#include<linux/gpio.h>#include<asm/mach/map.h>#include<linux/of.h>#include<linux/of_address.h>#include<linux/of_gpio.h>#include<asm/io.h>#include<linux/device.h>#include<linux/timer.h>#include<linux/jiffies.h>#include<linux/platform_device.h>#include<linux/of_irq.h>#include<linux/wait.h>#include<linux/sched/signal.h>#include<linux/poll.h>#include<linux/atomic.h>#include<linux/i2c.h>#include<linux/input.h>#include<linux/input/mt.h>宏定义和数据结构:
#define HY_CHIP_ID_REG 0xA9#define HY_TP_RUN_MODE_REG 0x00 /* 0x00 工作模式 0xc0 测试模式 */#define HY_FITLTER_REG 0x8A /* 滤波器 0-5 */#define HY_PWR_NOISE_REG 0x89 /* 电源噪声 0 off 1 on */#define HY_FW_VERSION_REG 0xA6 #define HY_LIB_VERSION_REG 0xA7 #define HY_PWR_MODE_REG 0xA5 /* 0x03 tp enter sleep 需要 reset pin 拉 low 喚醒 */#define HY_REPORT_SPEED_REG 0x88 /* 报点率设置 0x64 */#define HY_GSTID_REG 0x02 /* 当前检测到的触摸情况 */#define HY_TP1_XH_REG 0X03 /* 第一个触摸点数据地址 */#define HY_TP1_XL_REG 0X04 /* 第一个触摸点数据地址 */#define HY_TP1_YH_REG 0X05 /* 第一个触摸点数据地址 */#define HY_TP1_YL_REG 0X06 /* 第一个触摸点数据地址 */#define HY_TP2_REG 0X09 /* 第二个触摸点数据地址 */#define HY_TP3_REG 0X0F /* 第三个触摸点数据地址 */#define HY_TP4_REG 0X15 /* 第四个触摸点数据地址 */#define HY_TP5_REG 0X1B /* 第五个触摸点数据地址 */#define HY_MAX_SUPPORT_POINTS 5#define HY46XX_HOR_RES 1024#define HY46XX_VER_RES 600#ifndef HY_COUNTOF#define HY_COUNTOF(a) (sizeof(a)/sizeof(a[0]))#endif#define DEV_NAME "hy46xx,ts"#define HY46XX_DTS_COMPATIBLE "hy46xx,ts"#define HY46XX_DTS_IRQ_GPIO_NAME "irq-gpios"#define HY46XX_DTS_RST_GPIO_NAME "reset-gpios"enumhy46xx_ts_state { HY46XX_TS_DOWN = 0x00, /* 按下 */ HY46XX_TS_UP = 0x01, /* 弹起 */ HY46XX_TS_CONTACT = 0x02, /* 持续性按下 */ HY46XX_TS_RESERVED = 0x03, };structtouch_data {short x;short y;uint8_t state;uint8_t id;};structhy46xx_device {int irq; /* 中断号 */int irq_gpio;int rst_gpio;dev_t dev_no; /* 设备号 */structi2c_client *i2c;structinput_dev *inputdev;/* input 结构体 */structtouch_datats_data[HY_MAX_SUPPORT_POINTS];};staticstructhy46xx_device *hy46xx_dev;熟悉的I2C子系统操作:
staticinthy46xx_write_regs(struct i2c_client *i2c, uint8_t reg, uint8_t *buf, uint8_t len){int ret = 0;uint8_t w_buf[300] = {0};structi2c_msgmsg; w_buf[0] = reg;memcpy(&w_buf[1], buf, len); msg.addr = i2c->addr; msg.buf = w_buf; msg.flags = 0; /* I2C direction : write */ msg.len = len + 1; ret = i2c_transfer(i2c->adapter, &msg, 1);if (ret < 0)return ret;elseif (ret != 1)return -EIO;return0;}staticinthy46xx_write_reg(struct i2c_client *client, uint8_t reg, uint8_t data){return hy46xx_write_regs(client, reg, &data, 1);}staticinthy46xx_read_regs(struct i2c_client *client, uint8_t reg, uint8_t *buf, uint8_t len){structi2c_msgmsgs[2];int ret; msgs[0].flags = 0; msgs[0].addr = client->addr; msgs[0].len = 1; msgs[0].buf = ® msgs[1].flags = I2C_M_RD; msgs[1].addr = client->addr; msgs[1].len = len; msgs[1].buf = buf; ret = i2c_transfer(client->adapter, msgs, 2);if (ret < 0)return ret;elseif (ret != 2)return -EIO;return0;}staticinthy46xx_i2c_read_reg(struct i2c_client *client, uint8_t reg, uint8_t *data){return hy46xx_read_regs(client, reg, data, 1);}staticinthy46xx_read_touch_data(struct hy46xx_device *dev){uint8_t buf[29];uint8_t *ts;int ret;int i; ret = hy46xx_read_regs(dev->i2c, HY_TP1_XH_REG, buf, 29);if (ret != 0) return ret;for (i = 0; i < HY_MAX_SUPPORT_POINTS; i++) { ts = &buf[i * 6]; dev->ts_data[i].state = (ts[0] & 0xC0) >> 6; dev->ts_data[i].x = ((ts[0] & 0x0f) << 8) | ts[1]; dev->ts_data[i].y = ((ts[2] & 0x0f) << 8) | ts[3]; dev->ts_data[i].id = (ts[2] & 0xf0) >> 4; }return0;}/* 设置为坐标模式, 默认也是坐标模式 */staticinthy46xx_set_tp_run_mode(struct hy46xx_device *dev){return hy46xx_write_reg(dev->i2c, HY_TP_RUN_MODE_REG, 0x00);}staticinthy46xx_ts_reset(struct hy46xx_device *dev){if (gpio_is_valid(dev->rst_gpio)) /* 检查 IO 是否有效 */ { gpio_set_value(dev->rst_gpio, 0); msleep(5); gpio_set_value(dev->rst_gpio, 1); msleep(1000);return0; }return-1;}probe 和 remove函数实现:
staticinthy46xx_driver_probe(struct i2c_client *client, conststruct i2c_device_id *id){int err = 0;structdevice_node *dev_node; hy46xx_dev = (struct hy46xx_device *)kzalloc(sizeof(struct hy46xx_device), GFP_KERNEL);if (!hy46xx_dev) { printk("can't kzalloc hy46xx device\n");return -ENOMEM; } dev_node = client->dev.of_node;if (!dev_node) { printk("hy46xx ts dts node err\r\n"); err = -EINVAL;goto exit_free_dev; } hy46xx_dev->i2c = client; printk("hy46xx dts irq %d !\r\n", client->irq); hy46xx_dev->irq_gpio = of_get_named_gpio(dev_node, HY46XX_DTS_IRQ_GPIO_NAME, 0); /* 获取irq-gpios */if (!gpio_is_valid( hy46xx_dev->irq_gpio)) { printk("don't get %s %s!\n", DEV_NAME, HY46XX_DTS_IRQ_GPIO_NAME); err = -EINVAL;goto exit_free_dev; } hy46xx_dev->irq = gpio_to_irq( hy46xx_dev->irq_gpio); /* 通过gpio得到irq */ hy46xx_dev->rst_gpio = of_get_named_gpio(dev_node, HY46XX_DTS_RST_GPIO_NAME, 0); /* 获取rst-gpios */if (!gpio_is_valid( hy46xx_dev->rst_gpio)) { printk("don't get %s %s!\n", DEV_NAME, HY46XX_DTS_RST_GPIO_NAME); err = -EINVAL;goto exit_free_dev; } printk("%s %d, %s %d", HY46XX_DTS_IRQ_GPIO_NAME, hy46xx_dev->irq_gpio, HY46XX_DTS_RST_GPIO_NAME, hy46xx_dev->rst_gpio);#if 0 err = request_irq(hy46xx_dev->irq, hy46xx_ts_isr, RQF_TRIGGER_FALLING, DEV_NAME, NULL); #else/* 中断线程化 */ err = devm_request_threaded_irq(&client->dev, client->irq, NULL, hy46xx_ts_isr, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, hy46xx_dev);#endifif (err) { printk(KERN_INFO "failed to request irq %d\r\n", hy46xx_dev->irq);goto exit_free_dev; } hy46xx_dev->inputdev = devm_input_allocate_device(&client->dev);; /* 申请输入设备结构 */if (!hy46xx_dev->inputdev) { printk(KERN_ERR "%s: Failed to allocate input device.\n", __func__); err = -ENOMEM;goto exit_free_irq; } hy46xx_dev->inputdev->name = DEV_NAME; hy46xx_dev->inputdev->id.bustype = BUS_I2C; /* 触摸屏通信总线类型 */ hy46xx_dev->inputdev->dev.parent = &client->dev;/* Single touch */ input_set_abs_params(hy46xx_dev->inputdev, ABS_X, 0, HY46XX_HOR_RES, 0, 0); input_set_abs_params(hy46xx_dev->inputdev, ABS_Y, 0, HY46XX_VER_RES, 0, 0); input_set_abs_params(hy46xx_dev->inputdev, ABS_MT_POSITION_X, 0, HY46XX_HOR_RES, 0, 0); input_set_abs_params(hy46xx_dev->inputdev, ABS_MT_POSITION_Y, 0, HY46XX_VER_RES, 0, 0); err = input_mt_init_slots(hy46xx_dev->inputdev, HY_MAX_SUPPORT_POINTS, 0); /* 初始化触摸屏,5点触摸 */if (err) { dev_err(&client->dev,"Failed to initialize MT slots: %d", err);goto exit_free_irq; } err = input_register_device(hy46xx_dev->inputdev); /* 注册input_device */if (err) { printk(KERN_ERR "%s: Failed to regist key device.\n", __func__);goto exit_free_irq; } gpio_direction_input(hy46xx_dev->irq_gpio); gpio_direction_output(hy46xx_dev->rst_gpio, 0); hy46xx_ts_reset(hy46xx_dev); /* 复位 */ hy46xx_set_tp_run_mode(hy46xx_dev);gotoexit;exit_free_irq: free_irq(hy46xx_dev->irq, NULL); /* 释放中断*/exit_free_dev: kfree(hy46xx_dev); hy46xx_dev = NULL;exit:return err;}staticinthy46xx_driver_remove(struct i2c_client *i2c){/* 释放中断*/ free_irq(hy46xx_dev->irq, NULL); /* 释放内存 */ kfree(hy46xx_dev); printk(KERN_INFO "%s success\n", DEV_NAME);return0;}出口入口函数实现:
/* 设备树的匹配列表 */staticstructof_device_iddts_match_table[] = { {.compatible = HY46XX_DTS_COMPATIBLE}, /* 通过设备树来匹配 */ {},};/* 传统匹配方式 ID 列表 ,即使不使用也要添加,不然probe匹配不成功 */staticconststructi2c_device_idid_table[] = { {.name = HY46XX_DTS_COMPATIBLE, 0}, {},};staticstructi2c_driverhy46xx_driver = { .probe = hy46xx_driver_probe, .remove = hy46xx_driver_remove, .driver = { .name = HY46XX_DTS_COMPATIBLE, .owner = THIS_MODULE, .of_match_table = dts_match_table, /* 通过设备树匹配 */ }, .id_table = id_table,};module_i2c_driver(hy46xx_driver);上报触摸数据的关键操作:
staticvoidhy46xx_report_events(struct hy46xx_device *dev){int i;bool touch;for (i = 0; i < HY_MAX_SUPPORT_POINTS; i++) { input_mt_slot(dev->inputdev, dev->ts_data[i].id); /* ABS_MT_SLOT事件 上报触摸ID */if (dev->ts_data[i].state == HY46XX_TS_RESERVED) continue; touch = dev->ts_data[i].state != HY46XX_TS_UP; /* 当触摸按下touch为true,弹起时touch为false */ input_mt_report_slot_state(dev->inputdev, MT_TOOL_FINGER, touch); /* ABS_MT_TRACKING_ID 事件 */if (touch) { input_report_abs(dev->inputdev, ABS_MT_POSITION_X, dev->ts_data[i].x); /* 上报触摸点的x坐标 */ input_report_abs(dev->inputdev, ABS_MT_POSITION_Y, dev->ts_data[i].y); /* 上报触摸点的y坐标 */ } } input_mt_report_pointer_emulation(dev->inputdev, true); input_sync(dev->inputdev); }staticirqreturn_thy46xx_ts_isr(int irq, void *dev){structhy46xx_device *hydev = (struct hy46xx_device *)dev;/* 上报触摸点数据 */ hy46xx_read_touch_data(hydev); hy46xx_report_events(hydev);return IRQ_RETVAL(IRQ_HANDLED);}hy46xx符合Type B类型的触摸设备时序,故而使用的是Type B类型时序。 在中断处理函数hy46xx_ts_isr中调用hy46xx_read_touch_data读取5点坐标,调用hy46xx_report_events上报事件
安装驱动出现错误:
debian@npi:~/nfs_root/driver$ sudo insmod hy46xx_ts_drv.ko[ 69.990212] hy46xx_ts_drv: loading out-of-tree module taints kernel.[ 70.003587] hy46xx dts irq 210 ![ 70.006999] irq-gpios 137, reset-gpios 68[ 70.016025] input: hy46xx,ts as /devices/soc0/soc/2100000.aips-bus/21a0000.i2c/i2c-0/0-0038/input/input1这是因为系统还有个gt9xx的触摸使用了设备树节点定义的资源,所以匹配失败,去掉gt9xx相关的设备节点即可。 我使用的系统触摸设备树节点是使用设备树插件实现的,只要禁用关于gt9xx触摸屏插件即可
debian@npi:~/nfs_root/driver$ sudo nano /boot/uEnv.txt GNU nano 3.2 /boot/uEnv.txtdtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-hdmi.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-cam.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-btwifi.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-can1.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-can2.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-dht11.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-ecspi3.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-key.dtbodtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-lcd.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-touch-capac$#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-led.dtbodtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-sound.dtbodtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-uart2.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-uart3.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-mpu6050.dtbo#dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-ds18b20.dtbo#overlay_end通过#号注释掉dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-touch-capac该项目接着保存重启系统使修改生效。
重新安装驱动模块:
debian@npi:~/nfs_root/driver$ sudo insmod hy46xx_ts_drv.ko[ 69.990212] hy46xx_ts_drv: loading out-of-tree module taints kernel.[ 70.003587] hy46xx dts irq 210 ![ 70.006999] irq-gpios 137, reset-gpios 68[ 70.016025] input: hy46xx,ts as /devices/soc0/soc/2100000.aips-bus/21a0000.i2c/i2c-0/0-0038/input/input1可以看到已经probe成功了
查看输入子系统生成设备节点:
debian@npi:~/nfs_root/driver$ ls /dev/input/ev*/dev/input/event0 /dev/input/event1/dev/input/event1 就是hy46xx触摸的设备节点
用命令方式测试驱动:
debian@npi:~/nfs_root/driver$ hexdump /dev/input/event1hexdump: /dev/input/event1: Permission denieddebian@npi:~/nfs_root/driver$ sudo hexdump /dev/input/event10000000 c6f9 624962ff 000e 00030039000c 00000000010 c6f9 624962ff 000e 00030035024b00000000020 c6f9 624962ff 000e 00030036010800000000030 c6f9 624962ff 000e 00030000024b00000000040 c6f9 624962ff 000e 00030001010800000000050 c6f9 624962ff 000e 00000000000000000000060 c6f9 62490498000f00030039 ffff ffff这样测试不太直观,编写测试程序:
#include"stdio.h"#include"unistd.h"#include"sys/types.h"#include"sys/stat.h"#include"sys/ioctl.h"#include"fcntl.h"#include"stdlib.h"#include"string.h"#include<poll.h>#include<sys/select.h>#include<sys/time.h>#include<signal.h>#include<fcntl.h>#include<linux/input.h>#define DEV_NAME "/dev/input/event1"staticstructinput_eventin_event;intmain(int argc, char *argv[]){int fd;int ret = 0; fd = open(DEV_NAME, O_RDWR);if (fd < 0) {printf("Can't open file %s\r\n", DEV_NAME);return-1; }while (1) { ret = read(fd, &in_event, sizeof(in_event));if (ret == sizeof(in_event)) /* 读取数据成功 */ {switch (in_event.type) {case EV_KEY: /* 按键事件类型 */break;/* 其他类型的事件,自行处理 */case EV_REL: break; case EV_ABS: if (in_event.code == ABS_X) {printf("x %d ", in_event.value); }if (in_event.code == ABS_Y) {printf("y %d\r\n", in_event.value); }break; case EV_MSC: break; case EV_SW: break; } }else { printf("读取数据失败\r\n"); } } return0; }执行sudo ./hy46xx_ts_test进行测试
debian@npi:~/nfs_root/driver$ sudo ./hy46xx_ts_testx 606 y 303x 621 y 464x 744 y 255x 734 y 276x 826 y 428x 972 y 573x 982 y 529代码:https://gitee.com/guangjieMVP/linux-driver-leanring