aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKT Liao2016-07-13 13:12:12 -0500
committerGreg Kroah-Hartman2016-08-20 11:09:26 -0500
commit7484fbecff63dd81e396565cdbe28ba598219fdd (patch)
tree3690ede90b7a8a1e502db31e556c652090805256 /drivers/input/mouse/elan_i2c_core.c
parentf5ba9a6e48bfb2b00a912a648b69063501637ed3 (diff)
downloadkernel-omap-7484fbecff63dd81e396565cdbe28ba598219fdd.tar.gz
kernel-omap-7484fbecff63dd81e396565cdbe28ba598219fdd.tar.xz
kernel-omap-7484fbecff63dd81e396565cdbe28ba598219fdd.zip
Input: elan_i2c - properly wake up touchpad on ASUS laptops
commit 2de4fcc64685def3e586856a2dc636df44532395 upstream. 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> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/input/mouse/elan_i2c_core.c')
-rw-r--r--drivers/input/mouse/elan_i2c_core.c79
1 files changed, 63 insertions, 16 deletions
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index 2f589857a039..d15b33813021 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -4,7 +4,8 @@
4 * Copyright (c) 2013 ELAN Microelectronics Corp. 4 * Copyright (c) 2013 ELAN Microelectronics Corp.
5 * 5 *
6 * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw> 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 * Based on cyapa driver: 10 * Based on cyapa driver:
10 * copyright (c) 2011-2012 Cypress Semiconductor, Inc. 11 * copyright (c) 2011-2012 Cypress Semiconductor, Inc.
@@ -40,7 +41,7 @@
40#include "elan_i2c.h" 41#include "elan_i2c.h"
41 42
42#define DRIVER_NAME "elan_i2c" 43#define DRIVER_NAME "elan_i2c"
43#define ELAN_DRIVER_VERSION "1.6.1" 44#define ELAN_DRIVER_VERSION "1.6.2"
44#define ELAN_VENDOR_ID 0x04f3 45#define ELAN_VENDOR_ID 0x04f3
45#define ETP_MAX_PRESSURE 255 46#define ETP_MAX_PRESSURE 255
46#define ETP_FWIDTH_REDUCE 90 47#define ETP_FWIDTH_REDUCE 90
@@ -199,9 +200,41 @@ static int elan_sleep(struct elan_tp_data *data)
199 return error; 200 return error;
200} 201}
201 202
203static int elan_query_product(struct elan_tp_data *data)
204{
205 int error;
206
207 error = data->ops->get_product_id(data->client, &data->product_id);
208 if (error)
209 return error;
210
211 error = data->ops->get_sm_version(data->client, &data->ic_type,
212 &data->sm_version);
213 if (error)
214 return error;
215
216 return 0;
217}
218
219static int elan_check_ASUS_special_fw(struct elan_tp_data *data)
220{
221 if (data->ic_type != 0x0E)
222 return false;
223
224 switch (data->product_id) {
225 case 0x05 ... 0x07:
226 case 0x09:
227 case 0x13:
228 return true;
229 default:
230 return false;
231 }
232}
233
202static int __elan_initialize(struct elan_tp_data *data) 234static int __elan_initialize(struct elan_tp_data *data)
203{ 235{
204 struct i2c_client *client = data->client; 236 struct i2c_client *client = data->client;
237 bool woken_up = false;
205 int error; 238 int error;
206 239
207 error = data->ops->initialize(client); 240 error = data->ops->initialize(client);
@@ -210,6 +243,27 @@ static int __elan_initialize(struct elan_tp_data *data)
210 return error; 243 return error;
211 } 244 }
212 245
246 error = elan_query_product(data);
247 if (error)
248 return error;
249
250 /*
251 * Some ASUS devices were shipped with firmware that requires
252 * touchpads to be woken up first, before attempting to switch
253 * them into absolute reporting mode.
254 */
255 if (elan_check_ASUS_special_fw(data)) {
256 error = data->ops->sleep_control(client, false);
257 if (error) {
258 dev_err(&client->dev,
259 "failed to wake device up: %d\n", error);
260 return error;
261 }
262
263 msleep(200);
264 woken_up = true;
265 }
266
213 data->mode |= ETP_ENABLE_ABS; 267 data->mode |= ETP_ENABLE_ABS;
214 error = data->ops->set_mode(client, data->mode); 268 error = data->ops->set_mode(client, data->mode);
215 if (error) { 269 if (error) {
@@ -218,11 +272,13 @@ static int __elan_initialize(struct elan_tp_data *data)
218 return error; 272 return error;
219 } 273 }
220 274
221 error = data->ops->sleep_control(client, false); 275 if (!woken_up) {
222 if (error) { 276 error = data->ops->sleep_control(client, false);
223 dev_err(&client->dev, 277 if (error) {
224 "failed to wake device up: %d\n", error); 278 dev_err(&client->dev,
225 return error; 279 "failed to wake device up: %d\n", error);
280 return error;
281 }
226 } 282 }
227 283
228 return 0; 284 return 0;
@@ -248,10 +304,6 @@ static int elan_query_device_info(struct elan_tp_data *data)
248{ 304{
249 int error; 305 int error;
250 306
251 error = data->ops->get_product_id(data->client, &data->product_id);
252 if (error)
253 return error;
254
255 error = data->ops->get_version(data->client, false, &data->fw_version); 307 error = data->ops->get_version(data->client, false, &data->fw_version);
256 if (error) 308 if (error)
257 return error; 309 return error;
@@ -261,11 +313,6 @@ static int elan_query_device_info(struct elan_tp_data *data)
261 if (error) 313 if (error)
262 return error; 314 return error;
263 315
264 error = data->ops->get_sm_version(data->client, &data->ic_type,
265 &data->sm_version);
266 if (error)
267 return error;
268
269 error = data->ops->get_version(data->client, true, &data->iap_version); 316 error = data->ops->get_version(data->client, true, &data->iap_version);
270 if (error) 317 if (error)
271 return error; 318 return error;