From 642aa86eaf8f1e6fe894f20fd7f12f0db52ee03c Mon Sep 17 00:00:00 2001 From: Dennis Kadioglu Date: Tue, 26 May 2020 23:03:13 -0700 Subject: Input: synaptics - add a second working PNP_ID for Lenovo T470s The Lenovo Thinkpad T470s I own has a different touchpad with "LEN007a" instead of the already included PNP ID "LEN006c". However, my touchpad seems to work well without any problems using RMI. So this patch adds the other PNP ID. Signed-off-by: Dennis Kadioglu Link: https://lore.kernel.org/r/ff770543cd53ae818363c0fe86477965@mail.eclipso.de Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 4d2036209b45..758dae8d6500 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -170,6 +170,7 @@ static const char * const smbus_pnp_ids[] = { "LEN005b", /* P50 */ "LEN005e", /* T560 */ "LEN006c", /* T470s */ + "LEN007a", /* T470s */ "LEN0071", /* T480 */ "LEN0072", /* X1 Carbon Gen 5 (2017) - Elan/ALPS trackpoint */ "LEN0073", /* X1 Carbon G5 (Elantech) */ -- cgit v1.2.3 From 77da21c5d3c698f5c9ce41d57c137244bc8b7b93 Mon Sep 17 00:00:00 2001 From: Jingle Wu Date: Wed, 15 Jul 2020 17:40:27 -0700 Subject: Input: elan_i2c - handle firmware not implementing "get pattern" command Not all versions of firmware implement "get pattern" command. When encountering those assume that the controllers use older pattern. Signed-off-by: Jingle Wu Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_i2c.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index 058b35b1f9a9..0d8a6a1b30d7 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -249,7 +249,13 @@ static int elan_i2c_get_pattern(struct i2c_client *client, u8 *pattern) dev_err(&client->dev, "failed to get pattern: %d\n", error); return error; } - *pattern = val[1]; + + /* + * Not all versions of firmware implement "get pattern" command. + * When this command is not implemented the device will respond + * with 0xFF 0xFF, which we will treat as "old" pattern 0. + */ + *pattern = val[0] == 0xFF && val[1] == 0xFF ? 0 : val[1]; return 0; } -- cgit v1.2.3 From fc7c882aa9b1643273c4bb77d31163355dcbc0b8 Mon Sep 17 00:00:00 2001 From: Jingle Wu Date: Wed, 15 Jul 2020 22:25:59 -0700 Subject: Input: elan_i2c - make fetching IC type of older controllers more robust On older controllers IC type is reported in the 2nd byte of ETP_I2C_OSM_VERSION_CMD, however if controller's firmware is not flashed correctly it may return incorrect data. Fortunately there is also ETP_I2C_IAP_VERSION_P0_CMD command that can be used when controller in either normal or IAP mode, and which is guaranteed to return accurate data, so let's use it. Signed-off-by: Jingle Wu Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_core.c | 8 +------- drivers/input/mouse/elan_i2c_i2c.c | 10 +++++++++- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 8719da540383..f1dade60f407 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -312,7 +312,6 @@ static int elan_initialize(struct elan_tp_data *data) static int elan_query_device_info(struct elan_tp_data *data) { int error; - u16 ic_type; error = data->ops->get_version(data->client, false, &data->fw_version); if (error) @@ -336,12 +335,7 @@ static int elan_query_device_info(struct elan_tp_data *data) if (error) return error; - if (data->pattern == 0x01) - ic_type = data->ic_type; - else - ic_type = data->iap_version; - - error = elan_get_fwinfo(ic_type, &data->fw_validpage_count, + error = elan_get_fwinfo(data->ic_type, &data->fw_validpage_count, &data->fw_signature_address); if (error) dev_warn(&data->client->dev, diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index 0d8a6a1b30d7..bceb4bc32697 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -43,6 +43,7 @@ #define ETP_I2C_RESOLUTION_CMD 0x0108 #define ETP_I2C_PRESSURE_CMD 0x010A #define ETP_I2C_IAP_VERSION_CMD 0x0110 +#define ETP_I2C_IC_TYPE_P0_CMD 0x0110 #define ETP_I2C_SET_CMD 0x0300 #define ETP_I2C_POWER_CMD 0x0307 #define ETP_I2C_FW_CHECKSUM_CMD 0x030F @@ -330,7 +331,14 @@ static int elan_i2c_get_sm_version(struct i2c_client *client, return error; } *version = val[0]; - *ic_type = val[1]; + + error = elan_i2c_read_cmd(client, ETP_I2C_IC_TYPE_P0_CMD, val); + if (error) { + dev_err(&client->dev, "failed to get ic type: %d\n", + error); + return error; + } + *ic_type = val[0]; error = elan_i2c_read_cmd(client, ETP_I2C_NSM_VERSION_CMD, val); -- cgit v1.2.3 From 40d8aa97131d16fe880cd48f8faabcd6a45019c4 Mon Sep 17 00:00:00 2001 From: Jingle Wu Date: Wed, 15 Jul 2020 22:12:08 -0700 Subject: Input: elan_i2c - handle devices with patterns above 1 Extend fetching and parsing parameters of the controllers to devices with "patterns" above 1 (which currently should be handled in the same fashion as devices with pattern 1). Signed-off-by: Jingle Wu Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index bceb4bc32697..bb499f0d0925 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -284,7 +284,7 @@ static int elan_i2c_get_version(struct i2c_client *client, return error; } - if (pattern_ver == 0x01) + if (pattern_ver >= 0x01) *version = iap ? val[1] : val[0]; else *version = val[0]; @@ -305,7 +305,7 @@ static int elan_i2c_get_sm_version(struct i2c_client *client, return error; } - if (pattern_ver == 0x01) { + if (pattern_ver >= 0x01) { error = elan_i2c_read_cmd(client, ETP_I2C_IC_TYPE_CMD, val); if (error) { dev_err(&client->dev, "failed to get ic type: %d\n", -- cgit v1.2.3 From df10cc8db1e13cfcbd851e02881e2ef815d21b37 Mon Sep 17 00:00:00 2001 From: Jingle Wu Date: Wed, 15 Jul 2020 22:02:19 -0700 Subject: Input: elan_i2c - fix detecting IAP version on older controllers Older controllers in bootloader mode need a different command to retrieve the IAP version. Signed-off-by: Jingle Wu Link: https://lore.kernel.org/r/20200714105641.15151-1-jingle.wu@emc.com.tw Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_i2c.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index bb499f0d0925..317166a264e6 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -44,6 +44,7 @@ #define ETP_I2C_PRESSURE_CMD 0x010A #define ETP_I2C_IAP_VERSION_CMD 0x0110 #define ETP_I2C_IC_TYPE_P0_CMD 0x0110 +#define ETP_I2C_IAP_VERSION_P0_CMD 0x0111 #define ETP_I2C_SET_CMD 0x0300 #define ETP_I2C_POWER_CMD 0x0307 #define ETP_I2C_FW_CHECKSUM_CMD 0x030F @@ -266,6 +267,7 @@ static int elan_i2c_get_version(struct i2c_client *client, { int error; u8 pattern_ver; + u16 cmd; u8 val[3]; error = elan_i2c_get_pattern(client, &pattern_ver); @@ -274,10 +276,14 @@ static int elan_i2c_get_version(struct i2c_client *client, return error; } - error = elan_i2c_read_cmd(client, - iap ? ETP_I2C_IAP_VERSION_CMD : - ETP_I2C_FW_VERSION_CMD, - val); + if (!iap) + cmd = ETP_I2C_FW_VERSION_CMD; + else if (pattern_ver == 0) + cmd = ETP_I2C_IAP_VERSION_P0_CMD; + else + cmd = ETP_I2C_IAP_VERSION_CMD; + + error = elan_i2c_read_cmd(client, cmd, val); if (error) { dev_err(&client->dev, "failed to get %s version: %d\n", iap ? "IAP" : "FW", error); -- cgit v1.2.3 From 059d6c2de6fd521d4d4a39d127eece3de114b767 Mon Sep 17 00:00:00 2001 From: Jingle Wu Date: Thu, 16 Jul 2020 21:32:23 -0700 Subject: Input: elan_i2c - add support for different firmware page sizes Prepare driver for devices that use different sizes of firmware pages. Signed-off-by: Jingle Wu Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c.h | 4 +++- drivers/input/mouse/elan_i2c_core.c | 24 +++++++++++++++--------- drivers/input/mouse/elan_i2c_i2c.c | 30 +++++++++++++++++++----------- drivers/input/mouse/elan_i2c_smbus.c | 8 ++++---- 4 files changed, 41 insertions(+), 25 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h index a9074ac9364f..b504f560a666 100644 --- a/drivers/input/mouse/elan_i2c.h +++ b/drivers/input/mouse/elan_i2c.h @@ -33,6 +33,8 @@ #define ETP_FW_IAP_PAGE_ERR (1 << 5) #define ETP_FW_IAP_INTF_ERR (1 << 4) #define ETP_FW_PAGE_SIZE 64 +#define ETP_FW_PAGE_SIZE_128 128 +#define ETP_FW_PAGE_SIZE_512 512 #define ETP_FW_SIGNATURE_SIZE 6 struct i2c_client; @@ -73,7 +75,7 @@ struct elan_transport_ops { int (*iap_reset)(struct i2c_client *client); int (*prepare_fw_update)(struct i2c_client *client); - int (*write_fw_block)(struct i2c_client *client, + int (*write_fw_block)(struct i2c_client *client, u16 fw_page_size, const u8 *page, u16 checksum, int idx); int (*finish_fw_update)(struct i2c_client *client, struct completion *reset_done); diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index f1dade60f407..46f334bcfc0e 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -89,7 +89,8 @@ struct elan_tp_data { u8 mode; u16 ic_type; u16 fw_validpage_count; - u16 fw_signature_address; + u16 fw_page_size; + u32 fw_signature_address; bool irq_wake; @@ -101,7 +102,7 @@ struct elan_tp_data { }; static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count, - u16 *signature_address) + u32 *signature_address, u16 *page_size) { switch (ic_type) { case 0x00: @@ -130,12 +131,15 @@ static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count, /* unknown ic type clear value */ *validpage_count = 0; *signature_address = 0; + *page_size = 0; return -ENXIO; } *signature_address = (*validpage_count * ETP_FW_PAGE_SIZE) - ETP_FW_SIGNATURE_SIZE; + *page_size = ETP_FW_PAGE_SIZE; + return 0; } @@ -336,7 +340,8 @@ static int elan_query_device_info(struct elan_tp_data *data) return error; error = elan_get_fwinfo(data->ic_type, &data->fw_validpage_count, - &data->fw_signature_address); + &data->fw_signature_address, + &data->fw_page_size); if (error) dev_warn(&data->client->dev, "unexpected iap version %#04x (ic type: %#04x), firmware update will not work\n", @@ -424,14 +429,14 @@ static int elan_query_device_parameters(struct elan_tp_data *data) * IAP firmware updater related routines ********************************************************** */ -static int elan_write_fw_block(struct elan_tp_data *data, +static int elan_write_fw_block(struct elan_tp_data *data, u16 page_size, const u8 *page, u16 checksum, int idx) { int retry = ETP_RETRY_COUNT; int error; do { - error = data->ops->write_fw_block(data->client, + error = data->ops->write_fw_block(data->client, page_size, page, checksum, idx); if (!error) return 0; @@ -460,15 +465,16 @@ static int __elan_update_firmware(struct elan_tp_data *data, iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]); - boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE; + boot_page_count = (iap_start_addr * 2) / data->fw_page_size; for (i = boot_page_count; i < data->fw_validpage_count; i++) { u16 checksum = 0; - const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE]; + const u8 *page = &fw->data[i * data->fw_page_size]; - for (j = 0; j < ETP_FW_PAGE_SIZE; j += 2) + for (j = 0; j < data->fw_page_size; j += 2) checksum += ((page[j + 1] << 8) | page[j]); - error = elan_write_fw_block(data, page, checksum, i); + error = elan_write_fw_block(data, data->fw_page_size, + page, checksum, i); if (error) { dev_err(dev, "write page %d fail: %d\n", i, error); return error; diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index 317166a264e6..4dfc3c2b4706 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -592,45 +593,52 @@ static int elan_i2c_prepare_fw_update(struct i2c_client *client) return 0; } -static int elan_i2c_write_fw_block(struct i2c_client *client, +static int elan_i2c_write_fw_block(struct i2c_client *client, u16 fw_page_size, const u8 *page, u16 checksum, int idx) { struct device *dev = &client->dev; - u8 page_store[ETP_FW_PAGE_SIZE + 4]; + u8 *page_store; u8 val[3]; u16 result; int ret, error; + page_store = kmalloc(fw_page_size + 4, GFP_KERNEL); + if (!page_store) + return -ENOMEM; + page_store[0] = ETP_I2C_IAP_REG_L; page_store[1] = ETP_I2C_IAP_REG_H; - memcpy(&page_store[2], page, ETP_FW_PAGE_SIZE); + memcpy(&page_store[2], page, fw_page_size); /* recode checksum at last two bytes */ - put_unaligned_le16(checksum, &page_store[ETP_FW_PAGE_SIZE + 2]); + put_unaligned_le16(checksum, &page_store[fw_page_size + 2]); - ret = i2c_master_send(client, page_store, sizeof(page_store)); - if (ret != sizeof(page_store)) { + ret = i2c_master_send(client, page_store, fw_page_size + 4); + if (ret != fw_page_size + 4) { error = ret < 0 ? ret : -EIO; dev_err(dev, "Failed to write page %d: %d\n", idx, error); - return error; + goto exit; } /* Wait for F/W to update one page ROM data. */ - msleep(35); + msleep(fw_page_size == ETP_FW_PAGE_SIZE_512 ? 50 : 35); error = elan_i2c_read_cmd(client, ETP_I2C_IAP_CTRL_CMD, val); if (error) { dev_err(dev, "Failed to read IAP write result: %d\n", error); - return error; + goto exit; } result = le16_to_cpup((__le16 *)val); if (result & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR)) { dev_err(dev, "IAP reports failed write: %04hx\n", result); - return -EIO; + error = -EIO; + goto exit; } - return 0; +exit: + kfree(page_store); + return error; } static int elan_i2c_finish_fw_update(struct i2c_client *client, diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index 8c3185d54c73..59eec1a2ed5c 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -414,7 +414,7 @@ static int elan_smbus_prepare_fw_update(struct i2c_client *client) } -static int elan_smbus_write_fw_block(struct i2c_client *client, +static int elan_smbus_write_fw_block(struct i2c_client *client, u16 fw_page_size, const u8 *page, u16 checksum, int idx) { struct device *dev = &client->dev; @@ -429,7 +429,7 @@ static int elan_smbus_write_fw_block(struct i2c_client *client, */ error = i2c_smbus_write_block_data(client, ETP_SMBUS_WRITE_FW_BLOCK, - ETP_FW_PAGE_SIZE / 2, + fw_page_size / 2, page); if (error) { dev_err(dev, "Failed to write page %d (part %d): %d\n", @@ -439,8 +439,8 @@ static int elan_smbus_write_fw_block(struct i2c_client *client, error = i2c_smbus_write_block_data(client, ETP_SMBUS_WRITE_FW_BLOCK, - ETP_FW_PAGE_SIZE / 2, - page + ETP_FW_PAGE_SIZE / 2); + fw_page_size / 2, + page + fw_page_size / 2); if (error) { dev_err(dev, "Failed to write page %d (part %d): %d\n", idx, 2, error); -- cgit v1.2.3 From bfd9b92bc8f9a3777961d27a08f62872a21ac507 Mon Sep 17 00:00:00 2001 From: Jingle Wu Date: Thu, 16 Jul 2020 22:49:09 -0700 Subject: Input: elan_i2c - handle firmware updated on newer ICs Newer ICs with IC type value starting with 0x0D and newer bootloader code use 128-byte firmware pages. Their bootloader also needs to be switched to proper mode before executing firmware update. Signed-off-by: Jingle Wu Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c.h | 3 ++- drivers/input/mouse/elan_i2c_core.c | 15 ++++++++---- drivers/input/mouse/elan_i2c_i2c.c | 46 +++++++++++++++++++++++++++++++++++- drivers/input/mouse/elan_i2c_smbus.c | 3 ++- 4 files changed, 60 insertions(+), 7 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h index b504f560a666..de10a78f0fc9 100644 --- a/drivers/input/mouse/elan_i2c.h +++ b/drivers/input/mouse/elan_i2c.h @@ -74,7 +74,8 @@ struct elan_transport_ops { int (*iap_get_mode)(struct i2c_client *client, enum tp_mode *mode); int (*iap_reset)(struct i2c_client *client); - int (*prepare_fw_update)(struct i2c_client *client); + int (*prepare_fw_update)(struct i2c_client *client, u16 ic_type, + u8 iap_version); int (*write_fw_block)(struct i2c_client *client, u16 fw_page_size, const u8 *page, u16 checksum, int idx); int (*finish_fw_update)(struct i2c_client *client, diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 46f334bcfc0e..e0f42def99aa 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -101,7 +101,7 @@ struct elan_tp_data { bool middle_button; }; -static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count, +static int elan_get_fwinfo(u16 ic_type, u8 iap_version, u16 *validpage_count, u32 *signature_address, u16 *page_size) { switch (ic_type) { @@ -138,7 +138,12 @@ static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count, *signature_address = (*validpage_count * ETP_FW_PAGE_SIZE) - ETP_FW_SIGNATURE_SIZE; - *page_size = ETP_FW_PAGE_SIZE; + if (ic_type >= 0x0D && iap_version >= 1) { + *validpage_count /= 2; + *page_size = ETP_FW_PAGE_SIZE_128; + } else { + *page_size = ETP_FW_PAGE_SIZE; + } return 0; } @@ -339,7 +344,8 @@ static int elan_query_device_info(struct elan_tp_data *data) if (error) return error; - error = elan_get_fwinfo(data->ic_type, &data->fw_validpage_count, + error = elan_get_fwinfo(data->ic_type, data->iap_version, + &data->fw_validpage_count, &data->fw_signature_address, &data->fw_page_size); if (error) @@ -459,7 +465,8 @@ static int __elan_update_firmware(struct elan_tp_data *data, u16 boot_page_count; u16 sw_checksum = 0, fw_checksum = 0; - error = data->ops->prepare_fw_update(client); + error = data->ops->prepare_fw_update(client, data->ic_type, + data->iap_version); if (error) return error; diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index 4dfc3c2b4706..4dfac2ea5084 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -56,6 +56,8 @@ #define ETP_I2C_CALIBRATE_CMD 0x0316 #define ETP_I2C_MAX_BASELINE_CMD 0x0317 #define ETP_I2C_MIN_BASELINE_CMD 0x0318 +#define ETP_I2C_IAP_TYPE_REG 0x0040 +#define ETP_I2C_IAP_TYPE_CMD 0x0304 #define ETP_I2C_REPORT_LEN 34 #define ETP_I2C_DESC_LENGTH 30 @@ -528,7 +530,43 @@ static int elan_i2c_set_flash_key(struct i2c_client *client) return 0; } -static int elan_i2c_prepare_fw_update(struct i2c_client *client) +static int elan_read_write_iap_type(struct i2c_client *client) +{ + int error; + u16 constant; + u8 val[3]; + int retry = 3; + + do { + error = elan_i2c_write_cmd(client, ETP_I2C_IAP_TYPE_CMD, + ETP_I2C_IAP_TYPE_REG); + if (error) { + dev_err(&client->dev, + "cannot write iap type: %d\n", error); + return error; + } + + error = elan_i2c_read_cmd(client, ETP_I2C_IAP_TYPE_CMD, val); + if (error) { + dev_err(&client->dev, + "failed to read iap type register: %d\n", + error); + return error; + } + constant = le16_to_cpup((__le16 *)val); + dev_dbg(&client->dev, "iap type reg: 0x%04x\n", constant); + + if (constant == ETP_I2C_IAP_TYPE_REG) + return 0; + + } while (--retry > 0); + + dev_err(&client->dev, "cannot set iap type\n"); + return -EIO; +} + +static int elan_i2c_prepare_fw_update(struct i2c_client *client, u16 ic_type, + u8 iap_version) { struct device *dev = &client->dev; int error; @@ -568,6 +606,12 @@ static int elan_i2c_prepare_fw_update(struct i2c_client *client) return -EIO; } + if (ic_type >= 0x0D && iap_version >= 1) { + error = elan_read_write_iap_type(client); + if (error) + return error; + } + /* Set flash key again */ error = elan_i2c_set_flash_key(client); if (error) diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index 59eec1a2ed5c..97c2c46be5f6 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -340,7 +340,8 @@ static int elan_smbus_set_flash_key(struct i2c_client *client) return 0; } -static int elan_smbus_prepare_fw_update(struct i2c_client *client) +static int elan_smbus_prepare_fw_update(struct i2c_client *client, u16 ic_type, + u8 iap_version) { struct device *dev = &client->dev; int len; -- cgit v1.2.3 From 8d73ec7411e084de8266bc3cb031d85a222458be Mon Sep 17 00:00:00 2001 From: Jingle Wu Date: Thu, 16 Jul 2020 22:55:57 -0700 Subject: Input: elan_i2c - add firmware update info for ICs 0x11, 0x13, 0x14 This adds firmware size and page sizes for ic types 0x11, 0x13 and 0x14. IC 0x14 uses 512-byte firmware page size. Signed-off-by: Jingle Wu . Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_core.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index e0f42def99aa..5c933e16abc1 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -127,6 +127,15 @@ static int elan_get_fwinfo(u16 ic_type, u8 iap_version, u16 *validpage_count, case 0x10: *validpage_count = 1024; break; + case 0x11: + *validpage_count = 1280; + break; + case 0x13: + *validpage_count = 2048; + break; + case 0x14: + *validpage_count = 1024; + break; default: /* unknown ic type clear value */ *validpage_count = 0; @@ -138,7 +147,10 @@ static int elan_get_fwinfo(u16 ic_type, u8 iap_version, u16 *validpage_count, *signature_address = (*validpage_count * ETP_FW_PAGE_SIZE) - ETP_FW_SIGNATURE_SIZE; - if (ic_type >= 0x0D && iap_version >= 1) { + if (ic_type == 0x14 && iap_version >= 2) { + *validpage_count /= 8; + *page_size = ETP_FW_PAGE_SIZE_512; + } else if (ic_type >= 0x0D && iap_version >= 1) { *validpage_count /= 2; *page_size = ETP_FW_PAGE_SIZE_128; } else { -- cgit v1.2.3 From 3d712af637e19a1c139c2b586c08b2a56bdff8c8 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 20 Jul 2020 14:56:54 -0700 Subject: Input: elan_i2c - do not constantly re-query pattern ID We do not need to constantly re-query pattern ID, we can instead query it once and then pass to methods that need it. Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c.h | 5 +++-- drivers/input/mouse/elan_i2c_core.c | 19 +++++++++++-------- drivers/input/mouse/elan_i2c_i2c.c | 27 ++++++--------------------- drivers/input/mouse/elan_i2c_smbus.c | 7 +++---- 4 files changed, 23 insertions(+), 35 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h index de10a78f0fc9..6e6f13a4489c 100644 --- a/drivers/input/mouse/elan_i2c.h +++ b/drivers/input/mouse/elan_i2c.h @@ -57,8 +57,9 @@ struct elan_transport_ops { int (*get_baseline_data)(struct i2c_client *client, bool max_baseliune, u8 *value); - int (*get_version)(struct i2c_client *client, bool iap, u8 *version); - int (*get_sm_version)(struct i2c_client *client, + int (*get_version)(struct i2c_client *client, u8 pattern, bool iap, + u8 *version); + int (*get_sm_version)(struct i2c_client *client, u8 pattern, u16 *ic_type, u8 *version, u8 *clickpad); int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum); int (*get_product_id)(struct i2c_client *client, u16 *id); diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 5c933e16abc1..3230aaf63dab 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -236,8 +236,13 @@ static int elan_query_product(struct elan_tp_data *data) if (error) return error; - error = data->ops->get_sm_version(data->client, &data->ic_type, - &data->sm_version, &data->clickpad); + error = data->ops->get_pattern(data->client, &data->pattern); + if (error) + return error; + + error = data->ops->get_sm_version(data->client, data->pattern, + &data->ic_type, &data->sm_version, + &data->clickpad); if (error) return error; @@ -334,7 +339,8 @@ static int elan_query_device_info(struct elan_tp_data *data) { int error; - error = data->ops->get_version(data->client, false, &data->fw_version); + error = data->ops->get_version(data->client, data->pattern, false, + &data->fw_version); if (error) return error; @@ -343,7 +349,8 @@ static int elan_query_device_info(struct elan_tp_data *data) if (error) return error; - error = data->ops->get_version(data->client, true, &data->iap_version); + error = data->ops->get_version(data->client, data->pattern, + true, &data->iap_version); if (error) return error; @@ -352,10 +359,6 @@ static int elan_query_device_info(struct elan_tp_data *data) if (error) return error; - error = data->ops->get_pattern(data->client, &data->pattern); - if (error) - return error; - error = elan_get_fwinfo(data->ic_type, data->iap_version, &data->fw_validpage_count, &data->fw_signature_address, diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index 4dfac2ea5084..b84e3bbe62b5 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -266,22 +266,15 @@ static int elan_i2c_get_pattern(struct i2c_client *client, u8 *pattern) } static int elan_i2c_get_version(struct i2c_client *client, - bool iap, u8 *version) + u8 pattern, bool iap, u8 *version) { int error; - u8 pattern_ver; u16 cmd; u8 val[3]; - error = elan_i2c_get_pattern(client, &pattern_ver); - if (error) { - dev_err(&client->dev, "failed to get pattern version\n"); - return error; - } - if (!iap) cmd = ETP_I2C_FW_VERSION_CMD; - else if (pattern_ver == 0) + else if (pattern == 0) cmd = ETP_I2C_IAP_VERSION_P0_CMD; else cmd = ETP_I2C_IAP_VERSION_CMD; @@ -293,28 +286,20 @@ static int elan_i2c_get_version(struct i2c_client *client, return error; } - if (pattern_ver >= 0x01) + if (pattern >= 0x01) *version = iap ? val[1] : val[0]; else *version = val[0]; return 0; } -static int elan_i2c_get_sm_version(struct i2c_client *client, - u16 *ic_type, u8 *version, - u8 *clickpad) +static int elan_i2c_get_sm_version(struct i2c_client *client, u8 pattern, + u16 *ic_type, u8 *version, u8 *clickpad) { int error; - u8 pattern_ver; u8 val[3]; - error = elan_i2c_get_pattern(client, &pattern_ver); - if (error) { - dev_err(&client->dev, "failed to get pattern version\n"); - return error; - } - - if (pattern_ver >= 0x01) { + if (pattern >= 0x01) { error = elan_i2c_read_cmd(client, ETP_I2C_IC_TYPE_CMD, val); if (error) { dev_err(&client->dev, "failed to get ic type: %d\n", diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index 97c2c46be5f6..f7af8b7b345f 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -147,7 +147,7 @@ static int elan_smbus_get_baseline_data(struct i2c_client *client, } static int elan_smbus_get_version(struct i2c_client *client, - bool iap, u8 *version) + u8 pattern, bool iap, u8 *version) { int error; u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; @@ -166,9 +166,8 @@ static int elan_smbus_get_version(struct i2c_client *client, return 0; } -static int elan_smbus_get_sm_version(struct i2c_client *client, - u16 *ic_type, u8 *version, - u8 *clickpad) +static int elan_smbus_get_sm_version(struct i2c_client *client, u8 pattern, + u16 *ic_type, u8 *version, u8 *clickpad) { int error; u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; -- cgit v1.2.3 From 04d5ce620f794f1df69b5f1b9ad62910fea547f1 Mon Sep 17 00:00:00 2001 From: Jingle Wu Date: Mon, 20 Jul 2020 12:46:10 -0700 Subject: Input: elan_i2c - add support for high resolution reports Newer controllers (identified as "pattern" version 2) send higher resolution reports, with 16-bit X and Y coordinates (previous generations used 12-bit values). These new high resolution reports use report ID of 0x60. SMbus controllers use the same buffer size for both the new and old reports, and because of that high resolution reports no longer carry area of contact data with SMbus. Signed-off-by: Jingle Wu Link: https://lore.kernel.org/r/20200710054116.5529-1-jingle.wu@emc.com.tw Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c.h | 8 ++- drivers/input/mouse/elan_i2c_core.c | 126 ++++++++++++++++++++++------------- drivers/input/mouse/elan_i2c_i2c.c | 34 +++++++--- drivers/input/mouse/elan_i2c_smbus.c | 17 ++++- 4 files changed, 126 insertions(+), 59 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h index 6e6f13a4489c..c75b00c45d75 100644 --- a/drivers/input/mouse/elan_i2c.h +++ b/drivers/input/mouse/elan_i2c.h @@ -26,6 +26,8 @@ #define ETP_CALIBRATE_MAX_LEN 3 +#define ETP_FEATURE_REPORT_MK BIT(0) + /* IAP Firmware handling */ #define ETP_PRODUCT_ID_FORMAT_STRING "%d.0" #define ETP_FW_NAME "elan_i2c_" ETP_PRODUCT_ID_FORMAT_STRING ".bin" @@ -82,7 +84,11 @@ struct elan_transport_ops { int (*finish_fw_update)(struct i2c_client *client, struct completion *reset_done); - int (*get_report)(struct i2c_client *client, u8 *report); + int (*get_report_features)(struct i2c_client *client, u8 pattern, + unsigned int *features, + unsigned int *report_len); + int (*get_report)(struct i2c_client *client, u8 *report, + unsigned int report_len); int (*get_pressure_adjustment)(struct i2c_client *client, int *adjustment); int (*get_pattern)(struct i2c_client *client, u8 *pattern); diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 3230aaf63dab..f10635a0b189 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -50,12 +50,14 @@ #define ETP_MAX_FINGERS 5 #define ETP_FINGER_DATA_LEN 5 #define ETP_REPORT_ID 0x5D +#define ETP_REPORT_ID2 0x60 /* High precision report */ #define ETP_TP_REPORT_ID 0x5E #define ETP_REPORT_ID_OFFSET 2 #define ETP_TOUCH_INFO_OFFSET 3 #define ETP_FINGER_DATA_OFFSET 4 #define ETP_HOVER_INFO_OFFSET 30 -#define ETP_MAX_REPORT_LEN 34 +#define ETP_MK_DATA_OFFSET 33 /* For high precision reports */ +#define ETP_MAX_REPORT_LEN 39 /* The main device structure */ struct elan_tp_data { @@ -85,6 +87,8 @@ struct elan_tp_data { u8 sm_version; u8 iap_version; u16 fw_checksum; + unsigned int report_features; + unsigned int report_len; int pressure_adjustment; u8 mode; u16 ic_type; @@ -359,6 +363,12 @@ static int elan_query_device_info(struct elan_tp_data *data) if (error) return error; + error = data->ops->get_report_features(data->client, data->pattern, + &data->report_features, + &data->report_len); + if (error) + return error; + error = elan_get_fwinfo(data->ic_type, data->iap_version, &data->fw_validpage_count, &data->fw_signature_address, @@ -371,16 +381,21 @@ static int elan_query_device_info(struct elan_tp_data *data) return 0; } -static unsigned int elan_convert_resolution(u8 val) +static unsigned int elan_convert_resolution(u8 val, u8 pattern) { /* - * (value from firmware) * 10 + 790 = dpi - * + * pattern <= 0x01: + * (value from firmware) * 10 + 790 = dpi + * else + * ((value from firmware) + 3) * 100 = dpi + */ + int res = pattern <= 0x01 ? + (int)(char)val * 10 + 790 : ((int)(char)val + 3) * 100; + /* * We also have to convert dpi to dots/mm (*10/254 to avoid floating * point). */ - - return ((int)(char)val * 10 + 790) * 10 / 254; + return res * 10 / 254; } static int elan_query_device_parameters(struct elan_tp_data *data) @@ -429,8 +444,8 @@ static int elan_query_device_parameters(struct elan_tp_data *data) if (error) return error; - data->x_res = elan_convert_resolution(hw_x_res); - data->y_res = elan_convert_resolution(hw_y_res); + data->x_res = elan_convert_resolution(hw_x_res, data->pattern); + data->y_res = elan_convert_resolution(hw_y_res, data->pattern); } else { data->x_res = (data->max_x + 1) / x_mm; data->y_res = (data->max_y + 1) / y_mm; @@ -908,24 +923,22 @@ static const struct attribute_group *elan_sysfs_groups[] = { * Elan isr functions ****************************************************************** */ -static void elan_report_contact(struct elan_tp_data *data, - int contact_num, bool contact_valid, - u8 *finger_data) +static void elan_report_contact(struct elan_tp_data *data, int contact_num, + bool contact_valid, bool high_precision, + u8 *packet, u8 *finger_data) { struct input_dev *input = data->input; unsigned int pos_x, pos_y; - unsigned int pressure, mk_x, mk_y; - unsigned int area_x, area_y, major, minor; - unsigned int scaled_pressure; + unsigned int pressure, scaled_pressure; if (contact_valid) { - pos_x = ((finger_data[0] & 0xf0) << 4) | - finger_data[1]; - pos_y = ((finger_data[0] & 0x0f) << 8) | - finger_data[2]; - mk_x = (finger_data[3] & 0x0f); - mk_y = (finger_data[3] >> 4); - pressure = finger_data[4]; + if (high_precision) { + pos_x = get_unaligned_be16(&finger_data[0]); + pos_y = get_unaligned_be16(&finger_data[2]); + } else { + pos_x = ((finger_data[0] & 0xf0) << 4) | finger_data[1]; + pos_y = ((finger_data[0] & 0x0f) << 8) | finger_data[2]; + } if (pos_x > data->max_x || pos_y > data->max_y) { dev_dbg(input->dev.parent, @@ -935,18 +948,8 @@ static void elan_report_contact(struct elan_tp_data *data, return; } - /* - * To avoid treating large finger as palm, let's reduce the - * width x and y per trace. - */ - area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE); - area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE); - - major = max(area_x, area_y); - minor = min(area_x, area_y); - + pressure = finger_data[4]; scaled_pressure = pressure + data->pressure_adjustment; - if (scaled_pressure > ETP_MAX_PRESSURE) scaled_pressure = ETP_MAX_PRESSURE; @@ -955,16 +958,37 @@ static void elan_report_contact(struct elan_tp_data *data, input_report_abs(input, ABS_MT_POSITION_X, pos_x); input_report_abs(input, ABS_MT_POSITION_Y, data->max_y - pos_y); input_report_abs(input, ABS_MT_PRESSURE, scaled_pressure); - input_report_abs(input, ABS_TOOL_WIDTH, mk_x); - input_report_abs(input, ABS_MT_TOUCH_MAJOR, major); - input_report_abs(input, ABS_MT_TOUCH_MINOR, minor); + + if (data->report_features & ETP_FEATURE_REPORT_MK) { + unsigned int mk_x, mk_y, area_x, area_y; + u8 mk_data = high_precision ? + packet[ETP_MK_DATA_OFFSET + contact_num] : + finger_data[3]; + + mk_x = mk_data & 0x0f; + mk_y = mk_data >> 4; + + /* + * To avoid treating large finger as palm, let's reduce + * the width x and y per trace. + */ + area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE); + area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE); + + input_report_abs(input, ABS_TOOL_WIDTH, mk_x); + input_report_abs(input, ABS_MT_TOUCH_MAJOR, + max(area_x, area_y)); + input_report_abs(input, ABS_MT_TOUCH_MINOR, + min(area_x, area_y)); + } } else { input_mt_slot(input, contact_num); input_mt_report_slot_state(input, MT_TOOL_FINGER, false); } } -static void elan_report_absolute(struct elan_tp_data *data, u8 *packet) +static void elan_report_absolute(struct elan_tp_data *data, u8 *packet, + bool high_precision) { struct input_dev *input = data->input; u8 *finger_data = &packet[ETP_FINGER_DATA_OFFSET]; @@ -973,11 +997,12 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet) u8 hover_info = packet[ETP_HOVER_INFO_OFFSET]; bool contact_valid, hover_event; - hover_event = hover_info & 0x40; - for (i = 0; i < ETP_MAX_FINGERS; i++) { - contact_valid = tp_info & (1U << (3 + i)); - elan_report_contact(data, i, contact_valid, finger_data); + hover_event = hover_info & BIT(6); + for (i = 0; i < ETP_MAX_FINGERS; i++) { + contact_valid = tp_info & BIT(3 + i); + elan_report_contact(data, i, contact_valid, high_precision, + packet, finger_data); if (contact_valid) finger_data += ETP_FINGER_DATA_LEN; } @@ -1034,7 +1059,7 @@ static irqreturn_t elan_isr(int irq, void *dev_id) goto out; } - error = data->ops->get_report(data->client, report); + error = data->ops->get_report(data->client, report, data->report_len); if (error) goto out; @@ -1042,7 +1067,10 @@ static irqreturn_t elan_isr(int irq, void *dev_id) switch (report[ETP_REPORT_ID_OFFSET]) { case ETP_REPORT_ID: - elan_report_absolute(data, report); + elan_report_absolute(data, report, false); + break; + case ETP_REPORT_ID2: + elan_report_absolute(data, report, true); break; case ETP_TP_REPORT_ID: elan_report_trackpoint(data, report); @@ -1133,7 +1161,9 @@ static int elan_setup_input_device(struct elan_tp_data *data) input_abs_set_res(input, ABS_X, data->x_res); input_abs_set_res(input, ABS_Y, data->y_res); input_set_abs_params(input, ABS_PRESSURE, 0, ETP_MAX_PRESSURE, 0, 0); - input_set_abs_params(input, ABS_TOOL_WIDTH, 0, ETP_FINGER_WIDTH, 0, 0); + if (data->report_features & ETP_FEATURE_REPORT_MK) + input_set_abs_params(input, ABS_TOOL_WIDTH, + 0, ETP_FINGER_WIDTH, 0, 0); input_set_abs_params(input, ABS_DISTANCE, 0, 1, 0, 0); /* And MT parameters */ @@ -1143,10 +1173,12 @@ static int elan_setup_input_device(struct elan_tp_data *data) input_abs_set_res(input, ABS_MT_POSITION_Y, data->y_res); input_set_abs_params(input, ABS_MT_PRESSURE, 0, ETP_MAX_PRESSURE, 0, 0); - input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, - ETP_FINGER_WIDTH * max_width, 0, 0); - input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, - ETP_FINGER_WIDTH * min_width, 0, 0); + if (data->report_features & ETP_FEATURE_REPORT_MK) { + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, + 0, ETP_FINGER_WIDTH * max_width, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MINOR, + 0, ETP_FINGER_WIDTH * min_width, 0, 0); + } data->input = input; diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index b84e3bbe62b5..5a496d4ffa49 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -60,6 +60,8 @@ #define ETP_I2C_IAP_TYPE_CMD 0x0304 #define ETP_I2C_REPORT_LEN 34 +#define ETP_I2C_REPORT_LEN_ID2 39 +#define ETP_I2C_REPORT_MAX_LEN 39 #define ETP_I2C_DESC_LENGTH 30 #define ETP_I2C_REPORT_DESC_LENGTH 158 #define ETP_I2C_INF_LENGTH 2 @@ -394,7 +396,7 @@ static int elan_i2c_get_max(struct i2c_client *client, return error; } - *max_x = le16_to_cpup((__le16 *)val) & 0x0fff; + *max_x = le16_to_cpup((__le16 *)val); error = elan_i2c_read_cmd(client, ETP_I2C_MAX_Y_AXIS_CMD, val); if (error) { @@ -402,7 +404,7 @@ static int elan_i2c_get_max(struct i2c_client *client, return error; } - *max_y = le16_to_cpup((__le16 *)val) & 0x0fff; + *max_y = le16_to_cpup((__le16 *)val); return 0; } @@ -674,12 +676,12 @@ static int elan_i2c_finish_fw_update(struct i2c_client *client, struct completion *completion) { struct device *dev = &client->dev; - int error; + int error = 0; int len; - u8 buffer[ETP_I2C_REPORT_LEN]; + u8 buffer[ETP_I2C_REPORT_MAX_LEN]; - len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_LEN); - if (len != ETP_I2C_REPORT_LEN) { + len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_MAX_LEN); + if (len <= 0) { error = len < 0 ? len : -EIO; dev_warn(dev, "failed to read I2C data after FW WDT reset: %d (%d)\n", error, len); @@ -713,20 +715,31 @@ static int elan_i2c_finish_fw_update(struct i2c_client *client, return 0; } -static int elan_i2c_get_report(struct i2c_client *client, u8 *report) +static int elan_i2c_get_report_features(struct i2c_client *client, u8 pattern, + unsigned int *features, + unsigned int *report_len) +{ + *features = ETP_FEATURE_REPORT_MK; + *report_len = pattern <= 0x01 ? + ETP_I2C_REPORT_LEN : ETP_I2C_REPORT_LEN_ID2; + return 0; +} + +static int elan_i2c_get_report(struct i2c_client *client, + u8 *report, unsigned int report_len) { int len; - len = i2c_master_recv(client, report, ETP_I2C_REPORT_LEN); + len = i2c_master_recv(client, report, report_len); if (len < 0) { dev_err(&client->dev, "failed to read report data: %d\n", len); return len; } - if (len != ETP_I2C_REPORT_LEN) { + if (len != report_len) { dev_err(&client->dev, "wrong report length (%d vs %d expected)\n", - len, ETP_I2C_REPORT_LEN); + len, report_len); return -EIO; } @@ -763,5 +776,6 @@ const struct elan_transport_ops elan_i2c_ops = { .get_pattern = elan_i2c_get_pattern, + .get_report_features = elan_i2c_get_report_features, .get_report = elan_i2c_get_report, }; diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c index f7af8b7b345f..8ff823751f3b 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -469,7 +469,21 @@ static int elan_smbus_write_fw_block(struct i2c_client *client, u16 fw_page_size return 0; } -static int elan_smbus_get_report(struct i2c_client *client, u8 *report) +static int elan_smbus_get_report_features(struct i2c_client *client, u8 pattern, + unsigned int *features, + unsigned int *report_len) +{ + /* + * SMBus controllers with pattern 2 lack area info, as newer + * high-precision packets use that space for coordinates. + */ + *features = pattern <= 0x01 ? ETP_FEATURE_REPORT_MK : 0; + *report_len = ETP_SMBUS_REPORT_LEN; + return 0; +} + +static int elan_smbus_get_report(struct i2c_client *client, + u8 *report, unsigned int report_len) { int len; @@ -534,6 +548,7 @@ const struct elan_transport_ops elan_smbus_ops = { .write_fw_block = elan_smbus_write_fw_block, .finish_fw_update = elan_smbus_finish_fw_update, + .get_report_features = elan_smbus_get_report_features, .get_report = elan_smbus_get_report, .get_pattern = elan_smbus_get_pattern, }; -- cgit v1.2.3