hy46xx Touch IC

hy46xx是HYCON科技一款触摸IC。

上电时序:

通信接口:

  • 使用IIC通信

中断方式:

  • INT引脚产生下降沿的时候,触摸数据就绪,这样就可以在中断中读取
  • 如果使用线程轮询方式获取触摸数据,则可以通过判断INT引脚是否为低电平来判断触摸数据是否就绪

两种实现驱动方式:

  • 按照IIC设备驱动一般框架驱动芯片获取触摸坐标,这种方式的缺点:不兼容旧的或别人的触摸相关的应用程序
  • 按照内核input输入子系统框架来实现触摸驱动

MT(Multi-touch)多点触摸协议

内核中MT协议相关文档:Documentation\input\multi-touch-protocol.rst

老旧版本的linux内核不支持MT协议,如2.x 版本 linux 内核的话可能找不到 MT 协议

MT协议数以input子系统的一部分。

凡是触摸屏驱动若是按照input子系统框架来实现触摸都要按照MT协议来

MT协议被分为两种:

  • Type A,用于触摸点不能被区分或追踪,需上报原始数据
  • Type B,用于具备硬件追踪并能区分触摸点的触摸设备,此类型设备通过 slot (也就是触摸点ID)更新某一个触摸点的信息,既然是多点触摸协议,触摸点也必须具备ID才能区分是哪个触摸点

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事件:

  • ABS_MT_SLOT, 上报触摸点ID
  • ABS_MT_POSITION_X,上报触摸X坐标
  • ABS_MT_POSITION_Y,上报触摸Y坐标
  • ABS_MT_TRACKING_ID,对于Type B类设备,需要该事件来区分触摸点
  • ABS_MT_TOOL_TYPE 事件用于上报触摸工具类型
    • MT_TOOL_FINGER(手指)
    • MT_TOOL_PEN(笔)
    • MT_TOOL_PALM(手掌)

Type A Touch Device 上报触摸数据流程 :

1、 ABS_MT_POSITION_X x[0] ,上报触摸点0的x坐标调用static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)上报2 、ABS_MT_POSITION_Y y[0] ,上报触摸点0的y坐标3、 SYN_MT_REPORT , 上报该事件,用于隔离区分不同触摸点,因为Type A设备无法区分触摸点,调用static inline void input_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 , 最后结束,上报同步事件,调用static inline void input_sync(struct input_dev *dev)来上报static inline void input_mt_sync(struct input_dev *dev)
{input_event(dev, EV_SYN, SYN_MT_REPORT, 0);
}static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)
{input_event(dev, EV_ABS, code, value);
}static inline void input_sync(struct input_dev *dev)
{input_event(dev, EV_SYN, SYN_REPORT, 0);
}

内核中的一个参考例子:drivers\input\touchscreen\st1232.c

static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
{struct st1232_ts_data *ts = dev_id;struct st1232_ts_finger *finger = ts->finger;struct input_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;}} else if (!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 46 7、 ABS_MT_POSITION_X x[1] 8、 ABS_MT_POSITION_Y y[1] .....                      // 以此类推上报所有触摸点x、 SYN_REPORT,调用input_sync上报static inline void input_mt_slot(struct input_dev *dev, int slot)
{input_event(dev, EV_ABS, ABS_MT_SLOT, slot);
}static inline void input_report_abs(struct input_dev *dev, unsigned int 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 bool input_mt_report_slot_state(struct input_dev *dev,unsigned int tool_type, bool active)
{struct input_mt *mt = dev->mt;struct input_mt_slot *slot;int id;if (!mt)return false;slot = &mt->slots[mt->slot];slot->frame = mt->frame;if (!active) {input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);return false;}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);return true;
}从input_mt_report_slot_state函数实现中可以看到,当active设置为false时,会调用
input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1)上报ABS_MT_TRACKING_ID,值为-1

hy46xx 触摸驱动实现

1、设备树节点编写

iomuxc节点增加复位引脚的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/
  • /usr/lib/linux-image-4.19.35-carp-imx6/ ,系统存放设备树的目录

重启系统设备树生效:

sudo reboot

查看设备树是否生效 :

debian@npi:~$ ls /sys/bus/i2c/devices/
0-001e  0-0038  0-005d  0-0068  1-001a  1-0039  i2c-0  i2c-1

可以看到出现了I2C设备地址为0x38的设备。

2、驱动编写

头文件:

#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"enum hy46xx_ts_state {HY46XX_TS_DOWN    = 0x00,      /* 按下 */HY46XX_TS_UP      = 0x01,        /* 弹起 */HY46XX_TS_CONTACT = 0x02,       /* 持续性按下 */HY46XX_TS_RESERVED = 0x03,
};struct touch_data {short x;short y;uint8_t state;uint8_t id;
};struct hy46xx_device {int irq; /* 中断号 */int irq_gpio;int rst_gpio;dev_t dev_no; /* 设备号 */struct i2c_client *i2c;struct input_dev *inputdev;    /* input 结构体 */ struct touch_data ts_data[HY_MAX_SUPPORT_POINTS];
};static struct hy46xx_device *hy46xx_dev;

熟悉的I2C子系统操作:

static int hy46xx_write_regs(struct i2c_client *i2c, uint8_t reg, uint8_t *buf, uint8_t len)
{int ret = 0;uint8_t w_buf[300] = {0};struct i2c_msg msg;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;else if (ret != 1)return -EIO;return 0;
}static int hy46xx_write_reg(struct i2c_client *client, uint8_t reg, uint8_t data)
{return hy46xx_write_regs(client, reg, &data, 1);
}static int hy46xx_read_regs(struct i2c_client *client, uint8_t reg, uint8_t *buf, uint8_t len)
{struct i2c_msg msgs[2];int ret;msgs[0].flags = 0;msgs[0].addr  = client->addr;msgs[0].len   = 1;msgs[0].buf   = &reg;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;else if (ret != 2)return -EIO;return 0;
}static int hy46xx_i2c_read_reg(struct i2c_client *client, uint8_t reg, uint8_t *data)
{return hy46xx_read_regs(client, reg, data, 1);
}static int hy46xx_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;            }return 0;
}/* 设置为坐标模式, 默认也是坐标模式 */
static int hy46xx_set_tp_run_mode(struct hy46xx_device *dev)
{return hy46xx_write_reg(dev->i2c, HY_TP_RUN_MODE_REG, 0x00);
}static int hy46xx_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);return 0;}return -1;
}

probe 和 remove函数实现:

static int hy46xx_driver_probe(struct i2c_client *client, const struct i2c_device_id *id)
{int err = 0;struct device_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 0err = 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);goto exit;
exit_free_irq:                                   free_irq(hy46xx_dev->irq, NULL);             /* 释放中断*/
exit_free_dev:kfree(hy46xx_dev);hy46xx_dev = NULL;
exit:return err;
}static int hy46xx_driver_remove(struct i2c_client *i2c)
{/* 释放中断*/free_irq(hy46xx_dev->irq, NULL);    /* 释放内存 */    kfree(hy46xx_dev);printk(KERN_INFO "%s success\n", DEV_NAME);return 0;
}

出口入口函数实现:

/* 设备树的匹配列表 */
static struct of_device_id dts_match_table[] = {{.compatible = HY46XX_DTS_COMPATIBLE}, /* 通过设备树来匹配 */{},
};/* 传统匹配方式 ID 列表 ,即使不使用也要添加,不然probe匹配不成功 */
static const struct i2c_device_id id_table[] = {{.name = HY46XX_DTS_COMPATIBLE, 0},{},
};static struct i2c_driver hy46xx_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);

上报触摸数据的关键操作:

static void hy46xx_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);
}static irqreturn_t hy46xx_ts_isr(int irq, void *dev)
{struct hy46xx_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上报事件

3、驱动测试

安装驱动出现错误:

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.txtGNU 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.dtbo
dtoverlay=/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.dtbo
dtoverlay=/usr/lib/linux-image-4.19.35-carp-imx6/overlays/imx-fire-sound.dtbo
dtoverlay=/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/event1
hexdump: /dev/input/event1: Permission denied
debian@npi:~/nfs_root/driver$ sudo hexdump /dev/input/event1
0000000 c6f9 6249 62ff 000e 0003 0039 000c 0000
0000010 c6f9 6249 62ff 000e 0003 0035 024b 0000
0000020 c6f9 6249 62ff 000e 0003 0036 0108 0000
0000030 c6f9 6249 62ff 000e 0003 0000 024b 0000
0000040 c6f9 6249 62ff 000e 0003 0001 0108 0000
0000050 c6f9 6249 62ff 000e 0000 0000 0000 0000
0000060 c6f9 6249 0498 000f 0003 0039 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"static struct input_event in_event; int main(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"); } }  return 0;
}

执行sudo ./hy46xx_ts_test进行测试

debian@npi:~/nfs_root/driver$ sudo ./hy46xx_ts_test
x 606 y 303
x 621 y 464
x 744 y 255
x 734 y 276
x 826 y 428
x 972 y 573
x 982 y 529

Linux 驱动 | hy46xx触摸屏驱动相关推荐

  1. linux下GT911触摸屏驱动优化记录

    linux下GT911触摸屏驱动优化记录 背景 由于最近要做linux内核启动速度优化,所以就对着驱动一点一点优化,加上QT应用程序的初始化,总共的启动时间要做到4S以内.目前先调试GT911驱动程序 ...

  2. linux内核关闭触摸屏校准,linux内核usb触摸屏驱动bug调试- selected device is not a touchscreen I understand...

    近期给客户调试一块数控板,今天客户带过来一个屏,并且有一个usb的触摸屏芯片接在屏上.屏很快就弄好正常显示. 触摸屏在内核下找到usb 触摸屏驱动,内核启动后这个usb转的触摸屏也正常找到,注册为ev ...

  3. linux rs232触摸屏驱动程序,Linux下的触摸屏驱动

    一.触摸屏理论概述 对于触摸屏驱动,我们主要需要掌握触摸屏驱动代码和应用层测试代码.下面讲的是基于Mini2440的触摸屏驱动,现在的驱动我们都将设备和驱动分离,挂在平台设备总线上,让设备和驱动去匹配 ...

  4. Linux下的触摸屏驱动

    版权所有,转载请说明转自 http://my.csdn.net/weiqing1981127 一.触摸屏理论概述 对于触摸屏驱动,我们主要需要掌握触摸屏驱动代码和应用层测试代码.下面讲的是基于Mini ...

  5. FL2440移植LINUX-3.4.2 -- 按键驱动和触摸屏驱动移植

    (一)先移植按键输入子系统驱动: 拿过去编译,改错,然后insmod: (二)触摸屏驱动拿过去编译,改错,然后insmod: 触摸屏驱动的使用: 编译: tar xzf tslib-1.4.tar.g ...

  6. Linux/Android——usb触摸屏驱动 - usbtouchscreen (一)

    版权声明:免责声明: 本人在此发文(包括但不限于汉字.拼音.拉丁字母)均为随意敲击键盘所出,用于检验本人电脑键盘录入.屏幕显示的机械.光电性能,并不代表本人局部或全部同意.支持或者反对观点.如需要详查 ...

  7. Linux内核---30.触摸屏驱动分析

    查看input系统 root@OK6410:~# cat /proc/bus/input/devices I: Bus=0013 Vendor=dead Product=beef Version=01 ...

  8. linux触摸屏代码解析,Linux触摸屏驱动解析

    Linux下开发触摸屏驱动,最好的范例莫过于mc68328digi.c的实现.在没有看到原文之前,我把其中用到的结构解析一下. 1,struct ts_pen_info 该结构是触摸屏的核心数据结构. ...

  9. 【正点原子Linux连载】第六十四章 Linux 多点电容触摸屏实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

最新文章

  1. JBoss 系列十六:JBoss7/WildFly配置domain模式
  2. 监控摄像机 我们要享受飞行的乐趣
  3. WPF-3D动效-文字球形环绕
  4. 反射工具类,如斯优雅
  5. Java实现单链表的合并(保证数据的有序性)
  6. c#中在工作线程创建窗体并操作
  7. 【母亲节快乐】程序员的表达方式,了解一下?
  8. C++模板函数/类示例
  9. 杭电多校第一场补题-1002 Balanced Sequence
  10. Jenkins非常详细的教程四(钩子程序,定时构建实现)
  11. 达梦数据库启用日志方法,达梦数据库查看日志是否启用,达梦数据库日志文件位置查找
  12. 猜拳游戏android报告,android 之猜拳游戏练习
  13. 南邮 OJ 1160 繁杂的道路
  14. html在ios上不执行js,Javascript onloadedmetadata事件未在iOS设备上触发
  15. (1)QlikView概述
  16. [魔方]魔方七步初级教程
  17. TTL(生存时间)介绍
  18. JAVA 面试(更新)
  19. 全球与中国琴键式拨码开关市场现状及未来发展趋势
  20. 新手必看!EEGLAB工具包下载、安装及数据导入教程

热门文章

  1. linux 剪刀石头布c语言,C语言实现最简单的剪刀石头布小游戏示例
  2. 通过设置路由器来实现局域网和外网的传奇SF架设
  3. 线上前端静态资源代理到本地的几种方式
  4. 研究生复试中的一些问题回答
  5. 通达信软件服务器文件是那个,通达信“指标模块”存放在哪个文件夹里
  6. mini车f和r的区别_f800r(宝马f800r的f和r是什么意思?)
  7. 可将视频转换成Gif动画的相关软件
  8. 使用JCreator进行servlet程序的开发
  9. 职场​潜规则你能忍受到第几条?
  10. 万网绑定二级域名_万网虚拟主机子目录绑定二级域名方法