设计了一块嵌入式电路板,运行linux系统,主控CPU为px30,需要适配一块触摸驱动IC为GT917S的5.0寸触摸屏。

SDK中原本适配的驱动IC为gsl680,.config配置如下:

Android触摸移植linux linux安装触摸板驱动_驱动程序

 取消gslX680 touchpad driver for 9tripod linux,选中Goodix gt9xx support for rockchip platform;

Android触摸移植linux linux安装触摸板驱动_驱动程序_02

进入到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命令,点击触屏时有数据上传,证明设备可以收到触摸时间以及坐标,执行结果如下:

Android触摸移植linux linux安装触摸板驱动_touchscreen_03

目前点击触屏,界面还是没有反应,怀疑是触屏里没有烧录配置文件或者配置文件不对,所以联系触屏(所使用的屏幕和液晶、触屏组合屏)厂家了解情况和获取配置文件,厂家反馈触屏里面烧写了配置文件,并且坐标零点在左上角,那触屏应该也没有问题,不过厂家也发送了一个驱动文件包,里面有两个版本的驱动,一个是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命令,配置如下:

Android触摸移植linux linux安装触摸板驱动_驱动程序_04

选中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软件,在屏幕上画了一条斜线,上位机上也显示了一条斜线,则证明触屏功能是正常的,效果如下:

Android触摸移植linux linux安装触摸板驱动_驱动程序_05

那接下来还是查找驱动的问题,在网上搜索了一些关于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;
}