Bootstrap

RK3568 android11 适配敦泰触摸屏 FocalTech-ft5526

一,FocalTech触摸屏简介

  1. FocalTech 的触控控制器常用于各种触摸屏,包括电容式和电阻式屏幕。支持多点触控,能够识别多个手指的输入。
    本文提到的 ft5526 支持多达 10 个触控点,能够同时识别多个手指的输入,适合需要复杂手势操作的应用。
  2. 工作电压:通常为 1.8V 或 3.3V,具体取决于设备设计。
  3. 通讯接口:支持 I2C 或 SPI 通信接口,方便与主控芯片连接。

二,DTS配置

查看原理图TP是挂在i2c1节点下:
在这里插入图片描述
注:不同主板节点以及GPIO引脚是不同的,可查看对应原理图确定。

&i2c1 {
        status = "okay";
        
         focaltech@38 {
                 status = "okay";
                 compatible = "focaltech,fts";
                 reg = <0x38>;
                 focaltech,irq-gpio = <&gpio0 RK_PB5 IRQ_TYPE_LEVEL_LOW>; //中断脚
                 focaltech,reset-gpio = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>; //复位脚
                 focaltech,max-touch-number = <5>; //最大触摸数支持
                 focaltech,display-coords = <0 0 1280 800>; //以像素为单位的显示分辨率。一个由minX, minY, maxX和maxY组成的四元数组
         };
};

属性解析:

focaltech,irq-gpio :中断脚
focaltech,reset-gpio :复位脚
focaltech,max-touch-number :最大触摸数支持
focaltech,display-coords :以像素为单位的显示分辨率。一个由minX, minY, maxX和maxY组成的四元数组


三,驱动文件配置

在这里插入图片描述
主要驱动文件如上图所示。

1. focaltech_core.c

static int fts_gpio_configure(struct fts_ts_data *data)   //用于配置 FocalTech 触摸屏 GPIO(通用输入输出)引脚

在这个函数中,可以看到读取dts中配置的GPIO引脚信息:

static int fts_gpio_configure(struct fts_ts_data *data)
{
    int ret = 0;

    FTS_FUNC_ENTER();
    /* request irq gpio */
    if (gpio_is_valid(data->pdata->irq_gpio)) {
        ret = gpio_request(data->pdata->irq_gpio, "fts_irq_gpio");
        if (ret) {
            FTS_ERROR("[GPIO]irq gpio request failed");
            goto err_irq_gpio_req;
        }

        ret = gpio_direction_input(data->pdata->irq_gpio);
        if (ret) {
            FTS_ERROR("[GPIO]set_direction for irq gpio failed");
            goto err_irq_gpio_dir;
        }
    }

    /* request reset gpio */
    if (gpio_is_valid(data->pdata->reset_gpio)) {
        ret = gpio_request(data->pdata->reset_gpio, "fts_reset_gpio");
        if (ret) {
            FTS_ERROR("[GPIO]reset gpio request failed");
            goto err_irq_gpio_dir;
        }

        ret = gpio_direction_output(data->pdata->reset_gpio, 1);
        if (ret) {
            FTS_ERROR("[GPIO]set_direction for reset gpio failed");
            goto err_reset_gpio_dir;
        }
    }

    FTS_FUNC_EXIT();
    return 0;

err_reset_gpio_dir:
    if (gpio_is_valid(data->pdata->reset_gpio))
        gpio_free(data->pdata->reset_gpio);
err_irq_gpio_dir:
    if (gpio_is_valid(data->pdata->irq_gpio))
        gpio_free(data->pdata->irq_gpio);
err_irq_gpio_req:
    FTS_FUNC_EXIT();
    return ret;
}

2. focaltech_core.h

头文件用来定义TP驱动程序的功能。使用#define定义私有常量和宏;
截取部分定义代码:

/*****************************************************************************
* Private constant and macro definitions using #define
*****************************************************************************/
#define FTS_MAX_POINTS_SUPPORT              10 /* constant value, can't be changed */
#define FTS_MAX_KEYS                        4
#define FTS_KEY_DIM                         10
#define FTS_COORDS_ARR_SIZE                 4
#define FTS_ONE_TCH_LEN                     6

3. 移植驱动

驱动包资源链接附在文末。

a. 将驱动包解压后整个拷贝到以下目录
./kernel/drivers/input/touchscreen
b. 修改 touchscreen 目录下的 Makefile以及Kconfig
kernel/drivers/input/touchscreen/Makefile中添加:

obj-$(CONFIG_TOUCHSCREEN_FTS)   += focaltech_touch/

------------------------------------------------------------------------
kernel/drivers/input/touchscreen/Kconfig中添加:

source "drivers/input/touchscreen/focaltech_touch/Kconfig"
c. 内核中加载驱动
kernel/arch/arm64/configs/rockchip_defconfig中添加:

CONFIG_TOUCHSCREEN_FTS=y
CONFIG_TOUCHSCREEN_FTS_DIRECTORY="focaltech_touch"

四,调试

1. 上电时的内核打印日志

和触摸屏相关的打印都是 [FTS_TS] 开头的:
在这里插入图片描述

2. 查看I2C设备

在这里插入图片描述
可以在目录下看到i2c挂载点。

3. 报点问题

源码路径:kernel/drivers/input/touchscreen/focaltech_touch/focaltech_core.c
fts_input_report_b函数是触摸屏驱动中处理触摸事件的一个部分,特别是处理触摸按下(DOWN)事件的逻辑。

static int fts_input_report_b(struct fts_ts_data *ts_data, struct ts_event *events)
{
    int i = 0;
    int touch_down_point_cur = 0;
    int touch_point_pre = ts_data->touch_points;
    u32 max_touch_num = ts_data->pdata->max_touch_number;
    bool touch_event_coordinate = false;
    struct input_dev *input_dev = ts_data->input_dev;

    for (i = 0; i < ts_data->touch_event_num; i++) {
        if (fts_input_report_key(ts_data, &events[i]) == 0) {
            continue;
        }

        touch_event_coordinate = true;
        if (EVENT_DOWN(events[i].flag)) {                  //EVENT_DOWN(events[i].flag) 检查当前事件标志是否表示触控按下.
            input_mt_slot(input_dev, events[i].id);        //input_mt_slot(input_dev, events[i].id);指定当前活动的触控点 ID,为以下的多点触控报告做准备.
            input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, true);    //报告当前插槽中的触控工具(例如手指)处于按下状态.
#if FTS_REPORT_PRESSURE_EN
            input_report_abs(input_dev, ABS_MT_PRESSURE, events[i].p);
#endif
            input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, events[i].area);    //触摸的主要面积.
            input_report_abs(input_dev, ABS_MT_POSITION_X, events[i].x);    //触摸点的 x 坐标
            input_report_abs(input_dev, ABS_MT_POSITION_Y, events[i].y);    //触摸点的 y 坐标


            touch_down_point_cur |= (1 << events[i].id); //用位运算更新当前和之前的触控点记录,标记按下的触控 ID.
            touch_point_pre |= (1 << events[i].id);


            if ((ts_data->log_level >= 2) ||
                ((1 == ts_data->log_level) && (FTS_TOUCH_DOWN == events[i].flag))) {
                FTS_DEBUG("[B]P%d(%d, %d)[p:%d,tm:%d] DOWN!",
                          events[i].id, events[i].x, events[i].y,
                          events[i].p, events[i].area);
            }
        } else {
            input_mt_slot(input_dev, events[i].id);
            input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false);
            touch_point_pre &= ~(1 << events[i].id);
            if (ts_data->log_level >= 1) FTS_DEBUG("[B]P%d UP!", events[i].id);
        }
    }

    if (unlikely(touch_point_pre ^ touch_down_point_cur)) {
        for (i = 0; i < max_touch_num; i++)  {
            if ((1 << i) & (touch_point_pre ^ touch_down_point_cur)) {
                if (ts_data->log_level >= 1) FTS_DEBUG("[B]P%d UP!", i);
                input_mt_slot(input_dev, i);
                input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false);
            }
        }
    }

    if (touch_down_point_cur)
        input_report_key(input_dev, BTN_TOUCH, 1);
    else if (touch_event_coordinate || ts_data->touch_points) {
        if (ts_data->touch_points && (ts_data->log_level >= 1))
            FTS_DEBUG("[B]Points All Up!");
        input_report_key(input_dev, BTN_TOUCH, 0);
    }

    ts_data->touch_points = touch_down_point_cur;
    input_sync(input_dev);
    return 0;
}

a. x,y轴坐标需要更换

在触摸事件的处理过程中,发现触摸事件的 x 坐标和 y 坐标被颠倒, 可以交换这两个函数调用的参数:

input_report_abs(input_dev, ABS_MT_POSITION_X, events[i].y);  // 将 y 赋值给 x  
input_report_abs(input_dev, ABS_MT_POSITION_Y, events[i].x);  // 将 x 赋值给 y
b. x,y轴需要镜像变换
int screen_width = 800;  // 假设屏幕的宽
int screen_length = 1280;   // 假设屏幕的长
input_report_abs(input_dev, ABS_MT_POSITION_X, screen_width - events[i].x);  
input_report_abs(input_dev, ABS_MT_POSITION_Y, screen_length - events[i].y);

screen_width 为触摸屏的实际宽度,以保证 X 轴的值在报告时被镜像翻转。
screen_length 为触摸屏的实际长度,以保证 Y 轴的值在报告时被镜像翻转。


TP驱动包资源链接:
https://download.csdn.net/download/weixin_45639314/90020237?spm=1001.2014.3001.5503

;