From c5928551fd41b2eecdad78fa2be2a4a13ed5fde9 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 19 Dec 2014 12:57:49 -0800 Subject: Input: elan_i2c - check if device is there before really probing Before trying to properly initialize the touchpad and generate bunch of errors, let's first see it there is anything at the given address. If we get error, fail silently with -ENXIO. Reviewed-by: Guenter Roeck Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_core.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index d5ab9ddef3e3..551ad2934fa7 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1077,6 +1077,13 @@ static int elan_probe(struct i2c_client *client, return error; } + /* Make sure there is something at this address */ + error = i2c_smbus_read_byte(client); + if (error < 0) { + dev_dbg(&client->dev, "nothing at this address: %d\n", error); + return -ENXIO; + } + /* Initialize the touchpad. */ error = elan_initialize(data); if (error) -- cgit v1.2.3 From a2eaf299d134cfe780c68c771f88d81516c1e70d Mon Sep 17 00:00:00 2001 From: KT Liao Date: Sun, 27 Nov 2016 20:59:29 -0800 Subject: Input: elan_i2c - add support for fetching chip type on newer hardware Newer Elantech hardware requires different way of fetching chip type and version data. Signed-off-by: KT Liao Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c.h | 3 +- drivers/input/mouse/elan_i2c_core.c | 33 +++++++++++++---- drivers/input/mouse/elan_i2c_i2c.c | 71 ++++++++++++++++++++++++++++++++---- drivers/input/mouse/elan_i2c_smbus.c | 9 ++++- 4 files changed, 99 insertions(+), 17 deletions(-) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h index c0ec26118732..61c202436250 100644 --- a/drivers/input/mouse/elan_i2c.h +++ b/drivers/input/mouse/elan_i2c.h @@ -58,7 +58,7 @@ struct elan_transport_ops { int (*get_version)(struct i2c_client *client, bool iap, u8 *version); int (*get_sm_version)(struct i2c_client *client, - u8* ic_type, u8 *version); + u16 *ic_type, u8 *version); int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum); int (*get_product_id)(struct i2c_client *client, u16 *id); @@ -82,6 +82,7 @@ struct elan_transport_ops { int (*get_report)(struct i2c_client *client, u8 *report); int (*get_pressure_adjustment)(struct i2c_client *client, int *adjustment); + int (*get_pattern)(struct i2c_client *client, u8 *pattern); }; extern const struct elan_transport_ops elan_smbus_ops, elan_i2c_ops; diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 551ad2934fa7..3b616cb7c67f 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -5,7 +5,7 @@ * * Author: 林政維 (Duson Lin) * Author: KT Liao - * Version: 1.6.2 + * Version: 1.6.3 * * Based on cyapa driver: * copyright (c) 2011-2012 Cypress Semiconductor, Inc. @@ -41,7 +41,7 @@ #include "elan_i2c.h" #define DRIVER_NAME "elan_i2c" -#define ELAN_DRIVER_VERSION "1.6.2" +#define ELAN_DRIVER_VERSION "1.6.3" #define ELAN_VENDOR_ID 0x04f3 #define ETP_MAX_PRESSURE 255 #define ETP_FWIDTH_REDUCE 90 @@ -78,6 +78,7 @@ struct elan_tp_data { unsigned int x_res; unsigned int y_res; + u8 pattern; u16 product_id; u8 fw_version; u8 sm_version; @@ -85,7 +86,7 @@ struct elan_tp_data { u16 fw_checksum; int pressure_adjustment; u8 mode; - u8 ic_type; + u16 ic_type; u16 fw_validpage_count; u16 fw_signature_address; @@ -96,10 +97,10 @@ struct elan_tp_data { bool baseline_ready; }; -static int elan_get_fwinfo(u8 iap_version, u16 *validpage_count, +static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count, u16 *signature_address) { - switch (iap_version) { + switch (ic_type) { case 0x00: case 0x06: case 0x08: @@ -119,6 +120,9 @@ static int elan_get_fwinfo(u8 iap_version, u16 *validpage_count, case 0x0E: *validpage_count = 640; break; + case 0x10: + *validpage_count = 1024; + break; default: /* unknown ic type clear value */ *validpage_count = 0; @@ -305,6 +309,7 @@ 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) @@ -324,7 +329,16 @@ static int elan_query_device_info(struct elan_tp_data *data) if (error) return error; - error = elan_get_fwinfo(data->iap_version, &data->fw_validpage_count, + error = data->ops->get_pattern(data->client, &data->pattern); + 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, &data->fw_signature_address); if (error) dev_warn(&data->client->dev, @@ -1108,10 +1122,13 @@ static int elan_probe(struct i2c_client *client, "Elan Touchpad Extra Information:\n" " Max ABS X,Y: %d,%d\n" " Width X,Y: %d,%d\n" - " Resolution X,Y: %d,%d (dots/mm)\n", + " Resolution X,Y: %d,%d (dots/mm)\n" + " ic type: 0x%x\n" + " info pattern: 0x%x\n", data->max_x, data->max_y, data->width_x, data->width_y, - data->x_res, data->y_res); + data->x_res, data->y_res, + data->ic_type, data->pattern); /* Set up input device properties based on queried parameters. */ error = elan_setup_input_device(data); diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index a679e56c44cd..3be75c6e8090 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -34,9 +34,12 @@ #define ETP_I2C_DESC_CMD 0x0001 #define ETP_I2C_REPORT_DESC_CMD 0x0002 #define ETP_I2C_STAND_CMD 0x0005 +#define ETP_I2C_PATTERN_CMD 0x0100 #define ETP_I2C_UNIQUEID_CMD 0x0101 #define ETP_I2C_FW_VERSION_CMD 0x0102 -#define ETP_I2C_SM_VERSION_CMD 0x0103 +#define ETP_I2C_IC_TYPE_CMD 0x0103 +#define ETP_I2C_OSM_VERSION_CMD 0x0103 +#define ETP_I2C_NSM_VERSION_CMD 0x0104 #define ETP_I2C_XY_TRACENUM_CMD 0x0105 #define ETP_I2C_MAX_X_AXIS_CMD 0x0106 #define ETP_I2C_MAX_Y_AXIS_CMD 0x0107 @@ -239,12 +242,34 @@ static int elan_i2c_get_baseline_data(struct i2c_client *client, return 0; } +static int elan_i2c_get_pattern(struct i2c_client *client, u8 *pattern) +{ + int error; + u8 val[3]; + + error = elan_i2c_read_cmd(client, ETP_I2C_PATTERN_CMD, val); + if (error) { + dev_err(&client->dev, "failed to get pattern: %d\n", error); + return error; + } + *pattern = val[1]; + + return 0; +} + static int elan_i2c_get_version(struct i2c_client *client, bool iap, u8 *version) { 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; + } + error = elan_i2c_read_cmd(client, iap ? ETP_I2C_IAP_VERSION_CMD : ETP_I2C_FW_VERSION_CMD, @@ -255,24 +280,54 @@ static int elan_i2c_get_version(struct i2c_client *client, return error; } - *version = val[0]; + if (pattern_ver == 0x01) + *version = iap ? val[1] : val[0]; + else + *version = val[0]; return 0; } static int elan_i2c_get_sm_version(struct i2c_client *client, - u8 *ic_type, u8 *version) + u16 *ic_type, u8 *version) { int error; + u8 pattern_ver; u8 val[3]; - error = elan_i2c_read_cmd(client, ETP_I2C_SM_VERSION_CMD, val); + error = elan_i2c_get_pattern(client, &pattern_ver); if (error) { - dev_err(&client->dev, "failed to get SM version: %d\n", error); + dev_err(&client->dev, "failed to get pattern version\n"); return error; } - *version = val[0]; - *ic_type = val[1]; + 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", + error); + return error; + } + *ic_type = be16_to_cpup((__be16 *)val); + + error = elan_i2c_read_cmd(client, ETP_I2C_NSM_VERSION_CMD, + val); + if (error) { + dev_err(&client->dev, "failed to get SM version: %d\n", + error); + return error; + } + *version = val[1]; + } else { + error = elan_i2c_read_cmd(client, ETP_I2C_OSM_VERSION_CMD, val); + if (error) { + dev_err(&client->dev, "failed to get SM version: %d\n", + error); + return error; + } + *version = val[0]; + *ic_type = val[1]; + } + return 0; } @@ -639,5 +694,7 @@ const struct elan_transport_ops elan_i2c_ops = { .write_fw_block = elan_i2c_write_fw_block, .finish_fw_update = elan_i2c_finish_fw_update, + .get_pattern = elan_i2c_get_pattern, + .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 e23b2495d52e..df7a57ca7331 100644 --- a/drivers/input/mouse/elan_i2c_smbus.c +++ b/drivers/input/mouse/elan_i2c_smbus.c @@ -166,7 +166,7 @@ static int elan_smbus_get_version(struct i2c_client *client, } static int elan_smbus_get_sm_version(struct i2c_client *client, - u8 *ic_type, u8 *version) + u16 *ic_type, u8 *version) { int error; u8 val[3]; @@ -495,6 +495,12 @@ static int elan_smbus_finish_fw_update(struct i2c_client *client, return 0; } +static int elan_smbus_get_pattern(struct i2c_client *client, u8 *pattern) +{ + *pattern = 0; + return 0; +} + const struct elan_transport_ops elan_smbus_ops = { .initialize = elan_smbus_initialize, .sleep_control = elan_smbus_sleep_control, @@ -524,4 +530,5 @@ const struct elan_transport_ops elan_smbus_ops = { .finish_fw_update = elan_smbus_finish_fw_update, .get_report = elan_smbus_get_report, + .get_pattern = elan_smbus_get_pattern, }; -- cgit v1.2.3 From d899520b0431e70279bfb5066ecb6dc91d0b7072 Mon Sep 17 00:00:00 2001 From: KT Liao Date: Mon, 12 Dec 2016 11:03:42 -0800 Subject: Input: elantech - force relative mode on a certain module One of Elan modules with sample version is 0x74 and hw_version is 0x03 has a bug in absolute mode implementation, so let it run in default PS/2 relative mode. Signed-off-by: KT Liao Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elantech.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/input/mouse') diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index efc8ec342351..3dbab0727376 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1687,6 +1687,17 @@ int elantech_init(struct psmouse *psmouse) etd->samples[0], etd->samples[1], etd->samples[2]); } + if (etd->samples[1] == 0x74 && etd->hw_version == 0x03) { + /* + * This module has a bug which makes absolute mode + * unusable, so let's abort so we'll be using standard + * PS/2 protocol. + */ + psmouse_info(psmouse, + "absolute mode broken, forcing standard PS/2 protocol\n"); + goto init_fail; + } + if (elantech_set_absolute_mode(psmouse)) { psmouse_err(psmouse, "failed to put touchpad into absolute mode.\n"); -- cgit v1.2.3