在公司实习时间快结束了,这段时间接触最多的就是触摸屏了,现在以gt9xx系列触摸屏总结下对于触摸屏的理解,当然首先分析源代码:
首先从probe函数开始
probe函数中比较重要的就是ret = gtp_init_panel(ts);
和ret = gtp_request_input_dev(ts);
这两个函数一个是将触摸屏的配置信息写入到触摸屏寄存器中,一个是申请input子系统
static int gtp_init_panel(struct goodix_ts_data *ts)
{
struct i2c_client *client = ts->client;
unsigned char *config_data;
int ret = -EIO;
#if GTP_DRIVER_SEND_CFG
int i;
u8 check_sum = 0;
u8 opr_buf[16];
u8 sensor_id = 0;
u8 cfg_info_group1[] = CTP_CFG_GROUP1;
u8 cfg_info_group2[] = CTP_CFG_GROUP2;
u8 cfg_info_group3[] = CTP_CFG_GROUP3;
u8 cfg_info_group4[] = CTP_CFG_GROUP4;
u8 cfg_info_group5[] = CTP_CFG_GROUP5;
u8 cfg_info_group6[] = CTP_CFG_GROUP6;
u8 cfg_info_group7[] = CTP_CFG_GROUP7;
u8 cfg_info_group8[] = CTP_CFG_GROUP8;
u8 cfg_info_group9[] = CTP_CFG_GROUP9;
u8 cfg_info_group10[] = CTP_CFG_GROUP10;
u8 cfg_info_group11[] = CTP_CFG_GROUP11;
u8 cfg_info_group12[] = CTP_CFG_GROUP12;
u8 *send_cfg_buf[] = {cfg_info_group1, cfg_info_group2,cfg_info_group3, cfg_info_group4,
cfg_info_group5, cfg_info_group6,cfg_info_group7, cfg_info_group8,
cfg_info_group9, cfg_info_group10,
cfg_info_group11, cfg_info_group12};
u8 cfg_info_len[] = {CFG_GROUP_LEN(cfg_info_group1),
CFG_GROUP_LEN(cfg_info_group2),
CFG_GROUP_LEN(cfg_info_group3),
CFG_GROUP_LEN(cfg_info_group4),
CFG_GROUP_LEN(cfg_info_group5),
CFG_GROUP_LEN(cfg_info_group6),
CFG_GROUP_LEN(cfg_info_group7),
CFG_GROUP_LEN(cfg_info_group8),
CFG_GROUP_LEN(cfg_info_group9),
CFG_GROUP_LEN(cfg_info_group10),
CFG_GROUP_LEN(cfg_info_group11),
CFG_GROUP_LEN(cfg_info_group12),};
lidbg("Config Groups\' Lengths: %d, %d, %d, %d, %d, %d",
cfg_info_len[0], cfg_info_len[1], cfg_info_len[2],
cfg_info_len[3], cfg_info_len[4], cfg_info_len[5]);
ret = gtp_i2c_read_dbl_check(ts->client, 0x41E4, opr_buf, 1);
if (SUCCESS == ret) {
if (opr_buf[0] != 0xBE) {
ts->fw_error = 1;
dev_err(&client->dev,
"Firmware error, no config sent!");
return -EINVAL;
}
}
if ((!cfg_info_len[1]) && (!cfg_info_len[2]) && (!cfg_info_len[3])
&& (!cfg_info_len[4]) && (!cfg_info_len[5])) {
sensor_id = 0;
} else {
ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_SENSOR_ID,
&sensor_id, 1);
if (SUCCESS == ret) {
if (sensor_id >= 0x06) {
dev_err(&client->dev,
"Invalid sensor_id(0x%02X), No Config Sent!",
sensor_id);
return -EINVAL;
}
} else {
dev_err(&client->dev,
"Failed to get sensor_id, No config sent!");
return -EINVAL;
}
}
lidbg("Sensor_ID: %d", sensor_id);
ret = lidbg_check_id(ts->client,"9271");
if(SUCCESS == ret)
{
sensor_id+=6;
}
lidbg_fs_log(TS_LOG_PATH, "SENSOR ID:%d\n", sensor_id);
ts->gtp_cfg_len = cfg_info_len[sensor_id];
if (ts->gtp_cfg_len < GTP_CONFIG_MIN_LENGTH) {
dev_err(&client->dev,
"Sensor_ID(%d) matches with NULL or INVALID CONFIG GROUP! NO Config Sent! You need to check you header file CFG_GROUP section!\n",
sensor_id);
return -EINVAL;
}
ret = gtp_i2c_read_dbl_check(ts->client, GTP_REG_CONFIG_DATA,
&opr_buf[0], 1);
if (ret == SUCCESS) {
if (opr_buf[0] < 90) {
/* backup group config version */
grp_cfg_version = send_cfg_buf[sensor_id][0];
send_cfg_buf[sensor_id][0] = 0x00;
ts->fixed_cfg = 0;
} else {
/* treated as fixed config, not send config */
dev_warn(&client->dev,
"Ic fixed config with config version(%d, 0x%02X)",
opr_buf[0], opr_buf[0]);
ts->fixed_cfg = 1;
}
} else {
dev_err(&client->dev,
"Failed to get ic config version!No config sent!");
return -EINVAL;
}
/*
if (ts->pdata->gtp_cfg_len) {// use config from dts
config_data = ts->pdata->config_data;
ts->config_data = ts->pdata->config_data;
ts->gtp_cfg_len = ts->pdata->gtp_cfg_len;
} else*/
{
config_data = devm_kzalloc(&client->dev,
GTP_CONFIG_MAX_LENGTH + GTP_ADDR_LENGTH,
GFP_KERNEL);
if (!config_data) {
dev_err(&client->dev,
"Not enough memory for panel config data\n");
return -ENOMEM;
}
ts->config_data = config_data;
config_data[0] = GTP_REG_CONFIG_DATA >> 8;
config_data[1] = GTP_REG_CONFIG_DATA & 0xff;
memset(&config_data[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
memcpy(&config_data[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id],
ts->gtp_cfg_len);
}
#if GTP_CUSTOM_CFG
config_data[RESOLUTION_LOC] =
(unsigned char)(GTP_MAX_WIDTH && 0xFF);
config_data[RESOLUTION_LOC + 1] =
(unsigned char)(GTP_MAX_WIDTH >> 8);
config_data[RESOLUTION_LOC + 2] =
(unsigned char)(GTP_MAX_HEIGHT && 0xFF);
config_data[RESOLUTION_LOC + 3] =
(unsigned char)(GTP_MAX_HEIGHT >> 8);
if (GTP_INT_TRIGGER == 0)
config_data[TRIGGER_LOC] &= 0xfe;
else if (GTP_INT_TRIGGER == 1)
config_data[TRIGGER_LOC] |= 0x01;
#endif /* !GTP_CUSTOM_CFG */
check_sum = 0;
for (i = GTP_ADDR_LENGTH; i < ts->gtp_cfg_len; i++)
check_sum += config_data[i];
config_data[ts->gtp_cfg_len] = (~check_sum) + 1;
#else /* DRIVER NOT SEND CONFIG */
ts->gtp_cfg_len = GTP_CONFIG_MAX_LENGTH;
ret = gtp_i2c_read(ts->client, config_data,
ts->gtp_cfg_len + GTP_ADDR_LENGTH);
if (ret < 0) {
dev_err(&client->dev,
"Read Config Failed, Using DEFAULT Resolution & INT Trigger!\n");
ts->abs_x_max = GTP_MAX_WIDTH;
ts->abs_y_max = GTP_MAX_HEIGHT;
ts->int_trigger_type = GTP_INT_TRIGGER;
}
#endif /* !DRIVER NOT SEND CONFIG */
GTP_DEBUG_FUNC();
if ((ts->abs_x_max == 0) && (ts->abs_y_max == 0)) {
ts->abs_x_max = (config_data[RESOLUTION_LOC + 1] << 8)
+ config_data[RESOLUTION_LOC];
ts->abs_y_max = (config_data[RESOLUTION_LOC + 3] << 8)
+ config_data[RESOLUTION_LOC + 2];
ts->int_trigger_type = (config_data[TRIGGER_LOC]) & 0x03;
}
ret = gtp_send_cfg(ts);
if (ret < 0)
dev_err(&client->dev, "%s: Send config error.\n", __func__);
GTP_DEBUG("X_MAX = %d, Y_MAX = %d, TRIGGER = 0x%02x",
ts->abs_x_max, ts->abs_y_max,
ts->int_trigger_type);
msleep(20);
return ret;
其中
memset(&config_data[GTP_ADDR_LENGTH], 0, GTP_CONFIG_MAX_LENGTH);
memcpy(&config_data[GTP_ADDR_LENGTH], send_cfg_buf[sensor_id],
ts->gtp_cfg_len);
作用就是将配置选择的配置信息介入到寄存器中,寄存器地址存储在config_data中
config_data[0] = GTP_REG_CONFIG_DATA >> 8;
config_data[1] = GTP_REG_CONFIG_DATA & 0xff;
gtp_request_input_dev则为申请input子系统,这里我没有用系统原来带的gtp_request_input_dev而是自己重新封装了一个接口这个后面再说把
申请万input子系统后最重要的事就是创建工作队列作为触摸屏中断底半部:
ts->goodix_wq = create_singlethread_workqueue("goodix_wq");
INIT_WORK(&ts->work, goodix_ts_work_func);
goodix_ts_work_func
函数如下:
static void goodix_ts_work_func(struct work_struct *work)
{
u8 end_cmd[3] = { GTP_READ_COOR_ADDR >> 8,
GTP_READ_COOR_ADDR & 0xFF, 0};
u8 point_data[2 + 1 + 8 * GTP_MAX_TOUCH + 1] = {
GTP_READ_COOR_ADDR >> 8,
GTP_READ_COOR_ADDR & 0xFF};
u8 touch_num = 0;
u8 finger = 0;
static u16 pre_touch;
static u8 pre_key;
#if GTP_WITH_PEN
static u8 pre_pen;
#endif
u8 key_value = 0;
u8 *coor_data = NULL;
s32 input_x = 0;
s32 input_y = 0;
s32 input_w = 0;
s32 id = 0;
s32 i = 0;
int ret = -1;
struct goodix_ts_data *ts = NULL;
#if GTP_SLIDE_WAKEUP
u8 doze_buf[3] = {0x81, 0x4B};
#endif
GTP_DEBUG_FUNC();
ts = container_of(work, struct goodix_ts_data, work);
#ifdef CONFIG_GT9XX_TOUCHPANEL_UPDATE
if (ts->enter_update)
return;
#endif
#if GTP_SLIDE_WAKEUP
if (DOZE_ENABLED == doze_status) {
ret = gtp_i2c_read(ts->client, doze_buf, 3);
GTP_DEBUG("0x814B = 0x%02X", doze_buf[2]);
if (ret > 0) {
if (doze_buf[2] == 0xAA) {
dev_dbg(&ts->client->dev,
"Slide(0xAA) To Light up the screen!");
doze_status = DOZE_WAKEUP;
input_report_key(
ts->input_dev, KEY_POWER, 1);
input_sync(ts->input_dev);
input_report_key(
ts->input_dev, KEY_POWER, 0);
input_sync(ts->input_dev);
/* clear 0x814B */
doze_buf[2] = 0x00;
gtp_i2c_write(ts->client, doze_buf, 3);
} else if (doze_buf[2] == 0xBB) {
dev_dbg(&ts->client->dev,
"Slide(0xBB) To Light up the screen!");
doze_status = DOZE_WAKEUP;
input_report_key(ts->input_dev, KEY_POWER, 1);
input_sync(ts->input_dev);
input_report_key(ts->input_dev, KEY_POWER, 0);
input_sync(ts->input_dev);
/* clear 0x814B*/
doze_buf[2] = 0x00;
gtp_i2c_write(ts->client, doze_buf, 3);
} else if (0xC0 == (doze_buf[2] & 0xC0)) {
dev_dbg(&ts->client->dev,
"double click to light up the screen!");
doze_status = DOZE_WAKEUP;
input_report_key(ts->input_dev, KEY_POWER, 1);
input_sync(ts->input_dev);
input_report_key(ts->input_dev, KEY_POWER, 0);
input_sync(ts->input_dev);
/* clear 0x814B */
doze_buf[2] = 0x00;
gtp_i2c_write(ts->client, doze_buf, 3);
} else {
gtp_enter_doze(ts);
}
}
if (ts->use_irq)
gtp_irq_enable(ts);
return;
}
#endif
ret = gtp_i2c_read(ts->client, point_data, 12);
if (ret < 0) {
dev_err(&ts->client->dev,
"I2C transfer error. errno:%d\n ", ret);
goto exit_work_func;
}
finger = point_data[GTP_ADDR_LENGTH];
if ((finger & 0x80) == 0)
goto exit_work_func;
touch_num = finger & 0x0f;
if (touch_num > GTP_MAX_TOUCH)
goto exit_work_func;
if (touch_num > 1) {
u8 buf[8 * GTP_MAX_TOUCH] = { (GTP_READ_COOR_ADDR + 10) >> 8,
(GTP_READ_COOR_ADDR + 10) & 0xff };
ret = gtp_i2c_read(ts->client, buf,
2 + 8 * (touch_num - 1));
memcpy(&point_data[12], &buf[2], 8 * (touch_num - 1));
}
#if GTP_HAVE_TOUCH_KEY
key_value = point_data[3 + 8 * touch_num];
if (key_value || pre_key) {
for (i = 0; i < GTP_MAX_KEY_NUM; i++) {
#if GTP_DEBUG_ON
for (ret = 0; ret < 4; ++ret) {
if (key_codes[ret] == touch_key_array[i]) {
GTP_DEBUG("Key: %s %s",
key_names[ret],
(key_value & (0x01 << i))
? "Down" : "Up");
break;
}
}
#endif
input_report_key(ts->input_dev,
touch_key_array[i], key_value & (0x01<input_dev, BTN_TOOL_PEN, 0);
input_mt_slot(ts->input_dev, 5);
input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
pre_pen = 0;
}
#endif
if (pre_touch || touch_num) {
s32 pos = 0;
u16 touch_index = 0;
coor_data = &point_data[3];
if (touch_num) {
id = coor_data[pos] & 0x0F;
#if GTP_WITH_PEN
id = coor_data[pos];
if (id == 128) {
GTP_DEBUG("Pen touch DOWN(Slot)!");
input_x = coor_data[pos + 1]
| (coor_data[pos + 2] << 8);
input_y = coor_data[pos + 3]
| (coor_data[pos + 4] << 8);
input_w = coor_data[pos + 5]
| (coor_data[pos + 6] << 8);
input_report_key(ts->input_dev,
BTN_TOOL_PEN, 1);
input_mt_slot(ts->input_dev, 5);
input_report_abs(ts->input_dev,
ABS_MT_TRACKING_ID, 5);
input_report_abs(ts->input_dev,
ABS_MT_POSITION_X, input_x);
input_report_abs(ts->input_dev,
ABS_MT_POSITION_Y, input_y);
input_report_abs(ts->input_dev,
ABS_MT_TOUCH_MAJOR, input_w);
GTP_DEBUG("Pen/Stylus: (%d, %d)[%d]",
input_x, input_y, input_w);
pre_pen = 1;
pre_touch = 0;
}
#endif
touch_index |= (0x01<input_dev);
exit_work_func:
if (!ts->gtp_rawdiff_mode) {
ret = gtp_i2c_write(ts->client, end_cmd, 3);
if (ret < 0)
dev_warn(&ts->client->dev, "I2C write end_cmd error!\n");
}
if (ts->use_irq)
gtp_irq_enable(ts);
return;
}
我的两个接口一个是用来初始化input子系统,一个用来上报坐标信息如下:
首先定义初始化和上报的函数:
struct lidbg_ts_data
{
s32 x[10];
s32 y[10];
s32 w[10];
s32 id[10];
u8 touch_num;
u16 touch_index;
u16 *pre_touch;
};
struct lidbg_input_data
{
u16 abs_x_max;
u16 abs_y_max;
};
void lidbg_touch_main(int argc, char **argv);
void lidbg_touch_report(struct input_dev * input_dev, struct lidbg_ts_data * pdata);
int lidbg_init_input(struct input_dev **input_dev,struct lidbg_input_data *pinput);
初始化的话我们要传入需要初始化的input指针,所以要用二级指针来:
int lidbg_init_input(struct input_dev **input_dev,struct lidbg_input_data *pinput)
{
int ret;
char phys[32];
lidbg("%s:----------------wsx-------------------\n",__FUNCTION__);
*input_dev = input_allocate_device();
if (input_dev == NULL) {
lidbg("Failed to allocate input device.\n");
return -ENOMEM;
}
(*input_dev)->evbit[0] =
BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
set_bit(BTN_TOOL_FINGER, (*input_dev)->keybit);
__set_bit(INPUT_PROP_DIRECT, (*input_dev)->propbit);
#if GTP_CHANGE_X2Y
GTP_SWAP(pinput->abs_x_max, pinput->abs_y_max);
#endif
input_mt_init_slots(*input_dev, 5);/* in case of "out of memory" */
input_set_abs_params(*input_dev, ABS_MT_POSITION_X,
0, pinput->abs_x_max, 0, 0);
input_set_abs_params(*input_dev, ABS_MT_POSITION_Y,
0, pinput->abs_y_max, 0, 0);
input_set_abs_params(*input_dev, ABS_MT_WIDTH_MAJOR,
0, 255, 0, 0);
input_set_abs_params(*input_dev, ABS_MT_TOUCH_MAJOR,
0, 255, 0, 0);
input_set_abs_params(*input_dev, ABS_MT_TRACKING_ID,
0, 255, 0, 0);
snprintf(phys, 32, "input/ts");
//strcpy(input_dev->name,"Goodix-CTP");
(*input_dev)->name = "Goodix-CTP";
(*input_dev)->phys = phys;
(*input_dev)->id.bustype = BUS_I2C;
(*input_dev)->id.vendor = 0xDEAD;
(*input_dev)->id.product = 0xBEEF;
(*input_dev)->id.version = 10427;
lidbg("before register\n");
ret = input_register_device(*input_dev);
if (ret) {
lidbg("---------wsx------input device failed.\n");
input_free_device(*input_dev);
input_dev = NULL;
return ret;
}
lidbg("after register\n");
return 0;
}
void lidbg_touch_report(struct input_dev *input_dev,struct lidbg_ts_data *pdata)
{
int i;
for (i = 0; i < GTP_MAX_TOUCH; i++)
{
input_mt_slot(input_dev, pdata->id[i]);
if ((pdata->touch_index) & (0x01<x[i], pdata->y[i]);
#endif
input_mt_slot(input_dev, pdata->id[i]);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, true);
input_report_abs(input_dev, ABS_MT_POSITION_X, pdata->x[i]);
input_report_abs(input_dev, ABS_MT_POSITION_Y, pdata->y[i]);
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, pdata->w[i]);
input_report_abs(input_dev, ABS_MT_WIDTH_MAJOR, pdata->w[i]);
lidbg("%d,%d[%d,%d];\n", pdata->touch_num,pdata->id[i], pdata->x[i], pdata->y[i]);
*(pdata->pre_touch) |= 0x01 << i;
pdata->touch_index |= (0x01 << pdata->id[i+1]);
}
else
{
lidbg("release\n");
input_mt_slot(input_dev, i);
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false);
*(pdata->pre_touch) &= ~(0x01 << i);
}
}
input_sync(input_dev);
}