GOODIX TOUCH驱动移植

本文详细介绍了如何在基于IMX6芯片的Linux系统中移植Goodix GA657X触控屏驱动,涉及IIC配置、设备树添加、Kconfig和Makefile修改,以及自检与配置文件校验过程。遇到问题时,需与供应商沟通并检查短路检测功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

1.总体架构

参考:https://blog.youkuaiyun.com/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
    };

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

Kconfig:
	source "drivers/input/touchscreen/ga657x/Kconfig"
Makefile
	obj-$(CONFIG_TOUCHSCREEN_GA657X)       +=  ga657x/

配置内核,打开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]   

在这里插入图片描述
以上配置完成可以进行下一步调试,重新刷写编译完成的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,
};
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值