Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Input: elan_i2c - properly wake up touchpad on ASUS laptops

Some ASUS laptops were shipped with touchpads that require to be woken up
first, before trying to switch them into absolute reporting mode, otherwise
touchpad would fail to work while flooding the logs with:

elan_i2c i2c-ELAN1000:00: invalid report id data (1)

Among affected devices are Asus E202SA, N552VW, X456UF, UX305CA, and
others. We detect such devices by checking the IC type and product ID
numbers and adjusting order of operations accordingly.

Signed-off-by: KT Liao <kt.liao@emc.com.tw>
Reported-by: Chris Chiu <chiu@endlessm.com>
Reported-by: Vlad Glagolev <stealth@vaygr.net>
Tested-by: Vlad Glagolev <stealth@vaygr.net>
Cc: stable@vger.kernel.org
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

KT Liao and committed by
Dmitry Torokhov
2de4fcc6 3197704c

+63 -16
+63 -16
drivers/input/mouse/elan_i2c_core.c
··· 4 4 * Copyright (c) 2013 ELAN Microelectronics Corp. 5 5 * 6 6 * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw> 7 - * Version: 1.6.0 7 + * Author: KT Liao <kt.liao@emc.com.tw> 8 + * Version: 1.6.2 8 9 * 9 10 * Based on cyapa driver: 10 11 * copyright (c) 2011-2012 Cypress Semiconductor, Inc. ··· 41 40 #include "elan_i2c.h" 42 41 43 42 #define DRIVER_NAME "elan_i2c" 44 - #define ELAN_DRIVER_VERSION "1.6.1" 43 + #define ELAN_DRIVER_VERSION "1.6.2" 45 44 #define ELAN_VENDOR_ID 0x04f3 46 45 #define ETP_MAX_PRESSURE 255 47 46 #define ETP_FWIDTH_REDUCE 90 ··· 200 199 return error; 201 200 } 202 201 202 + static int elan_query_product(struct elan_tp_data *data) 203 + { 204 + int error; 205 + 206 + error = data->ops->get_product_id(data->client, &data->product_id); 207 + if (error) 208 + return error; 209 + 210 + error = data->ops->get_sm_version(data->client, &data->ic_type, 211 + &data->sm_version); 212 + if (error) 213 + return error; 214 + 215 + return 0; 216 + } 217 + 218 + static int elan_check_ASUS_special_fw(struct elan_tp_data *data) 219 + { 220 + if (data->ic_type != 0x0E) 221 + return false; 222 + 223 + switch (data->product_id) { 224 + case 0x05 ... 0x07: 225 + case 0x09: 226 + case 0x13: 227 + return true; 228 + default: 229 + return false; 230 + } 231 + } 232 + 203 233 static int __elan_initialize(struct elan_tp_data *data) 204 234 { 205 235 struct i2c_client *client = data->client; 236 + bool woken_up = false; 206 237 int error; 207 238 208 239 error = data->ops->initialize(client); 209 240 if (error) { 210 241 dev_err(&client->dev, "device initialize failed: %d\n", error); 211 242 return error; 243 + } 244 + 245 + error = elan_query_product(data); 246 + if (error) 247 + return error; 248 + 249 + /* 250 + * Some ASUS devices were shipped with firmware that requires 251 + * touchpads to be woken up first, before attempting to switch 252 + * them into absolute reporting mode. 253 + */ 254 + if (elan_check_ASUS_special_fw(data)) { 255 + error = data->ops->sleep_control(client, false); 256 + if (error) { 257 + dev_err(&client->dev, 258 + "failed to wake device up: %d\n", error); 259 + return error; 260 + } 261 + 262 + msleep(200); 263 + woken_up = true; 212 264 } 213 265 214 266 data->mode |= ETP_ENABLE_ABS; ··· 272 218 return error; 273 219 } 274 220 275 - error = data->ops->sleep_control(client, false); 276 - if (error) { 277 - dev_err(&client->dev, 278 - "failed to wake device up: %d\n", error); 279 - return error; 221 + if (!woken_up) { 222 + error = data->ops->sleep_control(client, false); 223 + if (error) { 224 + dev_err(&client->dev, 225 + "failed to wake device up: %d\n", error); 226 + return error; 227 + } 280 228 } 281 229 282 230 return 0; ··· 304 248 { 305 249 int error; 306 250 307 - error = data->ops->get_product_id(data->client, &data->product_id); 308 - if (error) 309 - return error; 310 - 311 251 error = data->ops->get_version(data->client, false, &data->fw_version); 312 252 if (error) 313 253 return error; 314 254 315 255 error = data->ops->get_checksum(data->client, false, 316 256 &data->fw_checksum); 317 - if (error) 318 - return error; 319 - 320 - error = data->ops->get_sm_version(data->client, &data->ic_type, 321 - &data->sm_version); 322 257 if (error) 323 258 return error; 324 259