mirror of
https://github.com/torvalds/linux.git
synced 2024-12-04 01:51:34 +00:00
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 <jekhor@gmail.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
This commit is contained in:
parent
afce285b85
commit
bd3b848023
@ -53,6 +53,7 @@ struct goodix_ts_data {
|
||||
const char *cfg_name;
|
||||
struct completion firmware_loading_complete;
|
||||
unsigned long irq_flags;
|
||||
unsigned int contact_size;
|
||||
};
|
||||
|
||||
#define GOODIX_GPIO_INT_NAME "irq"
|
||||
@ -62,6 +63,7 @@ struct goodix_ts_data {
|
||||
#define GOODIX_MAX_WIDTH 4096
|
||||
#define GOODIX_INT_TRIGGER 1
|
||||
#define GOODIX_CONTACT_SIZE 8
|
||||
#define GOODIX_MAX_CONTACT_SIZE 9
|
||||
#define GOODIX_MAX_CONTACTS 10
|
||||
|
||||
#define GOODIX_CONFIG_MAX_LENGTH 240
|
||||
@ -144,6 +146,19 @@ static const struct dmi_system_id rotated_screen[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct dmi_system_id nine_bytes_report[] = {
|
||||
#if defined(CONFIG_DMI) && defined(CONFIG_X86)
|
||||
{
|
||||
.ident = "Lenovo YogaBook",
|
||||
/* YB1-X91L/F and YB1-X90L/F */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9")
|
||||
}
|
||||
},
|
||||
#endif
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* goodix_i2c_read - read data from a register of the i2c slave device.
|
||||
*
|
||||
@ -249,7 +264,7 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
|
||||
max_timeout = jiffies + msecs_to_jiffies(GOODIX_BUFFER_STATUS_TIMEOUT);
|
||||
do {
|
||||
error = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR,
|
||||
data, GOODIX_CONTACT_SIZE + 1);
|
||||
data, ts->contact_size + 1);
|
||||
if (error) {
|
||||
dev_err(&ts->client->dev, "I2C transfer error: %d\n",
|
||||
error);
|
||||
@ -262,12 +277,12 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
|
||||
return -EPROTO;
|
||||
|
||||
if (touch_num > 1) {
|
||||
data += 1 + GOODIX_CONTACT_SIZE;
|
||||
data += 1 + ts->contact_size;
|
||||
error = goodix_i2c_read(ts->client,
|
||||
GOODIX_READ_COOR_ADDR +
|
||||
1 + GOODIX_CONTACT_SIZE,
|
||||
1 + ts->contact_size,
|
||||
data,
|
||||
GOODIX_CONTACT_SIZE *
|
||||
ts->contact_size *
|
||||
(touch_num - 1));
|
||||
if (error)
|
||||
return error;
|
||||
@ -286,7 +301,7 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
|
||||
static void goodix_ts_report_touch_8b(struct goodix_ts_data *ts, u8 *coor_data)
|
||||
{
|
||||
int id = coor_data[0] & 0x0F;
|
||||
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)
|
||||
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
|
||||
}
|
||||
|
||||
static void goodix_ts_report_touch_9b(struct goodix_ts_data *ts, u8 *coor_data)
|
||||
{
|
||||
int id = coor_data[1] & 0x0F;
|
||||
int input_x = get_unaligned_le16(&coor_data[3]);
|
||||
int input_y = get_unaligned_le16(&coor_data[5]);
|
||||
int input_w = get_unaligned_le16(&coor_data[7]);
|
||||
|
||||
input_mt_slot(ts->input_dev, id);
|
||||
input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true);
|
||||
touchscreen_report_pos(ts->input_dev, &ts->prop,
|
||||
input_x, input_y, true);
|
||||
input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
|
||||
input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
|
||||
}
|
||||
|
||||
/**
|
||||
* goodix_process_events - Process incoming events
|
||||
*
|
||||
@ -311,7 +341,7 @@ static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
|
||||
*/
|
||||
static void goodix_process_events(struct goodix_ts_data *ts)
|
||||
{
|
||||
u8 point_data[1 + GOODIX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
|
||||
u8 point_data[1 + GOODIX_MAX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
|
||||
int touch_num;
|
||||
int i;
|
||||
|
||||
@ -326,8 +356,12 @@ static void goodix_process_events(struct goodix_ts_data *ts)
|
||||
input_report_key(ts->input_dev, KEY_LEFTMETA, point_data[0] & BIT(4));
|
||||
|
||||
for (i = 0; i < touch_num; i++)
|
||||
goodix_ts_report_touch(ts,
|
||||
&point_data[1 + GOODIX_CONTACT_SIZE * i]);
|
||||
if (ts->contact_size == 9)
|
||||
goodix_ts_report_touch_9b(ts,
|
||||
&point_data[1 + ts->contact_size * i]);
|
||||
else
|
||||
goodix_ts_report_touch_8b(ts,
|
||||
&point_data[1 + ts->contact_size * i]);
|
||||
|
||||
input_mt_sync_frame(ts->input_dev);
|
||||
input_sync(ts->input_dev);
|
||||
@ -730,6 +764,13 @@ static int goodix_configure_dev(struct goodix_ts_data *ts)
|
||||
"Applying '180 degrees rotated screen' quirk\n");
|
||||
}
|
||||
|
||||
if (dmi_check_system(nine_bytes_report)) {
|
||||
ts->contact_size = 9;
|
||||
|
||||
dev_dbg(&ts->client->dev,
|
||||
"Non-standard 9-bytes report format quirk\n");
|
||||
}
|
||||
|
||||
error = input_mt_init_slots(ts->input_dev, ts->max_touch_num,
|
||||
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
|
||||
if (error) {
|
||||
@ -810,6 +851,7 @@ static int goodix_ts_probe(struct i2c_client *client,
|
||||
ts->client = client;
|
||||
i2c_set_clientdata(client, ts);
|
||||
init_completion(&ts->firmware_loading_complete);
|
||||
ts->contact_size = GOODIX_CONTACT_SIZE;
|
||||
|
||||
error = goodix_get_gpio_config(ts);
|
||||
if (error)
|
||||
|
Loading…
Reference in New Issue
Block a user