18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Elan I2C/SMBus Touchpad driver - I2C interface 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2013 ELAN Microelectronics Corp. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw> 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Based on cyapa driver: 108c2ecf20Sopenharmony_ci * copyright (c) 2011-2012 Cypress Semiconductor, Inc. 118c2ecf20Sopenharmony_ci * copyright (c) 2011-2012 Google, Inc. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Trademarks are the property of their respective owners. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/completion.h> 178c2ecf20Sopenharmony_ci#include <linux/delay.h> 188c2ecf20Sopenharmony_ci#include <linux/i2c.h> 198c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 208c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 218c2ecf20Sopenharmony_ci#include <linux/kernel.h> 228c2ecf20Sopenharmony_ci#include <linux/slab.h> 238c2ecf20Sopenharmony_ci#include <linux/sched.h> 248c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include "elan_i2c.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* Elan i2c commands */ 298c2ecf20Sopenharmony_ci#define ETP_I2C_RESET 0x0100 308c2ecf20Sopenharmony_ci#define ETP_I2C_WAKE_UP 0x0800 318c2ecf20Sopenharmony_ci#define ETP_I2C_SLEEP 0x0801 328c2ecf20Sopenharmony_ci#define ETP_I2C_DESC_CMD 0x0001 338c2ecf20Sopenharmony_ci#define ETP_I2C_REPORT_DESC_CMD 0x0002 348c2ecf20Sopenharmony_ci#define ETP_I2C_STAND_CMD 0x0005 358c2ecf20Sopenharmony_ci#define ETP_I2C_PATTERN_CMD 0x0100 368c2ecf20Sopenharmony_ci#define ETP_I2C_UNIQUEID_CMD 0x0101 378c2ecf20Sopenharmony_ci#define ETP_I2C_FW_VERSION_CMD 0x0102 388c2ecf20Sopenharmony_ci#define ETP_I2C_IC_TYPE_CMD 0x0103 398c2ecf20Sopenharmony_ci#define ETP_I2C_OSM_VERSION_CMD 0x0103 408c2ecf20Sopenharmony_ci#define ETP_I2C_NSM_VERSION_CMD 0x0104 418c2ecf20Sopenharmony_ci#define ETP_I2C_XY_TRACENUM_CMD 0x0105 428c2ecf20Sopenharmony_ci#define ETP_I2C_MAX_X_AXIS_CMD 0x0106 438c2ecf20Sopenharmony_ci#define ETP_I2C_MAX_Y_AXIS_CMD 0x0107 448c2ecf20Sopenharmony_ci#define ETP_I2C_RESOLUTION_CMD 0x0108 458c2ecf20Sopenharmony_ci#define ETP_I2C_PRESSURE_CMD 0x010A 468c2ecf20Sopenharmony_ci#define ETP_I2C_IAP_VERSION_CMD 0x0110 478c2ecf20Sopenharmony_ci#define ETP_I2C_IC_TYPE_P0_CMD 0x0110 488c2ecf20Sopenharmony_ci#define ETP_I2C_IAP_VERSION_P0_CMD 0x0111 498c2ecf20Sopenharmony_ci#define ETP_I2C_SET_CMD 0x0300 508c2ecf20Sopenharmony_ci#define ETP_I2C_POWER_CMD 0x0307 518c2ecf20Sopenharmony_ci#define ETP_I2C_FW_CHECKSUM_CMD 0x030F 528c2ecf20Sopenharmony_ci#define ETP_I2C_IAP_CTRL_CMD 0x0310 538c2ecf20Sopenharmony_ci#define ETP_I2C_IAP_CMD 0x0311 548c2ecf20Sopenharmony_ci#define ETP_I2C_IAP_RESET_CMD 0x0314 558c2ecf20Sopenharmony_ci#define ETP_I2C_IAP_CHECKSUM_CMD 0x0315 568c2ecf20Sopenharmony_ci#define ETP_I2C_CALIBRATE_CMD 0x0316 578c2ecf20Sopenharmony_ci#define ETP_I2C_MAX_BASELINE_CMD 0x0317 588c2ecf20Sopenharmony_ci#define ETP_I2C_MIN_BASELINE_CMD 0x0318 598c2ecf20Sopenharmony_ci#define ETP_I2C_IAP_TYPE_REG 0x0040 608c2ecf20Sopenharmony_ci#define ETP_I2C_IAP_TYPE_CMD 0x0304 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define ETP_I2C_REPORT_LEN 34 638c2ecf20Sopenharmony_ci#define ETP_I2C_REPORT_LEN_ID2 39 648c2ecf20Sopenharmony_ci#define ETP_I2C_REPORT_MAX_LEN 39 658c2ecf20Sopenharmony_ci#define ETP_I2C_DESC_LENGTH 30 668c2ecf20Sopenharmony_ci#define ETP_I2C_REPORT_DESC_LENGTH 158 678c2ecf20Sopenharmony_ci#define ETP_I2C_INF_LENGTH 2 688c2ecf20Sopenharmony_ci#define ETP_I2C_IAP_PASSWORD 0x1EA5 698c2ecf20Sopenharmony_ci#define ETP_I2C_IAP_RESET 0xF0F0 708c2ecf20Sopenharmony_ci#define ETP_I2C_MAIN_MODE_ON (1 << 9) 718c2ecf20Sopenharmony_ci#define ETP_I2C_IAP_REG_L 0x01 728c2ecf20Sopenharmony_ci#define ETP_I2C_IAP_REG_H 0x06 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int elan_i2c_read_block(struct i2c_client *client, 758c2ecf20Sopenharmony_ci u16 reg, u8 *val, u16 len) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci __le16 buf[] = { 788c2ecf20Sopenharmony_ci cpu_to_le16(reg), 798c2ecf20Sopenharmony_ci }; 808c2ecf20Sopenharmony_ci struct i2c_msg msgs[] = { 818c2ecf20Sopenharmony_ci { 828c2ecf20Sopenharmony_ci .addr = client->addr, 838c2ecf20Sopenharmony_ci .flags = client->flags & I2C_M_TEN, 848c2ecf20Sopenharmony_ci .len = sizeof(buf), 858c2ecf20Sopenharmony_ci .buf = (u8 *)buf, 868c2ecf20Sopenharmony_ci }, 878c2ecf20Sopenharmony_ci { 888c2ecf20Sopenharmony_ci .addr = client->addr, 898c2ecf20Sopenharmony_ci .flags = (client->flags & I2C_M_TEN) | I2C_M_RD, 908c2ecf20Sopenharmony_ci .len = len, 918c2ecf20Sopenharmony_ci .buf = val, 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci }; 948c2ecf20Sopenharmony_ci int ret; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 978c2ecf20Sopenharmony_ci return ret == ARRAY_SIZE(msgs) ? 0 : (ret < 0 ? ret : -EIO); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int elan_i2c_read_cmd(struct i2c_client *client, u16 reg, u8 *val) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci int retval; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci retval = elan_i2c_read_block(client, reg, val, ETP_I2C_INF_LENGTH); 1058c2ecf20Sopenharmony_ci if (retval < 0) { 1068c2ecf20Sopenharmony_ci dev_err(&client->dev, "reading cmd (0x%04x) fail.\n", reg); 1078c2ecf20Sopenharmony_ci return retval; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci return 0; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic int elan_i2c_write_cmd(struct i2c_client *client, u16 reg, u16 cmd) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci __le16 buf[] = { 1168c2ecf20Sopenharmony_ci cpu_to_le16(reg), 1178c2ecf20Sopenharmony_ci cpu_to_le16(cmd), 1188c2ecf20Sopenharmony_ci }; 1198c2ecf20Sopenharmony_ci struct i2c_msg msg = { 1208c2ecf20Sopenharmony_ci .addr = client->addr, 1218c2ecf20Sopenharmony_ci .flags = client->flags & I2C_M_TEN, 1228c2ecf20Sopenharmony_ci .len = sizeof(buf), 1238c2ecf20Sopenharmony_ci .buf = (u8 *)buf, 1248c2ecf20Sopenharmony_ci }; 1258c2ecf20Sopenharmony_ci int ret; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, &msg, 1); 1288c2ecf20Sopenharmony_ci if (ret != 1) { 1298c2ecf20Sopenharmony_ci if (ret >= 0) 1308c2ecf20Sopenharmony_ci ret = -EIO; 1318c2ecf20Sopenharmony_ci dev_err(&client->dev, "writing cmd (0x%04x) failed: %d\n", 1328c2ecf20Sopenharmony_ci reg, ret); 1338c2ecf20Sopenharmony_ci return ret; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistatic int elan_i2c_initialize(struct i2c_client *client) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 1428c2ecf20Sopenharmony_ci int error; 1438c2ecf20Sopenharmony_ci u8 val[256]; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci error = elan_i2c_write_cmd(client, ETP_I2C_STAND_CMD, ETP_I2C_RESET); 1468c2ecf20Sopenharmony_ci if (error) { 1478c2ecf20Sopenharmony_ci dev_err(dev, "device reset failed: %d\n", error); 1488c2ecf20Sopenharmony_ci return error; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* Wait for the device to reset */ 1528c2ecf20Sopenharmony_ci msleep(100); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* get reset acknowledgement 0000 */ 1558c2ecf20Sopenharmony_ci error = i2c_master_recv(client, val, ETP_I2C_INF_LENGTH); 1568c2ecf20Sopenharmony_ci if (error < 0) { 1578c2ecf20Sopenharmony_ci dev_err(dev, "failed to read reset response: %d\n", error); 1588c2ecf20Sopenharmony_ci return error; 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci error = elan_i2c_read_block(client, ETP_I2C_DESC_CMD, 1628c2ecf20Sopenharmony_ci val, ETP_I2C_DESC_LENGTH); 1638c2ecf20Sopenharmony_ci if (error) { 1648c2ecf20Sopenharmony_ci dev_err(dev, "cannot get device descriptor: %d\n", error); 1658c2ecf20Sopenharmony_ci return error; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci error = elan_i2c_read_block(client, ETP_I2C_REPORT_DESC_CMD, 1698c2ecf20Sopenharmony_ci val, ETP_I2C_REPORT_DESC_LENGTH); 1708c2ecf20Sopenharmony_ci if (error) { 1718c2ecf20Sopenharmony_ci dev_err(dev, "fetching report descriptor failed.: %d\n", error); 1728c2ecf20Sopenharmony_ci return error; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci return 0; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic int elan_i2c_sleep_control(struct i2c_client *client, bool sleep) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci return elan_i2c_write_cmd(client, ETP_I2C_STAND_CMD, 1818c2ecf20Sopenharmony_ci sleep ? ETP_I2C_SLEEP : ETP_I2C_WAKE_UP); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int elan_i2c_power_control(struct i2c_client *client, bool enable) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci u8 val[2]; 1878c2ecf20Sopenharmony_ci u16 reg; 1888c2ecf20Sopenharmony_ci int error; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_POWER_CMD, val); 1918c2ecf20Sopenharmony_ci if (error) { 1928c2ecf20Sopenharmony_ci dev_err(&client->dev, 1938c2ecf20Sopenharmony_ci "failed to read current power state: %d\n", 1948c2ecf20Sopenharmony_ci error); 1958c2ecf20Sopenharmony_ci return error; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci reg = le16_to_cpup((__le16 *)val); 1998c2ecf20Sopenharmony_ci if (enable) 2008c2ecf20Sopenharmony_ci reg &= ~ETP_DISABLE_POWER; 2018c2ecf20Sopenharmony_ci else 2028c2ecf20Sopenharmony_ci reg |= ETP_DISABLE_POWER; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci error = elan_i2c_write_cmd(client, ETP_I2C_POWER_CMD, reg); 2058c2ecf20Sopenharmony_ci if (error) { 2068c2ecf20Sopenharmony_ci dev_err(&client->dev, 2078c2ecf20Sopenharmony_ci "failed to write current power state: %d\n", 2088c2ecf20Sopenharmony_ci error); 2098c2ecf20Sopenharmony_ci return error; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci return 0; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic int elan_i2c_set_mode(struct i2c_client *client, u8 mode) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci return elan_i2c_write_cmd(client, ETP_I2C_SET_CMD, mode); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic int elan_i2c_calibrate(struct i2c_client *client) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci return elan_i2c_write_cmd(client, ETP_I2C_CALIBRATE_CMD, 1); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic int elan_i2c_calibrate_result(struct i2c_client *client, u8 *val) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci return elan_i2c_read_block(client, ETP_I2C_CALIBRATE_CMD, val, 1); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int elan_i2c_get_baseline_data(struct i2c_client *client, 2328c2ecf20Sopenharmony_ci bool max_baseline, u8 *value) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci int error; 2358c2ecf20Sopenharmony_ci u8 val[3]; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, 2388c2ecf20Sopenharmony_ci max_baseline ? ETP_I2C_MAX_BASELINE_CMD : 2398c2ecf20Sopenharmony_ci ETP_I2C_MIN_BASELINE_CMD, 2408c2ecf20Sopenharmony_ci val); 2418c2ecf20Sopenharmony_ci if (error) 2428c2ecf20Sopenharmony_ci return error; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci *value = le16_to_cpup((__le16 *)val); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return 0; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int elan_i2c_get_pattern(struct i2c_client *client, u8 *pattern) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci int error; 2528c2ecf20Sopenharmony_ci u8 val[3]; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_PATTERN_CMD, val); 2558c2ecf20Sopenharmony_ci if (error) { 2568c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to get pattern: %d\n", error); 2578c2ecf20Sopenharmony_ci return error; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* 2618c2ecf20Sopenharmony_ci * Not all versions of firmware implement "get pattern" command. 2628c2ecf20Sopenharmony_ci * When this command is not implemented the device will respond 2638c2ecf20Sopenharmony_ci * with 0xFF 0xFF, which we will treat as "old" pattern 0. 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_ci *pattern = val[0] == 0xFF && val[1] == 0xFF ? 0 : val[1]; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return 0; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic int elan_i2c_get_version(struct i2c_client *client, 2718c2ecf20Sopenharmony_ci u8 pattern, bool iap, u8 *version) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci int error; 2748c2ecf20Sopenharmony_ci u16 cmd; 2758c2ecf20Sopenharmony_ci u8 val[3]; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (!iap) 2788c2ecf20Sopenharmony_ci cmd = ETP_I2C_FW_VERSION_CMD; 2798c2ecf20Sopenharmony_ci else if (pattern == 0) 2808c2ecf20Sopenharmony_ci cmd = ETP_I2C_IAP_VERSION_P0_CMD; 2818c2ecf20Sopenharmony_ci else 2828c2ecf20Sopenharmony_ci cmd = ETP_I2C_IAP_VERSION_CMD; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, cmd, val); 2858c2ecf20Sopenharmony_ci if (error) { 2868c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to get %s version: %d\n", 2878c2ecf20Sopenharmony_ci iap ? "IAP" : "FW", error); 2888c2ecf20Sopenharmony_ci return error; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (pattern >= 0x01) 2928c2ecf20Sopenharmony_ci *version = iap ? val[1] : val[0]; 2938c2ecf20Sopenharmony_ci else 2948c2ecf20Sopenharmony_ci *version = val[0]; 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic int elan_i2c_get_sm_version(struct i2c_client *client, u8 pattern, 2998c2ecf20Sopenharmony_ci u16 *ic_type, u8 *version, u8 *clickpad) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci int error; 3028c2ecf20Sopenharmony_ci u8 val[3]; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (pattern >= 0x01) { 3058c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_IC_TYPE_CMD, val); 3068c2ecf20Sopenharmony_ci if (error) { 3078c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to get ic type: %d\n", 3088c2ecf20Sopenharmony_ci error); 3098c2ecf20Sopenharmony_ci return error; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci *ic_type = be16_to_cpup((__be16 *)val); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_NSM_VERSION_CMD, 3148c2ecf20Sopenharmony_ci val); 3158c2ecf20Sopenharmony_ci if (error) { 3168c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to get SM version: %d\n", 3178c2ecf20Sopenharmony_ci error); 3188c2ecf20Sopenharmony_ci return error; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci *version = val[1]; 3218c2ecf20Sopenharmony_ci *clickpad = val[0] & 0x10; 3228c2ecf20Sopenharmony_ci } else { 3238c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_OSM_VERSION_CMD, val); 3248c2ecf20Sopenharmony_ci if (error) { 3258c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to get SM version: %d\n", 3268c2ecf20Sopenharmony_ci error); 3278c2ecf20Sopenharmony_ci return error; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci *version = val[0]; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_IC_TYPE_P0_CMD, val); 3328c2ecf20Sopenharmony_ci if (error) { 3338c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to get ic type: %d\n", 3348c2ecf20Sopenharmony_ci error); 3358c2ecf20Sopenharmony_ci return error; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci *ic_type = val[0]; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_NSM_VERSION_CMD, 3408c2ecf20Sopenharmony_ci val); 3418c2ecf20Sopenharmony_ci if (error) { 3428c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to get SM version: %d\n", 3438c2ecf20Sopenharmony_ci error); 3448c2ecf20Sopenharmony_ci return error; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci *clickpad = val[0] & 0x10; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci return 0; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic int elan_i2c_get_product_id(struct i2c_client *client, u16 *id) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci int error; 3558c2ecf20Sopenharmony_ci u8 val[3]; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_UNIQUEID_CMD, val); 3588c2ecf20Sopenharmony_ci if (error) { 3598c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to get product ID: %d\n", error); 3608c2ecf20Sopenharmony_ci return error; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci *id = le16_to_cpup((__le16 *)val); 3648c2ecf20Sopenharmony_ci return 0; 3658c2ecf20Sopenharmony_ci} 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_cistatic int elan_i2c_get_checksum(struct i2c_client *client, 3688c2ecf20Sopenharmony_ci bool iap, u16 *csum) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci int error; 3718c2ecf20Sopenharmony_ci u8 val[3]; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, 3748c2ecf20Sopenharmony_ci iap ? ETP_I2C_IAP_CHECKSUM_CMD : 3758c2ecf20Sopenharmony_ci ETP_I2C_FW_CHECKSUM_CMD, 3768c2ecf20Sopenharmony_ci val); 3778c2ecf20Sopenharmony_ci if (error) { 3788c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to get %s checksum: %d\n", 3798c2ecf20Sopenharmony_ci iap ? "IAP" : "FW", error); 3808c2ecf20Sopenharmony_ci return error; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci *csum = le16_to_cpup((__le16 *)val); 3848c2ecf20Sopenharmony_ci return 0; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic int elan_i2c_get_max(struct i2c_client *client, 3888c2ecf20Sopenharmony_ci unsigned int *max_x, unsigned int *max_y) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci int error; 3918c2ecf20Sopenharmony_ci u8 val[3]; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_MAX_X_AXIS_CMD, val); 3948c2ecf20Sopenharmony_ci if (error) { 3958c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to get X dimension: %d\n", error); 3968c2ecf20Sopenharmony_ci return error; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci *max_x = le16_to_cpup((__le16 *)val); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_MAX_Y_AXIS_CMD, val); 4028c2ecf20Sopenharmony_ci if (error) { 4038c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to get Y dimension: %d\n", error); 4048c2ecf20Sopenharmony_ci return error; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci *max_y = le16_to_cpup((__le16 *)val); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci return 0; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic int elan_i2c_get_resolution(struct i2c_client *client, 4138c2ecf20Sopenharmony_ci u8 *hw_res_x, u8 *hw_res_y) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci int error; 4168c2ecf20Sopenharmony_ci u8 val[3]; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_RESOLUTION_CMD, val); 4198c2ecf20Sopenharmony_ci if (error) { 4208c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to get resolution: %d\n", error); 4218c2ecf20Sopenharmony_ci return error; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci *hw_res_x = val[0]; 4258c2ecf20Sopenharmony_ci *hw_res_y = val[1]; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return 0; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int elan_i2c_get_num_traces(struct i2c_client *client, 4318c2ecf20Sopenharmony_ci unsigned int *x_traces, 4328c2ecf20Sopenharmony_ci unsigned int *y_traces) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci int error; 4358c2ecf20Sopenharmony_ci u8 val[3]; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_XY_TRACENUM_CMD, val); 4388c2ecf20Sopenharmony_ci if (error) { 4398c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to get trace info: %d\n", error); 4408c2ecf20Sopenharmony_ci return error; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci *x_traces = val[0]; 4448c2ecf20Sopenharmony_ci *y_traces = val[1]; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci return 0; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic int elan_i2c_get_pressure_adjustment(struct i2c_client *client, 4508c2ecf20Sopenharmony_ci int *adjustment) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci int error; 4538c2ecf20Sopenharmony_ci u8 val[3]; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_PRESSURE_CMD, val); 4568c2ecf20Sopenharmony_ci if (error) { 4578c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to get pressure format: %d\n", 4588c2ecf20Sopenharmony_ci error); 4598c2ecf20Sopenharmony_ci return error; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if ((val[0] >> 4) & 0x1) 4638c2ecf20Sopenharmony_ci *adjustment = 0; 4648c2ecf20Sopenharmony_ci else 4658c2ecf20Sopenharmony_ci *adjustment = ETP_PRESSURE_OFFSET; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci return 0; 4688c2ecf20Sopenharmony_ci} 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic int elan_i2c_iap_get_mode(struct i2c_client *client, enum tp_mode *mode) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci int error; 4738c2ecf20Sopenharmony_ci u16 constant; 4748c2ecf20Sopenharmony_ci u8 val[3]; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_IAP_CTRL_CMD, val); 4778c2ecf20Sopenharmony_ci if (error) { 4788c2ecf20Sopenharmony_ci dev_err(&client->dev, 4798c2ecf20Sopenharmony_ci "failed to read iap control register: %d\n", 4808c2ecf20Sopenharmony_ci error); 4818c2ecf20Sopenharmony_ci return error; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci constant = le16_to_cpup((__le16 *)val); 4858c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "iap control reg: 0x%04x.\n", constant); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci *mode = (constant & ETP_I2C_MAIN_MODE_ON) ? MAIN_MODE : IAP_MODE; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci return 0; 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic int elan_i2c_iap_reset(struct i2c_client *client) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci int error; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci error = elan_i2c_write_cmd(client, ETP_I2C_IAP_RESET_CMD, 4978c2ecf20Sopenharmony_ci ETP_I2C_IAP_RESET); 4988c2ecf20Sopenharmony_ci if (error) { 4998c2ecf20Sopenharmony_ci dev_err(&client->dev, "cannot reset IC: %d\n", error); 5008c2ecf20Sopenharmony_ci return error; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci return 0; 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic int elan_i2c_set_flash_key(struct i2c_client *client) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci int error; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci error = elan_i2c_write_cmd(client, ETP_I2C_IAP_CMD, 5118c2ecf20Sopenharmony_ci ETP_I2C_IAP_PASSWORD); 5128c2ecf20Sopenharmony_ci if (error) { 5138c2ecf20Sopenharmony_ci dev_err(&client->dev, "cannot set flash key: %d\n", error); 5148c2ecf20Sopenharmony_ci return error; 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci return 0; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic int elan_read_write_iap_type(struct i2c_client *client, u16 fw_page_size) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci int error; 5238c2ecf20Sopenharmony_ci u16 constant; 5248c2ecf20Sopenharmony_ci u8 val[3]; 5258c2ecf20Sopenharmony_ci int retry = 3; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci do { 5288c2ecf20Sopenharmony_ci error = elan_i2c_write_cmd(client, ETP_I2C_IAP_TYPE_CMD, 5298c2ecf20Sopenharmony_ci fw_page_size / 2); 5308c2ecf20Sopenharmony_ci if (error) { 5318c2ecf20Sopenharmony_ci dev_err(&client->dev, 5328c2ecf20Sopenharmony_ci "cannot write iap type: %d\n", error); 5338c2ecf20Sopenharmony_ci return error; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_IAP_TYPE_CMD, val); 5378c2ecf20Sopenharmony_ci if (error) { 5388c2ecf20Sopenharmony_ci dev_err(&client->dev, 5398c2ecf20Sopenharmony_ci "failed to read iap type register: %d\n", 5408c2ecf20Sopenharmony_ci error); 5418c2ecf20Sopenharmony_ci return error; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci constant = le16_to_cpup((__le16 *)val); 5448c2ecf20Sopenharmony_ci dev_dbg(&client->dev, "iap type reg: 0x%04x\n", constant); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (constant == fw_page_size / 2) 5478c2ecf20Sopenharmony_ci return 0; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci } while (--retry > 0); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci dev_err(&client->dev, "cannot set iap type\n"); 5528c2ecf20Sopenharmony_ci return -EIO; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic int elan_i2c_prepare_fw_update(struct i2c_client *client, u16 ic_type, 5568c2ecf20Sopenharmony_ci u8 iap_version, u16 fw_page_size) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 5598c2ecf20Sopenharmony_ci int error; 5608c2ecf20Sopenharmony_ci enum tp_mode mode; 5618c2ecf20Sopenharmony_ci u8 val[3]; 5628c2ecf20Sopenharmony_ci u16 password; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* Get FW in which mode (IAP_MODE/MAIN_MODE) */ 5658c2ecf20Sopenharmony_ci error = elan_i2c_iap_get_mode(client, &mode); 5668c2ecf20Sopenharmony_ci if (error) 5678c2ecf20Sopenharmony_ci return error; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (mode == IAP_MODE) { 5708c2ecf20Sopenharmony_ci /* Reset IC */ 5718c2ecf20Sopenharmony_ci error = elan_i2c_iap_reset(client); 5728c2ecf20Sopenharmony_ci if (error) 5738c2ecf20Sopenharmony_ci return error; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci msleep(30); 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* Set flash key*/ 5798c2ecf20Sopenharmony_ci error = elan_i2c_set_flash_key(client); 5808c2ecf20Sopenharmony_ci if (error) 5818c2ecf20Sopenharmony_ci return error; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* Wait for F/W IAP initialization */ 5848c2ecf20Sopenharmony_ci msleep(mode == MAIN_MODE ? 100 : 30); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* Check if we are in IAP mode or not */ 5878c2ecf20Sopenharmony_ci error = elan_i2c_iap_get_mode(client, &mode); 5888c2ecf20Sopenharmony_ci if (error) 5898c2ecf20Sopenharmony_ci return error; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci if (mode == MAIN_MODE) { 5928c2ecf20Sopenharmony_ci dev_err(dev, "wrong mode: %d\n", mode); 5938c2ecf20Sopenharmony_ci return -EIO; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (ic_type >= 0x0D && iap_version >= 1) { 5978c2ecf20Sopenharmony_ci error = elan_read_write_iap_type(client, fw_page_size); 5988c2ecf20Sopenharmony_ci if (error) 5998c2ecf20Sopenharmony_ci return error; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci /* Set flash key again */ 6038c2ecf20Sopenharmony_ci error = elan_i2c_set_flash_key(client); 6048c2ecf20Sopenharmony_ci if (error) 6058c2ecf20Sopenharmony_ci return error; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci /* Wait for F/W IAP initialization */ 6088c2ecf20Sopenharmony_ci msleep(30); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* read back to check we actually enabled successfully. */ 6118c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_IAP_CMD, val); 6128c2ecf20Sopenharmony_ci if (error) { 6138c2ecf20Sopenharmony_ci dev_err(dev, "cannot read iap password: %d\n", 6148c2ecf20Sopenharmony_ci error); 6158c2ecf20Sopenharmony_ci return error; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci password = le16_to_cpup((__le16 *)val); 6198c2ecf20Sopenharmony_ci if (password != ETP_I2C_IAP_PASSWORD) { 6208c2ecf20Sopenharmony_ci dev_err(dev, "wrong iap password: 0x%X\n", password); 6218c2ecf20Sopenharmony_ci return -EIO; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci return 0; 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_cistatic int elan_i2c_write_fw_block(struct i2c_client *client, u16 fw_page_size, 6288c2ecf20Sopenharmony_ci const u8 *page, u16 checksum, int idx) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 6318c2ecf20Sopenharmony_ci u8 *page_store; 6328c2ecf20Sopenharmony_ci u8 val[3]; 6338c2ecf20Sopenharmony_ci u16 result; 6348c2ecf20Sopenharmony_ci int ret, error; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci page_store = kmalloc(fw_page_size + 4, GFP_KERNEL); 6378c2ecf20Sopenharmony_ci if (!page_store) 6388c2ecf20Sopenharmony_ci return -ENOMEM; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci page_store[0] = ETP_I2C_IAP_REG_L; 6418c2ecf20Sopenharmony_ci page_store[1] = ETP_I2C_IAP_REG_H; 6428c2ecf20Sopenharmony_ci memcpy(&page_store[2], page, fw_page_size); 6438c2ecf20Sopenharmony_ci /* recode checksum at last two bytes */ 6448c2ecf20Sopenharmony_ci put_unaligned_le16(checksum, &page_store[fw_page_size + 2]); 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci ret = i2c_master_send(client, page_store, fw_page_size + 4); 6478c2ecf20Sopenharmony_ci if (ret != fw_page_size + 4) { 6488c2ecf20Sopenharmony_ci error = ret < 0 ? ret : -EIO; 6498c2ecf20Sopenharmony_ci dev_err(dev, "Failed to write page %d: %d\n", idx, error); 6508c2ecf20Sopenharmony_ci goto exit; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci /* Wait for F/W to update one page ROM data. */ 6548c2ecf20Sopenharmony_ci msleep(fw_page_size == ETP_FW_PAGE_SIZE_512 ? 50 : 35); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci error = elan_i2c_read_cmd(client, ETP_I2C_IAP_CTRL_CMD, val); 6578c2ecf20Sopenharmony_ci if (error) { 6588c2ecf20Sopenharmony_ci dev_err(dev, "Failed to read IAP write result: %d\n", error); 6598c2ecf20Sopenharmony_ci goto exit; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci result = le16_to_cpup((__le16 *)val); 6638c2ecf20Sopenharmony_ci if (result & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR)) { 6648c2ecf20Sopenharmony_ci dev_err(dev, "IAP reports failed write: %04hx\n", 6658c2ecf20Sopenharmony_ci result); 6668c2ecf20Sopenharmony_ci error = -EIO; 6678c2ecf20Sopenharmony_ci goto exit; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ciexit: 6718c2ecf20Sopenharmony_ci kfree(page_store); 6728c2ecf20Sopenharmony_ci return error; 6738c2ecf20Sopenharmony_ci} 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistatic int elan_i2c_finish_fw_update(struct i2c_client *client, 6768c2ecf20Sopenharmony_ci struct completion *completion) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 6798c2ecf20Sopenharmony_ci int error = 0; 6808c2ecf20Sopenharmony_ci int len; 6818c2ecf20Sopenharmony_ci u8 buffer[ETP_I2C_REPORT_MAX_LEN]; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_MAX_LEN); 6848c2ecf20Sopenharmony_ci if (len <= 0) { 6858c2ecf20Sopenharmony_ci error = len < 0 ? len : -EIO; 6868c2ecf20Sopenharmony_ci dev_warn(dev, "failed to read I2C data after FW WDT reset: %d (%d)\n", 6878c2ecf20Sopenharmony_ci error, len); 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci reinit_completion(completion); 6918c2ecf20Sopenharmony_ci enable_irq(client->irq); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci error = elan_i2c_write_cmd(client, ETP_I2C_STAND_CMD, ETP_I2C_RESET); 6948c2ecf20Sopenharmony_ci if (error) { 6958c2ecf20Sopenharmony_ci dev_err(dev, "device reset failed: %d\n", error); 6968c2ecf20Sopenharmony_ci } else if (!wait_for_completion_timeout(completion, 6978c2ecf20Sopenharmony_ci msecs_to_jiffies(300))) { 6988c2ecf20Sopenharmony_ci dev_err(dev, "timeout waiting for device reset\n"); 6998c2ecf20Sopenharmony_ci error = -ETIMEDOUT; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci disable_irq(client->irq); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci if (error) 7058c2ecf20Sopenharmony_ci return error; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci len = i2c_master_recv(client, buffer, ETP_I2C_INF_LENGTH); 7088c2ecf20Sopenharmony_ci if (len != ETP_I2C_INF_LENGTH) { 7098c2ecf20Sopenharmony_ci error = len < 0 ? len : -EIO; 7108c2ecf20Sopenharmony_ci dev_err(dev, "failed to read INT signal: %d (%d)\n", 7118c2ecf20Sopenharmony_ci error, len); 7128c2ecf20Sopenharmony_ci return error; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci return 0; 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_cistatic int elan_i2c_get_report_features(struct i2c_client *client, u8 pattern, 7198c2ecf20Sopenharmony_ci unsigned int *features, 7208c2ecf20Sopenharmony_ci unsigned int *report_len) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci *features = ETP_FEATURE_REPORT_MK; 7238c2ecf20Sopenharmony_ci *report_len = pattern <= 0x01 ? 7248c2ecf20Sopenharmony_ci ETP_I2C_REPORT_LEN : ETP_I2C_REPORT_LEN_ID2; 7258c2ecf20Sopenharmony_ci return 0; 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_cistatic int elan_i2c_get_report(struct i2c_client *client, 7298c2ecf20Sopenharmony_ci u8 *report, unsigned int report_len) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci int len; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci len = i2c_master_recv(client, report, report_len); 7348c2ecf20Sopenharmony_ci if (len < 0) { 7358c2ecf20Sopenharmony_ci dev_err(&client->dev, "failed to read report data: %d\n", len); 7368c2ecf20Sopenharmony_ci return len; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (len != report_len) { 7408c2ecf20Sopenharmony_ci dev_err(&client->dev, 7418c2ecf20Sopenharmony_ci "wrong report length (%d vs %d expected)\n", 7428c2ecf20Sopenharmony_ci len, report_len); 7438c2ecf20Sopenharmony_ci return -EIO; 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return 0; 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ciconst struct elan_transport_ops elan_i2c_ops = { 7508c2ecf20Sopenharmony_ci .initialize = elan_i2c_initialize, 7518c2ecf20Sopenharmony_ci .sleep_control = elan_i2c_sleep_control, 7528c2ecf20Sopenharmony_ci .power_control = elan_i2c_power_control, 7538c2ecf20Sopenharmony_ci .set_mode = elan_i2c_set_mode, 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci .calibrate = elan_i2c_calibrate, 7568c2ecf20Sopenharmony_ci .calibrate_result = elan_i2c_calibrate_result, 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci .get_baseline_data = elan_i2c_get_baseline_data, 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci .get_version = elan_i2c_get_version, 7618c2ecf20Sopenharmony_ci .get_sm_version = elan_i2c_get_sm_version, 7628c2ecf20Sopenharmony_ci .get_product_id = elan_i2c_get_product_id, 7638c2ecf20Sopenharmony_ci .get_checksum = elan_i2c_get_checksum, 7648c2ecf20Sopenharmony_ci .get_pressure_adjustment = elan_i2c_get_pressure_adjustment, 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci .get_max = elan_i2c_get_max, 7678c2ecf20Sopenharmony_ci .get_resolution = elan_i2c_get_resolution, 7688c2ecf20Sopenharmony_ci .get_num_traces = elan_i2c_get_num_traces, 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci .iap_get_mode = elan_i2c_iap_get_mode, 7718c2ecf20Sopenharmony_ci .iap_reset = elan_i2c_iap_reset, 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci .prepare_fw_update = elan_i2c_prepare_fw_update, 7748c2ecf20Sopenharmony_ci .write_fw_block = elan_i2c_write_fw_block, 7758c2ecf20Sopenharmony_ci .finish_fw_update = elan_i2c_finish_fw_update, 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci .get_pattern = elan_i2c_get_pattern, 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci .get_report_features = elan_i2c_get_report_features, 7808c2ecf20Sopenharmony_ci .get_report = elan_i2c_get_report, 7818c2ecf20Sopenharmony_ci}; 782