设计了一块嵌入式电路板,运行linux系统,主控CPU为px30,需要适配一块触摸驱动IC为GT917S的5.0寸触摸屏。
SDK中原本适配的驱动IC为gsl680,.config配置如下:
取消gslX680 touchpad driver for 9tripod linux,选中Goodix gt9xx support for rockchip platform;
进入到px30_linux/kernel/arch/arm64/boot/dts/rockchip目录下,打开x30.dts文件,i2c1下有gslx680和gt1x两个节点:
&i2c1 {
status = "okay";
gslx680@40 {
compatible = "9tripod,gslx680";
reg = <0x40>;
touch-gpio = <&gpio0 5 IRQ_TYPE_EDGE_RISING>;
reset-gpio = <&gpio0 12 GPIO_ACTIVE_LOW>;
max-x = <1024>;
max-y = <600>;
};
gt1x: gt1x@14 {
compatible = "goodix,gt1x";
reg = <0x14>;
power-supply = <&vcc3v3_lcd>;
goodix,rst-gpio = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>;
goodix,irq-gpio = <&gpio0 RK_PA5 IRQ_TYPE_LEVEL_LOW>;
};
};
将其中的gt1x节点改为gt9xx,更改之后如下:
&i2c1 {
status = "okay";
gslx680@40 {
compatible = "9tripod,gslx680";
reg = <0x40>;
touch-gpio = <&gpio0 5 IRQ_TYPE_EDGE_RISING>;
reset-gpio = <&gpio0 12 GPIO_ACTIVE_LOW>;
max-x = <1024>;
max-y = <600>;
};
gt9xx: gt9xx@14 {
compatible = "goodix,gt9xx";
reg = <0x14>;
power-supply = <&vcc3v3_lcd>;
goodix,rst-gpio = <&gpio0 RK_PB4 GPIO_ACTIVE_HIGH>;
goodix,irq-gpio = <&gpio0 RK_PA5 IRQ_TYPE_LEVEL_LOW>;
max-x = <720>;
max-y = <1280>;
};
};
我硬件电路上触屏是挂在i2c1总线上的,rst连接的PB4,irq连接的PA5,I2C地址需要根据驱动IC的datasheet来确定,GT917S有两个i2c地址,0x14和0x5d,任意设置其中一个即可,我这里设置0x14。
修改了.config和dts之后重新编译了kernel,将新生成的boot.img烧写到主板,待主板重新启动后,在触屏上操作了几下,界面没有任何反应,接下来需要确定i2c总线上是否有0x14这个设备;执行
i2cdetect -r -y 1
命令,检测到i2c1总线上有0x14的设备。
执行hexdump /dev/input/event1命令,点击触屏时有数据上传,证明设备可以收到触摸时间以及坐标,执行结果如下:
目前点击触屏,界面还是没有反应,怀疑是触屏里没有烧录配置文件或者配置文件不对,所以联系触屏(所使用的屏幕和液晶、触屏组合屏)厂家了解情况和获取配置文件,厂家反馈触屏里面烧写了配置文件,并且坐标零点在左上角,那触屏应该也没有问题,不过厂家也发送了一个驱动文件包,里面有两个版本的驱动,一个是V2.6.0.3适用于MTK Android M的,一个是v2.8.0.2适用于Android的。我又怀疑是SDK里的驱动版本太低,驱动GT917S有问题,所以参照的是v2.8.0.2驱动,将文件夹下的goodix_tool.c、gt9xx.c、gt9xx.h、gt9xx_update.c替换了SDK/kernel/drivers/input/touchscreen/gt9xx路径下对应的文件,将v2.8.0.2驱动中的Kconfig文件中的内容添加到SDK/kernel/drivers/input/touchscreen路径下的Kconfig文件中,添加之前需要删除关于gt9xx的一些配置,添加内容如下:
config TOUCHSCREEN_GT9XX
bool "Goodix touchpanel GT9xx series"
depends on I2C
help
Say Y here if you have a Goodix GT9xx touchscreen
controller.
If unsure, say N.
config TOUCHSCREEN_GT9XX_UPDATE
tristate "Goodix GT9xx touch controller auto update support"
depends on TOUCHSCREEN_GT9XX
default y
help
Enable this for support firmware update.
Say Y here if you want update touch controller firmware.
If unsure, say N.
config TOUCHSCREEN_GT9XX_TOOL
tristate "Goodix GT9xx Tools for debuging"
depends on TOUCHSCREEN_GT9XX
default y
help
This implement interface support for Goodix GT9xx
touchscreen debug.
Say Y here if you want to have a Android app debug interface
to your system.
If unsure, say N.
接下来修改SDK/kernel/arch/arm64/boot/dts/rockchip下的x30.dts文件,修改i2c1下的14节点,修改后的内容如下:
gt9xx: gt9xx@14 {
compatible = "goodix,gt9xx";
reg = <0x14>;
status = "okay";
interrupt-parent = <&gpio0>;
interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
pinctrl-names = "default", "int-output-low","int-output-high", "int-input";
pinctrl-0 = <&ts_int_default>;
pinctrl-1 = <&ts_int_output_low>;
pinctrl-2 = <&ts_int_output_high>;
pinctrl-3 = <&ts_int_input>;
power-supply = <&vcc3v3_lcd>;
vcc_i2c-supply = <&vcc_3v0>;
reset-gpios = <&gpio0 RK_PB4 GPIO_ACTIVE_LOW>;
irq-gpios = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>;
irq-flags = <2>;
touchscreen-max-id = <11>;
touchscreen-size-x = <720>;
touchscreen-size-y = <1280>;
touchscreen-max-w = <512>;
touchscreen-max-p = <512>;
/*touchscreen-key-map = <172>, <158>; *//*KEY_HOMEPAGE=172,KEY_BACK=158,KEY_MENU=139*/
goodix,slide-wakeup = <0>;
goodix,type-a-report = <0>;
goodix,driver-send-cfg = <0>;
goodix,resume-in-workqueue = <0>;
goodix,int-sync = <1>;
goodix,swap-x2y = <0>;
goodix,esd-protect = <1>;
goodix,auto-update-cfg = <0>;
goodix,power-off-sleep = <0>;
goodix,pen-suppress-finger = <0>;
goodix,cfg-group0 = [53 D0 02 00 05 05 F5 D5 21 48 2D 0F 5A 41 0E 05 00 00 32 32 20 00 05 14 14 1A 14 8B 2B 00];
};
参数的名称、如irq-flags、irq-flags、goodix,driver-send-cfg需要和gt9xx.c文件中引用的一致,不然驱动获取不了dts文件中配置的参数,会使用驱动中默认的,这里配置goodix,driver-send-cfg为1,则驱动不会发送配置文件。
打开命令终端,进入SDK/kernel目录,执行make menuconfig命令,配置如下:
选中Goodix touchpanel GT9xx series,其余两个不选,Goodix GT9xx Tools for debuging在android系统下才有效,如果选中,编译会保存,选中之后保存,然后执行如下命令保存内核和编译内核:
cp .config arch/arm64/configs/x30_linux_defconfig
cd ..
./mk.sh -k
将编译好的boot.img烧写到板卡上,点击触屏,界面依然没有反应,执行dmesg | grep goodix查找开机日志中关于goodix的日志,结果如下:
[root@px30_64:/]# dmesg | grep goodix
[ 3.035361] goodix-ts 1-0014: Error applying setting, reverse things back
[ 3.042333] goodix-ts 1-0014: GTP Driver Version: V2.8.0.2<2017/12/14>
[ 3.048901] goodix-ts 1-0014: GTP I2C Address: 0x14
[ 3.053840] goodix-ts 1-0014: touch input parameters is [id x y w p]<11 720 1280 512 512>
[ 3.062048] goodix-ts 1-0014: int-sync enabled
[ 3.066543] goodix-ts 1-0014: esd-protect enabled
[ 3.071292] goodix-ts 1-0014: key-map is [ac 9e 0 0]
[ 3.076398] goodix-ts 1-0014: Looking up vdd_ana-supply from device tree
[ 3.076422] goodix-ts 1-0014: Looking up vdd_ana-supply property in node /i2c@ff190000/gt9xx@14 failed
[ 3.082794] goodix-ts 1-0014: Looking up vcc_i2c-supply from device tree
[ 3.083774] goodix-ts 1-0014: Success init pinctrl
[ 3.088668] goodix-ts 1-0014: Success request irq-gpio
[ 3.093857] goodix-ts 1-0014: Success request rst-gpio
[ 3.099040] goodix-ts 1-0014: Guitar reset
[ 3.190676] goodix-ts 1-0014: Error applying setting, reverse things back
[ 3.198555] goodix-ts 1-0014: I2C Addr is 14
[ 3.203897] goodix-ts 1-0014: IC Version: 1158_0100
[ 3.209973] goodix-ts 1-0014: Driver set not send config
[ 3.237697] goodix-ts 1-0014: Use slot report protocol
[ 3.243282] input: goodix-ts as /devices/virtual/input/input1
[ 3.249424] goodix-ts 1-0014: INT num 53, trigger type:2
[ 3.255189] goodix-ts 1-0014: create proc entry gt9xx_config success
[ 3.261631] goodix-ts 1-0014: ESD on
可以看出检测到了触屏硬件设备,并且驱动也正常,这下不知问题在哪里,那就一步一步验证,先试用工具检测触屏,厂家除了发送驱动文件,还发送的汇顶的上位机检测工具:GuitarTestPlatform.exe,手上正好也有一个汇顶的触屏测试工装,然后将触屏接入到工装上,运行GuitarTestPlatform.exe软件,在屏幕上画了一条斜线,上位机上也显示了一条斜线,则证明触屏功能是正常的,效果如下:
那接下来还是查找驱动的问题,在网上搜索了一些关于linux系统下调试GT9xx触屏的博客,基本流程都是这样,没有什么特别的,不过有的博客中提到了可以使用evtest /dev/input/event1命令检测触屏上报的事件及坐标,结果如下:
[root@px30_64:/]# evtest /dev/input/event1
Input driver version is 1.0.1
Input device ID: bus 0x18 vendor 0xdead product 0xbeef version 0x28bb
Input device name: "goodix-ts"
Supported events:
Event type 0 (EV_SYN)
Event type 1 (EV_KEY)
Event code 330 (BTN_TOUCH)
Event code 331 (BTN_STYLUS)
Event code 332 (BTN_STYLUS2)
Event type 3 (EV_ABS)
Event code 47 (ABS_MT_SLOT)
Value 0
Min 0
Max 15
Event code 48 (ABS_MT_TOUCH_MAJOR)
Value 0
Min 0
Max 512
Event code 53 (ABS_MT_POSITION_X)
Value 0
Min 0
Max 720
Event code 54 (ABS_MT_POSITION_Y)
Value 0
Min 0
Max 1280
Event code 55 (ABS_MT_TOOL_TYPE)
Value 0
Min 0
Max 2
Event code 57 (ABS_MT_TRACKING_ID)
Value 0
Min 0
Max 11
Event code 58 (ABS_MT_PRESSURE)
Value 0
Min 0
Max 512
Properties:
Property type 1 (INPUT_PROP_DIRECT)
Testing ... (interrupt to exit)
Event: time 1501925732.831106, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 7
Event: time 1501925732.831106, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 642
Event: time 1501925732.831106, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 257
Event: time 1501925732.831106, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 14
Event: time 1501925732.831106, type 3 (EV_ABS), code 58 (ABS_MT_PRESSURE), value 14
Event: time 1501925732.831106, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1
Event: time 1501925732.831106, -------------- SYN_REPORT ------------
Event: time 1501925733.140501, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value -1
Event: time 1501925733.140501, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 0
Event: time 1501925733.140501, -------------- SYN_REPORT ------------
可以看出触屏上报的按下、松开事件及X、Y的坐标都是正确的,这时怀疑可能是系统还有什么配置需要修改,问了一些专职调试驱动的网友,他们也想不到问题在哪里,索性有自己在网友搜索一些博客浏览,经过了一天的摸索,还是没有找到问题的答案。
目前想通过对比开发板上的触屏上报的是什么内容,就将开发板烧写了厂家给的linux系统,然后使用串口进行命令调试,设备开机之后,执行evtest /dev/input/event1命令检测触屏上报的事件及坐标,结果如下:
gslX680
和我自己的触屏上报的内容对比,发现EV_ABS的code值不一样,开发板上报的code值为ABS_X、ABS_Y,我自己的触屏上报的code值为ABS_MT_POSITION_X、ABS_MT_POSITION_Y,并且还多了一些其它内容,在网上查了下这些code值的含义,MT相关的code值表示多点触摸事件,现在猜测问题点可能在这里,查看开发板的触屏驱动文件,发现开发板商家基于gslX680官方的驱动做了修改,做要是去掉了MT相关的参数设置、上报,改为了ABS相关的参数设置、上报,所以我也尝试着修改gt9xx.c文件的内容,重写了static void gtp_mt_slot_report(struct goodix_ts_data *ts, u8 touch_num, struct goodix_point_t *points)和static s8 gtp_request_input_dev(struct goodix_ts_data *ts)两个函数,经过几次修改验证之后,点击触屏界面有反应啦!
重写之后的代码如下:
static void gtp_mt_slot_report(struct goodix_ts_data *ts, u8 touch_num,
struct goodix_point_t *points)
{
int i;
u16 cur_touch = 0;
static u16 pre_touch;
static u8 pre_pen_id;
for (i = 0; i < ts->pdata->max_touch_id; i++)
{
if (touch_num && i == points->id)
{
input_mt_slot(ts->input_dev, points->id);
if (points->tool_type == GTP_TOOL_PEN)
{
input_mt_report_slot_state(ts->input_dev,
MT_TOOL_PEN, true);
pre_pen_id = points->id;
}
else
{
input_mt_report_slot_state(ts->input_dev,
MT_TOOL_FINGER, true);
}
// input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
// points->x);
// input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
// points->y);
// input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
// points->w);
// input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
// points->p);
input_report_abs(ts->input_dev, ABS_X, points->x);
input_report_abs(ts->input_dev, ABS_Y, points->y);
input_report_key(ts->input_dev, BTN_TOUCH, 1);
cur_touch |= 0x01 << points->id;
points++;
}
else if (pre_touch & 0x01 << i)
{
// input_mt_slot(ts->input_dev, i);
if (pre_pen_id == i)
{
// input_mt_report_slot_state(ts->input_dev,
// MT_TOOL_PEN, false);
/* valid id will < 10, so set id to 0xff to
* indicate a invalid state
*/
pre_pen_id = 0xff;
}
else
{
// input_mt_report_slot_state(ts->input_dev,
// MT_TOOL_FINGER, false);
}
}
}
pre_touch = cur_touch;
if (!pre_touch) {
input_report_key(ts->input_dev, BTN_TOUCH, 0);
}
/* report BTN_TOUCH event */
// input_mt_sync_frame(ts->input_dev);
input_sync(ts->input_dev);
}
static s8 gtp_request_input_dev(struct goodix_ts_data *ts)
{
s8 ret = -1;
u8 index = 0;
ts->input_dev = input_allocate_device();
if (!ts->input_dev) {
dev_err(&ts->client->dev, "Failed to allocate input device\n");
return -ENOMEM;
}
/*custom*/
// ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY)
// | BIT_MASK(EV_ABS);
// if (!ts->pdata->type_a_report) {
// input_mt_init_slots(ts->input_dev, 16, INPUT_MT_DIRECT);
// dev_info(&ts->client->dev, "Use slot report protocol\n");
// } else {
// __set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
// __set_bit(BTN_TOUCH, ts->input_dev->keybit);
// dev_info(&ts->client->dev, "Use type A report protocol\n");
// }
// input_set_capability(ts->input_dev, EV_KEY, GTP_PEN_BUTTON1); //必须注释
// input_set_capability(ts->input_dev, EV_KEY, GTP_PEN_BUTTON2); //必须注释
/* touch key register */
for (index = 0; index < ts->pdata->key_nums; index++)
input_set_capability(ts->input_dev, EV_KEY,
ts->pdata->key_map[index]);
if (ts->pdata->slide_wakeup)
input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);
if (ts->pdata->swap_x2y)
GTP_SWAP(ts->pdata->abs_size_x, ts->pdata->abs_size_y);
// input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0,
// ts->pdata->abs_size_x, 0, 0);
// input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0,
// ts->pdata->abs_size_y, 0, 0);
// input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0,
// ts->pdata->max_touch_width, 0, 0);
// input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0,
// ts->pdata->max_touch_pressure, 0, 0);
// input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0,
// ts->pdata->max_touch_id, 0, 0);
// if (!ts->pdata->type_a_report) {
// input_set_abs_params(ts->input_dev, ABS_MT_TOOL_TYPE,
// 0, MT_TOOL_MAX, 0, 0);
// } else {
// __set_bit(BTN_TOOL_PEN, ts->input_dev->keybit);
// __set_bit(BTN_TOOL_FINGER, ts->input_dev->keybit);
// }
set_bit(BTN_TOUCH, ts->input_dev->keybit);
set_bit(EV_ABS, ts->input_dev->evbit);
set_bit(EV_KEY, ts->input_dev->evbit);
input_set_abs_params(ts->input_dev, ABS_X, 0, ts->pdata->abs_size_x, 0, 0);
input_set_abs_params(ts->input_dev, ABS_Y, 0, ts->pdata->abs_size_y, 0, 0);
ts->input_dev->name = goodix_ts_name;
ts->input_dev->phys = goodix_input_phys;
ts->input_dev->id.bustype = BUS_I2C;
ts->input_dev->id.vendor = 0xDEAD;
ts->input_dev->id.product = 0xBEEF;
ts->input_dev->id.version = 10427;
ret = input_register_device(ts->input_dev);
if (ret) {
dev_err(&ts->client->dev, "Register %s input device failed\n",
ts->input_dev->name);
input_free_device(ts->input_dev);
return -ENODEV;
}
return 0;
}