.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Elan I2C/SMBus Touchpad driver - I2C interface |
---|
3 | 4 | * |
---|
.. | .. |
---|
9 | 10 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. |
---|
10 | 11 | * copyright (c) 2011-2012 Google, Inc. |
---|
11 | 12 | * |
---|
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 | | - * |
---|
16 | 13 | * Trademarks are the property of their respective owners. |
---|
17 | 14 | */ |
---|
18 | 15 | |
---|
.. | .. |
---|
22 | 19 | #include <linux/interrupt.h> |
---|
23 | 20 | #include <linux/jiffies.h> |
---|
24 | 21 | #include <linux/kernel.h> |
---|
| 22 | +#include <linux/slab.h> |
---|
25 | 23 | #include <linux/sched.h> |
---|
26 | 24 | #include <asm/unaligned.h> |
---|
27 | 25 | |
---|
.. | .. |
---|
46 | 44 | #define ETP_I2C_RESOLUTION_CMD 0x0108 |
---|
47 | 45 | #define ETP_I2C_PRESSURE_CMD 0x010A |
---|
48 | 46 | #define ETP_I2C_IAP_VERSION_CMD 0x0110 |
---|
| 47 | +#define ETP_I2C_IC_TYPE_P0_CMD 0x0110 |
---|
| 48 | +#define ETP_I2C_IAP_VERSION_P0_CMD 0x0111 |
---|
49 | 49 | #define ETP_I2C_SET_CMD 0x0300 |
---|
50 | 50 | #define ETP_I2C_POWER_CMD 0x0307 |
---|
51 | 51 | #define ETP_I2C_FW_CHECKSUM_CMD 0x030F |
---|
.. | .. |
---|
56 | 56 | #define ETP_I2C_CALIBRATE_CMD 0x0316 |
---|
57 | 57 | #define ETP_I2C_MAX_BASELINE_CMD 0x0317 |
---|
58 | 58 | #define ETP_I2C_MIN_BASELINE_CMD 0x0318 |
---|
| 59 | +#define ETP_I2C_IAP_TYPE_REG 0x0040 |
---|
| 60 | +#define ETP_I2C_IAP_TYPE_CMD 0x0304 |
---|
59 | 61 | |
---|
60 | 62 | #define ETP_I2C_REPORT_LEN 34 |
---|
| 63 | +#define ETP_I2C_REPORT_LEN_ID2 39 |
---|
| 64 | +#define ETP_I2C_REPORT_MAX_LEN 39 |
---|
61 | 65 | #define ETP_I2C_DESC_LENGTH 30 |
---|
62 | 66 | #define ETP_I2C_REPORT_DESC_LENGTH 158 |
---|
63 | 67 | #define ETP_I2C_INF_LENGTH 2 |
---|
.. | .. |
---|
252 | 256 | dev_err(&client->dev, "failed to get pattern: %d\n", error); |
---|
253 | 257 | return error; |
---|
254 | 258 | } |
---|
255 | | - *pattern = val[1]; |
---|
| 259 | + |
---|
| 260 | + /* |
---|
| 261 | + * Not all versions of firmware implement "get pattern" command. |
---|
| 262 | + * When this command is not implemented the device will respond |
---|
| 263 | + * with 0xFF 0xFF, which we will treat as "old" pattern 0. |
---|
| 264 | + */ |
---|
| 265 | + *pattern = val[0] == 0xFF && val[1] == 0xFF ? 0 : val[1]; |
---|
256 | 266 | |
---|
257 | 267 | return 0; |
---|
258 | 268 | } |
---|
259 | 269 | |
---|
260 | 270 | static int elan_i2c_get_version(struct i2c_client *client, |
---|
261 | | - bool iap, u8 *version) |
---|
| 271 | + u8 pattern, bool iap, u8 *version) |
---|
262 | 272 | { |
---|
263 | 273 | int error; |
---|
264 | | - u8 pattern_ver; |
---|
| 274 | + u16 cmd; |
---|
265 | 275 | u8 val[3]; |
---|
266 | 276 | |
---|
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 | | - } |
---|
| 277 | + if (!iap) |
---|
| 278 | + cmd = ETP_I2C_FW_VERSION_CMD; |
---|
| 279 | + else if (pattern == 0) |
---|
| 280 | + cmd = ETP_I2C_IAP_VERSION_P0_CMD; |
---|
| 281 | + else |
---|
| 282 | + cmd = ETP_I2C_IAP_VERSION_CMD; |
---|
272 | 283 | |
---|
273 | | - error = elan_i2c_read_cmd(client, |
---|
274 | | - iap ? ETP_I2C_IAP_VERSION_CMD : |
---|
275 | | - ETP_I2C_FW_VERSION_CMD, |
---|
276 | | - val); |
---|
| 284 | + error = elan_i2c_read_cmd(client, cmd, val); |
---|
277 | 285 | if (error) { |
---|
278 | 286 | dev_err(&client->dev, "failed to get %s version: %d\n", |
---|
279 | 287 | iap ? "IAP" : "FW", error); |
---|
280 | 288 | return error; |
---|
281 | 289 | } |
---|
282 | 290 | |
---|
283 | | - if (pattern_ver == 0x01) |
---|
| 291 | + if (pattern >= 0x01) |
---|
284 | 292 | *version = iap ? val[1] : val[0]; |
---|
285 | 293 | else |
---|
286 | 294 | *version = val[0]; |
---|
287 | 295 | return 0; |
---|
288 | 296 | } |
---|
289 | 297 | |
---|
290 | | -static int elan_i2c_get_sm_version(struct i2c_client *client, |
---|
291 | | - u16 *ic_type, u8 *version, |
---|
292 | | - u8 *clickpad) |
---|
| 298 | +static int elan_i2c_get_sm_version(struct i2c_client *client, u8 pattern, |
---|
| 299 | + u16 *ic_type, u8 *version, u8 *clickpad) |
---|
293 | 300 | { |
---|
294 | 301 | int error; |
---|
295 | | - u8 pattern_ver; |
---|
296 | 302 | u8 val[3]; |
---|
297 | 303 | |
---|
298 | | - error = elan_i2c_get_pattern(client, &pattern_ver); |
---|
299 | | - if (error) { |
---|
300 | | - dev_err(&client->dev, "failed to get pattern version\n"); |
---|
301 | | - return error; |
---|
302 | | - } |
---|
303 | | - |
---|
304 | | - if (pattern_ver == 0x01) { |
---|
| 304 | + if (pattern >= 0x01) { |
---|
305 | 305 | error = elan_i2c_read_cmd(client, ETP_I2C_IC_TYPE_CMD, val); |
---|
306 | 306 | if (error) { |
---|
307 | 307 | dev_err(&client->dev, "failed to get ic type: %d\n", |
---|
.. | .. |
---|
327 | 327 | return error; |
---|
328 | 328 | } |
---|
329 | 329 | *version = val[0]; |
---|
330 | | - *ic_type = val[1]; |
---|
| 330 | + |
---|
| 331 | + error = elan_i2c_read_cmd(client, ETP_I2C_IC_TYPE_P0_CMD, val); |
---|
| 332 | + if (error) { |
---|
| 333 | + dev_err(&client->dev, "failed to get ic type: %d\n", |
---|
| 334 | + error); |
---|
| 335 | + return error; |
---|
| 336 | + } |
---|
| 337 | + *ic_type = val[0]; |
---|
331 | 338 | |
---|
332 | 339 | error = elan_i2c_read_cmd(client, ETP_I2C_NSM_VERSION_CMD, |
---|
333 | 340 | val); |
---|
.. | .. |
---|
389 | 396 | return error; |
---|
390 | 397 | } |
---|
391 | 398 | |
---|
392 | | - *max_x = le16_to_cpup((__le16 *)val) & 0x0fff; |
---|
| 399 | + *max_x = le16_to_cpup((__le16 *)val); |
---|
393 | 400 | |
---|
394 | 401 | error = elan_i2c_read_cmd(client, ETP_I2C_MAX_Y_AXIS_CMD, val); |
---|
395 | 402 | if (error) { |
---|
.. | .. |
---|
397 | 404 | return error; |
---|
398 | 405 | } |
---|
399 | 406 | |
---|
400 | | - *max_y = le16_to_cpup((__le16 *)val) & 0x0fff; |
---|
| 407 | + *max_y = le16_to_cpup((__le16 *)val); |
---|
401 | 408 | |
---|
402 | 409 | return 0; |
---|
403 | 410 | } |
---|
.. | .. |
---|
510 | 517 | return 0; |
---|
511 | 518 | } |
---|
512 | 519 | |
---|
513 | | -static int elan_i2c_prepare_fw_update(struct i2c_client *client) |
---|
| 520 | +static int elan_read_write_iap_type(struct i2c_client *client, u16 fw_page_size) |
---|
| 521 | +{ |
---|
| 522 | + int error; |
---|
| 523 | + u16 constant; |
---|
| 524 | + u8 val[3]; |
---|
| 525 | + int retry = 3; |
---|
| 526 | + |
---|
| 527 | + do { |
---|
| 528 | + error = elan_i2c_write_cmd(client, ETP_I2C_IAP_TYPE_CMD, |
---|
| 529 | + fw_page_size / 2); |
---|
| 530 | + if (error) { |
---|
| 531 | + dev_err(&client->dev, |
---|
| 532 | + "cannot write iap type: %d\n", error); |
---|
| 533 | + return error; |
---|
| 534 | + } |
---|
| 535 | + |
---|
| 536 | + error = elan_i2c_read_cmd(client, ETP_I2C_IAP_TYPE_CMD, val); |
---|
| 537 | + if (error) { |
---|
| 538 | + dev_err(&client->dev, |
---|
| 539 | + "failed to read iap type register: %d\n", |
---|
| 540 | + error); |
---|
| 541 | + return error; |
---|
| 542 | + } |
---|
| 543 | + constant = le16_to_cpup((__le16 *)val); |
---|
| 544 | + dev_dbg(&client->dev, "iap type reg: 0x%04x\n", constant); |
---|
| 545 | + |
---|
| 546 | + if (constant == fw_page_size / 2) |
---|
| 547 | + return 0; |
---|
| 548 | + |
---|
| 549 | + } while (--retry > 0); |
---|
| 550 | + |
---|
| 551 | + dev_err(&client->dev, "cannot set iap type\n"); |
---|
| 552 | + return -EIO; |
---|
| 553 | +} |
---|
| 554 | + |
---|
| 555 | +static int elan_i2c_prepare_fw_update(struct i2c_client *client, u16 ic_type, |
---|
| 556 | + u8 iap_version, u16 fw_page_size) |
---|
514 | 557 | { |
---|
515 | 558 | struct device *dev = &client->dev; |
---|
516 | 559 | int error; |
---|
.. | .. |
---|
550 | 593 | return -EIO; |
---|
551 | 594 | } |
---|
552 | 595 | |
---|
| 596 | + if (ic_type >= 0x0D && iap_version >= 1) { |
---|
| 597 | + error = elan_read_write_iap_type(client, fw_page_size); |
---|
| 598 | + if (error) |
---|
| 599 | + return error; |
---|
| 600 | + } |
---|
| 601 | + |
---|
553 | 602 | /* Set flash key again */ |
---|
554 | 603 | error = elan_i2c_set_flash_key(client); |
---|
555 | 604 | if (error) |
---|
.. | .. |
---|
575 | 624 | return 0; |
---|
576 | 625 | } |
---|
577 | 626 | |
---|
578 | | -static int elan_i2c_write_fw_block(struct i2c_client *client, |
---|
| 627 | +static int elan_i2c_write_fw_block(struct i2c_client *client, u16 fw_page_size, |
---|
579 | 628 | const u8 *page, u16 checksum, int idx) |
---|
580 | 629 | { |
---|
581 | 630 | struct device *dev = &client->dev; |
---|
582 | | - u8 page_store[ETP_FW_PAGE_SIZE + 4]; |
---|
| 631 | + u8 *page_store; |
---|
583 | 632 | u8 val[3]; |
---|
584 | 633 | u16 result; |
---|
585 | 634 | int ret, error; |
---|
586 | 635 | |
---|
| 636 | + page_store = kmalloc(fw_page_size + 4, GFP_KERNEL); |
---|
| 637 | + if (!page_store) |
---|
| 638 | + return -ENOMEM; |
---|
| 639 | + |
---|
587 | 640 | page_store[0] = ETP_I2C_IAP_REG_L; |
---|
588 | 641 | page_store[1] = ETP_I2C_IAP_REG_H; |
---|
589 | | - memcpy(&page_store[2], page, ETP_FW_PAGE_SIZE); |
---|
| 642 | + memcpy(&page_store[2], page, fw_page_size); |
---|
590 | 643 | /* recode checksum at last two bytes */ |
---|
591 | | - put_unaligned_le16(checksum, &page_store[ETP_FW_PAGE_SIZE + 2]); |
---|
| 644 | + put_unaligned_le16(checksum, &page_store[fw_page_size + 2]); |
---|
592 | 645 | |
---|
593 | | - ret = i2c_master_send(client, page_store, sizeof(page_store)); |
---|
594 | | - if (ret != sizeof(page_store)) { |
---|
| 646 | + ret = i2c_master_send(client, page_store, fw_page_size + 4); |
---|
| 647 | + if (ret != fw_page_size + 4) { |
---|
595 | 648 | error = ret < 0 ? ret : -EIO; |
---|
596 | 649 | dev_err(dev, "Failed to write page %d: %d\n", idx, error); |
---|
597 | | - return error; |
---|
| 650 | + goto exit; |
---|
598 | 651 | } |
---|
599 | 652 | |
---|
600 | 653 | /* Wait for F/W to update one page ROM data. */ |
---|
601 | | - msleep(35); |
---|
| 654 | + msleep(fw_page_size == ETP_FW_PAGE_SIZE_512 ? 50 : 35); |
---|
602 | 655 | |
---|
603 | 656 | error = elan_i2c_read_cmd(client, ETP_I2C_IAP_CTRL_CMD, val); |
---|
604 | 657 | if (error) { |
---|
605 | 658 | dev_err(dev, "Failed to read IAP write result: %d\n", error); |
---|
606 | | - return error; |
---|
| 659 | + goto exit; |
---|
607 | 660 | } |
---|
608 | 661 | |
---|
609 | 662 | result = le16_to_cpup((__le16 *)val); |
---|
610 | 663 | if (result & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR)) { |
---|
611 | 664 | dev_err(dev, "IAP reports failed write: %04hx\n", |
---|
612 | 665 | result); |
---|
613 | | - return -EIO; |
---|
| 666 | + error = -EIO; |
---|
| 667 | + goto exit; |
---|
614 | 668 | } |
---|
615 | 669 | |
---|
616 | | - return 0; |
---|
| 670 | +exit: |
---|
| 671 | + kfree(page_store); |
---|
| 672 | + return error; |
---|
617 | 673 | } |
---|
618 | 674 | |
---|
619 | 675 | static int elan_i2c_finish_fw_update(struct i2c_client *client, |
---|
620 | 676 | struct completion *completion) |
---|
621 | 677 | { |
---|
622 | 678 | struct device *dev = &client->dev; |
---|
623 | | - int error; |
---|
| 679 | + int error = 0; |
---|
624 | 680 | int len; |
---|
625 | | - u8 buffer[ETP_I2C_REPORT_LEN]; |
---|
| 681 | + u8 buffer[ETP_I2C_REPORT_MAX_LEN]; |
---|
626 | 682 | |
---|
627 | | - len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_LEN); |
---|
628 | | - if (len != ETP_I2C_REPORT_LEN) { |
---|
| 683 | + len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_MAX_LEN); |
---|
| 684 | + if (len <= 0) { |
---|
629 | 685 | error = len < 0 ? len : -EIO; |
---|
630 | 686 | dev_warn(dev, "failed to read I2C data after FW WDT reset: %d (%d)\n", |
---|
631 | 687 | error, len); |
---|
.. | .. |
---|
659 | 715 | return 0; |
---|
660 | 716 | } |
---|
661 | 717 | |
---|
662 | | -static int elan_i2c_get_report(struct i2c_client *client, u8 *report) |
---|
| 718 | +static int elan_i2c_get_report_features(struct i2c_client *client, u8 pattern, |
---|
| 719 | + unsigned int *features, |
---|
| 720 | + unsigned int *report_len) |
---|
| 721 | +{ |
---|
| 722 | + *features = ETP_FEATURE_REPORT_MK; |
---|
| 723 | + *report_len = pattern <= 0x01 ? |
---|
| 724 | + ETP_I2C_REPORT_LEN : ETP_I2C_REPORT_LEN_ID2; |
---|
| 725 | + return 0; |
---|
| 726 | +} |
---|
| 727 | + |
---|
| 728 | +static int elan_i2c_get_report(struct i2c_client *client, |
---|
| 729 | + u8 *report, unsigned int report_len) |
---|
663 | 730 | { |
---|
664 | 731 | int len; |
---|
665 | 732 | |
---|
666 | | - len = i2c_master_recv(client, report, ETP_I2C_REPORT_LEN); |
---|
| 733 | + len = i2c_master_recv(client, report, report_len); |
---|
667 | 734 | if (len < 0) { |
---|
668 | 735 | dev_err(&client->dev, "failed to read report data: %d\n", len); |
---|
669 | 736 | return len; |
---|
670 | 737 | } |
---|
671 | 738 | |
---|
672 | | - if (len != ETP_I2C_REPORT_LEN) { |
---|
| 739 | + if (len != report_len) { |
---|
673 | 740 | dev_err(&client->dev, |
---|
674 | 741 | "wrong report length (%d vs %d expected)\n", |
---|
675 | | - len, ETP_I2C_REPORT_LEN); |
---|
| 742 | + len, report_len); |
---|
676 | 743 | return -EIO; |
---|
677 | 744 | } |
---|
678 | 745 | |
---|
.. | .. |
---|
709 | 776 | |
---|
710 | 777 | .get_pattern = elan_i2c_get_pattern, |
---|
711 | 778 | |
---|
| 779 | + .get_report_features = elan_i2c_get_report_features, |
---|
712 | 780 | .get_report = elan_i2c_get_report, |
---|
713 | 781 | }; |
---|