diff options
author | KT Liao <ktalex.liao@gmail.com> | 2016-11-27 23:59:29 -0500 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2017-05-11 20:44:23 -0400 |
commit | a2eaf299d134cfe780c68c771f88d81516c1e70d (patch) | |
tree | 76c6b5e035fefb17e15d4cfc60bdda871e1be9c0 | |
parent | c5928551fd41b2eecdad78fa2be2a4a13ed5fde9 (diff) |
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 <kt.liao@emc.com.tw>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r-- | drivers/input/mouse/elan_i2c.h | 3 | ||||
-rw-r--r-- | drivers/input/mouse/elan_i2c_core.c | 33 | ||||
-rw-r--r-- | drivers/input/mouse/elan_i2c_i2c.c | 71 | ||||
-rw-r--r-- | drivers/input/mouse/elan_i2c_smbus.c | 9 |
4 files changed, 99 insertions, 17 deletions
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 { | |||
58 | 58 | ||
59 | int (*get_version)(struct i2c_client *client, bool iap, u8 *version); | 59 | int (*get_version)(struct i2c_client *client, bool iap, u8 *version); |
60 | int (*get_sm_version)(struct i2c_client *client, | 60 | int (*get_sm_version)(struct i2c_client *client, |
61 | u8* ic_type, u8 *version); | 61 | u16 *ic_type, u8 *version); |
62 | int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum); | 62 | int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum); |
63 | int (*get_product_id)(struct i2c_client *client, u16 *id); | 63 | int (*get_product_id)(struct i2c_client *client, u16 *id); |
64 | 64 | ||
@@ -82,6 +82,7 @@ struct elan_transport_ops { | |||
82 | int (*get_report)(struct i2c_client *client, u8 *report); | 82 | int (*get_report)(struct i2c_client *client, u8 *report); |
83 | int (*get_pressure_adjustment)(struct i2c_client *client, | 83 | int (*get_pressure_adjustment)(struct i2c_client *client, |
84 | int *adjustment); | 84 | int *adjustment); |
85 | int (*get_pattern)(struct i2c_client *client, u8 *pattern); | ||
85 | }; | 86 | }; |
86 | 87 | ||
87 | extern const struct elan_transport_ops elan_smbus_ops, elan_i2c_ops; | 88 | 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 @@ | |||
5 | * | 5 | * |
6 | * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw> | 6 | * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw> |
7 | * Author: KT Liao <kt.liao@emc.com.tw> | 7 | * Author: KT Liao <kt.liao@emc.com.tw> |
8 | * Version: 1.6.2 | 8 | * Version: 1.6.3 |
9 | * | 9 | * |
10 | * Based on cyapa driver: | 10 | * Based on cyapa driver: |
11 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. | 11 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. |
@@ -41,7 +41,7 @@ | |||
41 | #include "elan_i2c.h" | 41 | #include "elan_i2c.h" |
42 | 42 | ||
43 | #define DRIVER_NAME "elan_i2c" | 43 | #define DRIVER_NAME "elan_i2c" |
44 | #define ELAN_DRIVER_VERSION "1.6.2" | 44 | #define ELAN_DRIVER_VERSION "1.6.3" |
45 | #define ELAN_VENDOR_ID 0x04f3 | 45 | #define ELAN_VENDOR_ID 0x04f3 |
46 | #define ETP_MAX_PRESSURE 255 | 46 | #define ETP_MAX_PRESSURE 255 |
47 | #define ETP_FWIDTH_REDUCE 90 | 47 | #define ETP_FWIDTH_REDUCE 90 |
@@ -78,6 +78,7 @@ struct elan_tp_data { | |||
78 | unsigned int x_res; | 78 | unsigned int x_res; |
79 | unsigned int y_res; | 79 | unsigned int y_res; |
80 | 80 | ||
81 | u8 pattern; | ||
81 | u16 product_id; | 82 | u16 product_id; |
82 | u8 fw_version; | 83 | u8 fw_version; |
83 | u8 sm_version; | 84 | u8 sm_version; |
@@ -85,7 +86,7 @@ struct elan_tp_data { | |||
85 | u16 fw_checksum; | 86 | u16 fw_checksum; |
86 | int pressure_adjustment; | 87 | int pressure_adjustment; |
87 | u8 mode; | 88 | u8 mode; |
88 | u8 ic_type; | 89 | u16 ic_type; |
89 | u16 fw_validpage_count; | 90 | u16 fw_validpage_count; |
90 | u16 fw_signature_address; | 91 | u16 fw_signature_address; |
91 | 92 | ||
@@ -96,10 +97,10 @@ struct elan_tp_data { | |||
96 | bool baseline_ready; | 97 | bool baseline_ready; |
97 | }; | 98 | }; |
98 | 99 | ||
99 | static int elan_get_fwinfo(u8 iap_version, u16 *validpage_count, | 100 | static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count, |
100 | u16 *signature_address) | 101 | u16 *signature_address) |
101 | { | 102 | { |
102 | switch (iap_version) { | 103 | switch (ic_type) { |
103 | case 0x00: | 104 | case 0x00: |
104 | case 0x06: | 105 | case 0x06: |
105 | case 0x08: | 106 | case 0x08: |
@@ -119,6 +120,9 @@ static int elan_get_fwinfo(u8 iap_version, u16 *validpage_count, | |||
119 | case 0x0E: | 120 | case 0x0E: |
120 | *validpage_count = 640; | 121 | *validpage_count = 640; |
121 | break; | 122 | break; |
123 | case 0x10: | ||
124 | *validpage_count = 1024; | ||
125 | break; | ||
122 | default: | 126 | default: |
123 | /* unknown ic type clear value */ | 127 | /* unknown ic type clear value */ |
124 | *validpage_count = 0; | 128 | *validpage_count = 0; |
@@ -305,6 +309,7 @@ static int elan_initialize(struct elan_tp_data *data) | |||
305 | static int elan_query_device_info(struct elan_tp_data *data) | 309 | static int elan_query_device_info(struct elan_tp_data *data) |
306 | { | 310 | { |
307 | int error; | 311 | int error; |
312 | u16 ic_type; | ||
308 | 313 | ||
309 | error = data->ops->get_version(data->client, false, &data->fw_version); | 314 | error = data->ops->get_version(data->client, false, &data->fw_version); |
310 | if (error) | 315 | if (error) |
@@ -324,7 +329,16 @@ static int elan_query_device_info(struct elan_tp_data *data) | |||
324 | if (error) | 329 | if (error) |
325 | return error; | 330 | return error; |
326 | 331 | ||
327 | error = elan_get_fwinfo(data->iap_version, &data->fw_validpage_count, | 332 | error = data->ops->get_pattern(data->client, &data->pattern); |
333 | if (error) | ||
334 | return error; | ||
335 | |||
336 | if (data->pattern == 0x01) | ||
337 | ic_type = data->ic_type; | ||
338 | else | ||
339 | ic_type = data->iap_version; | ||
340 | |||
341 | error = elan_get_fwinfo(ic_type, &data->fw_validpage_count, | ||
328 | &data->fw_signature_address); | 342 | &data->fw_signature_address); |
329 | if (error) | 343 | if (error) |
330 | dev_warn(&data->client->dev, | 344 | dev_warn(&data->client->dev, |
@@ -1108,10 +1122,13 @@ static int elan_probe(struct i2c_client *client, | |||
1108 | "Elan Touchpad Extra Information:\n" | 1122 | "Elan Touchpad Extra Information:\n" |
1109 | " Max ABS X,Y: %d,%d\n" | 1123 | " Max ABS X,Y: %d,%d\n" |
1110 | " Width X,Y: %d,%d\n" | 1124 | " Width X,Y: %d,%d\n" |
1111 | " Resolution X,Y: %d,%d (dots/mm)\n", | 1125 | " Resolution X,Y: %d,%d (dots/mm)\n" |
1126 | " ic type: 0x%x\n" | ||
1127 | " info pattern: 0x%x\n", | ||
1112 | data->max_x, data->max_y, | 1128 | data->max_x, data->max_y, |
1113 | data->width_x, data->width_y, | 1129 | data->width_x, data->width_y, |
1114 | data->x_res, data->y_res); | 1130 | data->x_res, data->y_res, |
1131 | data->ic_type, data->pattern); | ||
1115 | 1132 | ||
1116 | /* Set up input device properties based on queried parameters. */ | 1133 | /* Set up input device properties based on queried parameters. */ |
1117 | error = elan_setup_input_device(data); | 1134 | 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 @@ | |||
34 | #define ETP_I2C_DESC_CMD 0x0001 | 34 | #define ETP_I2C_DESC_CMD 0x0001 |
35 | #define ETP_I2C_REPORT_DESC_CMD 0x0002 | 35 | #define ETP_I2C_REPORT_DESC_CMD 0x0002 |
36 | #define ETP_I2C_STAND_CMD 0x0005 | 36 | #define ETP_I2C_STAND_CMD 0x0005 |
37 | #define ETP_I2C_PATTERN_CMD 0x0100 | ||
37 | #define ETP_I2C_UNIQUEID_CMD 0x0101 | 38 | #define ETP_I2C_UNIQUEID_CMD 0x0101 |
38 | #define ETP_I2C_FW_VERSION_CMD 0x0102 | 39 | #define ETP_I2C_FW_VERSION_CMD 0x0102 |
39 | #define ETP_I2C_SM_VERSION_CMD 0x0103 | 40 | #define ETP_I2C_IC_TYPE_CMD 0x0103 |
41 | #define ETP_I2C_OSM_VERSION_CMD 0x0103 | ||
42 | #define ETP_I2C_NSM_VERSION_CMD 0x0104 | ||
40 | #define ETP_I2C_XY_TRACENUM_CMD 0x0105 | 43 | #define ETP_I2C_XY_TRACENUM_CMD 0x0105 |
41 | #define ETP_I2C_MAX_X_AXIS_CMD 0x0106 | 44 | #define ETP_I2C_MAX_X_AXIS_CMD 0x0106 |
42 | #define ETP_I2C_MAX_Y_AXIS_CMD 0x0107 | 45 | #define ETP_I2C_MAX_Y_AXIS_CMD 0x0107 |
@@ -239,12 +242,34 @@ static int elan_i2c_get_baseline_data(struct i2c_client *client, | |||
239 | return 0; | 242 | return 0; |
240 | } | 243 | } |
241 | 244 | ||
245 | static int elan_i2c_get_pattern(struct i2c_client *client, u8 *pattern) | ||
246 | { | ||
247 | int error; | ||
248 | u8 val[3]; | ||
249 | |||
250 | error = elan_i2c_read_cmd(client, ETP_I2C_PATTERN_CMD, val); | ||
251 | if (error) { | ||
252 | dev_err(&client->dev, "failed to get pattern: %d\n", error); | ||
253 | return error; | ||
254 | } | ||
255 | *pattern = val[1]; | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | |||
242 | static int elan_i2c_get_version(struct i2c_client *client, | 260 | static int elan_i2c_get_version(struct i2c_client *client, |
243 | bool iap, u8 *version) | 261 | bool iap, u8 *version) |
244 | { | 262 | { |
245 | int error; | 263 | int error; |
264 | u8 pattern_ver; | ||
246 | u8 val[3]; | 265 | u8 val[3]; |
247 | 266 | ||
267 | error = elan_i2c_get_pattern(client, &pattern_ver); | ||
268 | if (error) { | ||
269 | dev_err(&client->dev, "failed to get pattern version\n"); | ||
270 | return error; | ||
271 | } | ||
272 | |||
248 | error = elan_i2c_read_cmd(client, | 273 | error = elan_i2c_read_cmd(client, |
249 | iap ? ETP_I2C_IAP_VERSION_CMD : | 274 | iap ? ETP_I2C_IAP_VERSION_CMD : |
250 | ETP_I2C_FW_VERSION_CMD, | 275 | ETP_I2C_FW_VERSION_CMD, |
@@ -255,24 +280,54 @@ static int elan_i2c_get_version(struct i2c_client *client, | |||
255 | return error; | 280 | return error; |
256 | } | 281 | } |
257 | 282 | ||
258 | *version = val[0]; | 283 | if (pattern_ver == 0x01) |
284 | *version = iap ? val[1] : val[0]; | ||
285 | else | ||
286 | *version = val[0]; | ||
259 | return 0; | 287 | return 0; |
260 | } | 288 | } |
261 | 289 | ||
262 | static int elan_i2c_get_sm_version(struct i2c_client *client, | 290 | static int elan_i2c_get_sm_version(struct i2c_client *client, |
263 | u8 *ic_type, u8 *version) | 291 | u16 *ic_type, u8 *version) |
264 | { | 292 | { |
265 | int error; | 293 | int error; |
294 | u8 pattern_ver; | ||
266 | u8 val[3]; | 295 | u8 val[3]; |
267 | 296 | ||
268 | error = elan_i2c_read_cmd(client, ETP_I2C_SM_VERSION_CMD, val); | 297 | error = elan_i2c_get_pattern(client, &pattern_ver); |
269 | if (error) { | 298 | if (error) { |
270 | dev_err(&client->dev, "failed to get SM version: %d\n", error); | 299 | dev_err(&client->dev, "failed to get pattern version\n"); |
271 | return error; | 300 | return error; |
272 | } | 301 | } |
273 | 302 | ||
274 | *version = val[0]; | 303 | if (pattern_ver == 0x01) { |
275 | *ic_type = val[1]; | 304 | error = elan_i2c_read_cmd(client, ETP_I2C_IC_TYPE_CMD, val); |
305 | if (error) { | ||
306 | dev_err(&client->dev, "failed to get ic type: %d\n", | ||
307 | error); | ||
308 | return error; | ||
309 | } | ||
310 | *ic_type = be16_to_cpup((__be16 *)val); | ||
311 | |||
312 | error = elan_i2c_read_cmd(client, ETP_I2C_NSM_VERSION_CMD, | ||
313 | val); | ||
314 | if (error) { | ||
315 | dev_err(&client->dev, "failed to get SM version: %d\n", | ||
316 | error); | ||
317 | return error; | ||
318 | } | ||
319 | *version = val[1]; | ||
320 | } else { | ||
321 | error = elan_i2c_read_cmd(client, ETP_I2C_OSM_VERSION_CMD, val); | ||
322 | if (error) { | ||
323 | dev_err(&client->dev, "failed to get SM version: %d\n", | ||
324 | error); | ||
325 | return error; | ||
326 | } | ||
327 | *version = val[0]; | ||
328 | *ic_type = val[1]; | ||
329 | } | ||
330 | |||
276 | return 0; | 331 | return 0; |
277 | } | 332 | } |
278 | 333 | ||
@@ -639,5 +694,7 @@ const struct elan_transport_ops elan_i2c_ops = { | |||
639 | .write_fw_block = elan_i2c_write_fw_block, | 694 | .write_fw_block = elan_i2c_write_fw_block, |
640 | .finish_fw_update = elan_i2c_finish_fw_update, | 695 | .finish_fw_update = elan_i2c_finish_fw_update, |
641 | 696 | ||
697 | .get_pattern = elan_i2c_get_pattern, | ||
698 | |||
642 | .get_report = elan_i2c_get_report, | 699 | .get_report = elan_i2c_get_report, |
643 | }; | 700 | }; |
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, | |||
166 | } | 166 | } |
167 | 167 | ||
168 | static int elan_smbus_get_sm_version(struct i2c_client *client, | 168 | static int elan_smbus_get_sm_version(struct i2c_client *client, |
169 | u8 *ic_type, u8 *version) | 169 | u16 *ic_type, u8 *version) |
170 | { | 170 | { |
171 | int error; | 171 | int error; |
172 | u8 val[3]; | 172 | u8 val[3]; |
@@ -495,6 +495,12 @@ static int elan_smbus_finish_fw_update(struct i2c_client *client, | |||
495 | return 0; | 495 | return 0; |
496 | } | 496 | } |
497 | 497 | ||
498 | static int elan_smbus_get_pattern(struct i2c_client *client, u8 *pattern) | ||
499 | { | ||
500 | *pattern = 0; | ||
501 | return 0; | ||
502 | } | ||
503 | |||
498 | const struct elan_transport_ops elan_smbus_ops = { | 504 | const struct elan_transport_ops elan_smbus_ops = { |
499 | .initialize = elan_smbus_initialize, | 505 | .initialize = elan_smbus_initialize, |
500 | .sleep_control = elan_smbus_sleep_control, | 506 | .sleep_control = elan_smbus_sleep_control, |
@@ -524,4 +530,5 @@ const struct elan_transport_ops elan_smbus_ops = { | |||
524 | .finish_fw_update = elan_smbus_finish_fw_update, | 530 | .finish_fw_update = elan_smbus_finish_fw_update, |
525 | 531 | ||
526 | .get_report = elan_smbus_get_report, | 532 | .get_report = elan_smbus_get_report, |
533 | .get_pattern = elan_smbus_get_pattern, | ||
527 | }; | 534 | }; |