[Linux Device Driver] TP手套模式代码分析

0. 设备树配置

百度搜了下手套模式…
在这里插入图片描述

goodix@5d {
		compatible = "goodix,gt1x";
		reg = <0x5d>;
        ......
		goodix,default-config0 = [
			41 A0 05 D0 02 0A 05 0C 20 E1
			8E 05 50 32 05 01 00 32 00 00
			28 00 00 00 08 04 03 00 0F 14
			3C 44 00 22 00 00 00 00 00 40
			00 00 00 00 00 00 88 25 1C 17
			15 31 0D 28 2E 20 9B 03 25 44
			01 23 46 40 94 25 00 00 54 A5
			28 90 2E 7F 34 73 3A 68 40 60
			65 56 17 00 00 00 00 F0 4C 3C
			FF FF 07 50 3C 00 00 00 00 00
			00 00 00 00 00 00 00 19 02 78
			0A 46 FF E4 04 00 00 00 00 00
			00 00 00 20 00 00 00 00 00 00
			00 00 00 00 00 00 DF 07 3C 1E
			0E 0F 10 12 13 14 15 16 17 18
			19 1A 1B 1D 1F 0D 00 01 02 03
			04 05 06 07 08 09 0A 0B FF FF
			FF FF 1C 1B 1A 19 18 17 15 14
			06 08 0C 12 13 FF FF FF FF FF
			FF FF FF FF 00 30 00 00 00 FF
			14 64 00 00 00 00 00 00 00 00
			00 00 00 00 00 00 00 11 02 62
			32 03 14 00 0D 90 14 50 00 44
			10 00 28 EB 06 50 F2 88 01
		];
		goodix,charger-config2 = [
		];
		goodix,smartcover-config0 = [
			60 A0 13 D0 02 0A F2 0C 20 E1
			8E 05 69 32 05 01 00 32 00 00
			28 03 00 00 08 04 03 00 0F 14
			17 44 00 22 00 00 00 00 00 40
			00 00 00 EE 00 00 88 25 1C 17
			15 31 03 28 2E 20 9B 03 25 44
			01 23 46 40 94 2F 00 00 54 A5
			28 90 2E 77 34 73 3A 68 40 60
			65 56 17 A1 00 00 00 F0 4C 3C
			FF FF 07 50 3C 00 00 00 14 00
			00 00 0F 00 00 00 00 19 02 78
			3A 46 FF E4 04 00 00 00 00 00
			14 00 00 20 00 00 00 00 00 00
			00 00 00 00 9E 00 DF 07 3C 1E
			0E 0F 10 12 13 29 15 16 17 18
			19 1A 1F 1D 1F 0D 00 01 02 03
			1E 05 06 07 08 09 0A 0B FF FF
			FF FF 1C 1B 1B 19 18 17 15 14
			06 08 07 12 13 FF FF FF FF FF
			FF FF FF FE 00 30 00 00 00 FF
			14 64 0F 00 00 00 00 00 00 00
			00 00 00 00 00 00 15 11 02 62
			32 03 14 00 0D 90 14 50 00 4E
			00 00 28 EB 06 50 F2 88 01
		];
		panel = <&dsi_boe_hsd057bhw1_d_ili9881d_720p_video>;
	};

goodix,smartcover-config0是手套模式走的参数,goodix,default-config0是正常模式的参数。

1. goodix,default-config0

~/android10/LA.UM.8.13$ grep -nr "goodix,gt1x"  ./kernel/msm-4.19/drivers/
./kernel/msm-4.19/drivers/input/touchscreen/gt1x/gt1x.c:922:            
{.compatible = "goodix,gt1x",},

进入代码:

在这里插入图片描述
设备驱动匹配,然后我们看probe函数:

static int gt1x_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
	int ret = -1;

	tp_kobj = kobject_create_and_add("tp_kobj", kernel_kobj);

	sysfs_create_file(tp_kobj, &dev_attr_tp_info.attr); 

	
	/* check firmware, initialize and send
	 * chip configuration data, initialize nodes */
	gt1x_init();
	ret = gt1x_request_input_dev();
	if (ret < 0)
		goto err_input;
	ret = gt1x_request_irq();
	if (ret < 0)
		goto err_irq;
   ....
}

查看gt1x_init()函数:

LA.UM.8.13$ grep -nr "gt1x_init"  ./kernel/msm-4.19/drivers/input/touchscreen/gt1x/

在这里插入图片描述
得到两个重要信息:

a. gt1x_init为全局的。
b. 函数原型位置:

 ./kernel/msm-4.19/drivers/input/touchscreen/gt1x/gt1x_generic.c  

接下来我们看 :

  ret = gt1x_init_panel();

在这里插入图片描述

gt1x_init_panel这个函数也是全局的,具体如下:

grep -nr "gt1x_init_panel"  ./kernel/msm-4.19/drivers/input/touchscreen/gt1x/

在这里插入图片描述

找到关键函数: gt1x_find_tp_config

s32 gt1x_init_panel(void)
{
    ......
	cfg_len = gt1x_find_tp_config(dev, "default-config",
			gt1x_version.sensor_id, gt1x_config);
	if (cfg_len < 0) {
		GTP_ERROR("Failed to obtain config data:%d", cfg_len);
		return -EINVAL;
	}
    .....
	gt1x_config[0] &= 0x7F;

2. gt1x_find_tp_config

int gt1x_find_tp_config(struct device *dev,
		char *cfg_name, u8 sensor_id, u8 *config)
{
	struct property *prop;
	char name[32];
	u8 extcfg_flag;
	int size, requ_size;

	if (!dev || !dev->of_node || !cfg_name ||
			!config || sensor_id > 6)
		return -EINVAL;

	snprintf(name, sizeof(name), "goodix,%s%d", cfg_name, sensor_id);
	printk(KERN_ERR "%s=====>%s\n",__func__,name);
	prop = of_find_property(dev->of_node, name, &size);
	if (!prop || !prop->value || size < GTP_CONFIG_ORG_LENGTH) {
		GTP_ERROR("Property %s not found", name);
		return -ENOENT;
	}
	......
snprintf(name, sizeof(name), "goodix,%s%d", cfg_name, sensor_id);

这句代码把传进来的default-config,goodix,以及sensor_id这个值是0,从系统固件中读出,然后拼接起来(sensor id不是重点,稍后补充)。

拼接的结果就是"goodix,default-config0" ,于是就和设备树对应起来了,

在这里插入图片描述

然后俺们就解析"goodix,default-config0",然后存到config指针里面。

int gt1x_find_tp_config(struct device *dev,
		char *cfg_name, u8 sensor_id, u8 *config)
{
	struct property *prop;
	char name[32];
	u8 extcfg_flag;
	int size, requ_size;

	if (!dev || !dev->of_node || !cfg_name ||
			!config || sensor_id > 6)
		return -EINVAL;

	snprintf(name, sizeof(name), "goodix,%s%d", cfg_name, sensor_id);
	printk(KERN_ERR "%s=====>%s\n",__func__,name);
	prop = of_find_property(dev->of_node, name, &size);
	if (!prop || !prop->value || size < GTP_CONFIG_ORG_LENGTH) {
		GTP_ERROR("Property %s not found", name);
		return -ENOENT;
	}

	extcfg_flag = ((u8 *)prop->value)[GTP_REG_EXT_CFG_FLAG -
			GTP_REG_CONFIG_DATA];
	if (extcfg_flag & 0x40) /* has extended config  data*/
		requ_size = GTP_CONFIG_ORG_LENGTH + GTP_CONFIG_EXT_LENGTH;
	else
		requ_size = GTP_CONFIG_ORG_LENGTH;

	if (size != requ_size) {
		GTP_ERROR("Invalid config size:%d", size);
		return -EINVAL;
	}

	memcpy(config, prop->value, size);
	GTP_INFO("Find %s, size:%d, ver:%02xh ",
			name, size, config[0]);
	return size;
}

总结下goodix,default-config0的代码流程:

 gt1x_ts_probe
       ->  gt1x_init()
             ->  gt1x_init_panel()
                    ->   gt1x_find_tp_config

3. goodix,smartcover-config0

继续看下goodix,smartcover-config0是如何被解析的。

在gt1x_init函数的最后会函数调用gt1x_smart_cover_init():

s32 gt1x_init(void)
......
#ifdef CONFIG_GTP_CHARGER_SWITCH
	gt1x_init_charger();
	gt1x_charger_config(1);
	gt1x_charger_switch(SWITCH_ON);
#endif

#ifdef CONFIG_GTP_SMART_COVER
    gt1x_smart_cover_init();
#endif

#ifdef CONFIG_GTP_WITH_STYLUS
	gt1x_pen_init();
#endif

	return ret;
}
......

gt1x_smart_cover_init(); 然后会调用

gt1x_parse_sc_cfg(gt1x_version.sensor_id);
static int gt1x_smart_cover_init(void)
{
    int err = 0;

    gt1x_sc_dev = kzalloc(sizeof(struct smart_cover_device), GFP_KERNEL);
    if (!gt1x_sc_dev) {
        GTP_ERROR("SmartCover init failed in step: 1.");
        return -ENOMEM;
    }

    gt1x_sc_dev->enabled = 1;
    gt1x_parse_sc_cfg(gt1x_version.sensor_id);

然后调用gt1x_find_tp_config函数:

int gt1x_parse_sc_cfg(int sensor_id) 
{
#ifdef CONFIG_MTK_PLATFORM
	struct device *dev = tpd->tpd_dev;
#else
	struct device *dev = &gt1x_i2c_client->dev;
#endif
    u8 *cfg;
    int size;
    
    if (!gt1x_sc_dev) 
        return -ENODEV;
    cfg = gt1x_sc_dev->config;

	size = gt1x_find_tp_config(dev, "smartcover-config",
			sensor_id, cfg);
	if (size < 0) {
		GTP_ERROR("Failed to obtain smartcover config");
		return size;
	}
	......

再次回到gt1x_find_tp_config函数

int gt1x_find_tp_config(struct device *dev,
		char *cfg_name, u8 sensor_id, u8 *config)
{
	struct property *prop;
	char name[32];
	u8 extcfg_flag;
	int size, requ_size;

	if (!dev || !dev->of_node || !cfg_name ||
			!config || sensor_id > 6)
		return -EINVAL;

	snprintf(name, sizeof(name), "goodix,%s%d", cfg_name, sensor_id);
	printk(KERN_ERR "%s=====>%s\n",__func__,name);
	prop = of_find_property(dev->of_node, name, &size);
	if (!prop || !prop->value || size < GTP_CONFIG_ORG_LENGTH) {
		GTP_ERROR("Property %s not found", name);
		return -ENOENT;
	}
	......
snprintf(name, sizeof(name), "goodix,%s%d", cfg_name, sensor_id);

这句代码拼接成"goodix,smartcover-config0",
在这里插入图片描述

然后俺们就解析设备树里面的"goodix,smartcover-config0",然后存到config指针里面。

总结下goodix,smartcover-config0的代码流程:

 gt1x_ts_probe
       ->  gt1x_init()
              -> gt1x_smart_cover_init
                     ->   gt1x_parse_sc_cfg
                          -> gt1x_find_tp_config

4. Sysfs节点

static ssize_t smart_cover_store(struct kobject *kobj,
		struct kobj_attribute *attr, const char *buf, size_t count)
{
    struct smart_cover_device *dev = gt1x_sc_dev;
    int s = (buf[0] - '0');
    
    if (!dev || !dev->enabled || s > 1 || s == dev->state) {
        return count;
    }

    dev->state = s;
    gt1x_smart_cover_update_state();
	
	return count;
}

其实还有Sysfs节点,我们看下store函数,这个会把echo的值,通过buf传dev->state。

再看下smart_cover_store函数里面的gt1x_smart_cover_update_state函数:

static int gt1x_smart_cover_update_state(void)
{
	int ret = 0;
    struct smart_cover_device *dev = gt1x_sc_dev;

    if (!dev) {
        return -ENODEV;
    }
    
	if(!dev->suspended) {
		if(dev->state) {  /* near */
			ret = gt1x_send_cfg(dev->config, dev->cfg_len);
		} else {
	    #ifdef CONFIG_GTP_CHARGER_SWITCH
			gt1x_charger_config(1); // charger detector module check and 
			                        // send a config
	    #else
			ret = gt1x_send_cfg(gt1x_config, gt1x_cfg_length);
	    #endif
		}
		GTP_DEBUG("Update cover state %s.", dev->state ? "Nearby" : "Far away");
	} else {
		GTP_DEBUG("TP is suspended, do nothing.");
	}
	return ret;
}

比如我们通过echo传1给dev->state,那么代码就走:

ret = gt1x_send_cfg(dev->config, dev->cfg_len);

看下gt1x_parse_sc_cfg函数,其实就是解析到设备树里面的信息最终就存到了dev->config里面。
在这里插入图片描述

那么若是echo 0的话,那么就是默认存到gt1x_config里面:

在这里插入图片描述

这和以下代码对应:

ret = gt1x_send_cfg(gt1x_config, gt1x_cfg_length);

5. 补充说明sensor_id

代码路径:

./kernel/msm-4.19/drivers/input/touchscreen/gt1x/gt1x_extents.c
s32 gt1x_read_version(struct gt1x_version_info * ver_info)
{
   ......

	while (retry--) {
		ret = gt1x_i2c_read_dbl_check(GTP_REG_VERSION, buf, sizeof(buf));
		if (!ret) {
			checksum = 0;

			for (i = 0; i < sizeof(buf); i++) {
				checksum += buf[i];
			}

			if (checksum == 0 &&	/* first 3 bytes must be number or char */
			    IS_NUM_OR_CHAR(buf[0]) && IS_NUM_OR_CHAR(buf[1]) &&
				IS_NUM_OR_CHAR(buf[2]) && buf[10] != 0xFF) {
				/*sensor id == 0xFF, retry */
				break;
			} else {
				GTP_ERROR("Read version failed!(checksum error)");
			}
		} else {
			GTP_ERROR("Read version failed!");
		}
		GTP_DEBUG("Read version : %d", retry);
		msleep(100);
	}

在这里插入图片描述

gt1x_i2c_read_dbl_check从TP固件里面读值,存到buf里面,然后我们的sensor_id就是从buf里面读出来的值,这里是0。

其实手套模式并没有验证,好像要特殊的工具验证…这个一会找 FAE问清楚了,有时间再更新下操作验证方法。

#更新2021.05.29

之后验证方法就拿各种手套操作设备,棉布的,硅胶的,都有效果,能很灵敏的滑动手机屏幕-_-。

#更新2021.05.29

本文OVER! 篇幅略长,感谢阅读。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值