• GOODIX TOUCH驱动移植


    基于imx6芯片,Linux系统的touch驱动移植,IC是GOODIX GA657X

    1.总体架构

    参考:https://blog.csdn.net/zhaoxiaoqiang10_/article/details/24009889
    硬件部分:其实触摸屏原理也比较简单,触摸屏和主控芯片间的联系,如下主要有三部分:

    1、IIC部分,初始化gt657x的数据和传回主控制的坐标位置信息就是通过IIC这条线传输的;

    2、INT,当gt657x初触摸时,会发出中断通知主控接收信息(坐标数据);

    3、gt657x电源、复位这一部分,不同芯片有所不同,可以根据触摸屏芯片来配置

    软件部分:
    在这里插入图片描述

    2.移植

    配置iic,在设备树中添加ga657x的配置信息,包括设备地址、ping脚定义、参数配置

    ga657x@5d {
        	compatible = "goodix,ga657x";
        	reg = <0x5d>;	//设备地址
        	status = "okay";
    
    //    	pinctrl-names = "default";
    //    	pinctrl-0 = <&ts_int_default>;
    		reset-gpios = <&gpio3 31 GPIO_ACTIVE_LOW>;	//reset管脚
        	tp-irq-gpio = <&gpio4 10 GPIO_ACTIVE_LOW>;	//中断脚
        	irq-flags = <2>;
    
        	touchscreen-max-id = <5>;
        	touchscreen-size-x = <1279>;	//触摸屏的分辨率大小
        	touchscreen-size-y = <719>;
        	touchscreen-max-w = <255>;
        	touchscreen-max-p = <255>;
        	touchscreen-key-map = <50>, <35>, <103>, <108>; 	//按键地址
        	goodix,slide-wakeup = <0>;
        	goodix,type-a-report = <0>;
        	goodix,driver-send-cfg = <1>;	//根据需求配置,1 会将驱动中的touch配置更新到固件中,0 则默认使用固件中刷写的配置
        	goodix,resume-in-workqueue = <0>;
        	goodix,swap-x2y = <0>;
        	goodix,esd-protect = <0>;
        	goodix,auto-update = <0>;
        	goodix,auto-update-cfg = <0>;
        	goodix,power-off-sleep = <0>;
        	goodix,pen-suppress-finger = <0>;
        	goodix,cfg-group2 = [
    			 42 65 1B 1D 24 18 00 3B 52 9C 96 00 1E 50 3C 00 00 17 19 1C 14 22 FF 1E 78 00 00 0F 11 5E 22 22 F4 00 00 00 F0 00 05 D0 02 12 11 AA 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 01 00 14 15 16 17 18 19 1A 1B 1C 1D 26 25 24 23 22 21 20 1F 1E 1D 1C 1B 19 18 17 16 15 14 13 12 11 10 0F 0E 0D 0C 0B 0A 09 08 07 06 05 04 03 02 27 FF FF FF FF FF 00 19 2D 94 C1 52 0A 04 B4 B4 1B 9C 9C 26 80 80 2D 00 76 76 00 00 00 00 00 00 02 00 D4 04 5C 46 32 20 AA 02 27 12 10 8E 8C BF BF BF BF BF BF 02 14 03 2D 23 AF 05 0F 28 06 81 28 14 1E 3C A0 6F 64 28 00 00 24 01
    		];	//配置信息,不同的屏配置不同,需要原厂提供适配的cfg
        };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    移植代码,并修改上一级目录的Makefile和Kconfig文件,因为原厂提供的驱动代码已经将makefile和Kconfig写好,所以移植时,只需要将适配到我们自己的目录环境中添加编译

    Kconfig:
    	source "drivers/input/touchscreen/ga657x/Kconfig"
    Makefile
    	obj-$(CONFIG_TOUCHSCREEN_GA657X)       +=  ga657x/
    
    • 1
    • 2
    • 3
    • 4

    配置内核,打开ga657x的配置选项,参与编译

    │ Symbol: TOUCHSCREEN_GA657X [=y]                                                                                                                                   │
      │ Type  : boolean                                                                                                                                                   │
      │ Prompt: Goodix touchpanel GA657X series                                                                                                                           │
      │   Location:                                                                                                                                                       │
      │     -> Device Drivers                                                                                                                                             │
      │       -> Input device support                                                                                                                                     │
      │         -> Generic input layer (needed for keyboard, mouse, ...) (INPUT [=y])                                                                                     │
      │ (1)       -> Touchscreens (INPUT_TOUCHSCREEN [=y])                                                                                                                │
      │   Defined at drivers/input/touchscreen/ga657x/Kconfig:4                                                                                                           │
      │   Depends on: !UML && INPUT [=y] && INPUT_TOUCHSCREEN [=y] && I2C [=y]   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述
    以上配置完成可以进行下一步调试,重新刷写编译完成的kernel,确保硬件连接正常,开机后应该就可以在/dev/input/下发现设备节点
    在这里插入图片描述
    使用evtest工具测试,一般就可以测试触摸事件了: evtest /dev/input/event0

    问题

    点击触屏,界面还是没有反应,可能是触屏里没有烧录配置文件或者配置文件不对,所以联系触屏(所使用的屏幕和液晶、触屏组合屏)厂家了解情况和获取配置文件,或者是IIC等ping脚配置错误,需要结合原理图分析。

    开短路检测

    在GA657x的代码中,原厂已经增加了上电开短路自测的功能,需要把接口映射出来给EOL测试。
    总体流程如下:
    下发自检命令,读取自检结果-》复位IC-》读取自诊断结果

    #ifdef SELF_TEST_ENABLE
    static int current_self_test_status = 1;
    static int current_self_result = GTP_SELT_TEST_WAIT_FOR_RESPONSE;
    static int current_self_result_oc = GTP_SELT_TEST_WAIT_FOR_RESPONSE;
    struct goodix_ts_data *Self_ts;
    /*******************************************************
     * Function:
     *	Short current test result get		//获取短路测试自检结果
     * Input:
     *	ts: goodix tp private data
     * Output:
     *	.
     *********************************************************/
    static int gtp_sc_handler(struct goodix_ts_data *ts)
    {
    	u8 doze_buf[3] = {GTP_REG_SC_TEST_STATE >> 8, GTP_REG_SC_TEST_STATE & 0xFF};
    	int ret;
    
    	dev_info(&ts->client->dev, "enter gtp_sc_handler\n");
    
    
    	ret = gtp_i2c_read(ts->client, doze_buf, 3);
    	if (ret < 0) {
    		dev_err(&ts->client->dev, "Failed read doze buf");
    		current_self_result = GTP_ERROR_TIMEOUT;
    		return -EINVAL;
    	}
    
    	if(doze_buf[2] == 0x88){
    		doze_buf[0] = GTP_REG_SC_TEST_RESULT >> 8;
    		doze_buf[1] = GTP_REG_SC_TEST_RESULT & 0xff;
    		dev_info(&ts->client->dev, "Short current test complete\n");
    	}
    	else{
            int i = 5;
    
            while(i--){
    			/* Write for a moment */
    			usleep_range(10000,11000);
    			doze_buf[0] = GTP_REG_SC_TEST_STATE >> 8;
    			doze_buf[1] = GTP_REG_SC_TEST_STATE & 0xff;
    
    			ret = gtp_i2c_read(ts->client, doze_buf, 3);
    			if (ret < 0) {
    				dev_err(&ts->client->dev, "Failed read doze buf");
    				current_self_result = GTP_ERROR_TIMEOUT;
    				return -EINVAL;
    			}
    			if(doze_buf[2] == 0x88){
    				doze_buf[0] = GTP_REG_SC_TEST_RESULT >> 8;
    				doze_buf[1] = GTP_REG_SC_TEST_RESULT & 0xff;
    				break;
    			}
    			else{
    				dev_err(&ts->client->dev, "Short current test state is %02x\n",doze_buf[2]);
    			}
    		}
    
            if(i == 0){
                current_self_result = GTP_ERROR_TIMEOUT;
    			dev_err(&ts->client->dev, "sc error code %d\n",doze_buf[2]);
                return -EINVAL;
            }
    	}
    
    	ret = gtp_i2c_read(ts->client, doze_buf, 3);
    	if (ret < 0) {
    		dev_err(&ts->client->dev, "Failed read doze buf");
    		return -EINVAL;
    	}
    
        if(doze_buf[2] != 0){
    		current_self_result = GTP_ERROR_SELF_TEST_ANALOG;
    		dev_err(&ts->client->dev, "sc error code %d\n",doze_buf[2]);
        }
        else{
            current_self_result = GTP_SELF_TEST_SUCCESS;
        }
    
        ts->pdata->short_current_test = false;
    
    	return 0;
    }
    
    /*******************************************************
     * Function:
     *	open current test result get		//获取开路测试自检结果
     * Input:
     *	ts: goodix tp private data
     * Output:
     *	.
     *********************************************************/
    static int gtp_oc_handler(struct goodix_ts_data *ts)
    {
    	u8 doze_buf[3] = {GTP_REG_OC_TEST_RESULT >> 8, GTP_REG_OC_TEST_RESULT & 0xFF};
    	int ret;
    
    	dev_info(&ts->client->dev, "enter gtp_oc_handler\n");
    
    
    	ret = gtp_i2c_read(ts->client, doze_buf, 3);
    	if (ret < 0) {
    		dev_err(&ts->client->dev, "Failed read doze buf");
    		current_self_result_oc = GTP_ERROR_TIMEOUT;
    		return -EINVAL;
    	}
    
    	if(doze_buf[2] != 0x00){
    		dev_err(&ts->client->dev, "TP open current\n");
    		current_self_result_oc = GTP_ERROR_OPEN_CURRENT;
    		doze_buf[0] = GTP_REG_OC_TEST_RESULT >> 8;
    		doze_buf[1] = GTP_REG_OC_TEST_RESULT & 0xff;
    		doze_buf[2] = 0;
    		gtp_i2c_write(ts->client, doze_buf, 3);
    	}
    	else{
    		current_self_result_oc = GTP_SELF_TEST_SUCCESS;
    	}
    	ts->pdata->open_current_test = false;
    	return 0;
    }
    
    #endif
    /*******************************************************
     * Function:
     *	Goodix touchscreen sensor report function
     * Input:
     *	ts: goodix tp private data
     * Output:
     *	None.
     *********************************************************/
    static void gtp_work_func(struct goodix_ts_data *ts)
    {
    	u8 point_state = 0;
    	int key_value = 0;
    	s32 i = 0;
    	s32 ret = -1;
    	static int pre_key;
    	struct goodix_point_t points[GTP_MAX_TOUCH_ID];
    
    #ifdef  SELF_TEST_ENABLE
    	/* Short current test result event */
    	if(ts->pdata->short_current_test ){
    	    gtp_sc_handler(ts);
    	}
    
    	if(ts->pdata->open_current_test ){
    		gtp_oc_handler(ts);
    		gtp_reset_guitar(ts->client, 20);
    		return;
        }
    #endif
        ......
      }
    /*******************************************************
     * Function:
     *	Enter doze mode for sliding wakeup.	
     * Input:
     *	ts: goodix tp private data
     * Output:
     *	1: succeed, otherwise failed
     *******************************************************/
    static int gtp_enter_doze(struct goodix_ts_data *ts)
    {
    	int ret = -1;
    	int retry = 0;
    	u8 i2c_control_buf[3] = { (u8)(GTP_REG_COMMAND >> 8),
    				  (u8)GTP_REG_COMMAND, 8 };
    
    	/*  resend doze command
    	 * if (test_and_set_bit(DOZE_MODE, &ts->flags)) {
    	 *	dev_info(&ts->client->dev, "Already in doze mode\n");
    	 *	return SUCCESS;
    	 * }
    	 */
    	set_bit(DOZE_MODE, &ts->flags);
    	dev_dbg(&ts->client->dev, "Entering gesture mode.");
    	while (retry++ < 5) {
    		i2c_control_buf[0] = (u8)(GTP_REG_COMMAND_CHECK >> 8);
    		i2c_control_buf[1] = (u8)GTP_REG_COMMAND_CHECK;
    		ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
    		if (ret < 0) {
    			dev_dbg(&ts->client->dev,
    				"failed to set doze flag into 0x8046, %d\n",
    				retry);
    			continue;
    		}
    		i2c_control_buf[0] = (u8)(GTP_REG_COMMAND >> 8);
    		i2c_control_buf[1] = (u8)GTP_REG_COMMAND;
    		ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
    		if (ret > 0) {
    			dev_dbg(&ts->client->dev, "Gesture mode enabled\n");
    			return ret;
    		}
    		usleep_range(10000, 11000);
    	}
    
    	dev_err(&ts->client->dev, "Failed enter doze mode\n");
    	clear_bit(DOZE_MODE, &ts->flags);
    	return ret;
    }
    
    /* short current test start cmd */
    static s8 gtp_sc_test_start(struct goodix_ts_data *ts)
    {
    	s8 ret = -1;
    	s8 retry = 0;
    	u8 i2c_control_buf[12] = { (u8)(GTP_REG_COMMAND_SC_TEST >> 8),
    				  (u8)GTP_REG_COMMAND_SC_TEST, 0 };
    
        /* Read the state */
    
        while (retry++ < 20){
    		ret = gtp_i2c_read(ts->client, i2c_control_buf, 3);
    		if (ret > 0) {
    	        if(i2c_control_buf[2] == 0xaa){
    				dev_info(&ts->client->dev, "TP enter to selftest mode successful\n");
    				i2c_control_buf[2] = 0;
    				break;
    	        }
    	        else{
    				dev_info(&ts->client->dev, "TP is not in selftest mode, %02x\n", i2c_control_buf[2]);
    	        }
    	    }  
    	    else{
    			dev_err(&ts->client->dev, "iic read error\n");
    	    }
    		usleep_range(30000, 31000);
        }
        
    #ifdef SELF_TEST_ENABLE
    static int do_goodix_self_test(void)
    {
    	s8 ret;
    	/* Send cmd to touch ic to enter self test mode */
    	ret = gtp_enter_doze(Self_ts);//执行切换自检固件
    	usleep_range(30000, 31000);
    
    	/* Send start short current test cmd to touch ic */
    	ret = gtp_sc_test_start(Self_ts);//进入自检流程
    
    	Self_ts->pdata->short_current_test= true;
    	Self_ts->pdata->open_current_test = true;
    
    	return 1;
    }
    
    static ssize_t set_self_test_status(struct device *dev, struct device_attribute *attr,
    		const char *buf, size_t count)
    {
    	unsigned long test_status;
    
    	if (kstrtoul(buf, 10, &test_status)) {
    		dev_info(dev, "invalid input!!!\n");
    		return 1;
    	}
    
    	current_self_test_status = test_status;
    	dev_info(dev, "set touch IC self test mode to %d\n", current_self_test_status);
    
    	if (current_self_test_status == 0) {
    		current_self_result = GTP_SELT_TEST_WAIT_FOR_RESPONSE;
    		//current_self_result_oc = GTP_SELF_TEST_SUCCESS;
    		do_goodix_self_test();
    	}
    
    	return count;
    }
    
    static ssize_t get_self_test_status(struct device *dev, struct device_attribute *attr,
    		char *buf)
    {
    	int len;
    	len = snprintf(buf, PAGE_SIZE, "%d", current_self_test_status);
    	dev_info(dev, "get self test state is %d, %d\n", current_self_test_status, len);
    	return len;
    }
    static DEVICE_ATTR(self_test_mode, S_IRUGO | S_IWUSR, get_self_test_status, set_self_test_status);
    
    static ssize_t set_self_test_result(struct device *dev, struct device_attribute *attr,
    		const char *buf, size_t count)
    {
    	return count;
    }
    
    static ssize_t get_self_test_result(struct device *dev, struct device_attribute *attr,
                    char *buf)
    {
            int len;
            int result;
    
            result = current_self_result || current_self_result_oc;
            len = snprintf(buf, PAGE_SIZE, "%d", result);
    		//Self_ts->pdata->open_current_test = true;
            dev_info(dev, "Get self test state is %d\n", current_self_result);
            return len;
    }
    static DEVICE_ATTR(self_test_result, S_IRUGO | S_IWUSR, get_self_test_result, set_self_test_result);
    
    #endif
    
    static struct attribute *gtp_attrs[] = {
    	&dev_attr_workmode.attr,
    	&dev_attr_productinfo.attr,
    
    #ifdef CONFIG_TOUCHSCREEN_GA657X_UPDATE
    	&dev_attr_dofwupdate.attr,
    #endif
    
    #ifdef SELF_TEST_ENABLE
    	&dev_attr_self_test_result.attr,
    	&dev_attr_self_test_mode.attr,
    #endif
    
    	&dev_attr_drv_irq.attr,
    	&dev_attr_reset.attr,
    	NULL
    };
    
    static const struct attribute_group gtp_attr_group = {
    	.attrs = gtp_attrs,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
  • 相关阅读:
    现在的00后,实在是太卷了,我们这些老油条都想辞职了......
    Docker安装
    低代码常见场景【上】|如何解决业务问题
    低代码平台技术分享官 | 漫话iGIX前端设计模式
    C盘扩容(微PE工具箱)
    人工智能内容生成元年—AI绘画原理解析
    CSDN21天学习挑战赛——day1 正则表达式大总结
    基于LADRC自抗扰控制的虚拟同步发电机VSG三相逆变器预同步并网控制策略
    通过内网穿透远程控制家中Home Assistant智能家居系统
    小学生写作业用什么灯最好?分享学生专用的暖光LED灯
  • 原文地址:https://blog.csdn.net/UUUUUltraman/article/details/126468209