驱动程序开发:多点电容触摸屏

时间:2023-01-09 10:54:44

一、编写驱动前的知识准备

  这里我要吐槽一下正点原子的触摸屏了,本人使用的是正点原子的7寸触摸屏,万万没想到的是他们家的7寸触摸屏使用过多款的触摸屏芯片,正是这个“因”,导致我在做触摸屏裸机实验时使用FT5426触摸屏芯片的驱动程序可以完整正确运行,但到了使用FT5426驱动程序时却不能正常的读、写寄存器了,经过多次折腾,终于忍不住请了外援FAE帮忙,它说FT5426驱动可以兼容好几款的7寸触摸屏,但又有一些略微的不同,正因为这略微的不同导致我掉坑里那么久的“果”。
  经过我手机的百倍放大终于看清楚了高温黄油纸下的芯片上的型号字体,其型号是CST340,FAE说这款芯片是兼容FT5426驱动,但是略微不同的是,该芯片不需要进行初始化,也就是说上电就给你自动初始化了,而且CST340芯片的寄存器好像只支持读,而且不是所有都能读,由于和FT5426芯片读触摸点坐标相同位置的寄存器才能读,这是我实验测试出来的,不太准,因为CST340这款芯片网上可以说找不到资料。

1、CST340触摸屏芯片寄存器

FT5426芯片寄存器,如下图所示:


驱动程序开发:多点电容触摸屏

  注意:FT5426和CST340都是I2C通讯,其I2C设备地址都是0x38,而且其两的触摸点寄存器地址都是相同的,也就是上图红色框框里的,但是不同的是CST340的X和Y坐标的数据存储的寄存器是和FT5426相反过来的。

2、CST340触摸屏的硬件原理图

驱动程序开发:多点电容触摸屏
上图可以看出,CST340芯片的I2C数据线、时钟线引脚、中断引脚和复位引脚连接到对应的IMX6ULL芯片的引脚。

3、电容触摸屏驱动是由几种linux驱动框架组成的

①、 IIC 设备驱动,因为电容触摸 IC 基本都是 IIC 接口的,因此大框架就是 IIC 设备驱动。
②、通过中断引脚(INT)向 linux 内核上报触摸信息,因此需要用到 linux 中断驱动框架。坐标的上报在中断服务函数中完成。
③、触摸屏的坐标信息、屏幕按下和抬起信息都属于 linux 的 input 子系统,因此向 linux 内核上报触摸屏坐标信息就得使用 input 子系统。只是,我们得按照 linux 内核规定的规则来上报坐标信息。

4、linux多点电容触摸的(Multi-touch,简称 MT)协议

MT 协议被分为两种类型, TypeA 和 TypeB,这两种类型的区别如下:
Type A:适用于触摸点不能被区分或者追踪,此类型的设备上报原始数据(此类型在实际使用中非常少!)。
Type B:适用于有硬件追踪并能区分触摸点的触摸设备,此类型设备通过 slot 更新某一个触摸点的信息, FT5426 就属于此类型,一般的多点电容触摸屏 IC 都有此能力。
 
  其实触摸点的信息通过一系列的 ABS_MT 事件(有的资料也叫消息)上报给 linux 内核,只有ABS_MT 事件是用于多点触摸的, ABS_MT 事件定义在文件 include/uapi/linux/input.h 中,相关事件如下所示:
驱动程序开发:多点电容触摸屏
  在 上 面 这 些 众 多 的 ABS_MT 事 件 中 , 我 们 最 常 用 的 就 是 ABS_MT_SLOT 、ABS_MT_POSITION_X 、 ABS_MT_POSITION_Y 和 ABS_MT_TRACKING_ID 。 其 中ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y 用来上 报触摸 点的 (X,Y) 坐标 信息 ,ABS_MT_SLOT 用 来 上 报 触 摸 点 ID , 对 于 Type B 类 型 的 设 备 , 需 要 用 到ABS_MT_TRACKING_ID 事件来区分触摸点。
  对于 Type A 类型的设备,通过 input_mt_sync()函数来隔离不同的触摸点数据信息,此函数原型如下所示:

void input_mt_sync(struct input_dev *dev)

  此函数只要一个参数,类型为 input_dev,用于指定具体的 input_dev 设备。 input_mt_sync()函数会触发 SYN_MT_REPORT 事件,此事件会通知接收者获取当前触摸数据,并且准备接收下一个触摸点数据。
  对于 Type B 类型的设备,上报触摸点信息的时候需要通过 input_mt_slot()函数区分是哪一个触摸点, input_mt_slot()函数原型如下所示:

void input_mt_slot(struct input_dev *dev, int slot)

  此函数有两个参数,第一个参数是 input_dev 设备,第二个参数 slot 用于指定当前上报的是哪个触摸点信息。 input_mt_slot()函数会触发 ABS_MT_SLOT 事件,此事件会告诉接收者当前正在更新的是哪个触摸点(slot)的数据。
 
  Ⅰ、对于 Type A 类型的设备,发送触摸点信息的时序如下所示,这里以 2 个触摸点为例:

						示例代码 64.1.2.1 Type A 触摸点数据上报时序
ABS_MT_POSITION_X x[0]		//通过 ABS_MT_POSITION_X 事件上报第一个触摸点的 X 坐标数据,通过input_report_abs 函数实现,下面同理
ABS_MT_POSITION_Y y[0]		//通过 ABS_MT_POSITION_Y 事件上报第一个触摸点的 Y 坐标数据
SYN_MT_REPORT				//上报 SYN_MT_REPORT 事件,通过调用 input_mt_sync 函数来实现
ABS_MT_POSITION_X x[1]		//通过 ABS_MT_POSITION_X 事件上报第二个触摸点的 X 坐标数据
ABS_MT_POSITION_Y y[1]		//通过 ABS_MT_POSITION_Y 事件上报第二个触摸点的 Y 坐标数据
SYN_MT_REPORT				//上报 SYN_MT_REPORT 事件,通过调用 input_mt_sync 函数来实现
SYN_REPORT					//上报 SYN_REPORT 事件,通过调用 input_sync 函数实现

  以下是某个TypeA类型驱动的代码段案例:
驱动程序开发:多点电容触摸屏


  Ⅱ、对于 Type B 类型的设备,发送触摸点信息的时序如下所示,这里以 2 个触摸点为例:

							示例代码 64.1.3.1 Type B 触摸点数据上报时序
ABS_MT_SLOT 0				//报 ABS_MT_SLOT 事件,也就是触摸点对应的 SLOT。每次上报一个触摸点坐标之前要先使用input_mt_slot函数上报当前触摸点SLOT,触摸点的SLOT其实就是触摸点ID,需要由触摸 IC 提供
ABS_MT_TRACKING_ID 45		//根据 Type B 的要求,每个 SLOT 必须关联一个 ABS_MT_TRACKING_ID,通过修改 SLOT 关联的 ABS_MT_TRACKING_ID 来完成对触摸点的添加、替换或删除。具体用到的函数就是 input_mt_report_slot_state,如果是添加一个新的触摸点,那么此函数的第三个参数active 要设置为 true, linux 内核会自动分配一个 ABS_MT_TRACKING_ID 值,不需要用户去指定具体的 ABS_MT_TRACKING_ID 值
ABS_MT_POSITION_X x[0]		//上报触摸点 0 的 X 轴坐标,使用函数 input_report_abs 来完成
ABS_MT_POSITION_Y y[0]		//上报触摸点 0 的 Y 轴坐标,使用函数 input_report_abs 来完成
ABS_MT_SLOT 1
ABS_MT_TRACKING_ID 46
ABS_MT_POSITION_X x[1]
ABS_MT_POSITION_Y y[1]
SYN_REPORT					//当所有的触摸点坐标都上传完毕以后就得发送 SYN_REPORT 事件,使用 input_sync函数来完成

  以下是某个TypeB类型驱动的代码段案例:
驱动程序开发:多点电容触摸屏
 
 

二、驱动程序的编写

1、修改设备树

  CST340触摸屏芯片用到了4个IO,一个复位IO、一个中断IO、I2C的SCL和SDA,所以我们需要先在设备树中添加IO相关的信息。(具体电器属性的意思可以看我前面的博客,有介绍怎么查看手册的电器属性设置)
  ①、中断IO,在IOMUXC节点下的imx6ul-evk子节点中添加触摸屏的中断引脚信息:


驱动程序开发:多点电容触摸屏

  ②、触摸屏复位IO使用的是SNVS_TAMPER9,因此复位引脚信息要添加到iomuxc_snvs节点下的imx6ul-evk子节点中:


驱动程序开发:多点电容触摸屏

  ③、添加 I2C2 的 SCL 和 SDA 这两个 IO 信息, imx6ull-alientek-emmc.dts 里面默认就已经
添加了 I2C2 的 IO 信息,这是 NXP 官方添加的,所以不需要我们去修改。找到“pinctrl_i2c2”
节点,此节点就是用于描述 I2C2 的 IO 信息,节点内容如下所示:


驱动程序开发:多点电容触摸屏


最后,一定要检查一下设备树,确保触摸屏所使用的 IO 没有被其他的外设使用,如果有的 话就需要将其屏蔽掉,保证只有触摸屏用到了这四个 IO。

  ④、CST340这个触摸 IC 挂载 I2C2 下,因此需要向 I2C2 节点下添加一个子节点,此子节点用
于描述 CST340,添加完成以后的 I2C2 节点内容如下所示:


驱动程序开发:多点电容触摸屏

  因为正点原子的触摸芯片CST340和FT5426连接的IO引脚都是相同的,并且I2C的设备地址和触摸点寄存器地址也是相同的.

  从ft5426:ft5426@32依次往下解释:
  第一行设置的节点名称为ft5426,且ft5426器件地址为0x38。
  第二行是兼容属性,是用来在驱动程序中匹配设备树对应的节点使用的,只有匹配成功才会进入probe函数。
  第三行是触摸屏芯片的设备地址,也就是0x38。
  第四行是状态属性,这里设置的是“default”。
  第五行是描述 CST340的复位 IO 和中断 IO 所使用的节点为 pinctrl_tsc
和 pinctrl_tsc_reset。
  第七行interrupt-parent 属性描述中断 IO 对应的 GPIO 组为 GPIO1。
  第八行interrupts 属性描述中断 IO 对应的是 GPIO1 组的 IOI09。
  第九行reset-gpios 属性描述复位 IO 对应的 GPIO 为 GPIO5_IO09。
  第十行interrupt-gpios 属性描述中断 IO 对应的 GPIO 为 GPIO1_IO09。
 

2、驱动程序编写

  这里先再描述驱动程序的编写过程了,程序都有注释和编写顺序。如下:

/* 
 *  根据linux内核的程序查找所使用函数的对应头文件。 
 */  
#include <linux/module.h>       //MODULE_LICENSE,MODULE_AUTHOR  
#include <linux/init.h>         //module_init,module_exit  
#include <linux/kernel.h>       //printk  
#include <linux/fs.h>           //struct file_operations  
#include <linux/slab.h>         //kmalloc, kfree  
#include <linux/uaccess.h>      //copy_to_user,copy_from_user  
#include <linux/io.h>           //ioremap,iounmap  
#include <linux/cdev.h>         //struct cdev,cdev_init,cdev_add,cdev_del  
#include <linux/device.h>       //class  
#include <linux/of.h>           //of_find_node_by_path  
#include <linux/of_gpio.h>      //of_get_named_gpio  
#include <linux/gpio.h>         //gpio_request,gpio_direction_output,gpio_set_number  
#include <linux/atomic.h>       //atomic_t  
#include <linux/of_irq.h>       //irq_of_parse_and_map
#include <linux/interrupt.h>    //request_irq
#include <linux/timer.h>        //timer_list
#include <linux/jiffies.h>      //jiffies
#include <linux/atomic.h>       //atomic_set
#include <linux/input.h>        //input
#include <linux/platform_device.h>  //platform
#include <linux/delay.h>        //mdelay
#include <linux/i2c.h>          //i2c
#include <linux/input/mt.h>     //input multi touch

#define MAX_SUPPORT_POINTS 5 /* 5 点触摸 */
#define TOUCH_EVENT_DOWN 0x00 /* 按下 */
#define TOUCH_EVENT_UP 0x01 /* 抬起 */
#define TOUCH_EVENT_ON 0x02 /* 接触 */
#define TOUCH_EVENT_RESERVED 0x03 /* 保留 */

/* FT5426 寄存器相关宏定义 */
#define ft5426_TD_STATUS_REG 0X02 /* 状态寄存器地址 */
#define ft5426_DEVICE_MODE_REG 0X00 /* 模式寄存器 */
#define FT5426_IDG_MODE_REG 0XA4 /* 中断模式 */
#define ft5426_READLEN 29 /* 要读取的寄存器个数 */

/* 设备结构体 */
struct ft5426_dev {
    struct device_node *nd;     /* 设备节点 */
    int irq_pin, reset_pin;     /* 中断和复位的GPIO号 */
    int irq_num;                /* 中断号 */
    void *private_data;         /* 私有数据 */
    struct i2c_client *client;  /* 保存系统分配的client */
    struct input_dev *input;    /* input_dev结构体成员变量 */
};
static struct ft5426_dev ft5426;  /* 实例ft5426_dev结构体 */

/* 3.1 读取ft5426的N个寄存器值 */
static int ft5426_read_regs(struct ft5426_dev *dev, u8 reg, void *val, int len) {
    struct i2c_client *client = (struct i2c_client *)dev->client;
    /* msg[0]发送从机地址来连接对应的从机   msg[1]发送连接从机设备对应的寄存器 */
    struct i2c_msg msg[2] = {
        [0] = {
            .addr  = client->addr,  //从机地址
            .flags = 0,             //表示发送数据,也就是控制位为写
            .buf   = &reg,          //发送需要读取的寄存器地址
            .len   = 1,             //发送读取的寄存器地址长度为1个字节
        },

        [1] = {
            .addr  = client->addr,  //从机地址
            .flags = I2C_M_RD,      //表示读取数据,控制位为读
            .buf   = val,           //将接收到的数据保存到缓存val中
            .len   = len,           //读取的寄存器数据长度
            
        },
    };  
    if (2 != i2c_transfer(client->adapter, msg, 2)) //判断是否为执行的消息个数
        return -1;
    return 0;
}


/* 3.2 读取ft5426一个寄存器值 */
static u8 ft5426_read_reg(struct ft5426_dev *dev, u8 reg)
{
    u8 data = 0;
    ft5426_read_regs(dev, reg, &data, 1);
    return data;
}

/* 3.3 向ft5426的N个寄存器写入数值 */
static int ft5426_write_regs(struct ft5426_dev *dev, u8 reg, u8 *buf, int len) {
    u8 send_buf[256];
    struct i2c_client *client = (struct i2c_client *)dev->client;
    /* 构建要发送的数据,也就是寄存器首地址+实际发送的数据 */
    send_buf[0] = reg;  //寄存器地址
    memcpy(&send_buf[1], buf, len); //发送的数据
    struct i2c_msg msg = {
        .addr  = client->addr,  //从机地址
        .flags = 0,             //表示发送数据,也就是控制位为写
        .buf   = send_buf,      //发送的数据,寄存器首地址+实际发送的数据
        .len   = len + 1,       //要发送的数据长度,寄存器长度+实际发送的数据的长度
    }; 
    if (1 != i2c_transfer(client->adapter, &msg, 1)) //判断是否为执行的消息个数
        return -1;
    return 0;   
}

/* 3.4 向ft5426一个寄存器写数据 */
static void ft5426_write_reg(struct ft5426_dev *dev, u8 reg, u8 data) {
    ft5426_write_regs(dev, reg, &data, 1);
}

/* 2.4 FT5426中断处理函数线程 */
static irqreturn_t ft5426_handler(int irq, void *dev_id)
{   
    int i,x,y,touch_id;
    u8 touch_type;  //触摸类型
    struct ft5426_dev *dev = dev_id;    //获取设备结构体
    u8 read_buf[29] = {0};
    int TouchPoint_len = 6; //一个触摸点信息占用6个寄存器
    bool down;

    // printk("\r\nft5426_handler\r\n");
/************************ 5 从FT5426芯片读取触摸点信息 ************************/
    ft5426_read_regs(dev, ft5426_TD_STATUS_REG, read_buf, ft5426_READLEN);
    /* 提取每个触摸点的触摸坐标数据,并以TypeB格式上报 */
    for(i = 0; i < MAX_SUPPORT_POINTS; i++) {
        u8 *buf = &read_buf[i * TouchPoint_len + 1]; //读取每个坐标点的第一个寄存器位置,偏移1位

        /* 以第一个触摸点为例,寄存器 TOUCH1_XH(地址 0X03),各位描述如下:
        * bit7:6 Event flag 0:按下 1:释放 2:接触 3:没有事件
        * bit5:4 保留
        * bit3:0 X 轴触摸点的 11~8 位。
        */
        touch_type = buf[0] >> 6;   //获取触摸类型
        if(touch_type == TOUCH_EVENT_RESERVED)    //如果没有事件,就继续下一个
            continue;

        /* 使用的CST340芯片的X、Y寄存器是反过来的,也就是X寄存器是Y寄存器的 */
        x = ((buf[2] << 8) | buf[3]) & 0x0FFF;  //高位只有4位,低位有8位
        y = ((buf[0] << 8) | buf[1]) & 0x0FFF;

        /* 以第一个触摸点为例,寄存器 TOUCH1_YH(地址 0X05),各位描述如下:
        * bit7:4 Touch ID 触摸 ID,表示是哪个触摸点
        * bit3:0 Y 轴触摸点的 11~8 位。
        */      
        touch_id = (buf[2] >> 4) & 0x0F;    //获取触摸点的ID
        down = touch_type != TOUCH_EVENT_UP;    //触摸按下,先运行后面的touch_type != TOUCH_EVENT_UP;返回真或假
        /* 上报触摸点信息 */
        input_mt_slot(dev->input, touch_id);   //设置input多点触摸槽信息
        input_mt_report_slot_state(dev->input, MT_TOOL_FINGER, down);  //设置上报槽函数的状态,参数2为手指按下工具,参数3为触摸点按下
        if(!down) { //如果按下为假,那么就获取下一个触摸点
            continue;
        }
        input_report_abs(dev->input, ABS_MT_POSITION_X, x); //上报触摸点的绝对坐标值
        input_report_abs(dev->input, ABS_MT_POSITION_Y, y); //上报触摸点的绝对坐标值
    }
    input_mt_report_pointer_emulation(dev->input, true);    //上报指针模拟,相当与模拟触摸板手指计数
    input_sync(dev->input);    //将input输入的数据同步上报
/***************************************************************************/
    return IRQ_HANDLED;
}

/* 2.2 FT5426复位引脚初始化 */
static int ft5426_ts_reset(struct i2c_client *client, struct ft5426_dev *dev)
{
    int ret = 0;
    /* 检查IO是否有效 */
    if(gpio_is_valid(dev->reset_pin)) {
        /* 申请复位IO,并且默认输出低电平,devm开头的表示申请资源后不需要手动释放,系统会自动释放 */
        ret = devm_gpio_request_one(&client->dev, dev->reset_pin, GPIOF_OUT_INIT_LOW, "edt-ft5426 reset");
        if(ret) {
            return ret;
        }
        gpio_set_value(dev->reset_pin, 0);  /* 输出低电平,开始复位 */
        msleep(20);
        gpio_set_value(dev->reset_pin, 1);  /* 输出高点平,停止复位 */
        msleep(20);
    }
    return 0;
}

/* 2.3 FT5426中断引脚初始化 */
static int ft5426_ts_irq(struct i2c_client *client, struct ft5426_dev *dev)
{
    int ret = 0;
    /* 申请中断gpio */
    if(gpio_is_valid(dev->irq_pin)) {
        ret = devm_gpio_request_one(&client->dev, dev->irq_pin, GPIOF_IN, "edt-ft5426 irq");
        if(ret) {
            dev_err(&client->dev, "Failed to request GPIO %d, errot %d\r\n", dev->irq_pin, ret);
            return ret;
        }
    }
    /* 申请中断,client->irq就是中断 */
    ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, ft5426_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, &ft5426);
    if(ret) {
        dev_err(&client->dev, "Unable to request touchscreen IRQ.\r\n");
        return ret;
    }
    return 0;
}

/* 1.2 probe函数 */
static int ft5426_probe(struct i2c_client *client, const struct i2c_device_id *id) {
    int ret = 0;
    printk("ft5426_probe\r\n");

    /* 2.1 */
    ft5426.client = client; //获取系统分配的client
    ft5426.irq_pin = of_get_named_gpio(client->dev.of_node, "interrupt-gpios", 0);   //获取irq的gpio引脚
    ft5426.reset_pin = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0); //获取reset的gpio引脚
    ft5426_ts_reset(client, &ft5426);   //ft5426复位引脚初始化
    ft5426_ts_irq(client, &ft5426);     //ft5426中断引脚初始化

    /* 3.5 初始化FT5426,我使用的是CST340触摸芯片,因此只是兼容触摸点坐标寄存器地址,但无需进行初始化,上电会自动初始化的 */
    ft5426_write_reg(&ft5426, ft5426_DEVICE_MODE_REG, 0); //进入正常模式
    ft5426_write_reg(&ft5426, FT5426_IDG_MODE_REG, 1); //FT5426中断模式

/************************** 4 input子系统框架 **************************/
    ft5426.input = devm_input_allocate_device(&client->dev);    //申请input子系统,参数是属于哪个设备
    if(!ft5426.input) {
        ret = -ENOMEM;
        goto fail;
    }
    ft5426.input->name = client->name;  //设置 input_dev 名字
    ft5426.input->id.bustype = BUS_I2C; //input_id总线类型为BUS_I2C
    ft5426.input->dev.parent = &client->dev; //设置其父设备为client->dev

    __set_bit(EV_SYN, ft5426.input->evbit); //设置同步事件
    __set_bit(EV_KEY, ft5426.input->evbit); //设置产生按键事件
    __set_bit(EV_ABS, ft5426.input->evbit); //设置绝对坐标事件
    __set_bit(BTN_TOUCH, ft5426.input->keybit); //设置产生哪些按键值

    /* 单点触摸 */
    input_set_abs_params(ft5426.input, ABS_X, 0, 1024, 0, 0);
    input_set_abs_params(ft5426.input, ABS_Y, 0, 600, 0, 0);

    /* 多点触摸 */
    input_mt_init_slots(ft5426.input, MAX_SUPPORT_POINTS, 0);   //初始化input多点触摸槽,最大支持5个触摸点
    input_set_abs_params(ft5426.input, ABS_MT_POSITION_X, 0, 1024, 0, 0);
    input_set_abs_params(ft5426.input, ABS_MT_POSITION_Y, 0, 600, 0, 0);
    
    /* 注册input子系统 */
    ret = input_register_device(ft5426.input);
    if (ret)
        goto fail;    
/*********************************************************************/
fail:
    return ret;
}

/* 1.3 remove函数 */
static int ft5426_remove(struct i2c_client *client) {
    int ret = 0;
    printk("ft5426_remove\r\n");
    /* 释放 input_dev */
    input_unregister_device(ft5426.input);
    return ret;
}

/* 1.4 传统的匹配表 */
static const struct i2c_device_id ft5426_id[] = {
    {"edt-ft5426",0},
    {}
};

/* 1.5 设备树匹配表 */
static const struct of_device_id ft5426_of_match[] = {
    { .compatible = "edt,edt-ft5426" },
    {}
};

/* 1.1 i2c_driver结构体 */
static struct i2c_driver ft5426_driver = {
    .probe = ft5426_probe,
    .remove = ft5426_remove,
    .driver = {
        .name = "edt_ft5426",
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(ft5426_of_match),
    },
    .id_table = ft5426_id,
};

/* 1.6 i2c驱动模块注册和注销 */
module_i2c_driver(ft5426_driver);	  

/* 1.7 许可证和作者 */
MODULE_LICENSE("GPL");  
MODULE_AUTHOR("djw");  

3、驱动运行测试

①使用命令:depmod 和 modprobe ft5426.ko 加载驱动程序
驱动加载成功后会显示下图信息:
驱动程序开发:多点电容触摸屏
在/dev/input目录下可以看到多出一个没有加载驱动前的事件event2,如下图:
驱动程序开发:多点电容触摸屏
②使用命令:hexdump /dev/input/event2 可查看到多点触摸屏上报的TypeB类型的原始数据,如下图:
驱动程序开发:多点电容触摸屏

4、将驱动添加到内核中

①linux 内核里面将触摸屏驱动放到了 drivers/input/touchscreen 目录下,因此我们要将 ft5x06.c 拷贝到此目录下,命令如下:

cp ft5426.c /drivers/input/touchscreen/ -f

②修改 drivers/input/touchscreen 目录下的 Makefile,在最下面添加下面一行,如下图:
驱动程序开发:多点电容触摸屏
③进入 linux 内核源码目录,输入make menuconfig命令打开图形化配置界面,Touchscreens项要使能能,linux内核才会初始化调用触摸屏功能的驱动。

Location:
 -> Device Drivers
  -> Input device support
   -> Generic input layer (needed for keyboard, mouse, …) (INPUT [=y])
    -> Touchscreens (INPUT_TOUCHSCREEN [=y])

④这时再调用 hexdump /dev/input/event2 命令可能就不行了,因为内核在一开始启动就初始化了ft5426.c触摸屏驱动程序,那么它应该就在event1中了,不过具体还是要看实际的。
 
其重启开机后可以看到加载ft5426.c驱动程序的日志,如下图:
驱动程序开发:多点电容触摸屏

 
 

三、tslib移植

①获取 tslib 源码,在git 地址为 tslib源码链接,下载解压后,得到名为“tslib-1.21”的目录,此目录下就是 tslib 源码。
②修改 tslib 源码所属用户,命令如下:注意:我的ubuntu登陆用户名是djw

sudo chown djw:djw tslib-1.21 -R

③编译 tslib 的时候需要先在 ubuntu 中安装一些文件,防止编译 tslib 过程中出错,命令如下:

sudo apt-get install autoconf
sudo apt-get install automake
sudo apt-get install libtool

④首先在 ubuntu 中创建一个名为“tslib”的目录存放编译结果,列如我的是/home/djw/linux/IMX6ULL/tool/tslib,输入如下配置命令得到我们想要的tslib相关文件,如下:

cd tslib-1.21/ //进入 tslib 源码目录
./autogen.sh
./configure --host=arm-linux-gnueabihf --prefix=/home/djwi/linux/IMX6ULL/tool/tslib
make //编译
make install //安装

完成以后,tslib目录如下图:


驱动程序开发:多点电容触摸屏

⑤将tslib目录下的文件拷贝到开发板的跟文件系统中,命令如下:

sudo cp * -rf /home/djw/linux/nfs/rootfs

⑥开启开发板,打开/etc/ts.conf文件,如下图,该行不能屏蔽:

命令:vi /etc/ts.conf

驱动程序开发:多点电容触摸屏
⑦配置tslib,打开/etc/profile文件,没有的可以自己创建一个,添加如下图内容:
驱动程序开发:多点电容触摸屏
加好后的profile文件,如下图:


驱动程序开发:多点电容触摸屏

⑧配置好上面的步骤,就可以对tslib工具进行测试了,先重启开发板,然后输入 ts_test_mt命令即可在开发板触摸屏上看到触摸测试界面了,如下图:
驱动程序开发:多点电容触摸屏