| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Elan I2C/SMBus Touchpad driver - SMBus interface |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 8 | 9 | * Based on cyapa driver: |
|---|
| 9 | 10 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. |
|---|
| 10 | 11 | * copyright (c) 2011-2012 Google, Inc. |
|---|
| 11 | | - * |
|---|
| 12 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 13 | | - * under the terms of the GNU General Public License version 2 as published |
|---|
| 14 | | - * by the Free Software Foundation. |
|---|
| 15 | 12 | * |
|---|
| 16 | 13 | * Trademarks are the property of their respective owners. |
|---|
| 17 | 14 | */ |
|---|
| .. | .. |
|---|
| 48 | 45 | #define ETP_SMBUS_CALIBRATE_QUERY 0xC5 |
|---|
| 49 | 46 | |
|---|
| 50 | 47 | #define ETP_SMBUS_REPORT_LEN 32 |
|---|
| 48 | +#define ETP_SMBUS_REPORT_LEN2 7 |
|---|
| 51 | 49 | #define ETP_SMBUS_REPORT_OFFSET 2 |
|---|
| 52 | 50 | #define ETP_SMBUS_HELLOPACKET_LEN 5 |
|---|
| 53 | 51 | #define ETP_SMBUS_IAP_PASSWORD 0x1234 |
|---|
| .. | .. |
|---|
| 150 | 148 | } |
|---|
| 151 | 149 | |
|---|
| 152 | 150 | static int elan_smbus_get_version(struct i2c_client *client, |
|---|
| 153 | | - bool iap, u8 *version) |
|---|
| 151 | + u8 pattern, bool iap, u8 *version) |
|---|
| 154 | 152 | { |
|---|
| 155 | 153 | int error; |
|---|
| 156 | 154 | u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; |
|---|
| .. | .. |
|---|
| 169 | 167 | return 0; |
|---|
| 170 | 168 | } |
|---|
| 171 | 169 | |
|---|
| 172 | | -static int elan_smbus_get_sm_version(struct i2c_client *client, |
|---|
| 173 | | - u16 *ic_type, u8 *version, |
|---|
| 174 | | - u8 *clickpad) |
|---|
| 170 | +static int elan_smbus_get_sm_version(struct i2c_client *client, u8 pattern, |
|---|
| 171 | + u16 *ic_type, u8 *version, u8 *clickpad) |
|---|
| 175 | 172 | { |
|---|
| 176 | 173 | int error; |
|---|
| 177 | 174 | u8 val[I2C_SMBUS_BLOCK_MAX] = {0}; |
|---|
| .. | .. |
|---|
| 343 | 340 | return 0; |
|---|
| 344 | 341 | } |
|---|
| 345 | 342 | |
|---|
| 346 | | -static int elan_smbus_prepare_fw_update(struct i2c_client *client) |
|---|
| 343 | +static int elan_smbus_prepare_fw_update(struct i2c_client *client, u16 ic_type, |
|---|
| 344 | + u8 iap_version, u16 fw_page_size) |
|---|
| 347 | 345 | { |
|---|
| 348 | 346 | struct device *dev = &client->dev; |
|---|
| 349 | 347 | int len; |
|---|
| .. | .. |
|---|
| 417 | 415 | } |
|---|
| 418 | 416 | |
|---|
| 419 | 417 | |
|---|
| 420 | | -static int elan_smbus_write_fw_block(struct i2c_client *client, |
|---|
| 418 | +static int elan_smbus_write_fw_block(struct i2c_client *client, u16 fw_page_size, |
|---|
| 421 | 419 | const u8 *page, u16 checksum, int idx) |
|---|
| 422 | 420 | { |
|---|
| 423 | 421 | struct device *dev = &client->dev; |
|---|
| .. | .. |
|---|
| 432 | 430 | */ |
|---|
| 433 | 431 | error = i2c_smbus_write_block_data(client, |
|---|
| 434 | 432 | ETP_SMBUS_WRITE_FW_BLOCK, |
|---|
| 435 | | - ETP_FW_PAGE_SIZE / 2, |
|---|
| 433 | + fw_page_size / 2, |
|---|
| 436 | 434 | page); |
|---|
| 437 | 435 | if (error) { |
|---|
| 438 | 436 | dev_err(dev, "Failed to write page %d (part %d): %d\n", |
|---|
| .. | .. |
|---|
| 442 | 440 | |
|---|
| 443 | 441 | error = i2c_smbus_write_block_data(client, |
|---|
| 444 | 442 | ETP_SMBUS_WRITE_FW_BLOCK, |
|---|
| 445 | | - ETP_FW_PAGE_SIZE / 2, |
|---|
| 446 | | - page + ETP_FW_PAGE_SIZE / 2); |
|---|
| 443 | + fw_page_size / 2, |
|---|
| 444 | + page + fw_page_size / 2); |
|---|
| 447 | 445 | if (error) { |
|---|
| 448 | 446 | dev_err(dev, "Failed to write page %d (part %d): %d\n", |
|---|
| 449 | 447 | idx, 2, error); |
|---|
| .. | .. |
|---|
| 472 | 470 | return 0; |
|---|
| 473 | 471 | } |
|---|
| 474 | 472 | |
|---|
| 475 | | -static int elan_smbus_get_report(struct i2c_client *client, u8 *report) |
|---|
| 473 | +static int elan_smbus_get_report_features(struct i2c_client *client, u8 pattern, |
|---|
| 474 | + unsigned int *features, |
|---|
| 475 | + unsigned int *report_len) |
|---|
| 476 | +{ |
|---|
| 477 | + /* |
|---|
| 478 | + * SMBus controllers with pattern 2 lack area info, as newer |
|---|
| 479 | + * high-precision packets use that space for coordinates. |
|---|
| 480 | + */ |
|---|
| 481 | + *features = pattern <= 0x01 ? ETP_FEATURE_REPORT_MK : 0; |
|---|
| 482 | + *report_len = ETP_SMBUS_REPORT_LEN; |
|---|
| 483 | + return 0; |
|---|
| 484 | +} |
|---|
| 485 | + |
|---|
| 486 | +static int elan_smbus_get_report(struct i2c_client *client, |
|---|
| 487 | + u8 *report, unsigned int report_len) |
|---|
| 476 | 488 | { |
|---|
| 477 | 489 | int len; |
|---|
| 478 | 490 | |
|---|
| .. | .. |
|---|
| 486 | 498 | return len; |
|---|
| 487 | 499 | } |
|---|
| 488 | 500 | |
|---|
| 489 | | - if (len != ETP_SMBUS_REPORT_LEN) { |
|---|
| 501 | + if (report[ETP_REPORT_ID_OFFSET] == ETP_TP_REPORT_ID2) |
|---|
| 502 | + report_len = ETP_SMBUS_REPORT_LEN2; |
|---|
| 503 | + |
|---|
| 504 | + if (len != report_len) { |
|---|
| 490 | 505 | dev_err(&client->dev, |
|---|
| 491 | 506 | "wrong report length (%d vs %d expected)\n", |
|---|
| 492 | | - len, ETP_SMBUS_REPORT_LEN); |
|---|
| 507 | + len, report_len); |
|---|
| 493 | 508 | return -EIO; |
|---|
| 494 | 509 | } |
|---|
| 495 | 510 | |
|---|
| .. | .. |
|---|
| 537 | 552 | .write_fw_block = elan_smbus_write_fw_block, |
|---|
| 538 | 553 | .finish_fw_update = elan_smbus_finish_fw_update, |
|---|
| 539 | 554 | |
|---|
| 555 | + .get_report_features = elan_smbus_get_report_features, |
|---|
| 540 | 556 | .get_report = elan_smbus_get_report, |
|---|
| 541 | 557 | .get_pattern = elan_smbus_get_pattern, |
|---|
| 542 | 558 | }; |
|---|