| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Elan I2C/SMBus Touchpad driver |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 10 | 11 | * Based on cyapa driver: |
|---|
| 11 | 12 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. |
|---|
| 12 | 13 | * copyright (c) 2011-2012 Google, Inc. |
|---|
| 13 | | - * |
|---|
| 14 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 15 | | - * under the terms of the GNU General Public License version 2 as published |
|---|
| 16 | | - * by the Free Software Foundation. |
|---|
| 17 | 14 | * |
|---|
| 18 | 15 | * Trademarks are the property of their respective owners. |
|---|
| 19 | 16 | */ |
|---|
| .. | .. |
|---|
| 37 | 34 | #include <linux/completion.h> |
|---|
| 38 | 35 | #include <linux/of.h> |
|---|
| 39 | 36 | #include <linux/property.h> |
|---|
| 37 | +#include <linux/input/elan-i2c-ids.h> |
|---|
| 40 | 38 | #include <linux/regulator/consumer.h> |
|---|
| 41 | 39 | #include <asm/unaligned.h> |
|---|
| 42 | 40 | |
|---|
| .. | .. |
|---|
| 48 | 46 | #define ETP_FWIDTH_REDUCE 90 |
|---|
| 49 | 47 | #define ETP_FINGER_WIDTH 15 |
|---|
| 50 | 48 | #define ETP_RETRY_COUNT 3 |
|---|
| 51 | | - |
|---|
| 52 | | -#define ETP_MAX_FINGERS 5 |
|---|
| 53 | | -#define ETP_FINGER_DATA_LEN 5 |
|---|
| 54 | | -#define ETP_REPORT_ID 0x5D |
|---|
| 55 | | -#define ETP_TP_REPORT_ID 0x5E |
|---|
| 56 | | -#define ETP_REPORT_ID_OFFSET 2 |
|---|
| 57 | | -#define ETP_TOUCH_INFO_OFFSET 3 |
|---|
| 58 | | -#define ETP_FINGER_DATA_OFFSET 4 |
|---|
| 59 | | -#define ETP_HOVER_INFO_OFFSET 30 |
|---|
| 60 | | -#define ETP_MAX_REPORT_LEN 34 |
|---|
| 61 | 49 | |
|---|
| 62 | 50 | /* The main device structure */ |
|---|
| 63 | 51 | struct elan_tp_data { |
|---|
| .. | .. |
|---|
| 87 | 75 | u8 sm_version; |
|---|
| 88 | 76 | u8 iap_version; |
|---|
| 89 | 77 | u16 fw_checksum; |
|---|
| 78 | + unsigned int report_features; |
|---|
| 79 | + unsigned int report_len; |
|---|
| 90 | 80 | int pressure_adjustment; |
|---|
| 91 | 81 | u8 mode; |
|---|
| 92 | 82 | u16 ic_type; |
|---|
| 93 | 83 | u16 fw_validpage_count; |
|---|
| 94 | | - u16 fw_signature_address; |
|---|
| 84 | + u16 fw_page_size; |
|---|
| 85 | + u32 fw_signature_address; |
|---|
| 95 | 86 | |
|---|
| 96 | 87 | bool irq_wake; |
|---|
| 97 | 88 | |
|---|
| .. | .. |
|---|
| 99 | 90 | u8 max_baseline; |
|---|
| 100 | 91 | bool baseline_ready; |
|---|
| 101 | 92 | u8 clickpad; |
|---|
| 93 | + bool middle_button; |
|---|
| 102 | 94 | }; |
|---|
| 103 | 95 | |
|---|
| 104 | | -static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count, |
|---|
| 105 | | - u16 *signature_address) |
|---|
| 96 | +static int elan_get_fwinfo(u16 ic_type, u8 iap_version, u16 *validpage_count, |
|---|
| 97 | + u32 *signature_address, u16 *page_size) |
|---|
| 106 | 98 | { |
|---|
| 107 | 99 | switch (ic_type) { |
|---|
| 108 | 100 | case 0x00: |
|---|
| .. | .. |
|---|
| 127 | 119 | case 0x10: |
|---|
| 128 | 120 | *validpage_count = 1024; |
|---|
| 129 | 121 | break; |
|---|
| 122 | + case 0x11: |
|---|
| 123 | + *validpage_count = 1280; |
|---|
| 124 | + break; |
|---|
| 125 | + case 0x13: |
|---|
| 126 | + *validpage_count = 2048; |
|---|
| 127 | + break; |
|---|
| 128 | + case 0x14: |
|---|
| 129 | + case 0x15: |
|---|
| 130 | + *validpage_count = 1024; |
|---|
| 131 | + break; |
|---|
| 130 | 132 | default: |
|---|
| 131 | 133 | /* unknown ic type clear value */ |
|---|
| 132 | 134 | *validpage_count = 0; |
|---|
| 133 | 135 | *signature_address = 0; |
|---|
| 136 | + *page_size = 0; |
|---|
| 134 | 137 | return -ENXIO; |
|---|
| 135 | 138 | } |
|---|
| 136 | 139 | |
|---|
| 137 | 140 | *signature_address = |
|---|
| 138 | 141 | (*validpage_count * ETP_FW_PAGE_SIZE) - ETP_FW_SIGNATURE_SIZE; |
|---|
| 139 | 142 | |
|---|
| 143 | + if ((ic_type == 0x14 || ic_type == 0x15) && iap_version >= 2) { |
|---|
| 144 | + *validpage_count /= 8; |
|---|
| 145 | + *page_size = ETP_FW_PAGE_SIZE_512; |
|---|
| 146 | + } else if (ic_type >= 0x0D && iap_version >= 1) { |
|---|
| 147 | + *validpage_count /= 2; |
|---|
| 148 | + *page_size = ETP_FW_PAGE_SIZE_128; |
|---|
| 149 | + } else { |
|---|
| 150 | + *page_size = ETP_FW_PAGE_SIZE; |
|---|
| 151 | + } |
|---|
| 152 | + |
|---|
| 140 | 153 | return 0; |
|---|
| 141 | 154 | } |
|---|
| 142 | 155 | |
|---|
| 143 | | -static int elan_enable_power(struct elan_tp_data *data) |
|---|
| 156 | +static int elan_set_power(struct elan_tp_data *data, bool on) |
|---|
| 144 | 157 | { |
|---|
| 145 | 158 | int repeat = ETP_RETRY_COUNT; |
|---|
| 146 | 159 | int error; |
|---|
| 147 | 160 | |
|---|
| 148 | | - error = regulator_enable(data->vcc); |
|---|
| 149 | | - if (error) { |
|---|
| 150 | | - dev_err(&data->client->dev, |
|---|
| 151 | | - "failed to enable regulator: %d\n", error); |
|---|
| 152 | | - return error; |
|---|
| 153 | | - } |
|---|
| 154 | | - |
|---|
| 155 | 161 | do { |
|---|
| 156 | | - error = data->ops->power_control(data->client, true); |
|---|
| 162 | + error = data->ops->power_control(data->client, on); |
|---|
| 157 | 163 | if (error >= 0) |
|---|
| 158 | 164 | return 0; |
|---|
| 159 | 165 | |
|---|
| 160 | 166 | msleep(30); |
|---|
| 161 | 167 | } while (--repeat > 0); |
|---|
| 162 | 168 | |
|---|
| 163 | | - dev_err(&data->client->dev, "failed to enable power: %d\n", error); |
|---|
| 164 | | - return error; |
|---|
| 165 | | -} |
|---|
| 166 | | - |
|---|
| 167 | | -static int elan_disable_power(struct elan_tp_data *data) |
|---|
| 168 | | -{ |
|---|
| 169 | | - int repeat = ETP_RETRY_COUNT; |
|---|
| 170 | | - int error; |
|---|
| 171 | | - |
|---|
| 172 | | - do { |
|---|
| 173 | | - error = data->ops->power_control(data->client, false); |
|---|
| 174 | | - if (!error) { |
|---|
| 175 | | - error = regulator_disable(data->vcc); |
|---|
| 176 | | - if (error) { |
|---|
| 177 | | - dev_err(&data->client->dev, |
|---|
| 178 | | - "failed to disable regulator: %d\n", |
|---|
| 179 | | - error); |
|---|
| 180 | | - /* Attempt to power the chip back up */ |
|---|
| 181 | | - data->ops->power_control(data->client, true); |
|---|
| 182 | | - break; |
|---|
| 183 | | - } |
|---|
| 184 | | - |
|---|
| 185 | | - return 0; |
|---|
| 186 | | - } |
|---|
| 187 | | - |
|---|
| 188 | | - msleep(30); |
|---|
| 189 | | - } while (--repeat > 0); |
|---|
| 190 | | - |
|---|
| 191 | | - dev_err(&data->client->dev, "failed to disable power: %d\n", error); |
|---|
| 169 | + dev_err(&data->client->dev, "failed to set power %s: %d\n", |
|---|
| 170 | + on ? "on" : "off", error); |
|---|
| 192 | 171 | return error; |
|---|
| 193 | 172 | } |
|---|
| 194 | 173 | |
|---|
| .. | .. |
|---|
| 216 | 195 | if (error) |
|---|
| 217 | 196 | return error; |
|---|
| 218 | 197 | |
|---|
| 219 | | - error = data->ops->get_sm_version(data->client, &data->ic_type, |
|---|
| 220 | | - &data->sm_version, &data->clickpad); |
|---|
| 198 | + error = data->ops->get_pattern(data->client, &data->pattern); |
|---|
| 199 | + if (error) |
|---|
| 200 | + return error; |
|---|
| 201 | + |
|---|
| 202 | + error = data->ops->get_sm_version(data->client, data->pattern, |
|---|
| 203 | + &data->ic_type, &data->sm_version, |
|---|
| 204 | + &data->clickpad); |
|---|
| 221 | 205 | if (error) |
|---|
| 222 | 206 | return error; |
|---|
| 223 | 207 | |
|---|
| .. | .. |
|---|
| 313 | 297 | static int elan_query_device_info(struct elan_tp_data *data) |
|---|
| 314 | 298 | { |
|---|
| 315 | 299 | int error; |
|---|
| 316 | | - u16 ic_type; |
|---|
| 317 | 300 | |
|---|
| 318 | | - error = data->ops->get_version(data->client, false, &data->fw_version); |
|---|
| 301 | + error = data->ops->get_version(data->client, data->pattern, false, |
|---|
| 302 | + &data->fw_version); |
|---|
| 319 | 303 | if (error) |
|---|
| 320 | 304 | return error; |
|---|
| 321 | 305 | |
|---|
| .. | .. |
|---|
| 324 | 308 | if (error) |
|---|
| 325 | 309 | return error; |
|---|
| 326 | 310 | |
|---|
| 327 | | - error = data->ops->get_version(data->client, true, &data->iap_version); |
|---|
| 311 | + error = data->ops->get_version(data->client, data->pattern, |
|---|
| 312 | + true, &data->iap_version); |
|---|
| 328 | 313 | if (error) |
|---|
| 329 | 314 | return error; |
|---|
| 330 | 315 | |
|---|
| .. | .. |
|---|
| 333 | 318 | if (error) |
|---|
| 334 | 319 | return error; |
|---|
| 335 | 320 | |
|---|
| 336 | | - error = data->ops->get_pattern(data->client, &data->pattern); |
|---|
| 321 | + error = data->ops->get_report_features(data->client, data->pattern, |
|---|
| 322 | + &data->report_features, |
|---|
| 323 | + &data->report_len); |
|---|
| 337 | 324 | if (error) |
|---|
| 338 | 325 | return error; |
|---|
| 339 | 326 | |
|---|
| 340 | | - if (data->pattern == 0x01) |
|---|
| 341 | | - ic_type = data->ic_type; |
|---|
| 342 | | - else |
|---|
| 343 | | - ic_type = data->iap_version; |
|---|
| 344 | | - |
|---|
| 345 | | - error = elan_get_fwinfo(ic_type, &data->fw_validpage_count, |
|---|
| 346 | | - &data->fw_signature_address); |
|---|
| 327 | + error = elan_get_fwinfo(data->ic_type, data->iap_version, |
|---|
| 328 | + &data->fw_validpage_count, |
|---|
| 329 | + &data->fw_signature_address, |
|---|
| 330 | + &data->fw_page_size); |
|---|
| 347 | 331 | if (error) |
|---|
| 348 | 332 | dev_warn(&data->client->dev, |
|---|
| 349 | 333 | "unexpected iap version %#04x (ic type: %#04x), firmware update will not work\n", |
|---|
| .. | .. |
|---|
| 352 | 336 | return 0; |
|---|
| 353 | 337 | } |
|---|
| 354 | 338 | |
|---|
| 355 | | -static unsigned int elan_convert_resolution(u8 val) |
|---|
| 339 | +static unsigned int elan_convert_resolution(u8 val, u8 pattern) |
|---|
| 356 | 340 | { |
|---|
| 357 | 341 | /* |
|---|
| 358 | | - * (value from firmware) * 10 + 790 = dpi |
|---|
| 359 | | - * |
|---|
| 342 | + * pattern <= 0x01: |
|---|
| 343 | + * (value from firmware) * 10 + 790 = dpi |
|---|
| 344 | + * else |
|---|
| 345 | + * ((value from firmware) + 3) * 100 = dpi |
|---|
| 346 | + */ |
|---|
| 347 | + int res = pattern <= 0x01 ? |
|---|
| 348 | + (int)(char)val * 10 + 790 : ((int)(char)val + 3) * 100; |
|---|
| 349 | + /* |
|---|
| 360 | 350 | * We also have to convert dpi to dots/mm (*10/254 to avoid floating |
|---|
| 361 | 351 | * point). |
|---|
| 362 | 352 | */ |
|---|
| 363 | | - |
|---|
| 364 | | - return ((int)(char)val * 10 + 790) * 10 / 254; |
|---|
| 353 | + return res * 10 / 254; |
|---|
| 365 | 354 | } |
|---|
| 366 | 355 | |
|---|
| 367 | 356 | static int elan_query_device_parameters(struct elan_tp_data *data) |
|---|
| 368 | 357 | { |
|---|
| 358 | + struct i2c_client *client = data->client; |
|---|
| 369 | 359 | unsigned int x_traces, y_traces; |
|---|
| 360 | + u32 x_mm, y_mm; |
|---|
| 370 | 361 | u8 hw_x_res, hw_y_res; |
|---|
| 371 | 362 | int error; |
|---|
| 372 | 363 | |
|---|
| 373 | | - error = data->ops->get_max(data->client, &data->max_x, &data->max_y); |
|---|
| 374 | | - if (error) |
|---|
| 375 | | - return error; |
|---|
| 364 | + if (device_property_read_u32(&client->dev, |
|---|
| 365 | + "touchscreen-size-x", &data->max_x) || |
|---|
| 366 | + device_property_read_u32(&client->dev, |
|---|
| 367 | + "touchscreen-size-y", &data->max_y)) { |
|---|
| 368 | + error = data->ops->get_max(data->client, |
|---|
| 369 | + &data->max_x, |
|---|
| 370 | + &data->max_y); |
|---|
| 371 | + if (error) |
|---|
| 372 | + return error; |
|---|
| 373 | + } else { |
|---|
| 374 | + /* size is the maximum + 1 */ |
|---|
| 375 | + --data->max_x; |
|---|
| 376 | + --data->max_y; |
|---|
| 377 | + } |
|---|
| 376 | 378 | |
|---|
| 377 | | - error = data->ops->get_num_traces(data->client, &x_traces, &y_traces); |
|---|
| 378 | | - if (error) |
|---|
| 379 | | - return error; |
|---|
| 380 | | - |
|---|
| 379 | + if (device_property_read_u32(&client->dev, |
|---|
| 380 | + "elan,x_traces", |
|---|
| 381 | + &x_traces) || |
|---|
| 382 | + device_property_read_u32(&client->dev, |
|---|
| 383 | + "elan,y_traces", |
|---|
| 384 | + &y_traces)) { |
|---|
| 385 | + error = data->ops->get_num_traces(data->client, |
|---|
| 386 | + &x_traces, &y_traces); |
|---|
| 387 | + if (error) |
|---|
| 388 | + return error; |
|---|
| 389 | + } |
|---|
| 381 | 390 | data->width_x = data->max_x / x_traces; |
|---|
| 382 | 391 | data->width_y = data->max_y / y_traces; |
|---|
| 383 | 392 | |
|---|
| 384 | | - error = data->ops->get_resolution(data->client, &hw_x_res, &hw_y_res); |
|---|
| 385 | | - if (error) |
|---|
| 386 | | - return error; |
|---|
| 393 | + if (device_property_read_u32(&client->dev, |
|---|
| 394 | + "touchscreen-x-mm", &x_mm) || |
|---|
| 395 | + device_property_read_u32(&client->dev, |
|---|
| 396 | + "touchscreen-y-mm", &y_mm)) { |
|---|
| 397 | + error = data->ops->get_resolution(data->client, |
|---|
| 398 | + &hw_x_res, &hw_y_res); |
|---|
| 399 | + if (error) |
|---|
| 400 | + return error; |
|---|
| 387 | 401 | |
|---|
| 388 | | - data->x_res = elan_convert_resolution(hw_x_res); |
|---|
| 389 | | - data->y_res = elan_convert_resolution(hw_y_res); |
|---|
| 402 | + data->x_res = elan_convert_resolution(hw_x_res, data->pattern); |
|---|
| 403 | + data->y_res = elan_convert_resolution(hw_y_res, data->pattern); |
|---|
| 404 | + } else { |
|---|
| 405 | + data->x_res = (data->max_x + 1) / x_mm; |
|---|
| 406 | + data->y_res = (data->max_y + 1) / y_mm; |
|---|
| 407 | + } |
|---|
| 408 | + |
|---|
| 409 | + if (device_property_read_bool(&client->dev, "elan,clickpad")) |
|---|
| 410 | + data->clickpad = 1; |
|---|
| 411 | + |
|---|
| 412 | + if (device_property_read_bool(&client->dev, "elan,middle-button")) |
|---|
| 413 | + data->middle_button = true; |
|---|
| 390 | 414 | |
|---|
| 391 | 415 | return 0; |
|---|
| 392 | 416 | } |
|---|
| .. | .. |
|---|
| 396 | 420 | * IAP firmware updater related routines |
|---|
| 397 | 421 | ********************************************************** |
|---|
| 398 | 422 | */ |
|---|
| 399 | | -static int elan_write_fw_block(struct elan_tp_data *data, |
|---|
| 423 | +static int elan_write_fw_block(struct elan_tp_data *data, u16 page_size, |
|---|
| 400 | 424 | const u8 *page, u16 checksum, int idx) |
|---|
| 401 | 425 | { |
|---|
| 402 | 426 | int retry = ETP_RETRY_COUNT; |
|---|
| 403 | 427 | int error; |
|---|
| 404 | 428 | |
|---|
| 405 | 429 | do { |
|---|
| 406 | | - error = data->ops->write_fw_block(data->client, |
|---|
| 430 | + error = data->ops->write_fw_block(data->client, page_size, |
|---|
| 407 | 431 | page, checksum, idx); |
|---|
| 408 | 432 | if (!error) |
|---|
| 409 | 433 | return 0; |
|---|
| .. | .. |
|---|
| 426 | 450 | u16 boot_page_count; |
|---|
| 427 | 451 | u16 sw_checksum = 0, fw_checksum = 0; |
|---|
| 428 | 452 | |
|---|
| 429 | | - error = data->ops->prepare_fw_update(client); |
|---|
| 453 | + error = data->ops->prepare_fw_update(client, data->ic_type, |
|---|
| 454 | + data->iap_version, |
|---|
| 455 | + data->fw_page_size); |
|---|
| 430 | 456 | if (error) |
|---|
| 431 | 457 | return error; |
|---|
| 432 | 458 | |
|---|
| 433 | 459 | iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]); |
|---|
| 434 | 460 | |
|---|
| 435 | | - boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE; |
|---|
| 461 | + boot_page_count = (iap_start_addr * 2) / data->fw_page_size; |
|---|
| 436 | 462 | for (i = boot_page_count; i < data->fw_validpage_count; i++) { |
|---|
| 437 | 463 | u16 checksum = 0; |
|---|
| 438 | | - const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE]; |
|---|
| 464 | + const u8 *page = &fw->data[i * data->fw_page_size]; |
|---|
| 439 | 465 | |
|---|
| 440 | | - for (j = 0; j < ETP_FW_PAGE_SIZE; j += 2) |
|---|
| 466 | + for (j = 0; j < data->fw_page_size; j += 2) |
|---|
| 441 | 467 | checksum += ((page[j + 1] << 8) | page[j]); |
|---|
| 442 | 468 | |
|---|
| 443 | | - error = elan_write_fw_block(data, page, checksum, i); |
|---|
| 469 | + error = elan_write_fw_block(data, data->fw_page_size, |
|---|
| 470 | + page, checksum, i); |
|---|
| 444 | 471 | if (error) { |
|---|
| 445 | 472 | dev_err(dev, "write page %d fail: %d\n", i, error); |
|---|
| 446 | 473 | return error; |
|---|
| .. | .. |
|---|
| 852 | 879 | * Elan isr functions |
|---|
| 853 | 880 | ****************************************************************** |
|---|
| 854 | 881 | */ |
|---|
| 855 | | -static void elan_report_contact(struct elan_tp_data *data, |
|---|
| 856 | | - int contact_num, bool contact_valid, |
|---|
| 857 | | - u8 *finger_data) |
|---|
| 882 | +static void elan_report_contact(struct elan_tp_data *data, int contact_num, |
|---|
| 883 | + bool contact_valid, bool high_precision, |
|---|
| 884 | + u8 *packet, u8 *finger_data) |
|---|
| 858 | 885 | { |
|---|
| 859 | 886 | struct input_dev *input = data->input; |
|---|
| 860 | 887 | unsigned int pos_x, pos_y; |
|---|
| 861 | | - unsigned int pressure, mk_x, mk_y; |
|---|
| 862 | | - unsigned int area_x, area_y, major, minor; |
|---|
| 863 | | - unsigned int scaled_pressure; |
|---|
| 888 | + unsigned int pressure, scaled_pressure; |
|---|
| 864 | 889 | |
|---|
| 865 | 890 | if (contact_valid) { |
|---|
| 866 | | - pos_x = ((finger_data[0] & 0xf0) << 4) | |
|---|
| 867 | | - finger_data[1]; |
|---|
| 868 | | - pos_y = ((finger_data[0] & 0x0f) << 8) | |
|---|
| 869 | | - finger_data[2]; |
|---|
| 870 | | - mk_x = (finger_data[3] & 0x0f); |
|---|
| 871 | | - mk_y = (finger_data[3] >> 4); |
|---|
| 872 | | - pressure = finger_data[4]; |
|---|
| 891 | + if (high_precision) { |
|---|
| 892 | + pos_x = get_unaligned_be16(&finger_data[0]); |
|---|
| 893 | + pos_y = get_unaligned_be16(&finger_data[2]); |
|---|
| 894 | + } else { |
|---|
| 895 | + pos_x = ((finger_data[0] & 0xf0) << 4) | finger_data[1]; |
|---|
| 896 | + pos_y = ((finger_data[0] & 0x0f) << 8) | finger_data[2]; |
|---|
| 897 | + } |
|---|
| 873 | 898 | |
|---|
| 874 | 899 | if (pos_x > data->max_x || pos_y > data->max_y) { |
|---|
| 875 | 900 | dev_dbg(input->dev.parent, |
|---|
| .. | .. |
|---|
| 879 | 904 | return; |
|---|
| 880 | 905 | } |
|---|
| 881 | 906 | |
|---|
| 882 | | - /* |
|---|
| 883 | | - * To avoid treating large finger as palm, let's reduce the |
|---|
| 884 | | - * width x and y per trace. |
|---|
| 885 | | - */ |
|---|
| 886 | | - area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE); |
|---|
| 887 | | - area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE); |
|---|
| 888 | | - |
|---|
| 889 | | - major = max(area_x, area_y); |
|---|
| 890 | | - minor = min(area_x, area_y); |
|---|
| 891 | | - |
|---|
| 907 | + pressure = finger_data[4]; |
|---|
| 892 | 908 | scaled_pressure = pressure + data->pressure_adjustment; |
|---|
| 893 | | - |
|---|
| 894 | 909 | if (scaled_pressure > ETP_MAX_PRESSURE) |
|---|
| 895 | 910 | scaled_pressure = ETP_MAX_PRESSURE; |
|---|
| 896 | 911 | |
|---|
| .. | .. |
|---|
| 899 | 914 | input_report_abs(input, ABS_MT_POSITION_X, pos_x); |
|---|
| 900 | 915 | input_report_abs(input, ABS_MT_POSITION_Y, data->max_y - pos_y); |
|---|
| 901 | 916 | input_report_abs(input, ABS_MT_PRESSURE, scaled_pressure); |
|---|
| 902 | | - input_report_abs(input, ABS_TOOL_WIDTH, mk_x); |
|---|
| 903 | | - input_report_abs(input, ABS_MT_TOUCH_MAJOR, major); |
|---|
| 904 | | - input_report_abs(input, ABS_MT_TOUCH_MINOR, minor); |
|---|
| 917 | + |
|---|
| 918 | + if (data->report_features & ETP_FEATURE_REPORT_MK) { |
|---|
| 919 | + unsigned int mk_x, mk_y, area_x, area_y; |
|---|
| 920 | + u8 mk_data = high_precision ? |
|---|
| 921 | + packet[ETP_MK_DATA_OFFSET + contact_num] : |
|---|
| 922 | + finger_data[3]; |
|---|
| 923 | + |
|---|
| 924 | + mk_x = mk_data & 0x0f; |
|---|
| 925 | + mk_y = mk_data >> 4; |
|---|
| 926 | + |
|---|
| 927 | + /* |
|---|
| 928 | + * To avoid treating large finger as palm, let's reduce |
|---|
| 929 | + * the width x and y per trace. |
|---|
| 930 | + */ |
|---|
| 931 | + area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE); |
|---|
| 932 | + area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE); |
|---|
| 933 | + |
|---|
| 934 | + input_report_abs(input, ABS_TOOL_WIDTH, mk_x); |
|---|
| 935 | + input_report_abs(input, ABS_MT_TOUCH_MAJOR, |
|---|
| 936 | + max(area_x, area_y)); |
|---|
| 937 | + input_report_abs(input, ABS_MT_TOUCH_MINOR, |
|---|
| 938 | + min(area_x, area_y)); |
|---|
| 939 | + } |
|---|
| 905 | 940 | } else { |
|---|
| 906 | 941 | input_mt_slot(input, contact_num); |
|---|
| 907 | | - input_mt_report_slot_state(input, MT_TOOL_FINGER, false); |
|---|
| 942 | + input_mt_report_slot_inactive(input); |
|---|
| 908 | 943 | } |
|---|
| 909 | 944 | } |
|---|
| 910 | 945 | |
|---|
| 911 | | -static void elan_report_absolute(struct elan_tp_data *data, u8 *packet) |
|---|
| 946 | +static void elan_report_absolute(struct elan_tp_data *data, u8 *packet, |
|---|
| 947 | + bool high_precision) |
|---|
| 912 | 948 | { |
|---|
| 913 | 949 | struct input_dev *input = data->input; |
|---|
| 914 | 950 | u8 *finger_data = &packet[ETP_FINGER_DATA_OFFSET]; |
|---|
| .. | .. |
|---|
| 917 | 953 | u8 hover_info = packet[ETP_HOVER_INFO_OFFSET]; |
|---|
| 918 | 954 | bool contact_valid, hover_event; |
|---|
| 919 | 955 | |
|---|
| 920 | | - hover_event = hover_info & 0x40; |
|---|
| 921 | | - for (i = 0; i < ETP_MAX_FINGERS; i++) { |
|---|
| 922 | | - contact_valid = tp_info & (1U << (3 + i)); |
|---|
| 923 | | - elan_report_contact(data, i, contact_valid, finger_data); |
|---|
| 956 | + pm_wakeup_event(&data->client->dev, 0); |
|---|
| 924 | 957 | |
|---|
| 958 | + hover_event = hover_info & BIT(6); |
|---|
| 959 | + |
|---|
| 960 | + for (i = 0; i < ETP_MAX_FINGERS; i++) { |
|---|
| 961 | + contact_valid = tp_info & BIT(3 + i); |
|---|
| 962 | + elan_report_contact(data, i, contact_valid, high_precision, |
|---|
| 963 | + packet, finger_data); |
|---|
| 925 | 964 | if (contact_valid) |
|---|
| 926 | 965 | finger_data += ETP_FINGER_DATA_LEN; |
|---|
| 927 | 966 | } |
|---|
| 928 | 967 | |
|---|
| 929 | | - input_report_key(input, BTN_LEFT, tp_info & 0x01); |
|---|
| 930 | | - input_report_key(input, BTN_RIGHT, tp_info & 0x02); |
|---|
| 968 | + input_report_key(input, BTN_LEFT, tp_info & BIT(0)); |
|---|
| 969 | + input_report_key(input, BTN_MIDDLE, tp_info & BIT(2)); |
|---|
| 970 | + input_report_key(input, BTN_RIGHT, tp_info & BIT(1)); |
|---|
| 931 | 971 | input_report_abs(input, ABS_DISTANCE, hover_event != 0); |
|---|
| 932 | 972 | input_mt_report_pointer_emulation(input, true); |
|---|
| 933 | 973 | input_sync(input); |
|---|
| .. | .. |
|---|
| 938 | 978 | struct input_dev *input = data->tp_input; |
|---|
| 939 | 979 | u8 *packet = &report[ETP_REPORT_ID_OFFSET + 1]; |
|---|
| 940 | 980 | int x, y; |
|---|
| 981 | + |
|---|
| 982 | + pm_wakeup_event(&data->client->dev, 0); |
|---|
| 941 | 983 | |
|---|
| 942 | 984 | if (!data->tp_input) { |
|---|
| 943 | 985 | dev_warn_once(&data->client->dev, |
|---|
| .. | .. |
|---|
| 963 | 1005 | static irqreturn_t elan_isr(int irq, void *dev_id) |
|---|
| 964 | 1006 | { |
|---|
| 965 | 1007 | struct elan_tp_data *data = dev_id; |
|---|
| 966 | | - struct device *dev = &data->client->dev; |
|---|
| 967 | 1008 | int error; |
|---|
| 968 | 1009 | u8 report[ETP_MAX_REPORT_LEN]; |
|---|
| 969 | 1010 | |
|---|
| .. | .. |
|---|
| 977 | 1018 | goto out; |
|---|
| 978 | 1019 | } |
|---|
| 979 | 1020 | |
|---|
| 980 | | - error = data->ops->get_report(data->client, report); |
|---|
| 1021 | + error = data->ops->get_report(data->client, report, data->report_len); |
|---|
| 981 | 1022 | if (error) |
|---|
| 982 | 1023 | goto out; |
|---|
| 983 | 1024 | |
|---|
| 984 | 1025 | switch (report[ETP_REPORT_ID_OFFSET]) { |
|---|
| 985 | 1026 | case ETP_REPORT_ID: |
|---|
| 986 | | - elan_report_absolute(data, report); |
|---|
| 1027 | + elan_report_absolute(data, report, false); |
|---|
| 1028 | + break; |
|---|
| 1029 | + case ETP_REPORT_ID2: |
|---|
| 1030 | + elan_report_absolute(data, report, true); |
|---|
| 987 | 1031 | break; |
|---|
| 988 | 1032 | case ETP_TP_REPORT_ID: |
|---|
| 1033 | + case ETP_TP_REPORT_ID2: |
|---|
| 989 | 1034 | elan_report_trackpoint(data, report); |
|---|
| 990 | 1035 | break; |
|---|
| 991 | 1036 | default: |
|---|
| 992 | | - dev_err(dev, "invalid report id data (%x)\n", |
|---|
| 1037 | + dev_err(&data->client->dev, "invalid report id data (%x)\n", |
|---|
| 993 | 1038 | report[ETP_REPORT_ID_OFFSET]); |
|---|
| 994 | 1039 | } |
|---|
| 995 | 1040 | |
|---|
| .. | .. |
|---|
| 1059 | 1104 | |
|---|
| 1060 | 1105 | __set_bit(EV_ABS, input->evbit); |
|---|
| 1061 | 1106 | __set_bit(INPUT_PROP_POINTER, input->propbit); |
|---|
| 1062 | | - if (data->clickpad) |
|---|
| 1107 | + if (data->clickpad) { |
|---|
| 1063 | 1108 | __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); |
|---|
| 1064 | | - else |
|---|
| 1109 | + } else { |
|---|
| 1065 | 1110 | __set_bit(BTN_RIGHT, input->keybit); |
|---|
| 1111 | + if (data->middle_button) |
|---|
| 1112 | + __set_bit(BTN_MIDDLE, input->keybit); |
|---|
| 1113 | + } |
|---|
| 1066 | 1114 | __set_bit(BTN_LEFT, input->keybit); |
|---|
| 1067 | 1115 | |
|---|
| 1068 | 1116 | /* Set up ST parameters */ |
|---|
| .. | .. |
|---|
| 1071 | 1119 | input_abs_set_res(input, ABS_X, data->x_res); |
|---|
| 1072 | 1120 | input_abs_set_res(input, ABS_Y, data->y_res); |
|---|
| 1073 | 1121 | input_set_abs_params(input, ABS_PRESSURE, 0, ETP_MAX_PRESSURE, 0, 0); |
|---|
| 1074 | | - input_set_abs_params(input, ABS_TOOL_WIDTH, 0, ETP_FINGER_WIDTH, 0, 0); |
|---|
| 1122 | + if (data->report_features & ETP_FEATURE_REPORT_MK) |
|---|
| 1123 | + input_set_abs_params(input, ABS_TOOL_WIDTH, |
|---|
| 1124 | + 0, ETP_FINGER_WIDTH, 0, 0); |
|---|
| 1075 | 1125 | input_set_abs_params(input, ABS_DISTANCE, 0, 1, 0, 0); |
|---|
| 1076 | 1126 | |
|---|
| 1077 | 1127 | /* And MT parameters */ |
|---|
| .. | .. |
|---|
| 1081 | 1131 | input_abs_set_res(input, ABS_MT_POSITION_Y, data->y_res); |
|---|
| 1082 | 1132 | input_set_abs_params(input, ABS_MT_PRESSURE, 0, |
|---|
| 1083 | 1133 | ETP_MAX_PRESSURE, 0, 0); |
|---|
| 1084 | | - input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, |
|---|
| 1085 | | - ETP_FINGER_WIDTH * max_width, 0, 0); |
|---|
| 1086 | | - input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, |
|---|
| 1087 | | - ETP_FINGER_WIDTH * min_width, 0, 0); |
|---|
| 1134 | + if (data->report_features & ETP_FEATURE_REPORT_MK) { |
|---|
| 1135 | + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, |
|---|
| 1136 | + 0, ETP_FINGER_WIDTH * max_width, 0, 0); |
|---|
| 1137 | + input_set_abs_params(input, ABS_MT_TOUCH_MINOR, |
|---|
| 1138 | + 0, ETP_FINGER_WIDTH * min_width, 0, 0); |
|---|
| 1139 | + } |
|---|
| 1088 | 1140 | |
|---|
| 1089 | 1141 | data->input = input; |
|---|
| 1090 | 1142 | |
|---|
| .. | .. |
|---|
| 1096 | 1148 | struct elan_tp_data *data = _data; |
|---|
| 1097 | 1149 | |
|---|
| 1098 | 1150 | regulator_disable(data->vcc); |
|---|
| 1099 | | -} |
|---|
| 1100 | | - |
|---|
| 1101 | | -static void elan_remove_sysfs_groups(void *_data) |
|---|
| 1102 | | -{ |
|---|
| 1103 | | - struct elan_tp_data *data = _data; |
|---|
| 1104 | | - |
|---|
| 1105 | | - sysfs_remove_groups(&data->client->dev.kobj, elan_sysfs_groups); |
|---|
| 1106 | 1151 | } |
|---|
| 1107 | 1152 | |
|---|
| 1108 | 1153 | static int elan_probe(struct i2c_client *client, |
|---|
| .. | .. |
|---|
| 1154 | 1199 | return error; |
|---|
| 1155 | 1200 | } |
|---|
| 1156 | 1201 | |
|---|
| 1157 | | - error = devm_add_action(dev, elan_disable_regulator, data); |
|---|
| 1202 | + error = devm_add_action_or_reset(dev, elan_disable_regulator, data); |
|---|
| 1158 | 1203 | if (error) { |
|---|
| 1159 | | - regulator_disable(data->vcc); |
|---|
| 1160 | 1204 | dev_err(dev, "Failed to add disable regulator action: %d\n", |
|---|
| 1161 | 1205 | error); |
|---|
| 1162 | 1206 | return error; |
|---|
| .. | .. |
|---|
| 1229 | 1273 | return error; |
|---|
| 1230 | 1274 | } |
|---|
| 1231 | 1275 | |
|---|
| 1232 | | - error = sysfs_create_groups(&dev->kobj, elan_sysfs_groups); |
|---|
| 1276 | + error = devm_device_add_groups(dev, elan_sysfs_groups); |
|---|
| 1233 | 1277 | if (error) { |
|---|
| 1234 | 1278 | dev_err(dev, "failed to create sysfs attributes: %d\n", error); |
|---|
| 1235 | | - return error; |
|---|
| 1236 | | - } |
|---|
| 1237 | | - |
|---|
| 1238 | | - error = devm_add_action(dev, elan_remove_sysfs_groups, data); |
|---|
| 1239 | | - if (error) { |
|---|
| 1240 | | - elan_remove_sysfs_groups(data); |
|---|
| 1241 | | - dev_err(dev, "Failed to add sysfs cleanup action: %d\n", |
|---|
| 1242 | | - error); |
|---|
| 1243 | 1279 | return error; |
|---|
| 1244 | 1280 | } |
|---|
| 1245 | 1281 | |
|---|
| .. | .. |
|---|
| 1291 | 1327 | /* Enable wake from IRQ */ |
|---|
| 1292 | 1328 | data->irq_wake = (enable_irq_wake(client->irq) == 0); |
|---|
| 1293 | 1329 | } else { |
|---|
| 1294 | | - ret = elan_disable_power(data); |
|---|
| 1330 | + ret = elan_set_power(data, false); |
|---|
| 1331 | + if (ret) |
|---|
| 1332 | + goto err; |
|---|
| 1333 | + |
|---|
| 1334 | + ret = regulator_disable(data->vcc); |
|---|
| 1335 | + if (ret) { |
|---|
| 1336 | + dev_err(dev, "error %d disabling regulator\n", ret); |
|---|
| 1337 | + /* Attempt to power the chip back up */ |
|---|
| 1338 | + elan_set_power(data, true); |
|---|
| 1339 | + } |
|---|
| 1295 | 1340 | } |
|---|
| 1296 | 1341 | |
|---|
| 1342 | +err: |
|---|
| 1297 | 1343 | mutex_unlock(&data->sysfs_mutex); |
|---|
| 1298 | 1344 | return ret; |
|---|
| 1299 | 1345 | } |
|---|
| .. | .. |
|---|
| 1304 | 1350 | struct elan_tp_data *data = i2c_get_clientdata(client); |
|---|
| 1305 | 1351 | int error; |
|---|
| 1306 | 1352 | |
|---|
| 1307 | | - if (device_may_wakeup(dev) && data->irq_wake) { |
|---|
| 1353 | + if (!device_may_wakeup(dev)) { |
|---|
| 1354 | + error = regulator_enable(data->vcc); |
|---|
| 1355 | + if (error) { |
|---|
| 1356 | + dev_err(dev, "error %d enabling regulator\n", error); |
|---|
| 1357 | + goto err; |
|---|
| 1358 | + } |
|---|
| 1359 | + } else if (data->irq_wake) { |
|---|
| 1308 | 1360 | disable_irq_wake(client->irq); |
|---|
| 1309 | 1361 | data->irq_wake = false; |
|---|
| 1310 | 1362 | } |
|---|
| 1311 | 1363 | |
|---|
| 1312 | | - error = elan_enable_power(data); |
|---|
| 1364 | + error = elan_set_power(data, true); |
|---|
| 1313 | 1365 | if (error) { |
|---|
| 1314 | 1366 | dev_err(dev, "power up when resuming failed: %d\n", error); |
|---|
| 1315 | 1367 | goto err; |
|---|
| .. | .. |
|---|
| 1333 | 1385 | MODULE_DEVICE_TABLE(i2c, elan_id); |
|---|
| 1334 | 1386 | |
|---|
| 1335 | 1387 | #ifdef CONFIG_ACPI |
|---|
| 1336 | | -static const struct acpi_device_id elan_acpi_id[] = { |
|---|
| 1337 | | - { "ELAN0000", 0 }, |
|---|
| 1338 | | - { "ELAN0100", 0 }, |
|---|
| 1339 | | - { "ELAN0600", 0 }, |
|---|
| 1340 | | - { "ELAN0601", 0 }, |
|---|
| 1341 | | - { "ELAN0602", 0 }, |
|---|
| 1342 | | - { "ELAN0603", 0 }, |
|---|
| 1343 | | - { "ELAN0604", 0 }, |
|---|
| 1344 | | - { "ELAN0605", 0 }, |
|---|
| 1345 | | - { "ELAN0606", 0 }, |
|---|
| 1346 | | - { "ELAN0607", 0 }, |
|---|
| 1347 | | - { "ELAN0608", 0 }, |
|---|
| 1348 | | - { "ELAN0609", 0 }, |
|---|
| 1349 | | - { "ELAN060B", 0 }, |
|---|
| 1350 | | - { "ELAN060C", 0 }, |
|---|
| 1351 | | - { "ELAN060F", 0 }, |
|---|
| 1352 | | - { "ELAN0610", 0 }, |
|---|
| 1353 | | - { "ELAN0611", 0 }, |
|---|
| 1354 | | - { "ELAN0612", 0 }, |
|---|
| 1355 | | - { "ELAN0615", 0 }, |
|---|
| 1356 | | - { "ELAN0616", 0 }, |
|---|
| 1357 | | - { "ELAN0617", 0 }, |
|---|
| 1358 | | - { "ELAN0618", 0 }, |
|---|
| 1359 | | - { "ELAN0619", 0 }, |
|---|
| 1360 | | - { "ELAN061A", 0 }, |
|---|
| 1361 | | -/* { "ELAN061B", 0 }, not working on the Lenovo Legion Y7000 */ |
|---|
| 1362 | | - { "ELAN061C", 0 }, |
|---|
| 1363 | | - { "ELAN061D", 0 }, |
|---|
| 1364 | | - { "ELAN061E", 0 }, |
|---|
| 1365 | | - { "ELAN061F", 0 }, |
|---|
| 1366 | | - { "ELAN0620", 0 }, |
|---|
| 1367 | | - { "ELAN0621", 0 }, |
|---|
| 1368 | | - { "ELAN0622", 0 }, |
|---|
| 1369 | | - { "ELAN0623", 0 }, |
|---|
| 1370 | | - { "ELAN0624", 0 }, |
|---|
| 1371 | | - { "ELAN0625", 0 }, |
|---|
| 1372 | | - { "ELAN0626", 0 }, |
|---|
| 1373 | | - { "ELAN0627", 0 }, |
|---|
| 1374 | | - { "ELAN0628", 0 }, |
|---|
| 1375 | | - { "ELAN0629", 0 }, |
|---|
| 1376 | | - { "ELAN062A", 0 }, |
|---|
| 1377 | | - { "ELAN062B", 0 }, |
|---|
| 1378 | | - { "ELAN062C", 0 }, |
|---|
| 1379 | | - { "ELAN062D", 0 }, |
|---|
| 1380 | | - { "ELAN0631", 0 }, |
|---|
| 1381 | | - { "ELAN0632", 0 }, |
|---|
| 1382 | | - { "ELAN1000", 0 }, |
|---|
| 1383 | | - { } |
|---|
| 1384 | | -}; |
|---|
| 1385 | 1388 | MODULE_DEVICE_TABLE(acpi, elan_acpi_id); |
|---|
| 1386 | 1389 | #endif |
|---|
| 1387 | 1390 | |
|---|