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 = >1x_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! 篇幅略长,感谢阅读。