Skip to content

Commit bd3b848

Browse files
jekhordtor
authored andcommitted
Input: goodix - add support for 9-bytes reports
Some variants of Goodix touchscreen firmwares use 9-bytes finger report format instead of common 8-bytes format. This report format may be present as: struct goodix_contact_data { uint8_t unknown1; uint8_t track_id; uint8_t unknown2; uint16_t x; uint16_t y; uint16_t w; }__attribute__((packed)); Add support for such format and use it for Lenovo Yoga Book notebook (which uses a Goodix touchpad as a touch keyboard). Signed-off-by: Yauhen Kharuzhy <[email protected]> Signed-off-by: Dmitry Torokhov <[email protected]>
1 parent afce285 commit bd3b848

File tree

1 file changed

+50
-8
lines changed

1 file changed

+50
-8
lines changed

drivers/input/touchscreen/goodix.c

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ struct goodix_ts_data {
5353
const char *cfg_name;
5454
struct completion firmware_loading_complete;
5555
unsigned long irq_flags;
56+
unsigned int contact_size;
5657
};
5758

5859
#define GOODIX_GPIO_INT_NAME "irq"
@@ -62,6 +63,7 @@ struct goodix_ts_data {
6263
#define GOODIX_MAX_WIDTH 4096
6364
#define GOODIX_INT_TRIGGER 1
6465
#define GOODIX_CONTACT_SIZE 8
66+
#define GOODIX_MAX_CONTACT_SIZE 9
6567
#define GOODIX_MAX_CONTACTS 10
6668

6769
#define GOODIX_CONFIG_MAX_LENGTH 240
@@ -144,6 +146,19 @@ static const struct dmi_system_id rotated_screen[] = {
144146
{}
145147
};
146148

149+
static const struct dmi_system_id nine_bytes_report[] = {
150+
#if defined(CONFIG_DMI) && defined(CONFIG_X86)
151+
{
152+
.ident = "Lenovo YogaBook",
153+
/* YB1-X91L/F and YB1-X90L/F */
154+
.matches = {
155+
DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9")
156+
}
157+
},
158+
#endif
159+
{}
160+
};
161+
147162
/**
148163
* goodix_i2c_read - read data from a register of the i2c slave device.
149164
*
@@ -249,7 +264,7 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
249264
max_timeout = jiffies + msecs_to_jiffies(GOODIX_BUFFER_STATUS_TIMEOUT);
250265
do {
251266
error = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR,
252-
data, GOODIX_CONTACT_SIZE + 1);
267+
data, ts->contact_size + 1);
253268
if (error) {
254269
dev_err(&ts->client->dev, "I2C transfer error: %d\n",
255270
error);
@@ -262,12 +277,12 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
262277
return -EPROTO;
263278

264279
if (touch_num > 1) {
265-
data += 1 + GOODIX_CONTACT_SIZE;
280+
data += 1 + ts->contact_size;
266281
error = goodix_i2c_read(ts->client,
267282
GOODIX_READ_COOR_ADDR +
268-
1 + GOODIX_CONTACT_SIZE,
283+
1 + ts->contact_size,
269284
data,
270-
GOODIX_CONTACT_SIZE *
285+
ts->contact_size *
271286
(touch_num - 1));
272287
if (error)
273288
return error;
@@ -286,7 +301,7 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
286301
return 0;
287302
}
288303

289-
static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
304+
static void goodix_ts_report_touch_8b(struct goodix_ts_data *ts, u8 *coor_data)
290305
{
291306
int id = coor_data[0] & 0x0F;
292307
int input_x = get_unaligned_le16(&coor_data[1]);
@@ -301,6 +316,21 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
301316
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
302317
}
303318

319+
static void goodix_ts_report_touch_9b(struct goodix_ts_data *ts, u8 *coor_data)
320+
{
321+
int id = coor_data[1] & 0x0F;
322+
int input_x = get_unaligned_le16(&coor_data[3]);
323+
int input_y = get_unaligned_le16(&coor_data[5]);
324+
int input_w = get_unaligned_le16(&coor_data[7]);
325+
326+
input_mt_slot(ts->input_dev, id);
327+
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
328+
touchscreen_report_pos(ts->input_dev, &ts->prop,
329+
input_x, input_y, true);
330+
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
331+
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
332+
}
333+
304334
/**
305335
* goodix_process_events - Process incoming events
306336
*
@@ -311,7 +341,7 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
311341
*/
312342
static void goodix_process_events(struct goodix_ts_data *ts)
313343
{
314-
u8 point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
344+
u8 point_data[1 + GOODIX_MAX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
315345
int touch_num;
316346
int i;
317347

@@ -326,8 +356,12 @@ static void goodix_process_events(struct goodix_ts_data *ts)
326356
input_report_key(ts->input_dev, KEY_LEFTMETA, point_data[0] & BIT(4));
327357

328358
for (i = 0; i < touch_num; i++)
329-
goodix_ts_report_touch(ts,
330-
&point_data[1 + GOODIX_CONTACT_SIZE * i]);
359+
if (ts->contact_size == 9)
360+
goodix_ts_report_touch_9b(ts,
361+
&point_data[1 + ts->contact_size * i]);
362+
else
363+
goodix_ts_report_touch_8b(ts,
364+
&point_data[1 + ts->contact_size * i]);
331365

332366
input_mt_sync_frame(ts->input_dev);
333367
input_sync(ts->input_dev);
@@ -730,6 +764,13 @@ static int goodix_configure_dev(struct goodix_ts_data *ts)
730764
"Applying '180 degrees rotated screen' quirk\n");
731765
}
732766

767+
if (dmi_check_system(nine_bytes_report)) {
768+
ts->contact_size = 9;
769+
770+
dev_dbg(&ts->client->dev,
771+
"Non-standard 9-bytes report format quirk\n");
772+
}
773+
733774
error = input_mt_init_slots(ts->input_dev, ts->max_touch_num,
734775
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
735776
if (error) {
@@ -810,6 +851,7 @@ static int goodix_ts_probe(struct i2c_client *client,
810851
ts->client = client;
811852
i2c_set_clientdata(client, ts);
812853
init_completion(&ts->firmware_loading_complete);
854+
ts->contact_size = GOODIX_CONTACT_SIZE;
813855

814856
error = goodix_get_gpio_config(ts);
815857
if (error)

0 commit comments

Comments
 (0)